def testPackSequentialWidth(self): # AAAAAAAA # BBBBBBB # CCCCCC # DDDDD # EEEE # FFF # GG # H boxes = [Box(i, 1) for i in range(1, 9)] # AAAAAAAA # BBBBBBBH # CCCCCCGG # DDDDDFFF # EEEE packing = [ (0, 0, Box(8, 1)), (0, 1, Box(7, 1)), (7, 1, Box(1, 1)), (0, 2, Box(6, 1)), (6, 2, Box(2, 1)), (0, 3, Box(5, 1)), (5, 3, Box(3, 1)), (0, 4, Box(4, 1)), ] (_, _, actual) = pack_boxes(boxes, 8) self.assert_(check_no_overlap(actual)) self.assertEqual(actual, packing)
def testRandomNoOverlap(self): # Not having overlap is an important invariant we need to maintain. # This just checks it. boxes = [Box(random.randrange(1, 40), random.randrange(1, 40)) for _ in xrange(100)] (_, _, actual) = pack_boxes(boxes) self.assert_(check_no_overlap(actual))
def make_bundle(self, versioner): import Image # If this fails, you need the Python Imaging Library. # get the image paths excluding the sprite itself paths = [path for path in self.get_paths() if not os.path.basename(path) == self.name + self.get_extension()] boxes = [ImageBox(Image.open(path), path) for path in paths] # Pick a max_width so that the sprite is squarish and a multiple of 16, # and so no image is too wide to fit. total_area = sum(box.width * box.height for box in boxes) width = max(max(box.width for box in boxes), (int(math.sqrt(total_area)) // 16 + 1) * 16) (_, height, packing) = pack_boxes(boxes, width) sprite = Image.new("RGBA", (width, height)) for (left, top, box) in packing: # This is a bit of magic to make the transparencies work. To # preserve transparency, we pass the image so it can take its # alpha channel mask or something. However, if the image has no # alpha channels, then it fails, we we have to check if the # image is RGBA here. img = box.image mask = img if img.mode == "RGBA" else None sprite.paste(img, (left, top), mask) sprite.save(self.get_bundle_path(), "PNG") self._optimize_output() # It's *REALLY* important that this happen here instead of after the # generate_css() call, because if we waited, the CSS woudl have the URL # of the last version of this bundle. if versioner: versioner.update_bundle_version(self) self.generate_css(packing)
def make_bundle(self, versioner): import Image # If this fails, you need the Python Imaging Library. boxes = [ImageBox(Image.open(path), path) for path in self.get_paths()] # Pick a max_width so that the sprite is squarish and a multiple of 16, # and so no image is too wide to fit. total_area = sum(box.width * box.height for box in boxes) width = max(max(box.width for box in boxes), (int(math.sqrt(total_area)) // 16 + 1) * 16) (_, height, packing) = pack_boxes(boxes, width) sprite = Image.new("RGBA", (width, height)) for (left, top, box) in packing: # This is a bit of magic to make the transparencies work. To # preserve transparency, we pass the image so it can take its # alpha channel mask or something. However, if the image has no # alpha channels, then it fails, we we have to check if the # image is RGBA here. img = box.image mask = img if img.mode == "RGBA" else None sprite.paste(img, (left, top), mask) sprite.save(self.get_bundle_path(), "PNG") self._optimize_output() # It's *REALLY* important that this happen here instead of after the # generate_css() call, because if we waited, the CSS woudl have the URL # of the last version of this bundle. if versioner: versioner.update_bundle_version(self) self.generate_css(packing)
def testPackEasy(self): # AA # B # C boxes = [Box(2, 1), Box(1, 1), Box(1, 1)] # AA # BC packing = [(0, 0, Box(2, 1)), (0, 1, Box(1, 1)), (1, 1, Box(1, 1))] (_, _, actual) = pack_boxes(boxes, 2) self.assert_(check_no_overlap(actual)) self.assertEqual(actual, packing)
def testPackSequenceHeightWidth(self): # A # B # B # C # C # C # DD # EE # EE # FF # FF # FF # GGG # HHH # HHH # III # III # III boxes = [Box(i, j) for i in range(1, 4) for j in range(1, 4)] # III # III # III # FFC # FFC # FFC # HHH # HHH # EEB # EEB # GGG # DDA packing = [ (0, 0, Box(3, 3)), (0, 3, Box(2, 3)), (2, 3, Box(1, 3)), (0, 6, Box(3, 2)), (0, 8, Box(2, 2)), (2, 8, Box(1, 2)), (0, 10, Box(3, 1)), (0, 11, Box(2, 1)), (2, 11, Box(1, 1)), ] (_, _, actual) = pack_boxes(boxes, 3) self.assert_(check_no_overlap(actual)) self.assertEqual(actual, packing)
def testPackSequenceHeightWidth(self): # A # B # B # C # C # C # DD # EE # EE # FF # FF # FF # GGG # HHH # HHH # III # III # III boxes = [Box(i, j) for i in range(1, 4) for j in range(1, 4)] # III # III # III # HHH # HHH # GGG # FFC # FFC # FFC # EEB # EEB # DDA packing = [ (0, 0, Box(3, 3)), (0, 3, Box(3, 2)), (0, 5, Box(3, 1)), (0, 6, Box(2, 3)), (2, 6, Box(1, 3)), (0, 9, Box(2, 2)), (2, 9, Box(1, 2)), (0, 11, Box(2, 1)), (2, 11, Box(1, 1)), ] (_, _, actual) = pack_boxes(boxes, 3) self.assert_(check_no_overlap(actual)) self.assertEqual(actual, packing)
def testPackEasy(self): # AA # B # C boxes = [ Box(2, 1), Box(1, 1), Box(1, 1), ] # AA # BC packing = [ (0, 0, Box(2, 1)), (0, 1, Box(1, 1)), (1, 1, Box(1, 1)), ] (_, _, actual) = pack_boxes(boxes, 2) self.assert_(check_no_overlap(actual)) self.assertEqual(actual, packing)
def testPackSingle(self): boxes = [Box(1, 1)] packing = [(0, 0, Box(1, 1))] (_, _, actual) = pack_boxes(boxes, 1) self.assert_(check_no_overlap(actual)) self.assertEqual(actual, packing)
def handle_noargs(self, **options): version_stamp = str(int(time.mktime(datetime.now().timetuple()))) BUFFER_SIZE = 40 images = [] filenames = [] boxes = [] directories = getattr(settings, 'SPRITE_DIRS', ['/media/public_media/images/sprites']) for directory in directories: for image in [ f for f in os.listdir(directory) if f.endswith('.png') ]: image_file = Image.open('%s/%s' % ( directory, image, )) image_width, image_height = image_file.size boxes.append(Box(image_width, image_height, image_file)) max_width, y_off, packing = pack_boxes(boxes) master = Image.new(mode='RGBA', size=(max_width, y_off), color=(0, 0, 0, 0)) # fully transparent for x, y, image in packing: master.paste(image.filename, (x, y)) map_ouput = '%s' % getattr(settings, 'SPRITE_MAP_OUTPUT') location = '%ssprites.r%s.%s' % (getattr( settings, 'SPRITE_MAP_OUTPUT'), version_stamp, 'png') master.save(location) css_file_location = '%ssprites.css' % getattr(settings, 'SPRITE_CSS_OUTPUT') sprite_url = '../images/sprites.r%s.png' % version_stamp iconCssFile = open(css_file_location, 'w') print css_file_location for x, y, image in packing: image_file = image.filename image_width, image_height = image_file.size filename = image_file.filename.split('/')[-1].split('.')[0] css = """.sprite_%(filename)s { background-position: -%(top)spx -%(left)spx; width:%(width)spx; height:%(height)spx; display: inline-block; } """ % { 'filename': filename, 'top': x, 'left': y, 'width': image_width, 'height': image_height } iconCssFile.write(css) iconCssFile.write(""" .sprite, .sprite_inline { background-image: url('%s'); *background-image: url('%s'); } """ % (sprite_url, sprite_url)) iconCssFile.close()