2011-12-18 142 views
9

我有一个应用程序,我希望能够从Python中的数据生成PNG图像。我做了一些搜索,发现看起来相当过时的“PIL”。还有其他一些图书馆会更好吗?在Python中创建PNG文件

感谢,

+1

PIL是如何过期的? – 2011-12-18 19:48:10

+1

你使用的是好的旧PIL(如果你还没有开发出py3.2以上的版本) – joaquin 2011-12-18 20:22:02

回答

6

尝试使用png模块对于初学者。

+0

谢谢,这真是太棒了 – adam 2011-12-18 20:03:24

29

简单的PNG文件可以很容易地从纯Python代码生成 - 你需要的只是标准的zlib模块和一些字节编码来编写块。下面是一个完整的例子,休闲读者可以用它作为自己的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

比我们大多数人(包括OP)都要深入一点,但是需要+1来分享这么多的信息。如果我想要更深入地研究png,这是很好的参考资料。 – mightypile 2014-10-08 12:40:17

+0

这个例子很棒。你可以改变,以显示如何添加调色板(对于一些基本的红色/绿色/等颜色,并有一个alpha通道)? – 576i 2016-01-19 21:00:19

+0

我想提供一个非常简短的答案。显然,构建和编码图片的方式有很多。幸运的是,PNG标准非常清楚要在每个块中放入什么(https://www.w3.org/TR/PNG)。为了避免位填充,可以简单地查找选项,以便始终将值编码为一个字节。 /////对于一个可以非常简单的RGBA:一个PLTE块没有编码选项=>它总是每个颜色通道8bit,不多也不少。所以每个条目都是4个字节(R,G,B,A)。 IHDR bitdepth是指IDAT - 8bit可以再次写入索引字节。 – 2017-07-16 15:26:20