|
@@ -10,292 +10,310 @@ from PIL import Image, ImageDraw
|
|
|
from math import *
|
|
from math import *
|
|
|
import os
|
|
import os
|
|
|
|
|
|
|
|
|
|
+
|
|
|
class SubImage:
|
|
class SubImage:
|
|
|
- image = None
|
|
|
|
|
- image_name = ""
|
|
|
|
|
- width = 0
|
|
|
|
|
- height = 0
|
|
|
|
|
|
|
+ image = None
|
|
|
|
|
+ image_name = ""
|
|
|
|
|
+ width = 0
|
|
|
|
|
+ height = 0
|
|
|
|
|
+
|
|
|
|
|
+ mwidth = 0
|
|
|
|
|
+ mheight = 0
|
|
|
|
|
|
|
|
- mwidth = 0
|
|
|
|
|
- mheight = 0
|
|
|
|
|
|
|
+ atlas_x = 0xFFFFFFFF
|
|
|
|
|
+ atlas_y = 0xFFFFFFFF
|
|
|
|
|
|
|
|
- atlas_x = 0xFFFFFFFF
|
|
|
|
|
- atlas_y = 0xFFFFFFFF
|
|
|
|
|
|
|
|
|
|
class Frame:
|
|
class Frame:
|
|
|
- x = 0
|
|
|
|
|
- y = 0
|
|
|
|
|
- w = 0
|
|
|
|
|
- h = 0
|
|
|
|
|
|
|
+ x = 0
|
|
|
|
|
+ y = 0
|
|
|
|
|
+ w = 0
|
|
|
|
|
+ h = 0
|
|
|
|
|
|
|
|
- @classmethod
|
|
|
|
|
- def diagonal(self):
|
|
|
|
|
- return sqrt(self.w * self.w + self.h * self.h)
|
|
|
|
|
|
|
+ @classmethod
|
|
|
|
|
+ def diagonal(self):
|
|
|
|
|
+ return sqrt(self.w * self.w + self.h * self.h)
|
|
|
|
|
+
|
|
|
|
|
+ @classmethod
|
|
|
|
|
+ def area(self):
|
|
|
|
|
+ return self.w * self.h
|
|
|
|
|
|
|
|
- @classmethod
|
|
|
|
|
- def area(self):
|
|
|
|
|
- return self.w * self.h
|
|
|
|
|
|
|
|
|
|
class Context:
|
|
class Context:
|
|
|
- in_files = []
|
|
|
|
|
- out_file = ""
|
|
|
|
|
- margin = 0
|
|
|
|
|
- bg_color = 0
|
|
|
|
|
- rpath = ""
|
|
|
|
|
|
|
+ in_files = []
|
|
|
|
|
+ out_file = ""
|
|
|
|
|
+ margin = 0
|
|
|
|
|
+ bg_color = 0
|
|
|
|
|
+ rpath = ""
|
|
|
|
|
+
|
|
|
|
|
+ sub_images = []
|
|
|
|
|
+ atlas_width = 0
|
|
|
|
|
+ atlas_height = 0
|
|
|
|
|
+ mode = None
|
|
|
|
|
|
|
|
- sub_images = []
|
|
|
|
|
- atlas_width = 0
|
|
|
|
|
- atlas_height = 0
|
|
|
|
|
- mode = None
|
|
|
|
|
|
|
|
|
|
def next_power_of_two(x):
|
|
def next_power_of_two(x):
|
|
|
- return pow(2.0, ceil(log(x) / log(2)))
|
|
|
|
|
|
|
+ return pow(2.0, ceil(log(x) / log(2)))
|
|
|
|
|
+
|
|
|
|
|
|
|
|
def printi(msg):
|
|
def printi(msg):
|
|
|
- print("[I] %s" % msg)
|
|
|
|
|
|
|
+ print("[I] %s" % msg)
|
|
|
|
|
+
|
|
|
|
|
|
|
|
def parse_commandline():
|
|
def parse_commandline():
|
|
|
- """ Parse the command line arguments """
|
|
|
|
|
|
|
+ """ Parse the command line arguments """
|
|
|
|
|
+
|
|
|
|
|
+ parser = argparse.ArgumentParser(
|
|
|
|
|
+ description="This program creates a texture atlas", formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
|
|
|
|
|
|
- parser = argparse.ArgumentParser(description = "This program creates a texture atlas",
|
|
|
|
|
- formatter_class = argparse.ArgumentDefaultsHelpFormatter)
|
|
|
|
|
|
|
+ parser.add_argument(
|
|
|
|
|
+ "-i", "--input", nargs="+", required=True, help="specify the image(s) to convert. Seperate with space")
|
|
|
|
|
|
|
|
- parser.add_argument("-i", "--input", nargs = "+", required = True,
|
|
|
|
|
- help = "specify the image(s) to convert. Seperate with space")
|
|
|
|
|
|
|
+ parser.add_argument("-o", "--output", default="atlas.png", help="specify output PNG image.")
|
|
|
|
|
|
|
|
- parser.add_argument("-o", "--output", default = "atlas.png", help = "specify output PNG image.")
|
|
|
|
|
|
|
+ parser.add_argument("-m", "--margin", type=int, default=0, help="specify the margin.")
|
|
|
|
|
|
|
|
- parser.add_argument("-m", "--margin", type = int, default = 0, help = "specify the margin.")
|
|
|
|
|
|
|
+ parser.add_argument("-b", "--background-color", help="specify background of empty areas", default="ff00ff00")
|
|
|
|
|
|
|
|
- parser.add_argument("-b", "--background-color", help = "specify background of empty areas", default = "ff00ff00")
|
|
|
|
|
|
|
+ parser.add_argument("-r", "--rpath", help="Path to append to the .ankiatex", default="")
|
|
|
|
|
|
|
|
- parser.add_argument("-r", "--rpath", help = "Path to append to the .ankiatex", default = "")
|
|
|
|
|
|
|
+ args = parser.parse_args()
|
|
|
|
|
|
|
|
- args = parser.parse_args()
|
|
|
|
|
|
|
+ ctx = Context()
|
|
|
|
|
+ ctx.in_files = args.input
|
|
|
|
|
+ ctx.out_file = args.output
|
|
|
|
|
+ ctx.margin = args.margin
|
|
|
|
|
+ ctx.bg_color = int(args.background_color, 16)
|
|
|
|
|
+ ctx.rpath = args.rpath
|
|
|
|
|
|
|
|
- ctx = Context()
|
|
|
|
|
- ctx.in_files = args.input
|
|
|
|
|
- ctx.out_file = args.output
|
|
|
|
|
- ctx.margin = args.margin
|
|
|
|
|
- ctx.bg_color = int(args.background_color, 16)
|
|
|
|
|
- ctx.rpath = args.rpath
|
|
|
|
|
|
|
+ if len(ctx.in_files) < 2:
|
|
|
|
|
+ parser.error("Not enough images")
|
|
|
|
|
|
|
|
- if len(ctx.in_files) < 2:
|
|
|
|
|
- parser.error("Not enough images")
|
|
|
|
|
|
|
+ return ctx
|
|
|
|
|
|
|
|
- return ctx
|
|
|
|
|
|
|
|
|
|
def load_images(ctx):
|
|
def load_images(ctx):
|
|
|
- """ Load the images """
|
|
|
|
|
|
|
+ """ Load the images """
|
|
|
|
|
|
|
|
- for i in ctx.in_files:
|
|
|
|
|
- img = SubImage()
|
|
|
|
|
- img.image = Image.open(i)
|
|
|
|
|
- img.image_name = i
|
|
|
|
|
|
|
+ for i in ctx.in_files:
|
|
|
|
|
+ img = SubImage()
|
|
|
|
|
+ img.image = Image.open(i)
|
|
|
|
|
+ img.image_name = i
|
|
|
|
|
|
|
|
- if ctx.mode == None:
|
|
|
|
|
- ctx.mode = img.image.mode
|
|
|
|
|
- else:
|
|
|
|
|
- if ctx.mode != img.image.mode:
|
|
|
|
|
- raise Exception("Image \"%s\" has a different mode: \"%s\"" % (i, img.image.mode))
|
|
|
|
|
|
|
+ if ctx.mode == None:
|
|
|
|
|
+ ctx.mode = img.image.mode
|
|
|
|
|
+ else:
|
|
|
|
|
+ if ctx.mode != img.image.mode:
|
|
|
|
|
+ raise Exception("Image \"%s\" has a different mode: \"%s\"" % (i, img.image.mode))
|
|
|
|
|
|
|
|
- img.width = img.image.size[0]
|
|
|
|
|
- img.height = img.image.size[1]
|
|
|
|
|
|
|
+ img.width = img.image.size[0]
|
|
|
|
|
+ img.height = img.image.size[1]
|
|
|
|
|
|
|
|
- img.mwidth = img.width + ctx.margin
|
|
|
|
|
- img.mheight = img.height + ctx.margin
|
|
|
|
|
|
|
+ img.mwidth = img.width + ctx.margin
|
|
|
|
|
+ img.mheight = img.height + ctx.margin
|
|
|
|
|
|
|
|
- printi("Image \"%s\" loaded. Mode \"%s\"" % (i, img.image.mode))
|
|
|
|
|
|
|
+ printi("Image \"%s\" loaded. Mode \"%s\"" % (i, img.image.mode))
|
|
|
|
|
|
|
|
- for simage in ctx.sub_images:
|
|
|
|
|
- if os.path.basename(simage.image_name) == os.path.basename(i):
|
|
|
|
|
- raise Exception("Cannot have images with the same base %s" % i)
|
|
|
|
|
|
|
+ for simage in ctx.sub_images:
|
|
|
|
|
+ if os.path.basename(simage.image_name) == os.path.basename(i):
|
|
|
|
|
+ raise Exception("Cannot have images with the same base %s" % i)
|
|
|
|
|
+
|
|
|
|
|
+ ctx.sub_images.append(img)
|
|
|
|
|
|
|
|
- ctx.sub_images.append(img)
|
|
|
|
|
|
|
|
|
|
def compute_atlas_rough_size(ctx):
|
|
def compute_atlas_rough_size(ctx):
|
|
|
- for i in ctx.sub_images:
|
|
|
|
|
- ctx.atlas_width += i.mwidth
|
|
|
|
|
- ctx.atlas_height += i.mheight
|
|
|
|
|
|
|
+ for i in ctx.sub_images:
|
|
|
|
|
+ ctx.atlas_width += i.mwidth
|
|
|
|
|
+ ctx.atlas_height += i.mheight
|
|
|
|
|
+
|
|
|
|
|
+ ctx.atlas_width = next_power_of_two(ctx.atlas_width)
|
|
|
|
|
+ ctx.atlas_height = next_power_of_two(ctx.atlas_height)
|
|
|
|
|
|
|
|
- ctx.atlas_width = next_power_of_two(ctx.atlas_width)
|
|
|
|
|
- ctx.atlas_height = next_power_of_two(ctx.atlas_height)
|
|
|
|
|
|
|
|
|
|
def sort_image_key_diagonal(img):
|
|
def sort_image_key_diagonal(img):
|
|
|
- return img.width * img.width + img.height * img.height
|
|
|
|
|
|
|
+ return img.width * img.width + img.height * img.height
|
|
|
|
|
+
|
|
|
|
|
|
|
|
def sort_image_key_biggest_side(img):
|
|
def sort_image_key_biggest_side(img):
|
|
|
- return max(img.width, img.height)
|
|
|
|
|
|
|
+ return max(img.width, img.height)
|
|
|
|
|
+
|
|
|
|
|
|
|
|
def best_fit(img, crnt_frame, frame):
|
|
def best_fit(img, crnt_frame, frame):
|
|
|
- if img.mwidth > frame.w or img.mheight > frame.h:
|
|
|
|
|
- return False
|
|
|
|
|
|
|
+ if img.mwidth > frame.w or img.mheight > frame.h:
|
|
|
|
|
+ return False
|
|
|
|
|
+
|
|
|
|
|
+ if frame.area() < crnt_frame.area():
|
|
|
|
|
+ return True
|
|
|
|
|
+ else:
|
|
|
|
|
+ return False
|
|
|
|
|
|
|
|
- if frame.area() < crnt_frame.area():
|
|
|
|
|
- return True
|
|
|
|
|
- else:
|
|
|
|
|
- return False
|
|
|
|
|
|
|
|
|
|
def worst_fit(img, crnt_frame, new_frame):
|
|
def worst_fit(img, crnt_frame, new_frame):
|
|
|
- if img.mwidth > new_frame.w or img.mheight > new_frame.h:
|
|
|
|
|
- return False
|
|
|
|
|
|
|
+ if img.mwidth > new_frame.w or img.mheight > new_frame.h:
|
|
|
|
|
+ return False
|
|
|
|
|
+
|
|
|
|
|
+ if new_frame.area() > crnt_frame.area():
|
|
|
|
|
+ return True
|
|
|
|
|
+ else:
|
|
|
|
|
+ return False
|
|
|
|
|
|
|
|
- if new_frame.area() > crnt_frame.area():
|
|
|
|
|
- return True
|
|
|
|
|
- else:
|
|
|
|
|
- return False
|
|
|
|
|
|
|
|
|
|
def closer_to_00(img, crnt_frame, new_frame):
|
|
def closer_to_00(img, crnt_frame, new_frame):
|
|
|
- if img.mwidth > new_frame.w or img.mheight > new_frame.h:
|
|
|
|
|
- return False
|
|
|
|
|
|
|
+ if img.mwidth > new_frame.w or img.mheight > new_frame.h:
|
|
|
|
|
+ return False
|
|
|
|
|
|
|
|
- new_dist = new_frame.x * new_frame.x + new_frame.y * new_frame.y
|
|
|
|
|
- crnt_dist = crnt_frame.x * crnt_frame.x + crnt_frame.y * crnt_frame.y
|
|
|
|
|
|
|
+ new_dist = new_frame.x * new_frame.x + new_frame.y * new_frame.y
|
|
|
|
|
+ crnt_dist = crnt_frame.x * crnt_frame.x + crnt_frame.y * crnt_frame.y
|
|
|
|
|
+
|
|
|
|
|
+ if new_dist < crnt_dist:
|
|
|
|
|
+ return True
|
|
|
|
|
+ else:
|
|
|
|
|
+ return False
|
|
|
|
|
|
|
|
- if new_dist < crnt_dist:
|
|
|
|
|
- return True
|
|
|
|
|
- else:
|
|
|
|
|
- return False
|
|
|
|
|
|
|
|
|
|
def place_sub_images(ctx):
|
|
def place_sub_images(ctx):
|
|
|
- """ Place the sub images in the atlas """
|
|
|
|
|
-
|
|
|
|
|
- # Sort the images
|
|
|
|
|
- ctx.sub_images.sort(key = sort_image_key_diagonal, reverse = True)
|
|
|
|
|
-
|
|
|
|
|
- frame = Frame()
|
|
|
|
|
- frame.w = ctx.atlas_width
|
|
|
|
|
- frame.h = ctx.atlas_height
|
|
|
|
|
- frames = []
|
|
|
|
|
- frames.append(frame)
|
|
|
|
|
-
|
|
|
|
|
- unplaced_imgs = []
|
|
|
|
|
- for i in range(0, len(ctx.sub_images)):
|
|
|
|
|
- unplaced_imgs.append(i)
|
|
|
|
|
-
|
|
|
|
|
- while len(unplaced_imgs) > 0:
|
|
|
|
|
- sub_image = ctx.sub_images[unplaced_imgs[0]]
|
|
|
|
|
- unplaced_imgs.pop(0)
|
|
|
|
|
-
|
|
|
|
|
- printi("Will try to place image \"%s\" of size %ux%d" %
|
|
|
|
|
- (sub_image.image_name, sub_image.width, sub_image.height))
|
|
|
|
|
-
|
|
|
|
|
- # Find best frame
|
|
|
|
|
- best_frame = None
|
|
|
|
|
- best_frame_idx = 0
|
|
|
|
|
- idx = 0
|
|
|
|
|
- for frame in frames:
|
|
|
|
|
- if not best_frame or closer_to_00(sub_image, best_frame, frame):
|
|
|
|
|
- best_frame = frame
|
|
|
|
|
- best_frame_idx = idx
|
|
|
|
|
- idx += 1
|
|
|
|
|
-
|
|
|
|
|
- assert best_frame != None, "See file"
|
|
|
|
|
-
|
|
|
|
|
- # Update the sub_image
|
|
|
|
|
- sub_image.atlas_x = best_frame.x + ctx.margin
|
|
|
|
|
- sub_image.atlas_y = best_frame.y + ctx.margin
|
|
|
|
|
- printi("Image placed in %dx%d" % (sub_image.atlas_x, sub_image.atlas_y))
|
|
|
|
|
-
|
|
|
|
|
- # Split frame
|
|
|
|
|
- frame_top = Frame()
|
|
|
|
|
- frame_top.x = best_frame.x + sub_image.mwidth
|
|
|
|
|
- frame_top.y = best_frame.y
|
|
|
|
|
- frame_top.w = best_frame.w - sub_image.mwidth
|
|
|
|
|
- frame_top.h = sub_image.mheight
|
|
|
|
|
-
|
|
|
|
|
- frame_bottom = Frame()
|
|
|
|
|
- frame_bottom.x = best_frame.x
|
|
|
|
|
- frame_bottom.y = best_frame.y + sub_image.mheight
|
|
|
|
|
- frame_bottom.w = best_frame.w
|
|
|
|
|
- frame_bottom.h = best_frame.h - sub_image.mheight
|
|
|
|
|
-
|
|
|
|
|
- frames.pop(best_frame_idx)
|
|
|
|
|
- frames.append(frame_top)
|
|
|
|
|
- frames.append(frame_bottom)
|
|
|
|
|
|
|
+ """ Place the sub images in the atlas """
|
|
|
|
|
+
|
|
|
|
|
+ # Sort the images
|
|
|
|
|
+ ctx.sub_images.sort(key=sort_image_key_diagonal, reverse=True)
|
|
|
|
|
+
|
|
|
|
|
+ frame = Frame()
|
|
|
|
|
+ frame.w = ctx.atlas_width
|
|
|
|
|
+ frame.h = ctx.atlas_height
|
|
|
|
|
+ frames = []
|
|
|
|
|
+ frames.append(frame)
|
|
|
|
|
+
|
|
|
|
|
+ unplaced_imgs = []
|
|
|
|
|
+ for i in range(0, len(ctx.sub_images)):
|
|
|
|
|
+ unplaced_imgs.append(i)
|
|
|
|
|
+
|
|
|
|
|
+ while len(unplaced_imgs) > 0:
|
|
|
|
|
+ sub_image = ctx.sub_images[unplaced_imgs[0]]
|
|
|
|
|
+ unplaced_imgs.pop(0)
|
|
|
|
|
+
|
|
|
|
|
+ printi("Will try to place image \"%s\" of size %ux%d" % (sub_image.image_name, sub_image.width,
|
|
|
|
|
+ sub_image.height))
|
|
|
|
|
+
|
|
|
|
|
+ # Find best frame
|
|
|
|
|
+ best_frame = None
|
|
|
|
|
+ best_frame_idx = 0
|
|
|
|
|
+ idx = 0
|
|
|
|
|
+ for frame in frames:
|
|
|
|
|
+ if not best_frame or closer_to_00(sub_image, best_frame, frame):
|
|
|
|
|
+ best_frame = frame
|
|
|
|
|
+ best_frame_idx = idx
|
|
|
|
|
+ idx += 1
|
|
|
|
|
+
|
|
|
|
|
+ assert best_frame != None, "See file"
|
|
|
|
|
+
|
|
|
|
|
+ # Update the sub_image
|
|
|
|
|
+ sub_image.atlas_x = best_frame.x + ctx.margin
|
|
|
|
|
+ sub_image.atlas_y = best_frame.y + ctx.margin
|
|
|
|
|
+ printi("Image placed in %dx%d" % (sub_image.atlas_x, sub_image.atlas_y))
|
|
|
|
|
+
|
|
|
|
|
+ # Split frame
|
|
|
|
|
+ frame_top = Frame()
|
|
|
|
|
+ frame_top.x = best_frame.x + sub_image.mwidth
|
|
|
|
|
+ frame_top.y = best_frame.y
|
|
|
|
|
+ frame_top.w = best_frame.w - sub_image.mwidth
|
|
|
|
|
+ frame_top.h = sub_image.mheight
|
|
|
|
|
+
|
|
|
|
|
+ frame_bottom = Frame()
|
|
|
|
|
+ frame_bottom.x = best_frame.x
|
|
|
|
|
+ frame_bottom.y = best_frame.y + sub_image.mheight
|
|
|
|
|
+ frame_bottom.w = best_frame.w
|
|
|
|
|
+ frame_bottom.h = best_frame.h - sub_image.mheight
|
|
|
|
|
+
|
|
|
|
|
+ frames.pop(best_frame_idx)
|
|
|
|
|
+ frames.append(frame_top)
|
|
|
|
|
+ frames.append(frame_bottom)
|
|
|
|
|
+
|
|
|
|
|
|
|
|
def shrink_atlas(ctx):
|
|
def shrink_atlas(ctx):
|
|
|
- """ Compute the new atlas size """
|
|
|
|
|
|
|
+ """ Compute the new atlas size """
|
|
|
|
|
+
|
|
|
|
|
+ width = 0
|
|
|
|
|
+ height = 0
|
|
|
|
|
+ for sub_image in ctx.sub_images:
|
|
|
|
|
+ width = max(width, sub_image.atlas_x + sub_image.width + ctx.margin)
|
|
|
|
|
+ height = max(height, sub_image.atlas_y + sub_image.height + ctx.margin)
|
|
|
|
|
|
|
|
- width = 0
|
|
|
|
|
- height = 0
|
|
|
|
|
- for sub_image in ctx.sub_images:
|
|
|
|
|
- width = max(width, sub_image.atlas_x + sub_image.width + ctx.margin)
|
|
|
|
|
- height = max(height, sub_image.atlas_y + sub_image.height + ctx.margin)
|
|
|
|
|
|
|
+ ctx.atlas_width = next_power_of_two(width)
|
|
|
|
|
+ ctx.atlas_height = next_power_of_two(height)
|
|
|
|
|
|
|
|
- ctx.atlas_width = next_power_of_two(width)
|
|
|
|
|
- ctx.atlas_height = next_power_of_two(height)
|
|
|
|
|
|
|
|
|
|
def create_atlas(ctx):
|
|
def create_atlas(ctx):
|
|
|
- """ Create and populate the atlas """
|
|
|
|
|
|
|
+ """ Create and populate the atlas """
|
|
|
|
|
|
|
|
- # Change the color to something PIL can understand
|
|
|
|
|
- bg_color = (ctx.bg_color >> 24)
|
|
|
|
|
- bg_color |= (ctx.bg_color >> 8) & 0xFF00
|
|
|
|
|
- bg_color |= (ctx.bg_color << 8) & 0xFF0000
|
|
|
|
|
- bg_color |= (ctx.bg_color << 24) & 0xFF000000
|
|
|
|
|
|
|
+ # Change the color to something PIL can understand
|
|
|
|
|
+ bg_color = (ctx.bg_color >> 24)
|
|
|
|
|
+ bg_color |= (ctx.bg_color >> 8) & 0xFF00
|
|
|
|
|
+ bg_color |= (ctx.bg_color << 8) & 0xFF0000
|
|
|
|
|
+ bg_color |= (ctx.bg_color << 24) & 0xFF000000
|
|
|
|
|
|
|
|
- mode = "RGB"
|
|
|
|
|
- if ctx.mode == "RGB":
|
|
|
|
|
- color_space = (255, 255, 255)
|
|
|
|
|
- else:
|
|
|
|
|
- mode = "RGBA"
|
|
|
|
|
- color_space = (255, 255, 255, 255)
|
|
|
|
|
|
|
+ mode = "RGB"
|
|
|
|
|
+ if ctx.mode == "RGB":
|
|
|
|
|
+ color_space = (255, 255, 255)
|
|
|
|
|
+ else:
|
|
|
|
|
+ mode = "RGBA"
|
|
|
|
|
+ color_space = (255, 255, 255, 255)
|
|
|
|
|
|
|
|
- atlas_img = Image.new(mode, \
|
|
|
|
|
- (int(ctx.atlas_width), int(ctx.atlas_height)), color_space)
|
|
|
|
|
|
|
+ atlas_img = Image.new(mode, \
|
|
|
|
|
+ (int(ctx.atlas_width), int(ctx.atlas_height)), color_space)
|
|
|
|
|
|
|
|
- draw = ImageDraw.Draw(atlas_img)
|
|
|
|
|
- draw.rectangle((0, 0, ctx.atlas_width, ctx.atlas_height), bg_color)
|
|
|
|
|
|
|
+ draw = ImageDraw.Draw(atlas_img)
|
|
|
|
|
+ draw.rectangle((0, 0, ctx.atlas_width, ctx.atlas_height), bg_color)
|
|
|
|
|
|
|
|
- for sub_image in ctx.sub_images:
|
|
|
|
|
- assert sub_image.atlas_x != 0xFFFFFFFF and sub_image.atlas_y != 0xFFFFFFFF, "See file"
|
|
|
|
|
|
|
+ for sub_image in ctx.sub_images:
|
|
|
|
|
+ assert sub_image.atlas_x != 0xFFFFFFFF and sub_image.atlas_y != 0xFFFFFFFF, "See file"
|
|
|
|
|
|
|
|
- atlas_img.paste(sub_image.image, (int(sub_image.atlas_x), int(sub_image.atlas_y)))
|
|
|
|
|
|
|
+ atlas_img.paste(sub_image.image, (int(sub_image.atlas_x), int(sub_image.atlas_y)))
|
|
|
|
|
+
|
|
|
|
|
+ printi("Saving atlas \"%s\"" % ctx.out_file)
|
|
|
|
|
+ atlas_img.save(ctx.out_file)
|
|
|
|
|
|
|
|
- printi("Saving atlas \"%s\"" % ctx.out_file)
|
|
|
|
|
- atlas_img.save(ctx.out_file)
|
|
|
|
|
|
|
|
|
|
def write_xml(ctx):
|
|
def write_xml(ctx):
|
|
|
- """ Write the schema """
|
|
|
|
|
-
|
|
|
|
|
- fname = os.path.splitext(ctx.out_file)[0] + ".ankiatex"
|
|
|
|
|
- printi("Writing XML \"%s\"" % fname)
|
|
|
|
|
- f = open(fname, "w")
|
|
|
|
|
- f.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n")
|
|
|
|
|
- f.write("<textureAtlas>\n")
|
|
|
|
|
- out_filename = ctx.rpath + "/" + os.path.splitext(os.path.basename(ctx.out_file))[0] + ".ankitex"
|
|
|
|
|
- f.write("\t<texture>%s</texture>\n" % out_filename)
|
|
|
|
|
- f.write("\t<subTextureMargin>%u</subTextureMargin>\n" % ctx.margin)
|
|
|
|
|
- f.write("\t<subTextures>\n")
|
|
|
|
|
-
|
|
|
|
|
- for sub_image in ctx.sub_images:
|
|
|
|
|
- f.write("\t\t<subTexture>\n")
|
|
|
|
|
- f.write("\t\t\t<name>%s</name>\n" % os.path.basename(sub_image.image_name))
|
|
|
|
|
-
|
|
|
|
|
- # Now change coordinate system
|
|
|
|
|
- left = sub_image.atlas_x / ctx.atlas_width
|
|
|
|
|
- right = left + (sub_image.width / ctx.atlas_width)
|
|
|
|
|
- top = (ctx.atlas_height - sub_image.atlas_y) / ctx.atlas_height
|
|
|
|
|
- bottom = top - (sub_image.height / ctx.atlas_height)
|
|
|
|
|
-
|
|
|
|
|
- f.write("\t\t\t<uv>%f %f %f %f</uv>\n" % (left, bottom, right, top))
|
|
|
|
|
- f.write("\t\t</subTexture>\n")
|
|
|
|
|
-
|
|
|
|
|
- f.write("\t</subTextures>\n")
|
|
|
|
|
- f.write("</textureAtlas>\n")
|
|
|
|
|
|
|
+ """ Write the schema """
|
|
|
|
|
+
|
|
|
|
|
+ fname = os.path.splitext(ctx.out_file)[0] + ".ankiatex"
|
|
|
|
|
+ printi("Writing XML \"%s\"" % fname)
|
|
|
|
|
+ f = open(fname, "w")
|
|
|
|
|
+ f.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n")
|
|
|
|
|
+ f.write("<textureAtlas>\n")
|
|
|
|
|
+ out_filename = ctx.rpath + "/" + os.path.splitext(os.path.basename(ctx.out_file))[0] + ".ankitex"
|
|
|
|
|
+ f.write("\t<texture>%s</texture>\n" % out_filename)
|
|
|
|
|
+ f.write("\t<subTextureMargin>%u</subTextureMargin>\n" % ctx.margin)
|
|
|
|
|
+ f.write("\t<subTextures>\n")
|
|
|
|
|
+
|
|
|
|
|
+ for sub_image in ctx.sub_images:
|
|
|
|
|
+ f.write("\t\t<subTexture>\n")
|
|
|
|
|
+ f.write("\t\t\t<name>%s</name>\n" % os.path.basename(sub_image.image_name))
|
|
|
|
|
+
|
|
|
|
|
+ # Now change coordinate system
|
|
|
|
|
+ left = sub_image.atlas_x / ctx.atlas_width
|
|
|
|
|
+ right = left + (sub_image.width / ctx.atlas_width)
|
|
|
|
|
+ top = (ctx.atlas_height - sub_image.atlas_y) / ctx.atlas_height
|
|
|
|
|
+ bottom = top - (sub_image.height / ctx.atlas_height)
|
|
|
|
|
+
|
|
|
|
|
+ f.write("\t\t\t<uv>%f %f %f %f</uv>\n" % (left, bottom, right, top))
|
|
|
|
|
+ f.write("\t\t</subTexture>\n")
|
|
|
|
|
+
|
|
|
|
|
+ f.write("\t</subTextures>\n")
|
|
|
|
|
+ f.write("</textureAtlas>\n")
|
|
|
|
|
+
|
|
|
|
|
|
|
|
def main():
|
|
def main():
|
|
|
- """ The main """
|
|
|
|
|
|
|
+ """ The main """
|
|
|
|
|
|
|
|
- ctx = parse_commandline()
|
|
|
|
|
- load_images(ctx)
|
|
|
|
|
- compute_atlas_rough_size(ctx)
|
|
|
|
|
- place_sub_images(ctx)
|
|
|
|
|
- shrink_atlas(ctx)
|
|
|
|
|
- create_atlas(ctx)
|
|
|
|
|
- write_xml(ctx)
|
|
|
|
|
|
|
+ ctx = parse_commandline()
|
|
|
|
|
+ load_images(ctx)
|
|
|
|
|
+ compute_atlas_rough_size(ctx)
|
|
|
|
|
+ place_sub_images(ctx)
|
|
|
|
|
+ shrink_atlas(ctx)
|
|
|
|
|
+ create_atlas(ctx)
|
|
|
|
|
+ write_xml(ctx)
|
|
|
|
|
|
|
|
-if __name__ == "__main__":
|
|
|
|
|
- main()
|
|
|
|
|
|
|
|
|
|
|
|
+if __name__ == "__main__":
|
|
|
|
|
+ main()
|