2011-12-18 36 views
9

Tôi có một ứng dụng mà tôi muốn có thể tạo ra hình ảnh PNG từ dữ liệu bằng Python. Tôi đã thực hiện một số tìm kiếm và tìm thấy "PIL" trông khá lỗi thời. Có thư viện nào khác tốt hơn cho điều này không?Tạo tệp PNG bằng Python

Cảm ơn,

+1

PIL đã lỗi thời như thế nào? –

+1

bạn sử dụng PIL cũ tốt (nếu bạn chưa phát triển vượt quá py3.2) – joaquin

Trả lời

6

Hãy thử sử dụng các mô-đun png cho người mới bắt đầu.

+0

Cảm ơn, đó là tuyệt vời – adam

29

Các tệp PNG đơn giản có thể được tạo dễ dàng từ mã Python thuần túy - tất cả những gì bạn cần là mô-đun zlib chuẩn và một số byte mã hóa để ghi các khối. Dưới đây là một ví dụ hoàn chỉnh mà người đọc thông thường có thể sử dụng làm khởi động cho máy phát điện png riêng của mình:

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

Sâu hơn một chút so với hầu hết chúng ta, có thể bao gồm OP, đang tìm kiếm, nhưng +1 để chia sẻ rất nhiều thông tin. Đây là tài liệu tham khảo tuyệt vời nếu tôi muốn đi sâu hơn với png. – mightypile

+0

Ví dụ này thật tuyệt vời. Bất kỳ thay đổi nào bạn có thể thay đổi để hiển thị cách thêm bảng màu (đối với một số màu đỏ/xanh lục/vv cơ bản và có kênh alpha)? – 576i

+0

Tôi muốn cung cấp một câu trả lời rất ngắn. Rõ ràng có khá nhiều tùy chọn để xây dựng và mã hóa hình ảnh. May mắn là tiêu chuẩn PNG khá rõ ràng về những gì để đưa vào mỗi đoạn (https://www.w3.org/TR/PNG). Để tránh bit nhồi một trong những chỉ đơn giản là sẽ tìm các tùy chọn để luôn luôn mã hóa một giá trị vào chính xác một byte. ///// Đối với một RGBA có thể rất đơn giản: một đoạn PLTE không có tùy chọn mã hóa => nó luôn luôn chính xác 8 bit cho mỗi kênh màu, không nhiều hơn và không ít hơn. Vì vậy, mỗi mục nhập là 4 byte (R, G, B, A). Các bit IepDR đề cập đến IDAT - với 8 bit một có thể viết chỉ số byte một lần nữa. –