Advertisement
joric

packer2.py

Jun 9th, 2019
289
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.37 KB | None | 0 0
  1. import Image
  2. import math
  3. import re
  4. import os
  5. import sys
  6. import glob
  7. import array
  8.  
  9. class Img:
  10.     def __init__(self, sprite, image, dx, dy, x, y, w, h):
  11.         self.sprite = sprite
  12.         self.image = image
  13.         self.x = x
  14.         self.y = y
  15.         self.w = w
  16.         self.h = h
  17.         self.dx = dx
  18.         self.dy = dy
  19.     def __cmp__(self, other):
  20.         return cmp(other.h, self.h)
  21.  
  22. def power_of_two(input):
  23.     value = 1
  24.     while (value < input):
  25.         value <<= 1
  26.     return value
  27.  
  28. def inRange(value, vmin, vmax):
  29.     return (value >= vmin) and (value < vmax)
  30.  
  31. def rectOverlap(a, b):
  32.     Ax1,Ay1,Ax2,Ay2 = a
  33.     Bx1,By1,Bx2,By2 = b
  34.     xOverlap = inRange(Ax1, Bx1, Bx2) or inRange(Bx1, Ax1, Ax2)
  35.     yOverlap = inRange(Ay1, By1, By2) or inRange(By1, Ay1, Ay2)
  36.     return xOverlap and yOverlap
  37.  
  38. class Packer:
  39.     def __init__(self, imagelist, tile=False):
  40.  
  41.         if not tile:
  42.             sq = 0
  43.             for s in imagelist:
  44.                 sq += s.w * s.h
  45.             mw = power_of_two( math.sqrt(sq) )
  46.             mh = mw
  47.         else:
  48.             mw = imagelist[0].w
  49.             mh = mw * len(imagelist)
  50.  
  51.         print "Using image %dx%d" % (mw, mh)
  52.  
  53.         self.nodes = []
  54.         self.rect = []
  55.         self.nodes.append((0,0))
  56.         self.imagelist = imagelist
  57.         self.imap = Image.new("RGBA", (mw, mh))
  58.         self.mask = array.array("i", [0] * mw * mh)
  59.         self.imagelist = imagelist
  60.         self.tile = tile
  61.  
  62.     def place(self, x, y, img):
  63.         w, h = img.image.size
  64.         mw, mh = self.imap.size
  65.         self.rect.append((x,y, x+w, y+h))
  66.         self.nodes.append((x+w,y))
  67.         self.nodes.append((x,y+h))
  68.         self.nodes.sort(key=lambda s:int(s[1]*0xff+s[0]))
  69.         self.imap.paste(img.image, (x,y))
  70.         img.x = x
  71.         img.y = y
  72.         return 1
  73.  
  74.     def checkpos(self, x, y, w, h):
  75.         mw, mh = self.imap.size
  76.         if x + w > mw or y + h > mh:
  77.             return False
  78.         for r in self.rect:
  79.             if rectOverlap(r, (x, y, x+w, y+h)):
  80.                 return False
  81.         return True
  82.  
  83.     def putimage(self, img):
  84.         mw, mh = self.imap.size
  85.         w, h = img.image.size
  86.         for node in self.nodes:
  87.             x,y = node
  88.             if self.checkpos(x,y,w,h):
  89.                 return self.place(x,y,img)
  90.         return 0
  91.  
  92.     def process(self):
  93.         v = self.imagelist[:]
  94.  
  95.         if not self.tile:
  96.             v.sort()
  97.  
  98.         placed = 0
  99.         total = 0
  100.  
  101.         for img in v:
  102.             perc = (total+1) * 100 / len(v)
  103.             sys.stderr.write("\rPlacing: %d%%" % perc)
  104.             placed += self.putimage(img)
  105.             total += 1
  106.  
  107.         print "\nTotal images: %d placed: %d lost: %d" % (total, placed, (total-placed));
  108.  
  109.         b = self.imap.getbbox()
  110.         if b:
  111.             b = 0,0, power_of_two(b[2]), b[3]
  112.             print "Cropping map to %dx%d" % (b[2], b[3])
  113.             self.imap = self.imap.crop(b)
  114.  
  115.         return v
  116.  
  117.     def save_imap(self, outfile):
  118.         print "Saving %s" % outfile
  119.         self.imap.save(outfile);
  120.  
  121. def fkey(fname):
  122.     name, ext = os.path.splitext(os.path.basename(fname))
  123.     try:
  124.         return int(name)
  125.     except:
  126.         return name
  127.  
  128. def import_directory(path, sprite=0):
  129.     imagelist = []
  130.     files = glob.glob( os.path.join(path, '*.png') )
  131.     files.sort(key=fkey)
  132.     for fname in files:
  133.         image = Image.open(fname)
  134.         if image:
  135.             w, h = image.size
  136.             dx, dy = (0, 0)
  137.             m = re.search("\((\d+),(\d+)\).png", fname)
  138.             if m:
  139.                 dx, dy  = (int(m.group(1)), int(m.group(2)))
  140.             imagelist.append(Img(sprite, image, dx, dy, 0, 0, w, h))
  141.             sprite += 1
  142.  
  143.     if not imagelist:
  144.         print "Could not open imagelist"
  145.         exit(1)
  146.     else:
  147.         print "Loaded %d images" % len(imagelist)
  148.         return imagelist
  149.  
  150. def pack(fname):
  151.     name, e = os.path.splitext(fname)
  152.     pngfile = "%s.packed.png" % name
  153.     imagelist = import_directory(name,0)
  154.     packer = Packer(imagelist)
  155.     imagelist = packer.process()
  156.     packer.save_imap(pngfile)
  157.  
  158. def main():
  159.     if len(sys.argv) < 2:
  160.         print "Usage: %s <image dir>" % sys.argv[0]
  161.         pack('font10x14')
  162. #        pack('font-border-buttons')
  163.     else:
  164.         pack(sys.argv[1])
  165.  
  166. if __name__ == '__main__':
  167.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement