Advertisement
here2share

# png_encoder.py

May 8th, 2019
247
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.83 KB | None | 0 0
  1. # png_encoder.py
  2.  
  3. dir=r"C:/pydemo/test/"
  4.  
  5. DEPTH = 24
  6. # Color depth [bytes/pixel]
  7. #   1 Black and White
  8. #   8 Grayscale
  9. #  24 RGB
  10. #  32 RGBA
  11.  
  12. # Script
  13. import struct
  14. import zlib
  15. import binascii
  16. import os
  17.  
  18. def make_png(OUTPUT_FILE, DATA, IMAGE_W, IMAGE_H):
  19.     class pngEncorder:
  20.         compressor = zlib.compressobj(9) # max compression
  21.         out = lambda: None
  22.         length = 0
  23.         crc32 = 0x35AF061E # crc32("IDAT")
  24.  
  25.         def __init__(self, out):
  26.             self.out = out
  27.  
  28.         def writeRaw(self, b):
  29.             self.out(b)
  30.             self.length += len(b)
  31.             self.crc32 = zlib.crc32(b, self.crc32)
  32.  
  33.         def write(self, b):
  34.             self.writeRaw(self.compressor.compress(b))
  35.  
  36.         # improved write() for many zero bytes
  37.         def writez(self, num):
  38.             for i in range(num >> 14):
  39.                 self.out(self.compressor.compress(zero16KiB))
  40.                 self.crc32 = zlib.crc32(zero16KiB, self.crc32)
  41.             num &= 0x3FFF
  42.             self.out(self.compressor.compress(b"\0" * num))
  43.             self.crc32 = zlib.crc32(b"\0" * num, self.crc32)
  44.             self.length += num
  45.  
  46.         def finalize(self):
  47.             self.writePixels()
  48.             self.writeRaw(self.compressor.flush())
  49.        
  50.     def B(x):
  51.         return struct.pack(">B", x & 0xFF)
  52.  
  53.     def I4(x):
  54.         return struct.pack(">I", x & 0xFFFFFFFF)
  55.  
  56.     zero16KiB = b"\0" * 16383
  57.  
  58.     width = IMAGE_W
  59.     height = IMAGE_H
  60.     bitdepth = 8 # [bit/sample]
  61.     if DEPTH == 1:
  62.         bitdepth = 1
  63.         colortype = 0
  64.     elif DEPTH == 8:
  65.         colortype = 0
  66.     elif DEPTH == 24:
  67.         colortype = 2
  68.     elif DEPTH == 32:
  69.         colortype = 6
  70.     else:
  71.         raise NotImplementedError("Unsupported color depth {0}".format(DEPTH))
  72.     compresstype = 0 # zlib (only supported method)
  73.     filtermethod = 0 # adaptive (only supported method)
  74.     interlaced = 0 # no
  75.  
  76.     maxEntropyBits = DEPTH * IMAGE_W * IMAGE_H
  77.    
  78.     if DEPTH == 1:
  79.         bytesPerRow = (DEPTH * IMAGE_W + 7) >> 3
  80.     else:
  81.         bytesPerPixel = DEPTH >> 3
  82.         pixelPadding = bytesPerPixel
  83.         bytesPerRow = bytesPerPixel * IMAGE_W
  84.  
  85.     class rgbEncorder(pngEncorder):
  86.  
  87.         def writePixels(self):
  88.             # This method uses globals, which is probably bad...
  89.  
  90.             d = DATA[:]
  91.             for y in range(IMAGE_H):
  92.                 self.write(b"\x00") #
  93.                 for x in range(IMAGE_W):
  94.                     magic = d.pop(0)
  95.                     magic = [chr(z) for z in magic]
  96.                     self.write(''.join(magic))
  97.            
  98.  
  99.     with open(OUTPUT_FILE, "wb") as f:
  100.         # Signature
  101.         f.write(b"\x89PNG\r\n\x1A\n")
  102.         # IHDR
  103.         IHDR = b"IHDR" \
  104.             + I4(width) \
  105.             + I4(height) \
  106.             + B(bitdepth) \
  107.             + B(colortype) \
  108.             + B(compresstype) \
  109.             + B(filtermethod) \
  110.             + B(interlaced)
  111.  
  112.         f.write(I4(len(IHDR) - 4)) # 13
  113.         f.write(IHDR)
  114.         f.write(I4(zlib.crc32(IHDR)))
  115.         # IDAT
  116.         IDAT_len_offset = f.tell() # 33
  117.         f.write(b"\0\0\0\0IDAT")
  118.         rgb = rgbEncorder(f.write)
  119.         rgb.finalize()
  120.         f.write(I4(rgb.crc32))
  121.         f.seek(IDAT_len_offset)
  122.         f.write(I4(rgb.length))
  123.         f.seek(0, 2) #
  124.         f.write(b"\0\0\0\0IEND\xae\x42\x60\x82")
  125. 0
  126. make_png(dir+str(99)+"_demo.png",[(0,255,0)]*(100*100),100,100)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement