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
Introduction to image processing, most used and popular functions of OpenCV

👀 OpenCV 101 Introduction to image processing, most used and popular functions of OpenCV go here.

Vusal Ismayilov 3 Jul 02, 2022
Deep Learning Chinese Word Segment

引用 本项目模型BiLSTM+CRF参考论文:http://www.aclweb.org/anthology/N16-1030 ,IDCNN+CRF参考论文:https://arxiv.org/abs/1702.02098 构建 安装好bazel代码构建工具,安装好tensorflow(目前本项目需

2.1k Dec 23, 2022
Roboflow makes managing, preprocessing, augmenting, and versioning datasets for computer vision seamless.

Roboflow makes managing, preprocessing, augmenting, and versioning datasets for computer vision seamless. This is the official Roboflow python package that interfaces with the Roboflow API.

Roboflow 52 Dec 23, 2022
Code for AAAI 2021 paper: Sequential End-to-end Network for Efficient Person Search

This repository hosts the source code of our paper: [AAAI 2021]Sequential End-to-end Network for Efficient Person Search. SeqNet achieves the state-of

Zj Li 218 Dec 31, 2022
make a better chinese character recognition OCR than tesseract

deep ocr See README_en.md for English installation documentation. 只在ubuntu下面测试通过,需要virtualenv安装,安装路径可自行调整: git clone https://github.com/JinpengLI/deep

Jinpeng 1.5k Dec 28, 2022
Convert Text-to Handwriting Using Python

Convert Text-to Handwriting Using Python Description In this project we'll use python library that's "pywhatkit" for converting text to handwriting. t

8 Nov 19, 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
This is a GUI program which consist of 4 OpenCV projects

Tkinter-OpenCV Project Using Tkinter, Opencv, Mediapipe This is a python GUI program using Tkinter which consist of 4 OpenCV projects 1. Finger Counte

Arya Bagde 3 Feb 22, 2022
A dataset handling library for computer vision datasets in LOST-fromat

A dataset handling library for computer vision datasets in LOST-fromat

8 Dec 15, 2022
📷 Face Recognition using Haar-Cascade Classifier, OpenCV, and Python

Face-Recognition-System Face Recognition using Haar-Cascade Classifier, OpenCV and Python. This project is based on face detection and face recognitio

1 Jan 10, 2022
Code release for Hu et al., Learning to Segment Every Thing. in CVPR, 2018.

Learning to Segment Every Thing This repository contains the code for the following paper: R. Hu, P. Dollár, K. He, T. Darrell, R. Girshick, Learning

Ronghang Hu 417 Oct 03, 2022
Total Text Dataset. It consists of 1555 images with more than 3 different text orientations: Horizontal, Multi-Oriented, and Curved, one of a kind.

Total-Text-Dataset (Official site) Updated on April 29, 2020 (Detection leaderboard is updated - highlighted E2E methods. Thank you shine-lcy.) Update

Chee Seng Chan 671 Dec 27, 2022
Qrcode Attendence System with Opencv and Pyzbar

Setup process Creates a virtual environment (Scripts that ensure executed Python code uses the Python interpreter and site packages installed inside t

Ganesh 5 Aug 01, 2022
A synthetic data generator for text recognition

TextRecognitionDataGenerator A synthetic data generator for text recognition What is it for? Generating text image samples to train an OCR software. N

Edouard Belval 2.5k Jan 04, 2023
Motion detector, Full body detection, Upper body detection, Cat face detection, Smile detection, Face detection (haar cascade), Silverware detection, Face detection (lbp), and Sending email notifications

Security camera running OpenCV for object and motion detection. The camera will send email with image of any objects it detects. It also runs a server that provides web interface with live stream vid

Peace 10 Jun 30, 2021
Tools for manipulating and evaluating the hOCR format for representing multi-lingual OCR results by embedding them into HTML.

hocr-tools About About the code Installation System-wide with pip System-wide from source virtualenv Available Programs hocr-check -- check the hOCR f

OCRopus 285 Dec 08, 2022
Fast image augmentation library and easy to use wrapper around other libraries. Documentation: https://albumentations.ai/docs/ Paper about library: https://www.mdpi.com/2078-2489/11/2/125

Albumentations Albumentations is a Python library for image augmentation. Image augmentation is used in deep learning and computer vision tasks to inc

11.4k Jan 02, 2023
Learn computer graphics by writing GPU shaders!

This repo contains a selection of projects designed to help you learn the basics of computer graphics. We'll be writing shaders to render interactive two-dimensional and three-dimensional scenes.

Eric Zhang 1.9k Jan 02, 2023
Hiiii this is the Spanish for Linux and win 10 and in the near future the english version of PortScan my new tool on which you can see what ports are Open only with the IP adress.

PortScanner-by-IIT PortScanner es una herramienta programada en Python3. Como su nombre indica esta herramienta escanea los primeros 150 puertos de re

5 Sep 19, 2022
Repository for playing the computer vision apps: People analytics on Raspberry Pi.

play-with-torch Repository for playing the computer vision apps: People analytics on Raspberry Pi. Tools Tested Hardware RasberryPi 4 Model B here, RA

eMHa 1 Sep 23, 2021