我正在使用Notepad ++来完成我目前的大部分编码工作。但是,我想改变它的图标,只是为了定制而已。
所以我做的是用Resource Hacker打开.exe,看看图标在哪里。它们似乎是位图格式,这很奇怪,因为它们具有透明性,并且用我知道的任何“位图”(BM
标题,“Windows位图”)格式替换它们不起作用(图标不是'显示)。
所以我想问一下,这些文件的格式是什么,以及如何制作它们?
位图示例可在Notepad++ repository中找到:
newFile http://sourceforge.net/p/notepad-plus/code/735/tree/trunk/PowerEditor/src/icons/newFile.bmp?format=raw
openFile http://sourceforge.net/p/notepad-plus/code/735/tree/trunk/PowerEditor/src/icons/openFile.bmp?format=raw
saveFile http://sourceforge.net/p/notepad-plus/code/735/tree/trunk/PowerEditor/src/icons/saveFile.bmp?format=raw
saveAll http://sourceforge.net/p/notepad-plus/code/735/tree/trunk/PowerEditor/src/icons/saveAll.bmp?format=raw
closeFile http://sourceforge.net/p/notepad-plus/code/735/tree/trunk/PowerEditor/src/icons/closeFile.bmp?format=raw
closeAll http://sourceforge.net/p/notepad-plus/code/735/tree/trunk/PowerEditor/src/icons/closeAll.bmp?format=raw
正如您所看到的,它们具有灰色遮罩,这使我认为Alpha通道以某种非标准方式存储在格式中。 (或者,它具有二进制透明度,#C0C0C0
表示透明)。
它也相当大,每个像素表示超过5个字节(!)。
这就是上面第一个位图的标题:
有什么想法吗?只知道这是什么格式就足够了。
答案 0 :(得分:3)
这是8BPP(每像素8位)索引位图。在“BM”之后,有一个52字节的标题,256色的调色板和索引的像素数据。每种颜色都是4字节,采用BGR_格式(不使用第四个字节;如果是alpha通道,则会看到FF而不是00)。
索引像素数据从0x436开始。这很简单:一个字节代表调色板中的一个索引。例如,前几个字节是07 07 18 18. 0x07将使该像素使用调色板中的第8种颜色,即#C0C0C0;并且0x18将使该像素使用调色板中的第25种颜色,即#CECECE。
我猜测透明度是按照你的猜测来处理的。无论透明像素在哪里,我都会看到07,调色板中相应的颜色是#C0C0C0。
请注意,像素数据是颠倒存储的。也就是说,偏移量0x436处的前16个字节代表 bottom 像素行。
这里有更详细的解释:http://en.wikipedia.org/wiki/BMP_file_format#File_structure
编辑:至于如何制作它们,只需询问您喜欢的图像编辑软件,将图像导出为256色位图(或8BPP位图,无论哪个可用)。请注意,如果在绘制后保存颜色,Microsoft Paint将会破坏颜色,因此在实际绘制任何内容之前保存它。
答案 1 :(得分:0)
Jeff指出的所有内容都是正确的,并将继续作为公认的答案。但是,如果其他人可能想要调整NP ++,我已经制作了一个小转换器,您可以使用它将任何8位索引位图转换为可以与NP ++一起使用的位图(通过资源黑客或类似方法)。
它是用Javascript编写的,只在Chrome上测试过,代码非常草率:JsFiddle
要使用它,请在您喜欢的程序中创建一个8位16x16索引位图,然后将其拖放到该内容中。它将输出一些调试细节并为您提供一个链接,以便您可以下载"兼容的位图(但所有这些都发生在HTML5的客户端)。
编辑:SO抱怨我在没有发布相关代码的情况下给JsFiddle添加了一个链接,好吧,我发布它。这是完全自包含的HTML:
<!DOCTYPE html>
<html>
<head>
<title>Endoblast</title>
<style>
html { background: #F8F8F8; }
#drop-zone {
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 0;
border: 4px dashed #DDD;
z-index: -1;
}
#result { font: 12px Consolas; padding-bottom: 240px; }
.color { margin-right: -7px; position: relative; cursor: default; }
.color > .top, .color > .bottom { position: absolute; left: 0; right: 0; height: 2px; }
.color > .top { position: absolute; top: 0; background: rgba(255, 255, 255, 0.2); }
.color > .bottom { position: absolute; bottom: 0; background: rgba( 0, 0, 0, 0.05); }
</style>
</head>
<body>
<div id="drop-zone"></div>
<p id="result"></p>
<script>
if (window.File && window.FileReader && window.FileList && window.Blob) {
function Readr(bytes) {
var data = bytes;
var offset = 0;
this.nextStr = function(amount) {
var result = []
while (amount--) result.push(data[offset++]);
return toStr(result);
}
this.nextInt = function(amount) {
if (amount == 1 || !amount) return data[offset++];
if (amount == 2) return toInt16(data[offset++], data[offset++]);
if (amount == 4) return toInt32(data[offset++], data[offset++], data[offset++], data[offset++]);
return next(amount);
}
var next = this.next = function(amount) {
var result = []
while (amount--) result.push(data[offset++]);
return result;
}
}
function Color(r, g, b) {
this.r = r;
this.g = g;
this.b = b;
}
function toStr(bytes) {
var result = '';
for (var i = 0; i < bytes.length; i++) result += String.fromCharCode(bytes[i]);
return result;
}
function toInt16(b1, b2) { return (b1 << 0) + (b2 << 8); }
function toInt32(b1, b2, b3, b4) { return (b1 << 0) + (b2 << 8) + (b3 << 16) + (b4 << 24); }
function fromInt16(int16) {
return [
int16 & parseInt('00FF', 16),
(int16 & parseInt('FF00', 16)) >> 8
];
}
function fromInt32(int32) {
return [
int32 & parseInt('000000FF', 16),
(int32 & parseInt('0000FF00', 16)) >> 8,
(int32 & parseInt('00FF0000', 16)) >> 16,
(int32 & parseInt('FF000000', 16)) >> 24
];
}
function log(text) { document.getElementById('result').innerHTML += text + '\n<br/>'; }
function logHtml(html) { document.getElementById('result').innerHTML += html + '<br/>'; }
var bitCounts = {
'1': '1-bit',
'2': '2-bit',
'4': '4-bit',
'8': '8-bit',
'16': '16-bit',
'24': '24-bit',
'32': '32-bit'
};
var compressions = {
'0': 'RGB (uncompressed)'
};
function handleFileSelect(evt) {
evt.stopPropagation();
evt.preventDefault();
var files = evt.dataTransfer.files; // FileList object.
var reader = new FileReader();
reader.onload = function (event) {
var b = [].slice.call(new Uint8Array(event.target.result));
var r = new Readr(b);
if (r.nextStr(2) == 'BM')
log('BM header found.');
else
return log('File is not a BMP.');
var fileSize = r.nextInt(4);
log('File size: ' + fileSize + ' Bytes.');
var reserved = r.next(4)
var offset = r.nextInt(4);
log('Image data offset: ' + offset + ' Bytes.');
log('Image data size: ' + (fileSize - offset) + ' Bytes.');
var headerSize = r.nextInt(4);
log('DIB header size: ' + headerSize + ' Bytes.');
var header = r.next(headerSize - 4);
var hr = new Readr(header);
var width = hr.nextInt(4);
var height = hr.nextInt(4);
log('Image width: ' + width + 'px.');
log('Image height: ' + height + 'px.');
var planes = hr.nextInt(2);
log('Color planes: ' + planes + '.');
var bitCount = bitCounts[hr.nextInt(2)] || 'unknown';
var compression = compressions[hr.nextInt(4)] || 'unknown';
log('Bit depth: ' + bitCount + '.');
log('Compression: ' + compression + '.');
var pixelCount = hr.nextInt(4);
log('Pixel count: ' + pixelCount + '.');
var yPPM = hr.nextInt(4);
var xPPM = hr.nextInt(4);
var colorTableSize = hr.nextInt(4);
log('Color table size: ' + colorTableSize + '.');
var importantColors = hr.nextInt(4);
log('Important colors in color table: ' + importantColors + '.');
var colorTable = r.next(colorTableSize * 4);
var cr = new Readr(colorTable);
var colors = [];
for (var i = 0; i < colorTableSize; i++) {
var B = cr.nextInt(),
G = cr.nextInt(),
R = cr.nextInt(),
_ = cr.nextInt();
colors.push(new Color(R, G, B));
}
function createColorCell(r, g, b, desc) {
var title = 'title="' + desc + ': rgb(' + r + ', ' + g + ', ' + b + ')"'
return '<span class="color" ' + title + ' style="background:rgb(' + r + ',' + g + ',' + b + ')">'
+ '<span class="top"></span><span class="bottom"></span> </span> ';
}
var cells = '';
for (var i = 0; i < colors.length; i++) {
var c = colors[i];
cells += createColorCell(c.r, c.g, c.b, 'Color at index ' + i + ' in the color table');
}
if (colorTableSize) logHtml('Colors in the color table: ' + cells); else return log('No color table.');
log('Bitmap data, mapped to the color table is shown below.');
var bitmapCells = '';
var bitmapRows = [];
var indexes = [];
for (var y = height; y > 0; y--) {
for (var x = 0; x < width; x++) {
var index = r.nextInt();
indexes.push(index);
var color = colors[index];
var desc = 'Pixel x' + x + ', y' + y + ', mapped to index ' + index + ' in the color table, '
+ 'which has colors rgb(' + color.r + ', ' + color.g + ', ' + color.g + ')';
bitmapCells += createColorCell(color.r, color.g, color.b, desc);
}
bitmapRows.push(bitmapCells);
bitmapCells = '';
}
for (var row = height - 1; row > -1; row--) {
logHtml(bitmapRows[row]);
}
var fixedData = new ArrayBuffer(1334);
var fixed = new Uint8Array(fixedData);
var fixedOffset = 0;
function s8(b) { fixed[fixedOffset++] = b; }
function s16(i16) {
var bytes = fromInt16(i16);
s8(bytes[0]);
s8(bytes[1]);
}
function s32(i32) {
var bytes = fromInt32(i32);
s8(bytes[0]);
s8(bytes[1]);
s8(bytes[2]);
s8(bytes[3]);
}
// Now we build a fixed up bitmap.
s16(19778); // header.
s32(1334); // file size.
s32(0); // reserved.
s32(1078); // DIB data offset.
s32(40); // DIB header size.
s32(16); // width.
s32(16); // height.
s16(1); // planes.
s16(8); // bit depth.
s32(0); // compression.
s32(256); // image size.
s32(0); // Xpels.
s32(0); // Ypels.
s32(256); // Colors used.
s32(256); // Important colors.
for (var i = 0; i < 1024; i++) {
var c = colorTable[i];
if (typeof c !== 'undefined')
s8(colorTable[i])
else
s8(((i % 4) == 3) ? 0 : 255);
}
for (var i = 0; i < 256; i++) s8(indexes[i]);
window.URL = window.webkitURL || window.URL;
window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
var file = new window.BlobBuilder();
file.append(fixed);
var a = document.createElement('a');
a.href = window.URL.createObjectURL(file.getBlob('image/bmp'));
a.download = 'fixed.bmp';
a.textContent = 'Download Notepad++ compatible bitmap';
document.getElementById('result').appendChild(a);
};
reader.readAsArrayBuffer(files[0]);
}
function handleDragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.dataTransfer.dropEffect = 'copy';
}
var dropZone = document.getElementById('drop-zone');
dropZone.addEventListener('dragover', handleDragOver, false);
dropZone.addEventListener('drop', handleFileSelect, false);
} else {
alert('The File APIs are not fully supported in this browser.');
}
</script>
</body>
</html>