Skip to content

Commit

Permalink
mod format code & mod README.rst
Browse files Browse the repository at this point in the history
  • Loading branch information
wo1fsea committed Feb 14, 2024
1 parent 61ebbda commit 9c8f28c
Show file tree
Hide file tree
Showing 12 changed files with 75 additions and 61 deletions.
6 changes: 2 additions & 4 deletions PyTexturePacker/GuillotinePacker/GuillotineAtlas.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ def cut(self, main_rect, sub_rect):
def place_image_rect(self, rect_index, image_rect):
rect = self.max_rect_list[rect_index]

image_rect.x, image_rect.y = rect.x + self.inner_padding, rect.y + self.inner_padding
image_rect.x, image_rect.y = rect.x + \
self.inner_padding, rect.y + self.inner_padding

fake_image_rect = image_rect.clone()
fake_image_rect.left -= self.inner_padding
Expand All @@ -61,6 +62,3 @@ def place_image_rect(self, rect_index, image_rect):
self.max_rect_list.pop(rect_index)
self.max_rect_list.extend(self.cut(rect, fake_image_rect))
self.image_rect_list.append(image_rect)



3 changes: 1 addition & 2 deletions PyTexturePacker/ImageRect.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
from .Rect import Rect
from . import Utils


class ImageRect(Rect):
"""
image rect data
Expand Down Expand Up @@ -89,7 +88,7 @@ def trim(self, v=1):
self.width, self.height = self.image.size

self._trimmed = True

def extrude(self, size=0):
if size <= 0:
return
Expand Down
27 changes: 15 additions & 12 deletions PyTexturePacker/MaxRectsPacker/MaxRectsAtlas.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ def __init__(self, *args, **kwargs):

width, height = self.size
self.max_rect_list = [Rect(0 + self.border_padding,
0 + self.border_padding,
width - 2 * self.border_padding,
height - 2 * self.border_padding)]
0 + self.border_padding,
width - 2 * self.border_padding,
height - 2 * self.border_padding)]

def _is_in_max_size(self, size):
return size[0] <= self.max_size[0] and size[1] <= self.max_size[1]
Expand Down Expand Up @@ -83,19 +83,20 @@ def expand(self, method=EXPAND_SHORT_SIDE):

if old_size[0] != self.size[0]:
new_rect = Rect(old_size[0] - self.border_padding,
0 + self.border_padding,
self.size[0] - old_size[0],
self.size[1] - 2 * self.border_padding)
0 + self.border_padding,
self.size[0] - old_size[0],
self.size[1] - 2 * self.border_padding)
self.max_rect_list.append(new_rect)

if old_size[1] != self.size[1]:
new_rect = Rect(0 + self.border_padding,
old_size[1] - self.border_padding,
self.size[0] - 2 * self.border_padding,
self.size[1] - old_size[1])
old_size[1] - self.border_padding,
self.size[0] - 2 * self.border_padding,
self.size[1] - old_size[1])
self.max_rect_list.append(new_rect)

self.max_rect_list = list(filter(self._max_rect_list_pruning, self.max_rect_list))
self.max_rect_list = list(
filter(self._max_rect_list_pruning, self.max_rect_list))

return True

Expand Down Expand Up @@ -183,7 +184,8 @@ def find_best_rank_with_rotate(self, image_rect):
def place_image_rect(self, rect_index, image_rect):
rect = self.max_rect_list[rect_index]

image_rect.x, image_rect.y = rect.x + self.inner_padding, rect.y + self.inner_padding
image_rect.x, image_rect.y = rect.x + \
self.inner_padding, rect.y + self.inner_padding

fake_image_rect = image_rect.clone()
fake_image_rect.left -= self.inner_padding
Expand All @@ -200,7 +202,8 @@ def place_image_rect(self, rect_index, image_rect):
_max_rect_list.append(rect)

self.max_rect_list = _new_max_rect_list
self.max_rect_list = list(filter(self._max_rect_list_pruning, _new_max_rect_list))
self.max_rect_list = list(
filter(self._max_rect_list_pruning, _new_max_rect_list))
self.max_rect_list.extend(_max_rect_list)

self.image_rect_list.append(image_rect)
Expand Down
6 changes: 4 additions & 2 deletions PyTexturePacker/MaxRectsPacker/MaxRectsPacker.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ def __init__(self, *args, **kwargs):
def _pack(self, image_rect_list):
atlas_list = self._init_atlas_list(image_rect_list)

image_rect_list = sorted(image_rect_list, key=lambda x: max(x.width, x.height), reverse=True)
image_rect_list = sorted(image_rect_list, key=lambda x: max(
x.width, x.height), reverse=True)

for image_rect in image_rect_list:
best_atlas = -1
Expand All @@ -39,7 +40,8 @@ def _pack(self, image_rect_list):
best_rotated = False

for i, max_rect in enumerate(atlas_list):
index, rank, rotated = max_rect.find_best_rank(image_rect, self.enable_rotated)
index, rank, rotated = max_rect.find_best_rank(
image_rect, self.enable_rotated)

if rank < best_rank:
best_atlas = i
Expand Down
17 changes: 11 additions & 6 deletions PyTexturePacker/PackerInterface/AtlasInterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
AtlasInterface.py
----------------------------------------------------------------------------"""

from ..Utils import ATLAS_FORMAT_PLIST#, ATLAS_FORMAT_JSON
from ..Utils import ATLAS_FORMAT_PLIST # , ATLAS_FORMAT_JSON

MAX_RANK = 2 ** 32
MAX_WIDTH = 1024 * 16
Expand Down Expand Up @@ -57,11 +57,13 @@ def dump_plist(self, texture_file_name="", input_base_path=None, atlas_format=AT
if input_base_path is None:
_, path = os.path.split(path)
else:
path = os.path.relpath(os.path.abspath(path), os.path.abspath(input_base_path))
path = os.path.relpath(os.path.abspath(
path), os.path.abspath(input_base_path))

if atlas_format == ATLAS_FORMAT_PLIST:
frames[path] = dict(
frame="{{%d,%d},{%d,%d}}" % (image_rect.x, image_rect.y, width, height),
frame="{{%d,%d},{%d,%d}}" % (
image_rect.x, image_rect.y, width, height),
offset="{%d,%d}" % center_offset,
rotated=bool(image_rect.rotated),
sourceColorRect="{{%d,%d},{%d,%d}}" % (
Expand All @@ -70,13 +72,15 @@ def dump_plist(self, texture_file_name="", input_base_path=None, atlas_format=AT
)
else:
frames[path] = dict(
frame=dict(x=image_rect.x, y=image_rect.y, w=width, h=height),
frame=dict(x=image_rect.x, y=image_rect.y,
w=width, h=height),
rotated=bool(image_rect.rotated),
trimed=bool(image_rect.trimmed),
spriteSourceSize=dict(
x=image_rect.source_box[0], y=image_rect.source_box[1],
w=image_rect.source_box[2], h=image_rect.source_box[3]),
sourceSize=dict(w=image_rect.source_size[0], h=image_rect.source_size[1])
sourceSize=dict(
w=image_rect.source_size[0], h=image_rect.source_size[1])
)

plist_data["frames"] = frames
Expand Down Expand Up @@ -105,6 +109,7 @@ def dump_image(self, bg_color=0xffffffff):
image = image_rect.image.crop()
if image_rect.rotated:
image = image.transpose(Image.ROTATE_270)
packed_image.paste(image, (image_rect.left, image_rect.top, image_rect.right, image_rect.bottom))
packed_image.paste(
image, (image_rect.left, image_rect.top, image_rect.right, image_rect.bottom))

return packed_image
30 changes: 18 additions & 12 deletions PyTexturePacker/PackerInterface/PackerInterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ def _calculate_area(image_rect_list, inner_padding):
area = 0
for image_rect in image_rect_list:
area += image_rect.area + \
image_rect.width * inner_padding + \
image_rect.height * inner_padding + \
inner_padding ** 2
image_rect.width * inner_padding + \
image_rect.height * inner_padding + \
inner_padding ** 2
return area

@staticmethod
Expand Down Expand Up @@ -131,23 +131,25 @@ def _init_atlas_list(self, image_rect_list):

if self.enable_rotated:
if min(min_width, min_height) > min(self.max_width, self.max_height) or \
max(min_width, min_height) > max(self.max_width, self.max_height):
max(min_width, min_height) > max(self.max_width, self.max_height):
raise ValueError("size of image is larger than max size.")
else:
if min_height > self.max_height or min_width > self.max_width:
raise ValueError("size of image is larger than max size.")

atlas_list = []
area = self._calculate_area(image_rect_list, self.inner_padding)
w, h = self._cal_init_size(area, min_width, min_height, self.max_width, self.max_height)
w, h = self._cal_init_size(
area, min_width, min_height, self.max_width, self.max_height)

atlas_list.append(self.ATLAS_TYPE(w, h, self.max_width, self.max_height,
force_square=self.force_square, border_padding=self.border_padding,
shape_padding=self.shape_padding, inner_padding=self.inner_padding))

area = area - w * h
while area > 0:
w, h = self._cal_init_size(area, 0, 0, self.max_width, self.max_height)
w, h = self._cal_init_size(
area, 0, 0, self.max_width, self.max_height)
area = area - w * h
atlas_list.append(self.ATLAS_TYPE(w, h, self.max_width, self.max_height,
force_square=self.force_square, border_padding=self.border_padding,
Expand Down Expand Up @@ -176,14 +178,15 @@ def pack(self, input_images, output_name, output_path="", input_base_path=None):
if self.trim_mode:
for image_rect in image_rects:
image_rect.trim(self.trim_mode)

if self.extrude:
for image_rect in image_rects:
image_rect.extrude(self.extrude)

atlas_list = self._pack(image_rects)

assert "%d" in output_name or len(atlas_list) == 1, 'more than one output image, but no "%d" in output_name'
assert "%d" in output_name or len(
atlas_list) == 1, 'more than one output image, but no "%d" in output_name'

for i, atlas in enumerate(atlas_list):
texture_file_name = output_name if "%d" not in output_name else output_name % i
Expand All @@ -195,10 +198,12 @@ def pack(self, input_images, output_name, output_path="", input_base_path=None):
if self.reduce_border_artifacts:
packed_image = Utils.alpha_bleeding(packed_image)

atlas_data_ext = self.atlas_ext or Utils.get_atlas_data_ext(self.atlas_format)
Utils.save_atlas_data(packed_plist, os.path.join(output_path, "%s%s" % (texture_file_name, atlas_data_ext)),
atlas_data_ext = self.atlas_ext or Utils.get_atlas_data_ext(
self.atlas_format)
Utils.save_image(packed_image, os.path.join(output_path, "%s%s" % (texture_file_name, self.texture_format)))
Utils.save_atlas_data(packed_plist, os.path.join(output_path, "%s%s" % (texture_file_name, atlas_data_ext)),
self.atlas_format)
Utils.save_image(packed_image, os.path.join(
output_path, "%s%s" % (texture_file_name, self.texture_format)))

def multi_pack(self, pack_args_list):
"""
Expand All @@ -212,6 +217,7 @@ def multi_pack(self, pack_args_list):
pool_size = multiprocessing.cpu_count() * 2
pool = multiprocessing.Pool(processes=pool_size)

pool.map(multi_pack_handler, zip([self] * len(pack_args_list), pack_args_list))
pool.map(multi_pack_handler, zip(
[self] * len(pack_args_list), pack_args_list))
pool.close()
pool.join()
1 change: 0 additions & 1 deletion PyTexturePacker/Rect.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
Rect.py
----------------------------------------------------------------------------"""


class Rect(object):
"""
rect type data
Expand Down
23 changes: 13 additions & 10 deletions PyTexturePacker/Utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
Description:
Utils.py
----------------------------------------------------------------------------"""

import sys
import inspect
if sys.version_info.major > 2:
Expand Down Expand Up @@ -68,9 +69,10 @@ def get_atlas_data_ext(atlas_format):
return '.csv'
elif callable(atlas_format):
parameters = inspect.signature(atlas_format).parameters
required_args = sum(1 for param in parameters.values() if param.default is param.empty)
required_args = sum(1 for param in parameters.values()
if param.default is param.empty)
if len(parameters) >= 2 and required_args <= 2:
return '.txt'
return '.txt'

raise ValueError(f"Unsupported file format: {atlas_format}")

Expand All @@ -91,9 +93,10 @@ def save_atlas_data(data_dict, file_path, atlas_format):
return save_csv(data_dict, file_path)
elif callable(atlas_format):
parameters = inspect.signature(atlas_format).parameters
required_args = sum(1 for param in parameters.values() if param.default is param.empty)
required_args = sum(1 for param in parameters.values()
if param.default is param.empty)
if len(parameters) >= 2 and required_args <= 2:
return atlas_format(data_dict, file_path)
return atlas_format(data_dict, file_path)

raise ValueError(f"Unsupported file format: {atlas_format}")

Expand All @@ -106,12 +109,12 @@ def save_csv(data_dict, file_path):
:return:
"""
with open(file_path, 'w') as fp:
for name, data in data_dict['frames'].items():
frame = data['frame']
source = data['spriteSourceSize']
fp.write(f'{name},{frame["x"]},{frame["y"]},{frame["w"]},{frame["h"]},'
f'{source["x"]},{source["y"]},{source["w"]},{source["h"]},'
f'{data["rotated"]},{data["trimed"]}\n')
for name, data in data_dict['frames'].items():
frame = data['frame']
source = data['spriteSourceSize']
fp.write(f'{name},{frame["x"]},{frame["y"]},{frame["w"]},{frame["h"]},'
f'{source["x"]},{source["y"]},{source["w"]},{source["h"]},'
f'{data["rotated"]},{data["trimed"]}\n')


def save_json(data_dict, file_path):
Expand Down
10 changes: 5 additions & 5 deletions PyTexturePacker/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from . import Packer
from . import ImageRect
from . import PackerInterface
from . import Rect
from . import Utils
from . import Packer #noqa
from . import ImageRect #noqa
from . import PackerInterface #noqa
from . import Rect #noqa
from . import Utils #noqa
9 changes: 4 additions & 5 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Here comes an example of using PyTexturePacker to pack texture images from a dir
# create a MaxRectsBinPacker
packer = Packer.create(max_width=2048, max_height=2048, bg_color=0xffffff00)
# pack texture images under directory "test_case/" and name the output images as "test_case".
# "%d" in output file name "test_case%d" is a placeholder, which is a multipack index, starting with 0.
# "%d" in output file name "test_case%d" is a placeholder, which is the atlas index, starting with 0.
packer.pack("test_case/", "test_case%d")
Expand Down Expand Up @@ -172,13 +172,12 @@ The project is released under the terms of MIT License. You may find the content
.. _here: http://opensource.org/licenses/MIT



.. |build-status| image:: https://travis-ci.org/wo1fsea/PyTexturePacker.svg?branch=master
:target: https://travis-ci.org/wo1fsea/PyTexturePacker
.. |build-status| image:: https://github.com/wo1fsea/PyTexturePacker/actions/workflows/test.yml/badge.svg?branch=master
:target: https://github.com/wo1fsea/PyTexturePacker/actions/workflows/test.yml
:alt: Build status
.. |docs-status| image:: https://readthedocs.org/projects/pytexturepacker/badge/?version=master
:target: http://pytexturepacker.readthedocs.io/
:alt: Documentation Status
.. |pypi-status| image:: https://badge.fury.io/py/PyTexturePacker.svg
:target: https://pypi.org/project/pytexturepacker/
:alt: PyPI Status
:alt: PyPI Status
2 changes: 1 addition & 1 deletion docs/1_quick_start.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ Here comes an example of using PyTexturePacker to pack texture images from a dir
# create a MaxRectsBinPacker
packer = Packer.create(max_width=2048, max_height=2048, bg_color=0xffffff00)
# pack texture images under directory "test_case/" and name the output images as "test_case".
# "%d" in output file name "test_case%d" is a placeholder, which is a multipack index, starting with 0.
# "%d" in output file name "test_case%d" is a placeholder, which is the atlas index, starting with 0.
packer.pack("test_case/", "test_case%d")
2 changes: 1 addition & 1 deletion main.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def pack_test():
# create a MaxRectsPacker
packer = Packer.create(max_width=2048, max_height=2048, bg_color=0xffffff00)
# pack texture images under the directory "test_case/" and name the output images as "test_case".
# "%d" in output file name "test_case%d" is a placeholder, which is a multipack index, starting with 0.
# "%d" in output file name "test_case%d" is a placeholder, which is the atlas index, starting with 0.
packer.pack("test_image/", "test_image%d", "")


Expand Down

0 comments on commit 9c8f28c

Please sign in to comment.