Skip to content

Commit

Permalink
- Pillow and numpy as optional dependency
Browse files Browse the repository at this point in the history
- Reformat with black
  • Loading branch information
laggykiller committed Oct 7, 2023
1 parent d9a3dee commit 3b51973
Show file tree
Hide file tree
Showing 16 changed files with 586 additions and 472 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ else()
message(FATAL_ERROR "The conan_toolchain file could not be found: ${CONAN_TOOLCHAIN}")
endif()

project(apngasm-python VERSION 1.2.0)
project(apngasm-python VERSION 1.2.1)
set(PY_VERSION_SUFFIX "")
set(PY_FULL_VERSION ${PROJECT_VERSION}${PY_VERSION_SUFFIX})

Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ Documentations: https://apngasm-python.readthedocs.io/en/latest/
pip install apngasm-python
```

Optionally, you can also install `Pillow` and `numpy`
```
pip install Pillow numpy
```

## Example usage
The recommended usage is to `from apngasm_python.apngasm import APNGAsmBinder`, see [example/example_binder.py](example/example_binder.py)
```python
Expand Down
25 changes: 15 additions & 10 deletions conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,31 @@
from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps, cmake_layout
from conan.tools.apple import is_apple_os


class ApngasmRecipe(ConanFile):
settings = 'os', 'compiler', 'build_type', 'arch'
settings = "os", "compiler", "build_type", "arch"

def requirements(self):
self.requires("zlib/1.2.13")
self.requires("libpng/1.6.40")
self.requires("boost/1.75.0") # https://github.com/conan-io/conan-center-index/issues/19704
self.requires(
"boost/1.75.0"
) # https://github.com/conan-io/conan-center-index/issues/19704

def build_requirements(self):
self.build_requires("b2/4.10.1")
if not shutil.which('cmake'):
if not shutil.which("cmake"):
self.tool_requires("cmake/[>=3.27]")

def build(self):
build_type = 'Release'
build_type = "Release"

def generate(self):
tc = CMakeToolchain(self)
cmake = CMakeDeps(self)
if is_apple_os(self) and get_arch() == 'universal2':
tc.blocks['apple_system'].values['cmake_osx_architectures'] = 'x86_64; arm64'
if is_apple_os(self) and get_arch() == "universal2":
tc.blocks["apple_system"].values[
"cmake_osx_architectures"
] = "x86_64; arm64"
tc.generate()
cmake.generate()
cmake.generate()
30 changes: 15 additions & 15 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
import os

project = 'apngasm-python'
copyright = '2023, laggykiller'
author = 'laggykiller'
project = "apngasm-python"
copyright = "2023, laggykiller"
author = "laggykiller"

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

extensions = [
'autoapi.extension',
'sphinx.ext.mathjax',
'sphinx.ext.napoleon',
'myst_parser',
'sphinx_immaterial'
"autoapi.extension",
"sphinx.ext.mathjax",
"sphinx.ext.napoleon",
"myst_parser",
"sphinx_immaterial",
]

autosummary_generate = True
Expand All @@ -28,20 +28,20 @@
napoleon_numpy_docstring = True
napoleon_use_ivar = True

templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
templates_path = ["_templates"]
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]

autoapi_dirs = [
os.path.abspath('../src-python/apngasm_python'),
os.path.abspath('../src-python/apngasm_python/_apngasm_python')
os.path.abspath("../src-python/apngasm_python"),
os.path.abspath("../src-python/apngasm_python/_apngasm_python"),
]
autoapi_python_use_implicit_namespaces = True

# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_theme = 'sphinx_immaterial'
html_static_path = ['_static']
html_theme = "sphinx_immaterial"
html_static_path = ["_static"]
# material theme options (see theme.conf for more information)
html_theme_options = {
"repo_name": "rlottie-python",
Expand Down Expand Up @@ -85,4 +85,4 @@
},
],
"toc_title_is_page_title": True,
}
}
4 changes: 3 additions & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
myst_parser
sphinx-immaterial
sphinx-autoapi
sphinx-autoapi
numpy
Pillow
64 changes: 33 additions & 31 deletions example/example_binder.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,80 +6,82 @@
import numpy as np

# Cleanup
shutil.rmtree('output', ignore_errors=True)
os.mkdir('output')
shutil.rmtree("output", ignore_errors=True)
os.mkdir("output")

# Initialize
apngasm = APNGAsmBinder()

# Get libapngasm version
print(f'{apngasm.version() = }')
print(f"{apngasm.version() = }")

# Load png from one directory
for file_name in sorted(os.listdir('frames')):
apngasm.add_frame_from_file(os.path.join('frames', file_name), 100, 1000)
for file_name in sorted(os.listdir("frames")):
apngasm.add_frame_from_file(os.path.join("frames", file_name), 100, 1000)

# Getting information about one frame
frame = apngasm.get_frames()[0]

# Saving one frame as file
frame.save('output/elephant-frame.png')
frame.save("output/elephant-frame.png")

# Getting one frame as Pillow Image
im = apngasm.frame_pixels_as_pillow(0)
im.save('output/elephant-frame-pillow.png')
im.save("output/elephant-frame-pillow.png")

# Get inforamtion about whole animation
print(f'{apngasm.get_loops() = }')
print(f'{apngasm.is_skip_first() = }')
print(f'{apngasm.frame_count() = }')
print(f"{apngasm.get_loops() = }")
print(f"{apngasm.is_skip_first() = }")
print(f"{apngasm.frame_count() = }")

# Assemble
success = apngasm.assemble('output/elephant.apng')
print(f'{success = }')
success = apngasm.assemble("output/elephant.apng")
print(f"{success = }")

# Clear images loaded in apngasm object
apngasm.reset()

# Disassemble and get pillow image of one frame
frames = apngasm.disassemble_as_pillow('input/ball.apng')
frames = apngasm.disassemble_as_pillow("input/ball.apng")
frame = frames[0]
frame.save('output/ball0.png')
frame.save("output/ball0.png")

# Disassemble all APNG into PNGs
apngasm.save_pngs('output')
apngasm.save_pngs("output")

# Assemble from pillow images
# Just for fun, let's also make it spin
apngasm.reset()
angle = 0
angle_step = 360 / len(os.listdir('frames'))
for file_name in sorted(os.listdir('frames')):
image = Image.open(os.path.join('frames', file_name))
angle_step = 360 / len(os.listdir("frames"))
for file_name in sorted(os.listdir("frames")):
image = Image.open(os.path.join("frames", file_name))
image = image.rotate(angle)
apngasm.add_frame_from_pillow(image)

angle += angle_step

success = apngasm.assemble('output/elephant-spinning-pillow.apng')
print(f'{success = }')
success = apngasm.assemble("output/elephant-spinning-pillow.apng")
print(f"{success = }")
apngasm.reset()

# Assemble palette and grey PNGs
# You can use with statement to avoid calling reset()
with APNGAsmBinder() as apng:
apng.add_frame_from_file('input/palette.png', delay_num=1, delay_den=1)
apng.add_frame_from_file('input/grey.png', delay_num=1, delay_den=1)
success = apng.assemble('output/birds.apng')
print(f'{success = }')
apng.add_frame_from_file("input/palette.png", delay_num=1, delay_den=1)
apng.add_frame_from_file("input/grey.png", delay_num=1, delay_den=1)
success = apng.assemble("output/birds.apng")
print(f"{success = }")

# Assemble palette and grey PNGs, but with Pillow and numpy
image0 = Image.open('input/grey.png')
image0 = Image.open("input/grey.png")
frame0 = apngasm.add_frame_from_pillow(image0, delay_num=1, delay_den=1)
image1 = Image.open('input/grey.png').convert('RGB')
frame1 = apngasm.add_frame_from_numpy(np.array(image1), trns_color=np.array([255, 255, 255]), delay_num=1, delay_den=1)
image2 = Image.open('input/palette.png')
image1 = Image.open("input/grey.png").convert("RGB")
frame1 = apngasm.add_frame_from_numpy(
np.array(image1), trns_color=np.array([255, 255, 255]), delay_num=1, delay_den=1
)
image2 = Image.open("input/palette.png")
apngasm.add_frame_from_pillow(image2, delay_num=1, delay_den=1)

success = apngasm.assemble('output/birds-pillow.apng')
print(f'{success = }')
success = apngasm.assemble("output/birds-pillow.apng")
print(f"{success = }")
Loading

0 comments on commit 3b51973

Please sign in to comment.