def testCreateAtlas(self): # Verify that atlas is correct based on sampling pixels and output size. atlas_settings = montage.SpriteAtlasSettings(img_format='png') source_paths = [ '/some/path/file' + str(i) + '.jpg' for i in range(0, 4) ] images_with_statuses = [ (Image.new('RGBA', (50, 50), self.orange_rgb), ''), (Image.new('RGBA', (50, 50), self.red_rgb), ''), (Image.new('RGBA', (50, 50), self.green_rgb), ''), (Image.new('RGBA', (50, 50), self.yellow_rgb), '') ] atlas_generator = montage.SpriteAtlasGenerator( images_with_statuses=images_with_statuses, img_src_paths=source_paths, atlas_settings=atlas_settings, default_img=Image.new('RGBA', (50, 50), self.black_rgb)) atlases, manifests = atlas_generator.create_atlas() atlas = atlases[0] # Only care about a single atlas del manifests self.assertEqual(atlas.size, (100, 100)) # Verify pixels in corners of atlas. self.assertEqual(atlas.getpixel((0, 0))[0:3], self.orange_rgb) self.assertEqual(atlas.getpixel((99, 0))[0:3], self.red_rgb) self.assertEqual(atlas.getpixel((0, 99))[0:3], self.green_rgb) self.assertEqual(atlas.getpixel((99, 99))[0:3], self.yellow_rgb) # Verify pixels in center of atlas self.assertEqual(atlas.getpixel((49, 49))[0:3], self.orange_rgb) self.assertEqual(atlas.getpixel((50, 49))[0:3], self.red_rgb) self.assertEqual(atlas.getpixel((49, 50))[0:3], self.green_rgb) self.assertEqual(atlas.getpixel((50, 50))[0:3], self.yellow_rgb)
def testAtlasGeneratorDifferentInputSizes(self): # Should raise error if image count does not match source path count. atlas_settings = montage.SpriteAtlasSettings(img_format='png') source_images_with_statuses = [(Image.new('RGBA', (50, 30)), '')] * 5 source_paths = [ '/some/path/file' + str(i) + '.jpg' for i in range(0, 4) ] with self.assertRaises(ValueError): montage.SpriteAtlasGenerator( images_with_statuses=source_images_with_statuses, img_src_paths=source_paths, atlas_settings=atlas_settings, default_img=Image.new('RGBA', (50, 30)))
def testAtlasGeneratorDifferentImageSizes(self): # Should raise error if converted images are different sizes. atlas_settings = montage.SpriteAtlasSettings(img_format='png') source_images_with_statuses = [(Image.new('RGBA', (50, 30)), ''), (Image.new('RGBA', (50, 30)), ''), (Image.new('RGBA', (50, 30)), ''), (Image.new('RGBA', (50, 10)), '')] source_paths = [ '/some/path/file' + str(i) + '.jpg' for i in range(0, 4) ] with self.assertRaises(ValueError): montage.SpriteAtlasGenerator( images_with_statuses=source_images_with_statuses, img_src_paths=source_paths, atlas_settings=atlas_settings, default_img=Image.new('RGBA', (50, 30)))
def testCreateAtlasIfNoSizeSpecified(self): # Verify that manifests and atlases contains single items. # and verify atlas size is correct. atlas_settings = montage.SpriteAtlasSettings(img_format='png') source_images_with_statuses = [(Image.new('RGBA', (50, 30)), '')] * 20 source_paths = [ '/some/path/file' + str(i) + '.jpg' for i in range(0, 20) ] atlas_generator = montage.SpriteAtlasGenerator( images_with_statuses=source_images_with_statuses, img_src_paths=source_paths, atlas_settings=atlas_settings, default_img=Image.new('RGBA', (50, 30))) atlases, manifests = atlas_generator.create_atlas() self.assertEqual(len(atlases), 1) self.assertEqual(atlases[0].size, (250, 150)) self.assertEqual(len(manifests), 1) self.assertEqual(len(manifests[0]), 20)
def testCreateAtlasManifestWithImgFailures(self): # Verify manifest contains correct data when one image failed. atlas_settings = montage.SpriteAtlasSettings(img_format='png') source_images_with_statuses = [(Image.new('RGBA', (50, 30)), '')] * 3 + [ (None, 'Failure msg') ] source_paths = [ '/some/path/file' + str(i) + '.jpg' for i in range(0, 4) ] expected_manifest = [{ 'source_image': '/some/path/file0.jpg', 'offset_x': 0, 'image_name': 'file0.jpg', 'offset_y': 0 }, { 'source_image': '/some/path/file1.jpg', 'offset_x': 50, 'image_name': 'file1.jpg', 'offset_y': 0 }, { 'source_image': '/some/path/file2.jpg', 'offset_x': 0, 'image_name': 'file2.jpg', 'offset_y': 30 }, { 'source_image': '/some/path/file3.jpg', 'offset_x': 50, 'image_name': 'file3.jpg', 'offset_y': 30, 'errors': 'Failure msg' }] atlas_generator = montage.SpriteAtlasGenerator( images_with_statuses=source_images_with_statuses, img_src_paths=source_paths, atlas_settings=atlas_settings, default_img=Image.new('RGBA', (50, 50), self.black_rgb)) atlases, manifests = atlas_generator.create_atlas() del atlases # linter self.assertEqual(manifests[0], expected_manifest)
def main(argv): del argv # Unused. # TODO: Add more flag validations. if FLAGS.max_failures is not None and FLAGS.max_failures > 0: raise NotImplementedError( 'Does not yet handle image retrieval/conversion ' 'failures') if FLAGS.atlas_width is not None or FLAGS.atlas_height is not None: print(FLAGS.atlas_width, FLAGS.atlas_height) # raise NotImplementedError( # 'Does not yet support specifying an atlas size.') if FLAGS.sourcelist is None: raise flags.ValidationError( 'You must specify a list of image sources.') bg_color_rgb = _determine_bg_rgb() outputdir = FLAGS.output_dir if outputdir is None: outputdir = os.path.join(os.getcwd()) image_source_list = atlasmaker_io.read_src_list_csvfile( FLAGS.sourcelist, FLAGS.sourcelist_dups_handling) # Provide some useful confirmation info about settings to user. logging.info( 'Desired output size in pixels width, height for each image is: ' '(%d, %d)' % (FLAGS.image_width, FLAGS.image_height)) logging.info('Image format for Atlas is: %s' % FLAGS.image_format) logging.info('Background RGB is set to %s' % str(bg_color_rgb)) logging.info('Background opacity is set to %d' % FLAGS.image_opacity) logging.info( 'Should we preserve image aspect ratio during conversion? %s' % FLAGS.keep_aspect_ratio) image_convert_settings = convert.ImageConvertSettings( img_format=FLAGS.image_format, width=FLAGS.image_width, height=FLAGS.image_height, bg_color_rgb=bg_color_rgb, opacity=FLAGS.image_opacity, preserve_aspect_ratio=FLAGS.keep_aspect_ratio, resize_if_larger=FLAGS.resize_if_larger) # Ensure we can write to the output dir or fail fast. atlasmaker_io.create_output_dir_if_not_exist(FLAGS.output_dir) # Create default image to be used for images that we can't get or convert. if FLAGS.default_image_path is not None: logging.info('Using image %s as default image when a specified image ' 'can\'t be fetched or converted' % FLAGS.default_image_path) default_img = parallelize.convert_default_image( FLAGS.default_image_path, image_convert_settings) else: logging.info( 'No default image for failures specified by user, so just ' 'using the background as the default image.') default_img = convert.create_default_image(image_convert_settings) # Verify we can write the specified output format, or fail fast. try: testimage_file_name = '{}.{}'.format('testimage', str(FLAGS.image_format).lower()) atlasmaker_io.save_image(default_img, os.path.join(FLAGS.output_dir, testimage_file_name), delete_after_write=True) logging.info('Confirmed we can output images in %s format' % FLAGS.image_format) except: logging.error('Unable to write test image in desired output format. ' 'Please confirm that \'%s\' is a supported PIL output ' 'format.' % FLAGS.image_format) raise # Convert images in parallel. logging.info('Scheduling %d tasks.' % len(image_source_list)) converted_images_with_statuses = parallelize.get_and_convert_images_parallel( image_source_list, image_convert_settings, n_jobs=FLAGS.num_parallel_jobs, verbose=FLAGS.parallelization_verbosity, allow_truncated_images=FLAGS.use_truncated_images, request_timeout=FLAGS.http_request_timeout, http_max_retries=FLAGS.http_max_retries) sprite_atlas_settings = montage.SpriteAtlasSettings( img_format=FLAGS.image_format, height=FLAGS.atlas_height, width=FLAGS.atlas_width, filename=FLAGS.filename) # width=FLAGS.atlas_width) # Generate the atlas from converted images. sprite_atlas_generator = montage.SpriteAtlasGenerator( images_with_statuses=converted_images_with_statuses, img_src_paths=image_source_list, atlas_settings=sprite_atlas_settings, default_img=default_img) atlases, manifests = sprite_atlas_generator.create_atlas() atlasmaker_io.save_atlas_and_manifests( outdir=outputdir, atlases=atlases, manifests=manifests, sprite_atlas_settings=sprite_atlas_settings)