3

我目前正在使用 Notepad++ 来完成我的大部分编码工作。但是,我想更改它的图标,只是为了定制。

所以我所做的就是用Resource Hacker打开 .exe ,然后查看图标在哪里。它们似乎是位图格式,这很奇怪,因为它们具有透明度,并且用BM我知道的任何“位图”(标题,“Windows 位图”)格式替换它们都不起作用(未显示图标)。

所以我想问一下,这些文件是什么格式的,我怎样才能产生它们?

位图示例可以在Notepad++ 存储库中找到:
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 个字节(!)。

这是上面第一个位图的标题的样子:

十六进制车间

任何的想法?只要知道这是什么格式就足够了。

4

2 回答 2

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 个字节表示像素的底部行。

这里有更详细的解释:http ://en.wikipedia.org/wiki/BMP_file_format#File_structure

编辑:至于如何制作它们,只需询问您最喜欢的图像编辑软件将图像导出为 256 色位图(或 8BPP 位图,以可用者为准)。请注意,如果您在绘制后保存它,Microsoft Paint 会破坏颜色,因此请在实际绘制任何内容之前保存它。

于 2012-12-12T01:36:04.053 回答
0

杰夫指出的一切都是正确的,并将继续成为公认的答案。但是,如果其他人可能想要调整 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>&nbsp;&nbsp;</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>
于 2012-12-13T00:51:43.980 回答