Variants

Variants define a named group of image versions, each with its own transformation. Pass a mapping of names to Transform objects to variants() to generate a dictionary of URLs. Pass a dataclass class to return a typed instance with URL attributes.

Tip

Use the local Docker server on port 8080 for the examples in this chapter.

Generate variants

Define a complete transformation for each name, then generate URLs for a source image:

from imgproxykit import Client, Transform

# Public URL of your imgproxy server.
client = Client('http://localhost:8080')
source_url = 'https://picsum.photos/id/237/1600/1200'

# Define a complete transformation for each variant name.
products = {
    'small': Transform(width=320),
    'medium': Transform(width=640),
    'large': Transform(width=1280),
}

# Build one URL per variant for the same source image.
product_urls = client.variants(source=source_url, variants=products)
small_url = product_urls['small']  # Access a URL by its variant name.

print(small_url)

product_urls contains a URL for each of the three widths. Access a URL by its name, or pass the dictionary to a template or API response. The names belong to your application; each URL uses its transformation and the client’s signing settings.

Reuse a variant set

Define a set once and reuse it across source images. Keep shared settings in a base transformation and use extend() to add a width for each variant:

from imgproxykit import Client, Transform

# Public URL of your imgproxy server.
client = Client('http://localhost:8080')
dog_source = 'https://picsum.photos/id/237/1600/1200'
pug_source = 'https://picsum.photos/id/1025/1600/1200'

# Share quality and output format across all variants.
base = Transform(quality=85, format='webp')
sizes = {
    'small': base.extend(width=320),
    'medium': base.extend(width=640),
    'large': base.extend(width=1280),
}

# Reuse the same set for different source images.
dog_urls = client.variants(source=dog_source, variants=sizes)
pug_urls = client.variants(source=pug_source, variants=sizes)

print(dog_urls['small'])
print(pug_urls['small'])

Both dictionaries contain the same names and processing settings, with URLs pointing to their respective sources. The shared sizes mapping can be kept at module level and reused across requests.

Type variant names

Annotate the input mapping with a Literal union to check variant names when accessing the generated URLs:

from typing import Literal, assert_type

from imgproxykit import Client, Transform

# Public URL of your imgproxy server.
client = Client('http://localhost:8080')
source_url = 'https://picsum.photos/id/237/1600/1200'

# Limit the allowed variant names with a literal union.
type ProductKeys = Literal['small', 'medium', 'large']

products: dict[ProductKeys, Transform] = {
    'small': Transform(width=320),
    'medium': Transform(width=640),
    'large': Transform(width=1280),
}

# The returned dictionary preserves the annotated key type.
product_urls = client.variants(source=source_url, variants=products)
assert_type(product_urls, dict[ProductKeys, str])

print(product_urls['small'])

product_urls has type dict[ProductKeys, str]. A type checker accepts product_urls['small'] and reports product_urls['profile'] as an invalid key. Without an explicit key annotation, a regular string-keyed mapping typically produces dict[str, str].

Return a dataclass

Declare a standard-library dataclass when you want a named result type for an API response or application code. Each field combines its result type, str, with a transformation in Annotated:

from dataclasses import dataclass
from typing import Annotated, assert_type

from imgproxykit import Client, Transform

# Share processing settings across all variants.
base = Transform(quality=85, format='webp')


@dataclass(frozen=True, slots=True)
class ProductImages:
    """Declare the result fields and their transformations together."""

    small: Annotated[str, base.extend(width=320)]
    medium: Annotated[str, base.extend(width=640)]
    large: Annotated[str, base.extend(width=1280)]


client = Client('http://localhost:8080')
source_url = 'https://picsum.photos/id/237/1600/1200'

# Pass the class to build an instance containing the generated URLs.
product_urls = client.variants(source_url, variants=ProductImages)

assert_type(product_urls, ProductImages)
assert_type(product_urls.small, str)

print(product_urls.small)

Pass the class as variants=ProductImages and access the generated URLs as attributes, such as product_urls.small. Reuse the class with other sources or clients.

Note

Each field must declare exactly one Transform in Annotated[str, Transform(...)]. Use Transform() for a URL without processing options. InitVar and init=False fields are unsupported.

Use ProductImages as a field type in a Pydantic model or msgspec Struct, and pass the result of client.variants() to that field. See the FastAPI example.

Next steps

See the Client API reference for the complete variants() signature and return type.