Skip to main content

Advanced Topics

This section covers advanced topics for users who want to go beyond the basic functionality of wavy-totem-lib.

Creating Custom Styles

While wavy-totem-lib comes with built-in styles (WavyStyle and STTStyle), you might want to create your own style for a unique look. Here's a more detailed guide on creating custom styles:

Basic Structure

A custom style must inherit from AbstractStyle and implement the image property:

from PIL import Image
from wavy_totem_lib.styles.abstract import AbstractStyle
from wavy_totem_lib.options import TopLayer
from wavy_totem_lib.skin import Skin

class MyCustomStyle(AbstractStyle):
def __init__(self, skin: Skin, top_layers: list[TopLayer], **kwargs):
super().__init__(skin, top_layers, **kwargs)
# You can initialize additional attributes here

@property
def image(self) -> Image.Image:
# Implement your style logic here
# Use self.skin to access the skin parts
# Use self._canvas to build the totem image
return self._canvas

Adding Custom Parameters

You can add custom parameters to your style by accepting them in the __init__ method and storing them as attributes:

def __init__(self, skin: Skin, top_layers: list[TopLayer], **kwargs):
super().__init__(skin, top_layers, **kwargs)
self.custom_param = kwargs.get('custom_param', default_value)

Then you can use these parameters in your image property:

@property
def image(self) -> Image.Image:
if self.custom_param:
# Do something special
else:
# Do the default behavior
return self._canvas

Using the Custom Style

To use your custom style, pass it to the TotemBuilder:

from wavy_totem_lib import TotemBuilder, Skin
from my_module import MyCustomStyle

builder = TotemBuilder(
Skin('my_skin.png'),
style=MyCustomStyle,
# If your style accepts custom parameters:
# These will be passed as kwargs to your style's __init__ method
)

# If your style accepts custom parameters, you can also pass them here:
totem = builder.build(custom_param=value)

Error Handling

wavy-totem-lib can raise several exceptions that you might want to handle in your code:

SmallScale Exception

The SmallScale exception is raised when you try to scale a totem with a factor less than or equal to 0:

from wavy_totem_lib import TotemBuilder, Skin
from wavy_totem_lib.exceptions import SmallScale

try:
totem = TotemBuilder(Skin('my_skin.png')).build()
scaled = totem.scale(factor=0) # This will raise SmallScale
except SmallScale:
print("Scale factor must be greater than 0")

File Not Found

If the skin file doesn't exist, a FileNotFoundError will be raised:

from wavy_totem_lib import Skin

try:
skin = Skin('non_existent_file.png')
except FileNotFoundError:
print("Skin file not found")

Invalid Skin Format

If the skin file is not a valid image or has an invalid format, a PIL.UnidentifiedImageError might be raised:

from PIL import UnidentifiedImageError
from wavy_totem_lib import Skin

try:
skin = Skin('invalid_image.txt')
except UnidentifiedImageError:
print("Invalid image format")

Performance Optimization

If you're generating many totems, consider these optimization techniques:

Asynchronous Generation

Use the build_async method to generate totems asynchronously:

import asyncio
from wavy_totem_lib import TotemBuilder, Skin

async def generate_many_totems(skin_files):
results = []
for skin_file in skin_files:
builder = TotemBuilder(Skin(skin_file))
totem = await builder.build_async()
results.append(totem)
return results

# Run the async function
totems = asyncio.run(generate_many_totems(['skin1.png', 'skin2.png', 'skin3.png']))

Reusing Skin Objects

If you need to generate multiple totems with different styles for the same skin, reuse the Skin object:

from wavy_totem_lib import TotemBuilder, Skin, WavyStyle, STTStyle

skin = Skin('my_skin.png')

# Generate totems with different styles
wavy_totem = TotemBuilder(skin, style=WavyStyle).build()
stt_totem = TotemBuilder(skin, style=STTStyle).build()

Working with BytesIO

If you're working with web applications or want to avoid writing to disk, you can use BytesIO:

from io import BytesIO
from PIL import Image
from wavy_totem_lib import TotemBuilder, Skin

# Load skin from BytesIO
skin_bytes = BytesIO(skin_data) # skin_data could come from a web request
skin = Skin(skin_bytes)

# Generate totem
totem = TotemBuilder(skin).build()

# Save totem to BytesIO
output = BytesIO()
totem.image.save(output, format='PNG')
output.seek(0)

# Now you can use output.getvalue() to get the bytes
# or pass output to another function that accepts file-like objects

These advanced techniques should help you get the most out of wavy-totem-lib for your specific use case.