svg_path_editor.path_shade#

Attributes#

Classes#

ImageFormat

Abstract image encoder.

WebpFormat

Lossless WebP encoder.

PngFormat

PNG encoder.

PathShading

SVG fragments for shaded bevels.

Functions#

lambert_from_angle(normal)

Lambertian diffuse intensity from a surface normal.

lambert_shading_base64(*, r, phi, locally_convex, ...)

Render a Lambert–shaded elliptical cone, return encoded bytes and base64 URI.

shade_path(svg, *, d, threshold, resolution[, ...])

Per-bevel Lambert shading for an SVG path.

Module Contents#

svg_path_editor.path_shade.lambert_from_angle(normal)[source]#

Lambertian diffuse intensity from a surface normal.

The light direction is fixed to \((0, -1, 1)\) in world space. The result is

\[I = \max(0, \hat{\mathbf{n}}\cdot\hat{\mathbf{L}}),\]

evaluated via the signed angle of normal in the \(xy\)-plane.

Parameters:

normal (Point) – Surface normal.

Returns:

Lambertian intensity in \([0, 1]\).

Return type:

decimal.Decimal

class svg_path_editor.path_shade.ImageFormat[source]#

Bases: Protocol

Abstract image encoder.

Variables:
  • media_type – MIME type of the encoded image.

  • extension – File extension (without dot).

media_type: ClassVar[str]#
extension: ClassVar[str]#
encode(data)[source]#

Encode an RGBA image.

Parameters:

data (numpy.ndarray) – (H, W, 4) uint8 array in RGBA order.

Returns:

Encoded image bytes.

Return type:

bytes | bytearray

class svg_path_editor.path_shade.WebpFormat[source]#

Lossless WebP encoder.

Uses imagecodecs.webp_encode() with lossless=True.

media_type: ClassVar[str] = 'image/webp'#
extension: ClassVar[str] = 'webp'#
encode(data)[source]#
Parameters:

data (numpy.ndarray)

Return type:

bytes | bytearray

class svg_path_editor.path_shade.PngFormat[source]#

PNG encoder.

Uses imagecodecs.png_encode() with level=9.

media_type: ClassVar[str] = 'image/png'#
extension: ClassVar[str] = 'png'#
encode(data)[source]#
Parameters:

data (numpy.ndarray)

Return type:

bytes | bytearray

svg_path_editor.path_shade.WEBP#
svg_path_editor.path_shade.PNG#
svg_path_editor.path_shade.lambert_shading_base64(*, r, phi, locally_convex, resolution, t=0.25, format=WEBP, seed=None)[source]#

Render a Lambert–shaded elliptical cone, return encoded bytes and base64 URI.

The cone radii are \(r = (r_x, r_y)\) in image space. For a point \((x, y)\) on the grid

\[(x, y) \in \left[-\frac{1}{r_x}, \frac{1}{r_x}\right] \times \left[-\frac{1}{r_y}, \frac{1}{r_y}\right],\]

the unnormalized normal is

\[\mathbf{n}(x, y) = \left(\frac{x}{r_x^2}, \frac{y}{r_y^2}, 1\right).\]

The Lambert term is

\[I(x, y) = \max\left(0, \hat{\mathbf{n}}(x, y)\cdot\hat{\mathbf{L}}\right),\]

where \(\hat{\mathbf{L}}\) is the unit vector from \((0, s, 1)\), with \(s = -1\) if locally_convex else \(+1\), rotated in the \(xy\)-plane by \(-\varphi\) degrees.

Grayscale is binary (0 or 255) according to \(I > t\). Alpha is a symmetric remap of \(I\) around \(t\):

\[\begin{split}\alpha(I) = \begin{cases} \dfrac{I - t}{1 - t}, & I \geq t,\\ \dfrac{t - I}{t}, & I < t. \end{cases}\end{split}\]

Before 8-bit quantization, uniform noise in \([0, 1]\) is added to alpha for dithering.

The final RGBA image is encoded with format and returned both as raw bytes and as a data:...;base64,... URI.

Parameters:
  • r (Point) – Ellipse radii in \(x\) and \(y\).

  • phi (decimal.Decimal) – Rotation in degrees of the light direction in image space (clockwise in screen coordinates).

  • locally_convex (bool) – If true, the base light direction is \((0, -1, 1)\), otherwise \((0, 1, 1)\).

  • resolution (float) – Pixels per SVG unit. Image size is \(\lceil 2 r_x \, \mathrm{resolution} \rceil \times \lceil 2 r_y \, \mathrm{resolution} \rceil\).

  • t (float) – Neutral Lambert intensity in \([0, 1]\) (threshold).

  • format (ImageFormat) – Image format to use.

  • seed (int | None) – RNG seed for alpha dithering; None is non-deterministic.

Returns:

(img_bytes, img_data_uri) with img_data_uri suitable for SVG href.

Return type:

tuple[bytes, str]

class svg_path_editor.path_shade.PathShading[source]#

SVG fragments for shaded bevels.

Variables:
  • defs_body – Elements for a document-wide <defs> (e.g. shared <image> or <clipPath> definitions).

  • body – Per-path drawing elements (e.g. <path>, <g>, <use>) that reference defs_body.

defs_body: list[str]#
body: list[str]#
svg_path_editor.path_shade.shade_path(svg, *, d, threshold, resolution, max_opacity=1, format=WEBP, shade_offset=0, clip_offset=0, seed=None, prec=None)[source]#

Per-bevel Lambert shading for an SVG path.

The path is decomposed into bevel regions via svg_path_editor.path_offset.bevel_path(). Flat bevel polygons are shaded analytically with lambert_from_angle(). Curved bevel arcs use a small Lambert RGBA texture from lambert_shading_base64(), referenced by <image> / <use> and clipped to the arc geometry.

For each bevel polygon:

  • One <path> is emitted with fill="white" or fill="black" depending on whether the intensity is above or below threshold.

  • Opacity is a symmetric remap of the intensity around threshold in \([0, 1]\), scaled by max_opacity.

For each bevel arc:

  • A Lambert cone texture is generated (or reused from a cache) for (r.x, r.y, phi, locally_convex).

  • A base <image> at the origin with size \(2 r_x \times 2 r_y\) is placed in PathShading.defs_body once per unique key.

  • For each occurrence, a <clipPath> with the bevel geometry and a <use> of the base image are emitted into PathShading.body, translated so the image origin matches the lower-left corner of the ellipse bounding box, and rotated by phi around the ellipse center if non-zero.

  • <use> carries opacity max_opacity when it is less than 1.

To integrate into an SVG, place all defs_body entries inside a single document-level <defs> and insert body where the path should render.

Parameters:
  • svg (SvgPath) – Input path to bevel and shade.

  • d (Number) – Offset distance for bevel_path().

  • threshold (Number) – Neutral Lambert intensity in \([0, 1]\), shared between flat bevels and textures.

  • resolution (float) – Pixels per SVG unit for generated textures; image dimensions follow lambert_shading_base64().

  • max_opacity (Number) – Global opacity scale in \([0, 1]\).

  • format (ImageFormat) – Texture format, e.g. WEBP or PNG.

  • seed (int | None) – RNG seed for alpha dithering in lambert_shading_base64(); None for non-deterministic.

  • prec (Precision | Literal['auto', 'auto-intersections'] | None) – Precision/geometry mode passed to bevel_path(). "auto" and "auto-intersections" select automatic strategies; None uses the default.

  • shade_offset (int)

  • clip_offset (int)

Return type:

PathShading