diff --git a/.gitignore b/.gitignore index 82f1e02..044cfe4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,162 @@ +._* + +# Byte-compiled / optimized / DLL files __pycache__/ -example_* \ No newline at end of file +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ \ No newline at end of file diff --git a/__main__.py b/__main__.py new file mode 100644 index 0000000..34e4061 --- /dev/null +++ b/__main__.py @@ -0,0 +1,23 @@ +from pysheeter.pysheeter import Sheet as SpriteSheet + +# Simple PySheeter CLI +def main(): + print("Welcome to the PySheeter CLI") + + # Gather parameters from user input + folder = str(input("Enter path to folder of sprites:\n")) + ext = str(input("Enter the file extension of these sprites (without dot, 'png', 'jpg' etc.):\n")) + size = int(input("What width in pixels do you want each sprite to be? (1:1 aspect ratio):\n")) + vertical = not bool(input("Do you want a vertical sprite sheet? [Y,n]:\n")) + dest = str(input("Finally, enter a file name (or path) for the sprite sheet:\n")) + + print("Reading sprites from folder...") + sheet = SpriteSheet(folder, ext) + + print("Creating sprite sheet...") + sheet.put(dest, (size, size), vertical) + + print("Done!") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/example.py b/example/example.py deleted file mode 100644 index c22efcd..0000000 --- a/example/example.py +++ /dev/null @@ -1,10 +0,0 @@ -from pysheeter import PySheeter - -# Load sprites from './files/' (all sprites are 64x64) -spritesheet = PySheeter.Sheet("files") - -# Create a vertical spritesheet with the dimensions 16x16 (scaled) -spritesheet.put("example_v1616.png",(16,16)) - -# Create a horizontal spritesheet with the dimensions 16x32 (scaled & stretched) -spritesheet.put("example_h1632.png",(16,32),False) \ No newline at end of file diff --git a/example/files/1.png b/example/files/1.png deleted file mode 100644 index 0d6591b..0000000 Binary files a/example/files/1.png and /dev/null differ diff --git a/example/files/2.png b/example/files/2.png deleted file mode 100644 index 536ccbc..0000000 Binary files a/example/files/2.png and /dev/null differ diff --git a/example/files/3.png b/example/files/3.png deleted file mode 100644 index abbb891..0000000 Binary files a/example/files/3.png and /dev/null differ diff --git a/example/files/4.png b/example/files/4.png deleted file mode 100644 index 17d2368..0000000 Binary files a/example/files/4.png and /dev/null differ diff --git a/example/files/5.png b/example/files/5.png deleted file mode 100644 index ee6ad7f..0000000 Binary files a/example/files/5.png and /dev/null differ diff --git a/example/files/6.png b/example/files/6.png deleted file mode 100644 index ee6ad7f..0000000 Binary files a/example/files/6.png and /dev/null differ diff --git a/example/files/7.png b/example/files/7.png deleted file mode 100644 index ab7535e..0000000 Binary files a/example/files/7.png and /dev/null differ diff --git a/example/files/8.png b/example/files/8.png deleted file mode 100644 index ee6ad7f..0000000 Binary files a/example/files/8.png and /dev/null differ diff --git a/example/files/9.png b/example/files/9.png deleted file mode 100644 index 3068c1b..0000000 Binary files a/example/files/9.png and /dev/null differ diff --git a/pysheeter/PySheeter.py b/pysheeter/PySheeter.py deleted file mode 100644 index 9d3509a..0000000 --- a/pysheeter/PySheeter.py +++ /dev/null @@ -1,68 +0,0 @@ -import json -from PIL import Image -from pathlib import Path - -# Create new sprite -class Sprite: - - def __init__(self,image,size): - self.image = Image.open(image).convert("RGBA") - - # Resize image to size[width,height] if nessesary - if(self.image.width != size[0] or self.image.height != size[1]): - self.resize(size) - - # Resize image without maintaining aspect ratio - def resize(self,size,resample=Image.LANCZOS): - self.image = self.image.resize((size[0],size[1]),resample) - -# -------------------------------- - -# Create new sheet of sprites -class Sheet: - - def __init__(self,folder = None): - self.sprites = [] - - # Auto-import sprite folder - if(folder): - self.path = Path(folder).glob("**/*.png") - self.sprites = [x for x in self.path] - - print(f"Loaded {len(self.sprites)} sprites") - - # Concatinate sprites vertically - def concatV(self,size): - sheet = Image.new("RGBA",(size[0],size[1] * len(self.sprites))) - - for i, sprite in enumerate(self.sprites): - sheet.paste(Sprite(sprite,size).image,(0,size[1] * i)) - - return sheet - - # Concatinate sprites horizontally - def concatH(self,size): - sheet = Image.new("RGBA",(size[0] * len(self.sprites),size[1])) - - for i, sprite in enumerate(self.sprites): - sheet.paste(Sprite(sprite,size).image,(size[0] * i,0)) - - return sheet - - # Add sprite by path - def add(self,path): - self.sprites.append(path) - - # Remove sprite by path - def remove(self,path): - self.sprites.remove(path) - - # Create and save spritesheet - def put(self,dest,size,vertical = True): - if(vertical): - sheet = self.concatV(size) - else: - sheet = self.concatH(size) - - sheet.save(dest) - print(f"Saved spritesheet to '{dest}'") \ No newline at end of file diff --git a/pysheeter/__init__.py b/pysheeter/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pysheeter/pysheeter.py b/pysheeter/pysheeter.py new file mode 100644 index 0000000..a7629e5 --- /dev/null +++ b/pysheeter/pysheeter.py @@ -0,0 +1,66 @@ +from typing import Union +from pathlib import Path + +from PIL import Image + +# Create new sprite +class Sprite: + def __init__(self, image: str, resize: Union[tuple, list] = None): + self.image = Image.open(image).convert("RGBA") + + # Resize image if necessary + if (resize): + self.resize(resize) + + # Resize image without maintaining aspect ratio + def resize(self, size: Union[tuple, list], resample = Image.LANCZOS): + self.image = self.image.resize((size[0], size[1]), resample) + +# -------------------------------- + +# Create new sheet of sprites +class Sheet: + def __init__(self, folder: str = None): + self.sprites = [] + + # Auto-import PNGs from folder + if(folder): + self.path = Path(folder).glob(f"**/*.png") + self.sprites = [x for x in self.path] + + # Concatinate sprites vertically + def concat_vertical(self, size: Union[tuple, list]): + sheet_size = (size[0], size[1] * len(self.sprites)) + sheet = Image.new("RGBA", sheet_size) + + for i, sprite in enumerate(self.sprites): + sheet.paste(Sprite(sprite, size).image, (0, size[1] * i)) + + return sheet + + # Concatinate sprites horizontally + def concat_horizontal(self, size: Union[tuple, list]): + sheet_size = (size[0] * len(self.sprites), size[1]) + sheet = Image.new("RGBA", sheet_size) + + for i, sprite in enumerate(self.sprites): + sheet.paste(Sprite(sprite, size).image, (size[0] * i, 0)) + + return sheet + + # Add sprite by path + def add(self, path: str): + self.sprites.append(path) + + # Remove sprite by path + def remove(self, path: str): + self.sprites.remove(path) + + # Create and save spritesheet + def put(self, dest: str, size: Union[tuple, list], vertical: bool = True): + if(vertical): + sheet = self.concat_vertical(size) + else: + sheet = self.concat_horizontal(size) + + sheet.save(dest) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..122514b --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +# The requirements in setup.py should also be updated when changing this +pillow \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..d10ac34 --- /dev/null +++ b/setup.py @@ -0,0 +1,13 @@ +from setuptools import setup, find_packages + +setup( + name = "pysheeter", + version = "2.0.0", + description = "Simple python library for creating sprite sheets from images", + author = "Victor Westerlund", + author_email = "victor.vesterlund@gmail.com", + url = "https://github.com/victorwesterlund/reflect-client-python", + packages = ["pysheeter"], + # The requirement.txt file should also be updated when changing this + install_requires = ["pillow"] +) \ No newline at end of file