4

我有一堆图像,很多是手工制作的 16 色 8 位 PNG 格式,我需要 16 位 4 位格式,它们都有相同的调色板。

我正在谷歌搜索最好的库来使用,但我在这个特定问题上没有找到太多,所以我来到这里希望有一些更有针对性的解决方案。

我正在尝试根据我在这里找到的其他答案使用 PIL ,但没有任何运气。

img = Image.open('DownArrow_focused.png')
img = img.point(lambda i: i * 16, "L")
img.save('DownArrow_focused.png', 'PNG')

但这给了我一个灰度图像,而不是我想要的。

PIL 不起作用,尝试 PyPNG。GIMP 会这样做,但我需要批量处理数百个这样的东西。并获得批量转换,所以这不是一次性的事情。

基于 Java 的解决方案也是可以接受的,我可以从 Linux/OSX 机器上的命令行运行的几乎任何东西都是可以接受的。

4

2 回答 2

1

在 PNG 中,调色板始终存储在 RGB8 中(每个索引 = 颜色 3 个字节),具有任意(最多 256)个条目。如果您当前有一个带有 16 色调色板的 8 位图像(总共 16 个条目),则不需要更改调色板,只需重新打包像素字节(每个字节两个索引)。如果是这样,我认为您可以使用以下代码(未经测试)使用PNGJ来做到这一点:

public static void reencode(String orig, String dest) {
    PngReader png1 = FileHelper.createPngReader(new File(orig));
    ImageInfo pnginfo1 = png1.imgInfo;
    ImageInfo pnginfo2 = new ImageInfo(pnginfo1.cols, pnginfo1.rows, 4, false,false,true);  
    PngWriter png2 = FileHelper.createPngWriter(new File(dest), pnginfo2, false);
    png2.copyChunksFirst(png1, ChunksToWrite.COPY_ALL);
    ImageLine l2 = new ImageLine(pnginfo2);
    for (int row = 0; row < pnginfo1.rows; row++) {
        ImageLine l1 = png1.readRow(row);
        l2.tf_pack(l1.scanline, false);
        l2.setRown(row);
        png2.writeRow(l2);
    }
    png1.end();
    png2.copyChunksLast(png1, ChunksToWrite.COPY_ALL);
    png2.end();
    System.out.println("Done");
}

在其他地方,如果您当前的调色板有 16 种“已使用”颜色(但它的长度更大,因为它包含未使用的颜色),您需要做一些工作,修改调色板块(但也可以这样做)。

于 2011-09-26T01:44:20.300 回答
0

使用以下命令从 Python 脚本调用 Netpbm 程序 http://netpbm.sourceforge.net/ :

$ pngtopnm test.png | pnmquant 16 | pnmtopng > test16.png

$ file test16.png
test16.png: PNG image data, 700 x 303, 4-bit colormap, non-interlaced

并且 GIMP 将 test16.png 报告为有Color space: Indexed color (16 colors),我猜这就是你想要的。

这不是纯 Python 解决方案,但 PIL 也不是纯 Python,并且也依赖于共享库。我认为您无法避免对某些外部图像软件的依赖。

于 2011-09-25T16:34:09.147 回答