2011-12-18 19 views
9

Mam aplikację, w której chciałbym móc generować obrazy PNG z danych w Pythonie. Zrobiłem trochę wyszukiwania i znalazłem "PIL", który wyglądał na dość przestarzały. Czy jest jakaś inna biblioteka, która byłaby lepsza do tego?Tworzenie pliku PNG w Pythonie

Dzięki,

+1

W jaki sposób PIL jest nieaktualny? –

+1

używasz dobrej starej PIL (jeśli nie rozwijasz się już poza py3.2) – joaquin

Odpowiedz

6

Spróbuj użyć modułu png na początek.

+0

Dzięki, to świetnie – adam

29

Proste pliki PNG mogą być generowane dość prosto z czystego kodu Pythona - wszystko czego potrzebujesz to standardowy moduł zlib i kodowanie bajtów do napisania porcji. Oto pełny przykład, który zwykły czytelnik może wykorzystać jako starter dla własnego generatora png:

#! /usr/bin/python 
""" Converts a list of list into gray-scale PNG image. """ 
__copyright__ = "Copyright (C) 2014 Guido Draheim" 
__licence__ = "Public Domain" 

import zlib 
import struct 

def makeGrayPNG(data, height = None, width = None): 
    def I1(value): 
     return struct.pack("!B", value & (2**8-1)) 
    def I4(value): 
     return struct.pack("!I", value & (2**32-1)) 
    # compute width&height from data if not explicit 
    if height is None: 
     height = len(data) # rows 
    if width is None: 
     width = 0 
     for row in data: 
      if width < len(row): 
       width = len(row) 
    # generate these chunks depending on image type 
    makeIHDR = True 
    makeIDAT = True 
    makeIEND = True 
    png = b"\x89" + "PNG\r\n\x1A\n".encode('ascii') 
    if makeIHDR: 
     colortype = 0 # true gray image (no palette) 
     bitdepth = 8 # with one byte per pixel (0..255) 
     compression = 0 # zlib (no choice here) 
     filtertype = 0 # adaptive (each scanline seperately) 
     interlaced = 0 # no 
     IHDR = I4(width) + I4(height) + I1(bitdepth) 
     IHDR += I1(colortype) + I1(compression) 
     IHDR += I1(filtertype) + I1(interlaced) 
     block = "IHDR".encode('ascii') + IHDR 
     png += I4(len(IHDR)) + block + I4(zlib.crc32(block)) 
    if makeIDAT: 
     raw = b"" 
     for y in xrange(height): 
      raw += b"\0" # no filter for this scanline 
      for x in xrange(width): 
       c = b"\0" # default black pixel 
       if y < len(data) and x < len(data[y]): 
        c = I1(data[y][x]) 
       raw += c 
     compressor = zlib.compressobj() 
     compressed = compressor.compress(raw) 
     compressed += compressor.flush() #!! 
     block = "IDAT".encode('ascii') + compressed 
     png += I4(len(compressed)) + block + I4(zlib.crc32(block)) 
    if makeIEND: 
     block = "IEND".encode('ascii') 
     png += I4(0) + block + I4(zlib.crc32(block)) 
    return png 

def _example(): 
    with open("cross3x3.png","wb") as f: 
     f.write(makeGrayPNG([[0,255,0],[255,255,255],[0,255,0]])) 
+3

Trochę głębiej niż większość z nas, prawdopodobnie włączając OP, szukasz, ale +1 za udostępnianie tak dużej ilości informacji. To świetny materiał referencyjny, jeśli chcę głębiej zagłębić się w pngs. – mightypile

+0

Ten przykład jest niesamowity. Każda zmiana, którą możesz zmienić, aby pokazać, jak dodać paletę (dla niektórych podstawowych kolorów czerwonego/zielonego/etc i mieć kanał alfa)? – 576i

+0

Chciałem udzielić bardzo krótkiej odpowiedzi. Oczywiście istnieje wiele opcji do budowania i kodowania obrazu. Na szczęście standard PNG jasno określa, co umieścić w każdym kawałku (https://www.w3.org/TR/PNG). Aby uniknąć wypychania bitów, po prostu szukalibyśmy opcji zawsze kodującej wartość do dokładnie jednego bajtu. ///// Dla RGBA, które może być bardzo proste: porcja PLTE nie ma opcji kodowania => zawsze jest dokładnie 8bit na kanał koloru, nie więcej i nie mniej. Zatem każdy wpis ma 4 bajty (R, G, B, A). Bitdepth IHDR odnosi się do IDAT - z 8bit można ponownie napisać tylko bajty indeksu. –

Powiązane problemy