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
Indonesian ID Card OCR using tesseract OCR

KTP OCR Indonesian ID Card OCR using tesseract OCR KTP OCR is python-flask with tesseract web application to convert Indonesian ID Card to text / JSON

Revan Muhammad Dafa 5 Dec 06, 2021
MONAI Label is a server-client system that facilitates interactive medical image annotation by using AI.

MONAI Label is a server-client system that facilitates interactive medical image annotation by using AI. It is an open-source and easy-to-install ecosystem that can run locally on a machine with one

Project MONAI 344 Dec 23, 2022
caffe re-implementation of R2CNN: Rotational Region CNN for Orientation Robust Scene Text Detection

R2CNN: Rotational Region CNN for Orientation Robust Scene Text Detection Abstract This is a caffe re-implementation of R2CNN: Rotational Region CNN fo

candler 80 Dec 28, 2021
Driver Drowsiness Detection with OpenCV & Dlib

In this project, we have built a driver drowsiness detection system that will detect if the eyes of the driver are close for too long and infer if the driver is sleepy or inactive.

Mansi Mishra 4 Oct 26, 2022
Hand Detection and Finger Detection on Live Feed

Hand-Detection-On-Live-Feed Hand Detection and Finger Detection on Live Feed Getting Started Install the dependencies $ git clone https://github.com/c

Chauhan Mahaveer 2 Jan 02, 2022
Single Shot Text Detector with Regional Attention

Single Shot Text Detector with Regional Attention Introduction SSTD is initially described in our ICCV 2017 spotlight paper. A third-party implementat

Pan He 215 Dec 07, 2022
Convolutional Recurrent Neural Networks(CRNN) for Scene Text Recognition

CRNN_Tensorflow This is a TensorFlow implementation of a Deep Neural Network for scene text recognition. It is mainly based on the paper "An End-to-En

MaybeShewill-CV 1000 Dec 27, 2022
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
Code for the head detector (HeadHunter) proposed in our CVPR 2021 paper Tracking Pedestrian Heads in Dense Crowd.

Head Detector Code for the head detector (HeadHunter) proposed in our CVPR 2021 paper Tracking Pedestrian Heads in Dense Crowd. The head_detection mod

Ramana Subramanyam 76 Dec 06, 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
An Optical Character Recognition system using Pytesseract/Extracting data from Blood Pressure Reports.

Optical_Character_Recognition An Optical Character Recognition system using Pytesseract/Extracting data from Blood Pressure Reports. As an IOT/Compute

Ramsis Hammadi 1 Feb 12, 2022
Text-to-Image generation

Generate vivid Images for Any (Chinese) text CogView is a pretrained (4B-param) transformer for text-to-image generation in general domain. Read our p

THUDM 1.3k Jan 05, 2023
A set of workflows for corpus building through OCR, post-correction and normalisation

PICCL: Philosophical Integrator of Computational and Corpus Libraries PICCL offers a workflow for corpus building and builds on a variety of tools. Th

Language Machines 41 Dec 27, 2022
An advanced 2D image manipulation with features such as edge detection and image segmentation built using OpenCV

OpenCV-ToothPaint3-Advanced-Digital-Image-Editor This application named ‘Tooth Paint’ version TP_2020.3 (64-bit) or version 3 was developed within a w

JunHong 1 Nov 05, 2021
This repo contains a script that allows us to find range of colors in images using openCV, and then convert them into geo vectors.

Vectorizing color range This repo contains a script that allows us to find range of colors in images using openCV, and then convert them into geo vect

Development Seed 9 Jul 27, 2022
It is a image ocr tool using the Tesseract-OCR engine with the pytesseract package and has a GUI.

OCR-Tool It is a image ocr tool made in Python using the Tesseract-OCR engine with the pytesseract package and has a GUI. This is my second ever pytho

Khant Htet Aung 4 Jul 11, 2022
QuanTaichi: A Compiler for Quantized Simulations (SIGGRAPH 2021)

QuanTaichi: A Compiler for Quantized Simulations (SIGGRAPH 2021) Yuanming Hu, Jiafeng Liu, Xuanda Yang, Mingkuan Xu, Ye Kuang, Weiwei Xu, Qiang Dai, W

Taichi Developers 119 Dec 02, 2022
Regions sanitàries (RS), Sectors Sanitàris (SS) i Àrees Bàsiques de Salut (ABS) de Catalunya

Regions sanitàries (RS), Sectors Sanitaris (SS), Àrees de Gestió Assistencial (AGA) i Àrees Bàsiques de Salut (ABS) de Catalunya Fitxers GeoJSON de le

Glòria Macià Muñoz 2 Jan 23, 2022
Um simples projeto para fazer o reconhecimento do captcha usado pelo jogo bombcrypto

CaptchaSolver - LEIA ISSO 😓 Para iniciar o codigo: pip install -r requirements.txt python captcha_solver.py Se você deseja pegar ver o resultado das

Kawanderson 50 Mar 21, 2022
Make OpenCV camera loops less of a chore by skipping the boilerplate and getting right to the interesting stuff

camloop Forget the boilerplate from OpenCV camera loops and get to coding the interesting stuff Table of Contents Usage Install Quickstart More advanc

Gabriel Lefundes 9 Nov 12, 2021