Advertisement
Vearie

pypng - Python Sprite Strip Image Generator

Sep 10th, 2020
2,022
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.94 KB | None | 0 0
  1. import png # pip install pypng
  2. from math import sqrt, ceil
  3.  
  4. # Background color of the outputted strip image (RGBA bytes)
  5. TRANSPARENT_BG = b"\x00\x00\x00\x00"
  6.  
  7. # Take the given fixed-sized PNG files, and compile
  8. # them into a sigle rectangular image from left-to-right, top-to-bottom.
  9. def png_images_to_strip(input_file_list, output_name=None):
  10.     sprites_per_row = ceil(sqrt(len(input_file_list)))
  11.    
  12.     # Use the first image as the standard size and metadata to go by.
  13.     with open(input_file_list[0], "rb") as f:
  14.         sprite_w, sprite_h, rows, init_details = png.Reader(file=f).read()
  15.         bytes_per_pixel = 4 if init_details["alpha"] else 3
  16.    
  17.     if init_details["greyscale"] or init_details["bitdepth"] != 8:
  18.         raise Exception("PNG images must be 32 BPP RGBA or 24 BPP RGB")
  19.    
  20.     combined_w = sprite_w * sprites_per_row
  21.     combined_h = sprite_h * sprites_per_row
  22.     print("Geneating %dx%d image for %dx%d sprites..." % (combined_w, combined_h, sprite_w, sprite_h))
  23.    
  24.     # Generate entire bitmap in memory, write to it later
  25.     combined_row = [list(TRANSPARENT_BG * combined_w) for i in range(combined_h)]
  26.    
  27.     for sprite_index, file_name in enumerate(input_file_list):
  28.         sprite_y = sprite_index // sprites_per_row
  29.         sprite_x = sprite_index % sprites_per_row
  30.        
  31.         with open(file_name, "rb") as f:
  32.             r = png.Reader(file=f)
  33.             w, h, rows, details = r.read()
  34.            
  35.             if w != sprite_w or h != sprite_h:
  36.                 raise Exception("%r does not match dimensions %dx%d." % (file_name, sprite_w, sprite_h))
  37.            
  38.             if details["alpha"] != init_details["alpha"]:
  39.                 raise Exception("Sequential PNG alpha channel does not match.")
  40.                
  41.             if details["greyscale"] != init_details["greyscale"]:
  42.                 raise Exception("Sequential PNG greyscale setting does not match.")
  43.            
  44.             if details["bitdepth"] != init_details["bitdepth"]:
  45.                 raise Exception("Sequential PNG bit depth does not match.")
  46.            
  47.             for sprite_row_index, sprite_row in enumerate(rows):
  48.                 draw_at_row = (sprite_w * sprite_y) + sprite_row_index
  49.                
  50.                 start = sprite_x * sprite_w
  51.                 end = (sprite_x + 1) * sprite_w
  52.                
  53.                 combined_row[draw_at_row][start * bytes_per_pixel:end * bytes_per_pixel] = sprite_row
  54.    
  55.     w = png.Writer(
  56.         combined_w,
  57.         combined_h,
  58.         greyscale=init_details["greyscale"],
  59.         alpha=init_details["alpha"],
  60.         planes=init_details["planes"],
  61.         bitdepth=init_details["bitdepth"]
  62.     )
  63.    
  64.     file_name = output_name if output_name else "PNG COMBINED %dx%d.png" % (combined_w, combined_h)
  65.    
  66.     with open(file_name, "wb") as f:
  67.         w.write(f, combined_row)
  68.    
  69.     print("Saved as %r." % file_name)
  70.  
  71. if __name__ == "__main__":
  72.     # To use, simply pass a list of file paths into "png_images_to_strip()".
  73.     # Optionally set the output parameter.
  74.     # Note that all PNG 'sprites' must be the same dimensions.
  75.    
  76.     # In this use case sample, the files are individual fixed size animation frame outputs of a blender render
  77.     # rendered to files 0001.png to 0032.png.
  78.     png_images_to_strip(["%.4d.png" % i for i in range(1, 33)])
  79.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement