Exporting Your Image
Once you have built your visual composition, PicTex provides flexible options for exporting it to both raster (pixel-based) and vector (path-based) formats.
Exporting to Raster Images (.png, .jpg)
To generate a raster image, use the .render() method. This returns a BitmapImage object, which holds the pixel data and provides helpful methods to save, display, or convert it.
from pictex import Canvas
canvas = Canvas().font_size(80).color("blue")
image = canvas.render("Hello, World!")
# Save to a file (format is inferred from extension)
image.save("output.png")
image.save("output.jpg", quality=90)
Controlling Raster Size with crop_mode
The .render() method accepts a crop_mode argument to give you full control over the final image dimensions.
CropMode.NONE(Default): The canvas will be large enough to include all effects, including the full extent of shadows.CropMode.CONTENT_BOX: The canvas will be cropped to the "content box" of the root element. This is useful if you want to ignore shadows for layout purposes.CropMode.SMART: A smart crop that trims all fully transparent pixels from the edges of the image. This is often the best choice for the tightest possible output.
from pictex import Canvas, CropMode
canvas = Canvas().font_size(100).add_shadow(offset=(10,10), blur_radius=20, color="white")
canvas.background_color("blue")
# Render with different exporting modes
img_none = canvas.render("Test", crop_mode=CropMode.NONE)
img_smart = canvas.render("Test", crop_mode=CropMode.SMART)
img_content_box = canvas.render("Test", crop_mode=CropMode.CONTENT_BOX)
# We save them as JPG images to force a black background instead of transparent, so it's easier to see the difference
img_none.save("test_none.jpg")
img_smart.save("test_smart.jpg")
img_content_box.save("test_content_box.jpg")
CropMode.NONE (default):

CropMode.SMART:

CropMode.CONTENT_BOX:

Converting to Other Formats
The Image object can be easily converted for use with other popular libraries.
# Get a Pillow Image object (requires `pip install Pillow`)
pil_image = image.to_pillow()
# Get a NumPy array for use with OpenCV (BGRA format) or Matplotlib (RGBA).
numpy_array = image.to_numpy(mode="RGBA")
Exporting to Vector Images (.svg)
To generate an SVG, use the .render_as_svg() method. This returns a VectorImage object.
Note: Shadows are not supported yet in SVG
Understanding Font Handling in SVG
Handling fonts is the most critical aspect of creating portable SVGs. PicTex gives you precise control over this via the embed_font parameter in the render_as_svg() method.
The behavior changes depending on whether you are using a font file (e.g., from a .ttf path) or a system font (e.g., "Arial").
Scenario 1: Using a Font File (e.g., .font_family("path/to/font.ttf"))
This is the recommended approach for achieving consistent visual results.
embed_font=True (default)
- What it does: The entire font file is encoded in Base64 and embedded directly within the SVG file using a
@font-facerule. - Result: The SVG is fully self-contained and portable. It will render identically on any device, regardless of a user's installed fonts.
- Trade-off: The file size of the SVG will increase by roughly 133% of the original font file's size.
# This creates a completely portable SVG
vector_image = canvas.render_as_svg("Portable & Perfect", embed_font=True)
vector_image.save("portable_text.svg")
embed_font=False
- What it does: The SVG will contain a
@font-facerule referencing the font file. PicTex automatically copies all used font files to afonts/subdirectory relative to the SVG output path and updates the references accordingly. - Result: The SVG file itself is very small. The font files are distributed alongside the SVG in the
fonts/subdirectory, making the output portable as a package. - Customization: You can customize the subdirectory name using the
fonts_subdirparameter, or disable automatic copying entirely withcopy_fonts=False.
# This creates a lightweight SVG with automatic font copying
vector_image = canvas.render_as_svg("Linked Font", embed_font=False)
vector_image.save("output/linked_text.svg")
# Font files are automatically copied to output/fonts/
# Customize the fonts subdirectory
vector_image.save("output/linked_text.svg", fonts_subdir="my-fonts")
# Font files are copied to output/my-fonts/
# Disable automatic copying
vector_image.save("output/linked_text.svg", copy_fonts=False)
# No fonts are copied; SVG will only work if fonts exist in the same directory
Scenario 2: Using a System Font (e.g., .font_family("Arial"))
This applies when you specify a font by name or when PicTex uses a system font as a fallback (e.g., for an emoji).
- What it does: In this case, the
embed_fontparameter has no effect, asPicTexdoes not have access to the font's file path to be able to read and embed it. - Result: The SVG will always reference the font by its family name (e.g.,
font-family: 'Arial'). The rendering completely relies on the viewing system having that specific font installed. If the font is not found, the viewer will substitute it with a default, which may alter the appearance. - Warning: If you use
embed_font=Truewith a system font,PicTexwill issue a warning to inform you that the font could not be embedded.
Summary of Font Handling
| Font Source | embed_font=True (Default) |
embed_font=False |
|---|---|---|
| Font from File | Fully Portable SVG. Font is embedded (Base64). | Portable Package. Fonts are automatically copied to fonts/ subdirectory with SVG. |
| System Font | System-Dependent SVG. Font is referenced by name. (Warning issued) | System-Dependent SVG. Font is referenced by name. |