简体   繁体   English

如何使用PIL优化调色板图像的大小?

[英]How can I optimize the palette image size with PIL?

My goal is to draw some polygons on a black image such that the total size of the resulting image is as small as possible. 我的目标是在黑色图像上绘制一些多边形,以使所得图像的总尺寸尽可能小。

So I read an article on wiki about indexed colors ( link ) and it seems like it's a good choice for me (since I should support only a black color and the 5 other ones, ie 6 colors in total) and png image format should support 'P' mode (ie, palette images ). 因此,我在Wiki上阅读了一篇有关索引颜色( 链接 )的文章,这似乎对我来说是一个不错的选择(因为我应该仅支持黑色,而其他5种颜色,即总共6种颜色)和png图像格式应该支持 “ P”模式(即调色板图像 )。

That's the reason I created this piece of code to see what image size I'll get for 6 colors and 1224x1024 image: 这就是我创建这段代码以查看6种颜色和1224x1024图像可获得的图像大小的原因:

from PIL import Image, ImageDraw
# Create a black 1224x1024 image
img = Image.new('P', (1224, 1024))
img.putpalette([
    0, 0, 0,  # black background
    236, 98, 98, # red color
    236, 98, 97,
    236, 98, 96,
    236, 98, 95,
    236, 98, 94,
])

draw = ImageDraw.Draw(img)
# Draw a random red polygon at the top left corner of the image
draw.polygon(xy=list(1,1,2,2,3,3,4,4), fill=1)
del draw

img.save('1.png', format='PNG')

The result image size is 768 bytes which seems too much for me. 结果图像大小为768字节,这对我来说似乎太大了。

Is there something I can fix in my code to make the result image size even smaller? 我可以在代码中修复某些问题,以使结果图像尺寸变得更小吗?

768 bytes does not seem unreasonable to me to represent a 1.2 megapixel image. 768字节对我来说代表1.2兆像素的图像似乎并不合理。 You could try running the file produced by PIL through pngcrush like this to see if it can shave a few bytes: 您可以尝试像这样通过pngcrush运行PIL生成的文件,以查看它是否可以剃除一些字节:

pngcrush input.png result.png

If you really only want to draw a few solid-coloured polygons on a black background, I would suggest you look to a vector format, such as SVG example here rather than raster format PNG et al . 如果您真的只想在黑色背景上绘制一些纯色多边形,建议您使用矢量格式,例如SVG 示例,而不是栅格格式PNG

You can also use rsvg to render SVG images to PNG if you need to but neither your application, nor the reason you need such small images is clear from your question, so I have no idea if that is an option for you. 如果需要,也可以使用rsvg将SVG图像渲染为PNG,但是您的应用程序以及需要这样小图像的原因都不能从您的问题中弄清楚,因此我不知道这是否是您的选择。

Here is a 300 byte SVG image with a black background, 2 rectangles and a polygon like a red star shape at top-left: 这是一个300字节的SVG图像,具有黑色背景,2个矩形和左上角的类似红色星形的多边形:

<svg width="1224" height="1024">
  <rect width="100%" height="100%" fill="black"/>
  <polygon points="9.9, 1.1, 3.3, 21.78, 19.8, 8.58, 0, 8.58, 16.5, 21.78" fill="red"/>
  <rect x="100" y="200" width="100" height="400" fill="blue"/>
  <rect x="800" y="280" width="100" height="200" fill="lime"/>
</svg>

在此处输入图片说明


You could load an SVG into a Numpy array like this: 您可以像这样将SVG加载到Numpy数组中:

#!/usr/bin/env python3

import cairosvg
import io
from PIL import Image

def svgRead(filename):
   """Load an SVG file and return image in Numpy array"""
   # Make memory buffer
   mem = io.BytesIO()
   # Convert SVG to PNG in memory
   cairosvg.svg2png(url=filename, write_to=mem)
   # Convert PNG to Numpy array
   return np.array(Image.open(mem))

# Read SVG file into Numpy array
res = svgRead('image.svg')

If you are hell-bent on making the files even smaller, at the price of reduced compatibility with other image viewers, you could devise your own very simple format somewhat similar to SVG, so you could store the image represented by the SVG example I gave as a simple text file: 如果您迫不及待地想使文件更小(以与其他图像查看器的兼容性降低为代价),则可以设计自己的类似于SVG的非常简单的格式,因此可以存储我给出的SVG示例代表的图像作为一个简单的文本文件:

b,1224,1024,#00000
r,100,200,100,400,#0000ff
r,800,280,100,200,#00ff00
p,9.9,1.1,3.3,21.78,19.8,8.58,0,8.58,16.5,21.78,#ff0000

And I make that 127 bytes. 而我做了那127个字节。


You can view your SVG files by loading them into any web-browser, or make one into a PNG with ImageMagick in Terminal like this: 您可以通过将SVG文件加载到任何Web浏览器中来查看它们,或者使用Terminal中的ImageMagick将其制作为PNG文件,如下所示:

magick input.svg result.png

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM