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
Scale-aware Automatic Augmentation for Object Detection (CVPR 2021)

SA-AutoAug Scale-aware Automatic Augmentation for Object Detection Yukang Chen, Yanwei Li, Tao Kong, Lu Qi, Ruihang Chu, Lei Li, Jiaya Jia [Paper] [Bi

Jia Research Lab 182 Dec 29, 2022
Rest API Written In Python To Classify NSFW Images.

✨ NSFW Classifier API ✨ Rest API Written In Python To Classify NSFW Images. Fastest Solution If you don't want to selfhost it, there's already an inst

Akshay Rajput 23 Dec 30, 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
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 toolbox of scene text detection and recognition

FudanOCR This toolbox contains the implementations of the following papers: Scene Text Telescope: Text-Focused Scene Image Super-Resolution [Chen et a

FudanVIC Team 170 Dec 26, 2022
Msos searcher - A half-hearted attempt at finding a magic square of squares

MSOS searcher A half-hearted attempt at finding (or rather searching) a MSOS (Magic Square of Squares) in the spirit of the Parker Square. Running I r

Niels Mündler 1 Jan 02, 2022
Semantic-based Patch Detection for Binary Programs

PMatch Semantic-based Patch Detection for Binary Programs Requirement tensorflow-gpu 1.13.1 numpy 1.16.2 scikit-learn 0.20.3 ssdeep 3.4 Usage tar -xvz

Mr.Curiosity 3 Sep 02, 2022
Write-ups for the SwissHackingChallenge2021 CTF.

SwissHackingChallenge 2021 : Write-ups This repository contains a collection of my write-ups for challenges solved during the SwissHackingChallenge (S

Julien Béguin 3 Jun 07, 2021
EAST for ICPR MTWI 2018 Challenge II (Text detection of network images)

EAST_ICPR2018: EAST for ICPR MTWI 2018 Challenge II (Text detection of network images) Introduction This is a repository forked from argman/EAST for t

QichaoWu 49 Dec 24, 2022
BD-ALL-DIGIT - This Is Bangladeshi All Sim Cloner Tools

BANGLADESHI ALL SIM CLONER TOOLS INSTALL TOOL ON TERMUX $ apt update $ apt upgra

MAHADI HASAN AFRIDI 2 Jan 19, 2022
Python Computer Vision from Scratch

This repository explores the variety of techniques commonly used to analyze and interpret images. It also describes challenging real-world applications where vision is being successfully used, both f

Milaan Parmar / Милан пармар / _米兰 帕尔马 221 Dec 26, 2022
A real-time dolly zoom camera effect

Dolly-Zoom I've always been amazed by the gradual perspective change of dolly zoom, and I have some experience in python and OpenCV, so I decided to c

Dylan Kai Lau 52 Dec 08, 2022
Validate and transform various OCR file formats (hOCR, ALTO, PAGE, FineReader)

ocr-fileformat Validate and transform between OCR file formats (hOCR, ALTO, PAGE, FineReader) Installation Docker System-wide Usage CLI GUI API Transf

Universitätsbibliothek Mannheim 152 Dec 20, 2022
Detect handwritten words in a text-line (classic image processing method).

Word segmentation Implementation of scale space technique for word segmentation as proposed by R. Manmatha and N. Srimal. Even though the paper is fro

Harald Scheidl 190 Jan 03, 2023
~1000 book pages + OpenCV + python = page regions identified as paragraphs, lines, images, captions, etc.

cosc428-structor I had an open-ended Computer Vision assignment to complete, and an out-of-copyright book that I wanted to turn into an ebook. Convent

Chad Oliver 45 Dec 06, 2022
OCR software for recognition of handwritten text

Handwriting OCR The project tries to create software for recognition of a handwritten text from photos (also for Czech language). It uses computer vis

Břetislav Hájek 562 Jan 03, 2023
Distilling Knowledge via Knowledge Review, CVPR 2021

ReviewKD Distilling Knowledge via Knowledge Review Pengguang Chen, Shu Liu, Hengshuang Zhao, Jiaya Jia This project provides an implementation for the

DV Lab 194 Dec 28, 2022
Color Picker and Color Detection tool for METR4202

METR4202 Color Detection Help This is sample code that can be used for the METR4202 project demo. There are two files provided, both running on Python

Miguel Valencia 1 Oct 23, 2021
CellProfiler is a open-source application for biological image analysis

CellProfiler is a free open-source software designed to enable biologists without training in computer vision or programming to quantitatively measure phenotypes from thousands of images automaticall

CellProfiler 732 Dec 23, 2022
Go package for OCR (Optical Character Recognition), by using Tesseract C++ library

gosseract OCR Golang OCR package, by using Tesseract C++ library. OCR Server Do you just want OCR server, or see the working example of this package?

Hiromu OCHIAI 1.9k Dec 28, 2022