Pixie - A full-featured 2D graphics library for Python

Overview

Pixie - A full-featured 2D graphics library for Python

Pixie is a 2D graphics library similar to Cairo and Skia.

Github Actions

pip install pixie-python

Features:

  • Typesetting and rasterizing text, including styled rich text via spans.
  • Drawing paths, shapes and curves with even-odd and non-zero windings.
  • Pixel-perfect AA quality.
  • Supported file formats are PNG, BMP, JPG, SVG + more in development.
  • Strokes with joins and caps.
  • Shadows, glows and blurs.
  • Complex masking: Subtract, Intersect, Exclude.
  • Complex blends: Darken, Multiply, Color Dodge, Hue, Luminosity... etc.
  • Many operations are SIMD accelerated.

Image file formats

Format Read Write
PNG
JPEG
BMP
GIF
SVG

Font file formats

Format Read
TTF
OTF
SVG

Joins and caps

Supported Caps:

  • Butt
  • Round
  • Square

Supported Joins:

  • Miter (with miter angle limit)
  • Bevel
  • Round

Blending & masking

Supported Blend Modes:

  • Normal
  • Darken
  • Multiply
  • ColorBurn
  • Lighten
  • Screen
  • Color Dodge
  • Overlay
  • Soft Light
  • Hard Light
  • Difference
  • Exclusion
  • Hue
  • Saturation
  • Color
  • Luminosity

Supported Mask Modes:

  • Mask
  • Overwrite
  • Subtract Mask
  • Intersect Mask
  • Exclude Mask

SVG style paths:

Format Supported Description
M m move to
L l line to
h h horizontal line to
V v vertical line to
C c S s cublic to
Q q T t quadratic to
A a arc to
z close path

Testing

pytest

Examples

git clone https://github.com/treeform/pixie-python to run examples.

Text

python examples/text.py

font = pixie.read_font("examples/data/Roboto-Regular_1.ttf")
font.size = 20

text = "Typesetting is the arrangement and composition of text in graphic design and publishing in both digital and traditional medias."

image.fill_text(
    font,
    text,
    bounds = pixie.Vector2(180, 180),
    transform = pixie.translate(10, 10)
)

example output

Text spans

python examples/text_spans.py

typeface = pixie.read_typeface("examples/data/Ubuntu-Regular_1.ttf")

def make_font(typeface, size, color):
    font = typeface.new_font()
    font.size = size
    font.paints[0].color = color
    return font

spans = pixie.SeqSpan()
spans.append(pixie.Span(
    "verb [with object] ",
    make_font(typeface, 12, pixie.Color(0.78125, 0.78125, 0.78125, 1))
))
spans.append(pixie.Span(
    "strallow\n",
    make_font(typeface, 36, pixie.Color(0, 0, 0, 1))
))
spans.append(pixie.Span(
    "\nstral·low\n",
    make_font(typeface, 13, pixie.Color(0, 0.5, 0.953125, 1))
))
spans.append(pixie.Span(
    "\n1. free (something) from restrictive restrictions \"the regulations are intended to strallow changes in public policy\" ",
    make_font(typeface, 14, pixie.Color(0.3125, 0.3125, 0.3125, 1))
))

image.arrangement_fill_text(
    spans.typeset(bounds = pixie.Vector2(180, 180)),
    transform = pixie.translate(10, 10)
)

example output

Square

python examples/square.py

paint = pixie.Paint(pixie.PK_SOLID)
paint.color = pixie.Color(1, 0, 0, 1)

ctx = image.new_context()
ctx.fill_style = paint

ctx.fill_rect(50, 50, 100, 100)

example output

Line

python examples/line.py

paint = pixie.Paint(pixie.PK_SOLID)
paint.color = pixie.parse_color("#FF5C00")

ctx = image.new_context()
ctx.stroke_style = paint
ctx.line_width = 10

ctx.stroke_segment(25, 25, 175, 175)

example output

Rounded rectangle

python examples/rounded_rectangle.py

paint = pixie.Paint(pixie.PK_SOLID)
paint.color = pixie.Color(0, 1, 0, 1)

ctx = image.new_context()
ctx.fill_style = paint
ctx.rounded_rect(50, 50, 100, 100, 25, 25, 25, 25)
ctx.fill()

example output

Heart

python examples/heart.py

path = pixie.parse_path(
    """
    M 20 60
    A 40 40 90 0 1 100 60
    A 40 40 90 0 1 180 60
    Q 180 120 100 180
    Q 20 120 20 60
    z
    """
)

paint = pixie.Paint(pixie.PK_SOLID)
paint.color = pixie.parse_color("#FC427B")

image.fill_path(path, paint)

example output

Masking

python examples/masking.py

lines = pixie.Image(200, 200)
lines.fill(pixie.parse_color("#FC427B"))

paint = pixie.Paint(pixie.PK_SOLID)
paint.color = pixie.parse_color("#F8D1DD")

ctx = lines.new_context()
ctx.stroke_style = paint
ctx.line_width = 30

ctx.stroke_segment(25, 25, 175, 175)
ctx.stroke_segment(25, 175, 175, 25)

path = pixie.parse_path(
    """
    M 20 60
    A 40 40 90 0 1 100 60
    A 40 40 90 0 1 180 60
    Q 180 120 100 180
    Q 20 120 20 60
    z
    """
)

mask = pixie.Mask(200, 200)
mask.fill_path(path)

lines.mask_draw(mask)
image.draw(lines)

example output

Gradient

python examples/gradient.py

paint = pixie.Paint(pixie.PK_GRADIENT_RADIAL)

paint.gradient_handle_positions.append(pixie.Vector2(100, 100))
paint.gradient_handle_positions.append(pixie.Vector2(200, 100))
paint.gradient_handle_positions.append(pixie.Vector2(100, 200))

paint.gradient_stops.append(pixie.ColorStop(pixie.Color(1, 0, 0, 1), 0))
paint.gradient_stops.append(pixie.ColorStop(pixie.Color(1, 0, 0, 0.15625), 1))

path = pixie.parse_path(
    """
    M 20 60
    A 40 40 90 0 1 100 60
    A 40 40 90 0 1 180 60
    Q 180 120 100 180
    Q 20 120 20 60
    z
    """
)

image.fill_path(path, paint)

example output

Image tiled

python examples/image_tiled.py

path = pixie.Path()
path.polygon(100, 100, 70, 8)

paint = pixie.Paint(pixie.PK_IMAGE_TILED)
paint.image = pixie.read_image("examples/data/baboon.png")
paint.image_mat = pixie.scale(0.08, 0.08)

image.fill_path(path, paint)

example output

Shadow

python examples/shadow.py

path = pixie.Path()
path.polygon(100, 100, 70, sides = 8)

paint = pixie.Paint(pixie.PK_SOLID)
paint.color = pixie.Color(1, 1, 1, 1)

polygon_image = pixie.Image(200, 200)
polygon_image.fill_path(path, paint)

shadow = polygon_image.shadow(
    offset = pixie.Vector2(2, 2),
    spread = 2,
    blur = 10,
    color = pixie.Color(0, 0, 0, 0.78125)
)

image.draw(shadow)
image.draw(polygon_image)

example output

Blur

python examples/blur.py

trees = pixie.read_image("examples/data/trees.png")

path = pixie.Path()
path.polygon(100, 100, 70, 6)

mask = pixie.Mask(200, 200)
mask.fill_path(path)

blur = trees.copy()
blur.blur(20)
blur.mask_draw(mask)

image.draw(trees)
image.draw(blur)

example output

Tiger

python examples/tiger.py

tiger = pixie.read_image("examples/data/tiger.svg")

image.draw(
    tiger,
    pixie.translate(100, 100) *
    pixie.scale(0.2, 0.2) *
    pixie.translate(-450, -450)
)

example output

Comments
  • Having some trouble with vertical alignment

    Having some trouble with vertical alignment

    I'm trying to have some text with two lines, aligned to the bottom of some bounds, and with a small line-height so that the two lines are closer together. However the text is not going where I would expect. It looks like it's going too downwards. When aligned to bottom it even goes outside the bounds. If I leave the line-height to default it also doesn't look right. Am I missing something?

    Here's an example and it's output:

    import pixie
    
    image = pixie.Image(800, 800)
    image.fill(pixie.Color(1, 1, 1, 1))
    
    paint = pixie.Paint(pixie.PK_SOLID)
    paint.color = pixie.Color(1, 0, 0, 1)
    ctx = image.new_context()
    ctx.line_width = 1
    ctx.stroke_style = paint
    ctx.stroke_rect(0, 266, 800, 318)
    
    text = "AbCd\naBcD"
    
    font = pixie.read_font("./Inter-Bold.otf")
    font.size = 182
    font.line_height = 140
    
    font.paint.color = pixie.Color(1, 0, 0, 1)
    image.fill_text(
        font,
        text,
        bounds = pixie.Vector2(800, 318),
        h_align = pixie.HA_CENTER,
        v_align = pixie.VA_TOP,
        transform = pixie.translate(0, 266)
    )
    
    font.paint.color = pixie.Color(0, 1, 0, 1)
    image.fill_text(
        font,
        text,
        bounds = pixie.Vector2(800, 318),
        h_align = pixie.HA_CENTER,
        v_align = pixie.VA_MIDDLE,
        transform = pixie.translate(0, 266)
    )
    
    font.paint.color = pixie.Color(0, 0, 1, 1)
    image.fill_text(
        font,
        text,
        bounds = pixie.Vector2(800, 318),
        h_align = pixie.HA_CENTER,
        v_align = pixie.VA_BOTTOM,
        transform = pixie.translate(0, 266)
    )
    
    image.write_file("out.png")
    

    result

    opened by EnricoMonese 4
  • Unable to load jpg on Linux

    Unable to load jpg on Linux

    Installed pixie-python via pip, however when I try to load a JPG I get the following exception.

    Exception has occurred: PixieError
    Decoding JPG requires -d:pixieUseStb
    

    I guess pixie is using std image library under the hood and the package did not get compiled with the correct options to support this?

    opened by EdMUK 3
  • genny supporting dart ffi

    genny supporting dart ffi

    Hi treeform, very nice lib (looking at the python output), I have recently discovered Flutter over dart language, they create a nice vibrant UI experience. BUT:

    its ffi lib is just so ugly, shudders! it's ffi interop is very verbose and looks annoying to get done, at the same time, devs seem to flock to this (relatively) new platform but not many want to get hands dirty in C code, so Nim to the rescue right?

    Can genny also support the dart programming language? it's just generating a lot of ugly boilerplate code.

    I think it's a chance to get more people to use Nim, and thereby building more libs and contributing to it, which was one of your purposes with genny.

    Aside from that, I personally want to leverage Nim libraries that i and others have written, and use dart and flutter mainly for the GUI story (though in terms of features, dart looks to be a decent language. unfortunately for dart, in terms of syntax - verbose like java and I think no templates, but this is just first impressions.)

    opened by kobi2187 2
  • support encodeImage method

    support encodeImage method

    I see there is an encodeImage proc in the nim library, would it be possible to support that as well as the already existing write_file() in the python layer?

    https://nimdocs.com/treeform/pixie/pixie.html#encodeImage%2CImage%2CFileFormat

    opened by RobBrazier 2
  • OSError: /lib/x86_64-linux-gnu/libm.so.6: version `GLIBC_2.29' not found on Google Colab

    OSError: /lib/x86_64-linux-gnu/libm.so.6: version `GLIBC_2.29' not found on Google Colab

    import pixie gives error:

    ---------------------------------------------------------------------------
    
    OSError                                   Traceback (most recent call last)
    
    <ipython-input-14-4833f4429f21> in <module>()
    ----> 1 import pixie
          2 
          3 
    
    3 frames
    
    /usr/lib/python3.7/ctypes/__init__.py in __init__(self, name, mode, handle, use_errno, use_last_error)
        362 
        363         if handle is None:
    --> 364             self._handle = _dlopen(self._name, mode)
        365         else:
        366             self._handle = handle
    
    OSError: /lib/x86_64-linux-gnu/libm.so.6: version `GLIBC_2.29' not found (required by /usr/local/lib/python3.7/dist-packages/pixie/libpixie.so)
    

    https://i.imgur.com/N1ue3Ce.png

    opened by arye321 2
  • module 'pixie' has no attribute 'PK_SOLID'

    module 'pixie' has no attribute 'PK_SOLID'

    This is the source code:

    import pixie
    
    image = pixie.Image(200, 200)
    image.fill(pixie.Color(1, 1, 1, 1))
    
    paint = pixie.Paint(pixie.PK_SOLID)
    paint.color = pixie.Color(1, 0, 0, 1)
    
    ctx = image.new_context()
    ctx.fill_style = paint
    
    ctx.fill_rect(50, 50, 100, 100)
    
    image.write_file("examples/square.png")
    

    I got the following results: Traceback (most recent call last): File "F:\Python\Python Project\Test\test.py", line 6, in paint = pixie.Paint(pixie.PK_SOLID) AttributeError: module 'pixie' has no attribute 'PK_SOLID'

    opened by ZaneHuangPro 1
  • Request: Text h_align = pixie.JUSTIFY_ALIGN

    Request: Text h_align = pixie.JUSTIFY_ALIGN

    Would be nice if add this alignment style, also give access to Arrangement attributes(selectionRects, lines, positions).

    I've made this little library for making this feature for me, it behaves like the Microsoft Word Office.

    import
        nimpy,
        pixie,
        unicode
    
    pyExportModule("pixie_utils")
    
    const
        LF = Rune(10)
        NR = Rune(0)
    
    proc justifyArrangement*(arrangement: Arrangement, maxWidth: float32) {.raises: [].} =
        proc right(rect: Rect): float32 =
            rect.x + rect.w
    
        let
            runes: ptr = arrangement.runes.addr
            positions: ptr = arrangement.positions.addr
            rects: ptr = arrangement.selectionRects.addr
            last_lineId: int = arrangement.lines.len-1
        var
            rune, last_rune: Rune
            last_wordRuneId: int
            spaces_idx: seq[int]
            inc_width, space_width, line_width, x_offset: float32
        
        for lineId, (start, stop) in arrangement.lines:
            last_rune = runes[stop]
    
            # This line must not be justified, if it is the last or if the last rune is a breakline char.
            if lineId == last_lineId or last_rune.uint32 == LF.uint32:
                continue
    
            echo runes[start..stop]
            # Get the spaces indexes of this line to increase their width, and get the line width.
            spaces_idx = @[]
            last_rune = NR
            for r_id in start..stop:
                rune = runes[r_id]
                if not rune.isWhiteSpace():
                    if last_rune.isWhiteSpace():
                        spaces_idx.add(r_id-1)
                    last_wordRuneId = r_id
                last_rune = runes[r_id]
    
            line_width = rects[last_wordRuneId].right
    
            echo "Line spaces: ", spaces_idx.len
            if spaces_idx.len > 0:
                # Get the amount of pixels/units to increase each space width in the middle of the line.
                inc_width = (maxWidth - line_width) / spaces_idx.len.float32
    
                if inc_width > 0:
                    space_width = rects[spaces_idx[0]].w + inc_width
    
                    # Adjust the runes X position
                    x_offset = 0
                    for r_id in spaces_idx[0]..stop:
                        positions[r_id].x += x_offset
    
                        if r_id in spaces_idx:
                            rects[r_id].x += x_offset
                            rects[r_id].w = space_width
                            x_offset += inc_width
                        else:
                            rects[r_id].x += x_offset
    
    proc justifyArrangement(arrangement_ref: int, maxWidth: float32) {.exportpy: "justifyArrangement".} =
        justifyArrangement(cast[Arrangement](arrangement_ref), maxWidth)
    
    opened by IagoBeuller 0
  • Request: image.to_bytes() function

    Request: image.to_bytes() function

    I need the bytes of the images, for example, use them in pillow or pygame.

    I've made this little library for making this feature for me, it gets the image data bytes as well the png file bytes.

    import
        nimpy,
        pixie
    
    pyExportModule("pixie_utils")
    
    proc getImageBytes*(image: Image, format: string = "png"): string {.raises: [PixieError].} =
      # Gets the bytes from image.
      let encodeFormat = case format:
        of "png": PngFormat
        of "bmp": BmpFormat
        of "jpg", "jpeg": JpegFormat
        of "qoi": QoiFormat
        of "ppm": PpmFormat
        else:
          raise newException(PixieError, "Unsupported image format")
    
      result = image.encodeImage(encodeFormat)
    
    proc getImageData*(image: Image): string {.raises: [].} =
      # Gets the image data as bytes.
      result = newString(image.width * image.height * 4)
      var
        i = 0
        rgba: ColorRGBA
      
      for color in image.data:
        rgba = color.rgba()
        result[i] = rgba.r.char
        result[i+1] = rgba.g.char
        result[i+2] = rgba.b.char
        result[i+3] = rgba.a.char
        i += 4
    
    proc getImageBytes(image_ref: int, format: string = "png"): string {.exportpy: "getImageBytes".} =
        result = getImageBytes(cast[Image](image_ref), format)
    
    proc getImageData(image_ref: int): string {.exportpy: "getImageData".} =
        result = getImageData(cast[Image](image_ref))
    
    opened by IagoBeuller 0
  • Can I do Image Mosaic Using this library?

    Can I do Image Mosaic Using this library?

    Hi,

    If I have known the related offset of translation and angle in pixels between centers of 2 images, can I use this library to generate a mosaic without explicitly considering allocating a big matrix matching to final image size, compensating for non-integer offset values, and converting the offset between image centers to left-up image origin?

    Now, I'm doing these trivial things. It's fragile and troublesome.

    opened by HikariS97 0
Releases(4.3.0)
  • 4.3.0(May 24, 2022)

    What's Changed

    • 4.3.0 by @guzba in https://github.com/treeform/pixie-python/pull/21

    Full Changelog: https://github.com/treeform/pixie-python/compare/4.0.1...4.3.0

    Source code(tar.gz)
    Source code(zip)
  • 4.0.1(Feb 23, 2022)

    What's Changed

    • 4.0.1 by @guzba in https://github.com/treeform/pixie-python/pull/18

    Full Changelog: https://github.com/treeform/pixie-python/compare/3.1.4...4.0.1

    Source code(tar.gz)
    Source code(zip)
  • 3.1.4(Feb 6, 2022)

    What's Changed

    • pixie 3.1.4 by @guzba in https://github.com/treeform/pixie-python/pull/16

    Full Changelog: https://github.com/treeform/pixie-python/compare/3.0.2...3.1.4

    Source code(tar.gz)
    Source code(zip)
  • 3.0.2(Oct 28, 2021)

    What's Changed

    • font.paint by @guzba in https://github.com/treeform/pixie-python/pull/14

    Full Changelog: https://github.com/treeform/pixie-python/compare/0.1.4...3.0.2

    Source code(tar.gz)
    Source code(zip)
Owner
treeform
I like the Nim programming language.
treeform
Binarize document images

Binarization Binarization for document images Examples Introduction This tool performs document image binarization (i.e. transform colour/grayscale to

QURATOR-SPK 48 Jan 02, 2023
A curated list of papers and resources for scene text detection and recognition

Awesome Scene Text A curated list of papers and resources for scene text detection and recognition The year when a paper was first published, includin

Jan Zdenek 43 Mar 15, 2022
FastOCR is a desktop application for OCR API.

FastOCR FastOCR is a desktop application for OCR API. Installation Arch Linux fastocr-git @ AUR Build from AUR or install with your favorite AUR helpe

Bruce Zhang 58 Jan 07, 2023
GDB python tool to pretty print and debug c++ xtensor containers

gdb_xt2np GDB python tool to pretty print, examine, and debug c++ Xtensor containers. Xtensor is a c++ library for scientific computing using multidim

Christopher Burke 4 Oct 29, 2021
Read Japanese manga inside browser with selectable text.

mokuro Read Japanese manga with selectable text inside a browser. See demo: https://kha-white.github.io/manga-demo mokuro_demo.mp4 Demo contains excer

Maciej Budyś 170 Dec 27, 2022
With the virtual keyboard, you can write on the real time images by combining the thumb and index fingers on the letter you want.

Virtual Keyboard With the virtual keyboard, you can write on the real time images by combining the thumb and index fingers on the letter you want. At

Güldeniz Bektaş 5 Jan 23, 2022
Table Extraction Tool

Tree Structure - Table Extraction Fonduer has been successfully extended to perform information extraction from richly formatted data such as tables.

HazyResearch 88 Jun 02, 2022
Image processing in Python

scikit-image: Image processing in Python Website (including documentation): https://scikit-image.org/ Mailing list: https://mail.python.org/mailman3/l

Image Processing Toolbox for SciPy 5.2k Dec 30, 2022
Kornia is a open source differentiable computer vision library for PyTorch.

Open Source Differentiable Computer Vision Library

kornia 7.6k Jan 06, 2023
(CVPR 2021) Back-tracing Representative Points for Voting-based 3D Object Detection in Point Clouds

BRNet Introduction This is a release of the code of our paper Back-tracing Representative Points for Voting-based 3D Object Detection in Point Clouds,

86 Oct 05, 2022
Localization of thoracic abnormalities model based on VinBigData (top 1%)

Repository contains the code for 2nd place solution of VinBigData Chest X-ray Abnormalities Detection competition. The goal of competition was to auto

33 May 24, 2022
CNN+LSTM+CTC based OCR implemented using tensorflow.

CNN_LSTM_CTC_Tensorflow CNN+LSTM+CTC based OCR(Optical Character Recognition) implemented using tensorflow. Note: there is No restriction on the numbe

Watson Yang 356 Dec 08, 2022
Primary QPDF source code and documentation

QPDF QPDF is a command-line tool and C++ library that performs content-preserving transformations on PDF files. It supports linearization, encryption,

QPDF 2.2k Jan 04, 2023
The papers published in top-tier AI conferences in recent years.

AI-conference-papers The papers published in top-tier AI conferences in recent years. Paper table AAAI ICLR CVPR ICML ICCV ECCV NIPS 2019 ✔️ ✔️ ✔️ ✔️

Jinbae Park 6 Dec 09, 2022
EQFace: An implementation of EQFace: A Simple Explicit Quality Network for Face Recognition

EQFace: A Simple Explicit Quality Network for Face Recognition The first face recognition network that generates explicit face quality online.

DeepCam Shenzhen 141 Dec 31, 2022
This can be use to convert text in a file to handwritten text.

TextToHandwriting This can be used to convert text to handwriting. Clone this project or download the code. Run TextToImage.py give the filename of th

Ashutosh Mahapatra 2 Feb 06, 2022
Using python libraries to track hands

Python-HandTracking Using python libraries to track hands on a camera Uses cv2 and mediapipe libraries custom hand tracking module PyCharm IDE Final E

Martin Matsudaira 1 Dec 17, 2021
Virtualdragdrop - Virtual Drag and Drop Using OpenCV and Arduino

Virtualdragdrop - Virtual Drag and Drop Using OpenCV and Arduino

Rizky Dermawan 4 Mar 10, 2022
Opencv-image-filters - A camera to capture videos in real time by placing filters using Python with the help of the Tkinter and OpenCV libraries

Opencv-image-filters - A camera to capture videos in real time by placing filters using Python with the help of the Tkinter and OpenCV libraries

Sergio Díaz Fernández 1 Jan 13, 2022
A selectional auto-encoder approach for document image binarization

The code of this repository was used for the following publication. If you find this code useful please cite our paper: @article{Gallego2019, title =

Javier Gallego 89 Nov 18, 2022