¿Cómo puedo optimizar el tamaño de la imagen de la paleta con PIL?

Mi objective es dibujar algunos polígonos en una imagen en negro de modo que el tamaño total de la imagen resultante sea lo más pequeño posible.

Así que leí un artículo en wiki sobre colores indexados ( enlace ) y me parece que es una buena opción para mí (ya que debería admitir solo un color negro y los otros 5, es decir, 6 colores en total) y el png imagen png debería admitir Modo ‘P’ (es decir, imágenes de paleta ).

Esa es la razón por la que creé este fragmento de código para ver qué tamaño de imagen obtendré para 6 colores y 1224x1024 imágenes:

 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') 

El tamaño de la imagen resultante es de 768 bytes, lo que me parece demasiado.

¿Hay algo que pueda corregir en mi código para reducir aún más el tamaño de la imagen resultante?

768 bytes no me parece razonable representar una imagen de 1.2 megapíxeles. Puedes intentar ejecutar el archivo producido por PIL a través de pngcrush esta manera para ver si se pueden afeitar unos cuantos bytes:

 pngcrush input.png result.png 

Si realmente solo desea dibujar unos pocos polígonos de color sólido sobre un fondo negro, sugeriría que busque un formato vectorial, como el ejemplo SVG aquí, en lugar del formato raster PNG et al .

También puede usar rsvg para renderizar imágenes SVG a PNG si lo necesita, pero ni su aplicación ni la razón por la que necesita imágenes tan pequeñas queda claro en su pregunta, así que no tengo idea si esa es una opción para usted.

Aquí hay una imagen SVG de 300 bytes con un fondo negro, 2 rectangularjs y un polígono como una forma de estrella roja en la parte superior izquierda:

       

introduzca la descripción de la imagen aquí


Puedes cargar un SVG en una matriz de Numpy como esta:

 #!/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') 

Si está empeñado en hacer que los archivos sean aún más pequeños, al precio de la compatibilidad reducida con otros visores de imágenes, podría diseñar su propio formato muy simple algo parecido a SVG, de modo que podría almacenar la imagen representada por el ejemplo de SVG que proporcioné. como un simple archivo de texto:

 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 

Y eso lo hago 127 bytes.


Puedes ver tus archivos SVG al cargarlos en cualquier navegador web, o convertir uno en un PNG con ImageMagick en Terminal como esto:

 magick input.svg result.png