Standard library · AI

ai.image

Reading, editing and saving images, and writing text on them.

import ai.image

This package works with images without any outside library: it reads and writes PNG, JPEG and BMP. It also reads and writes WebP, both lossy and lossless. From a GIF it reads the first frame, and it saves an image in a GIF with at most 256 colors. Open and Save work the format out from the content or the extension. Drawing, resizing, cropping, rotating and filters such as blurring and sharpening are all there.

For text, read a TrueType font with LoadFont and write with DrawTextStyled; Persian and Arabic text is shaped and laid out right to left on its own. Use this package for thumbnails, generated cards and charts, watermarks and simple image checks. For computer vision (edges, contours, feature matching) see opencv, and to draw in a browser page, web.canvas.

Things to know

  • Pixels are 8 bit RGBA in memory. Every image owns that memory; release it with Free.
  • Save picks the format from the extension and returns false for one it does not know. It uses quality 90; SaveQuality takes your own.
  • JPEG has no transparency: transparent pixels are laid on white before saving. WebP at quality 100 is lossless, below that lossy.
  • GIF reading gives only the first frame of an animation, and saving reduces the image to 256 colors.
  • Persian shaping uses the Arabic presentation forms of the font, so the font must contain them. FindArabicFont looks for an installed one that does (or the file in $SALAM_FONT_ARABIC).

Thumbnails and fixed-size cards

An upload form usually needs the same picture in several sizes. Thumbnail shrinks the image so that its longer side fits and keeps the shape. ResizeFill fills an exact box and cuts off what sticks out, which suits square avatars and product cards. ResizeFit keeps the whole picture inside the box and centers it, leaving empty bands at the sides. Save chooses the format from the extension, so the same code writes PNG, JPEG or WebP.

image-guide-thumbs.salam
import ai.image

func size(img: image.Image): str:
    ret "" + img.width + "x" + img.height
end

func main:
    mut photo := image.New(1200, 800)
    defer image.Free(photo)
    image.FillHex(photo, "#3a6ea5")
    image.DrawCircleFilled(photo, 600, 400, 250, image.ParseHex("#f2c14e"))
    if image.Save(photo, "photo.jpg") == false:
        println "could not write photo.jpg"
        ret 1
    end

    mut ok := false
    mut loaded := image.Open("photo.jpg", ok)
    defer image.Free(loaded)
    println "opened:", ok, size(loaded)

    mut thumb := image.Thumbnail(loaded, 200)
    mut card := image.ResizeFill(loaded, 300, 300)
    mut banner := image.ResizeFit(loaded, 600, 200)
    defer image.Free(thumb)
    defer image.Free(card)
    defer image.Free(banner)
    println "thumbnail:", size(thumb)
    println "square card:", size(card)
    println "banner box:", size(banner)
    image.Save(thumb, "thumb.png")
    image.Save(card, "card.webp")
    println "formats:", image.FormatFromExt("thumb.png") == image.FormatPNG, image.FormatFromExt("card.webp") == image.FormatWebP
end
Outputopened: true 1200x800 thumbnail: 200x133 square card: 300x300 banner box: 600x200 formats: true true

Open reports through its bool argument whether the file could be read. Every image allocates memory for its pixels, so release each one with Free, as the defer lines do.

Draw a simple chart

Lines, rectangles and circles plus the built-in pixel font are enough for a small bar chart, a badge or a placeholder image, with no font file needed. LerpColor mixes two colors, here to make taller bars darker, and ParseHex and ToHexRGB move between colors and CSS-style hex. TextWidth measures text before you draw it, so labels can be centered under their bars.

image-guide-chart.salam
import ai.image

func main:
    sales := [12, 30, 22, 41, 35]
    labels := ["MON", "TUE", "WED", "THU", "FRI"]
    width := 260
    height := 160
    mut chart := image.NewFilled(width, height, image.RGB(255, 255, 255))
    defer image.Free(chart)
    low := image.ParseHex("#9ecae1")
    high := image.ParseHex("#08519c")
    image.DrawLine(chart, 20, 130, 250, 130, image.Gray(80))
    each i, value in sales:
        bar := value * 2
        x := 30 + i * 45
        shade := image.LerpColor(low, high, (value as f64) / 41.0)
        image.DrawRectFilled(chart, x, 130 - bar, 30, bar, shade)
        image.DrawText(chart, x + 15 - image.TextWidth(labels[i], 1) / 2, 136, labels[i], image.Gray(40), 1)
    end
    image.DrawText(chart, 20, 8, "SALES", image.Gray(20), 2)
    image.Save(chart, "chart.png")

    top := image.GetPixel(chart, 30 + 3 * 45 + 15, 130 - 41)
    println "tallest bar color:", image.ToHexRGB(top)
    println "first bar color:", image.ToHexRGB(image.GetPixel(chart, 45, 129))
    println "background:", image.ToHexRGB(image.GetPixel(chart, 5, 5))
    println "title width:", image.TextWidth("SALES", 2), "px"
end
Outputtallest bar color: #08519c first bar color: #72a6cc background: #ffffff title width: 60 px

The pixel font has only capital English letters, digits and the signs . , - : ! ?; anything else, lower case letters included, is drawn as a blank. For Persian or any other script, and for smooth text at large sizes, load a TrueType font with LoadFont and use DrawTextStyled, which shapes Persian letters and lays them out right to left.

Filters and measuring the difference

Blurred and Sharpened return new images; Grayscale, Threshold, Brightness and Contrast change the image in place. To compare two images, MeanAbsError gives the average difference per channel and PSNR the signal to noise ratio in decibels, where higher means more alike. The numbers show that sharpening a blurred image does not bring the original back: it makes the edges stronger, not correct.

image-guide-filters.salam
import ai.image
import fmt

func main:
    mut base := image.New(64, 64)
    defer image.Free(base)
    image.Fill(base, image.RGB(30, 30, 30))
    image.DrawRectFilled(base, 16, 16, 32, 32, image.RGB(240, 240, 240))

    mut soft := image.Blurred(base, 3)
    mut crisp := image.Sharpened(soft, 1.0)
    defer image.Free(soft)
    defer image.Free(crisp)
    println "edge pixel, original:", image.ToHexRGB(image.GetPixel(base, 16, 32))
    println "edge pixel, blurred: ", image.ToHexRGB(image.GetPixel(soft, 16, 32))
    println "blur error:", fmt.FloatPrec(image.MeanAbsError(base, soft), 2), "PSNR", fmt.FloatPrec(image.PSNR(base, soft), 1), "dB"
    println "sharpened again:", fmt.FloatPrec(image.PSNR(base, crisp), 1), "dB, edge", image.ToHexRGB(image.GetPixel(crisp, 16, 32))

    mut gray := image.Clone(base)
    defer image.Free(gray)
    image.FillHex(gray, "#cc3344")
    image.Grayscale(gray)
    println "red after Grayscale:", image.ToHexRGB(image.GetPixel(gray, 0, 0)), "luminance", image.Luminance(image.ParseHex("#cc3344"))
    image.Threshold(gray, 128)
    println "after Threshold(128):", image.ToHexRGB(image.GetPixel(gray, 0, 0))
end
Outputedge pixel, original: #f0f0f0 edge pixel, blurred: #969696 blur error: 10.94 PSNR 19.2 dB sharpened again: 15.0 dB, edge #969696 red after Grayscale: #626262 luminance 98 after Threshold(128): #000000

Grayscale uses perceived brightness, the same value Luminance returns, so a strong red becomes a fairly dark gray. These measures are also handy in tests: render an image and check that its PSNR against a stored reference stays above a limit.

A share card with Persian text

A link preview image is a fixed 1200 by 630 canvas with a title that must fit whatever its length. DrawTextFitBox finds the largest size up to a limit at which the text fits a share of the box, centers it and returns the size it chose. TextWidthStyled measures text first, here to right-align the address in the corner; the y coordinate of DrawTextStyled is the baseline.

image-guide-card.salam
import ai.image
import os

func main:
    args := os.Args()
    mut path := image.FindArabicFont()
    if args.len() > 1:
        path = args.get(1)
    end
    mut ok := false
    mut font := image.LoadFont(path, ok)
    if not ok:
        println "no font with Persian letters; pass a .ttf path"
        ret 1
    end
    defer image.FreeFont(font)
    mut card := image.NewFilled(1200, 630, image.ParseHex("#1b4332"))
    defer image.Free(card)
    white := image.RGB(255, 255, 255)
    title := image.TextStyle { size = 72.0 }
    size := image.DrawTextFitBox(card, 80.0, 120.0, 1040.0, 260.0, "سلام ۰٫۶ منتشر شد: سریع‌تر و کوچک‌تر", white, font, title, 0.9, 96.0)
    println "title size:", size
    small := image.TextStyle { size = 36.0 }
    width := image.TextWidthStyled(font, "salamlang.ir", small)
    image.DrawTextStyled(card, 1120.0 - width, 560.0, "salamlang.ir", image.ParseHex("#95d5b2"), font, small)
    println "saved:", image.Save(card, "release-card.png")
end

The program takes a font path as its first argument and otherwise asks FindArabicFont, so it needs a font file and the site only compiles it. With Vazirmatn the title came out at about 61 pixels; the joined letters, the zero width non-joiner in سریع‌تر and the right to left order are all handled by the package.

Watermark a photo

Overlay draws one image on top of another at a position, with an opacity from 0 to 1, and respects the transparency of the top image. Here the mark is a half transparent black box with white text, placed ten pixels from the bottom right corner.

image-guide-watermark.salam
import ai.image

func main:
    mut photo := image.NewFilled(400, 300, image.ParseHex("#2d6a4f"))
    defer image.Free(photo)
    text := "MADE WITH SALAM"
    scale := 2
    mut mark := image.New(image.TextWidth(text, scale) + 8, image.FontHeight * scale + 8)
    defer image.Free(mark)
    image.Fill(mark, image.RGBA(0, 0, 0, 160))
    image.DrawText(mark, 4, 4, text, image.RGB(255, 255, 255), scale)
    println "mark size:", mark.width, "x", mark.height

    x := photo.width - mark.width - 10
    y := photo.height - mark.height - 10
    image.Overlay(photo, mark, x, y, 0.6)
    println "placed at", x, y
    println "untouched corner:", image.ToHexRGB(image.GetPixel(photo, 0, 0))
    println "under the mark:", image.ToHexRGB(image.GetPixel(photo, x + 1, y + 1))
    image.Save(photo, "marked.png")
end
Outputmark size: 188 x 22 placed at 202 268 untouched corner: #2d6a4f under the mark: #1c4231
JobUse
Read and write filesOpen, Save, SaveQuality
Make smaller copiesThumbnail, ResizeFit, ResizeFill, Crop
Draw shapes and simple textDrawRectFilled, DrawLine, DrawCircleFilled, DrawText
Text with a real font, Persian tooLoadFont, DrawTextStyled, DrawTextFitBox
Adjust the lookBlurred, Sharpened, Grayscale, Contrast
Combine imagesOverlay
Compare imagesPSNR, MeanAbsError, Diff

Types

TextStyle

struct TextStyle
A text style.
NameTypeDescription
sizef64 = 16The size in pixels.
rotatef64 = 0The rotation in degrees.
skewf64 = 0The skew.
trackingf64 = 0The space added between the characters.
kernbool = trueAdjust the spacing of pairs.
dirint = 0The direction, one of the TextDir... constants.
shapebool = trueJoin the Persian and Arabic letters into their connected shapes.
ai-image-Font.salam
import ai.image
import io

func main:
    println image.FindSystemFont(), image.FindArabicFont()
    mut ok := false
    mut font := image.LoadSystemFont(ok)
    if not ok:
        font = image.LoadFont("Vazirmatn-Regular.ttf", ok)
    end
    if not ok:
        println "no font was found"
        ret
    end
    println image.FontValid(font), image.UnitsPerEm(font), image.NumGlyphs(font)
    size := 32.0
    println image.ScaleFactor(font, size), image.AscentPixels(font, size), image.DescentPixels(font, size), image.LineHeightPixels(font, size)
    a := image.GlyphIndex(font, 65)
    v := image.GlyphIndex(font, 86)
    println image.GlyphAdvance(font, a), image.KernAdvance(font, a, v), image.GlyphHasOutline(font, a)
    mut x0 := 0
    mut y0 := 0
    mut x1 := 0
    mut y1 := 0
    println image.GlyphBox(font, a, x0, y0, x1, y1), x1 - x0, y1 - y0

    mut img := image.NewFilled(400, 120, image.Gray(255))
    black := image.Gray(0)
    _ := image.DrawTextTTF(img, 10.0, 40.0, "Salam", black, font, size)
    println image.TextWidthTTF(font, "Salam", size)
    style := image.TextStyle { size = 28.0, tracking = 1.0, kern = true, dir = image.TextDirAuto, shape = true }
    _ := image.DrawTextStyled(img, 10.0, 80.0, "سلام دنیا", black, font, style)
    println image.TextWidthStyled(font, "سلام دنیا", style), image.TextInkWidth(font, "سلام", style), image.TextInkHeight(font, "سلام", style)
    mut width := 0.0
    mut height := 0.0
    println image.TextInkSize(font, "سلام", style, width, height), width, height
    mut a0 := 0.0
    mut b0 := 0.0
    mut a1 := 0.0
    mut b1 := 0.0
    println image.TextBounds(font, "سلام", style, a0, b0, a1, b1)
    println image.FitSizeToWidth(font, "سلام", style, 200.0, 96.0), image.FitSizeToBox(font, "سلام", style, 200.0, 50.0, 96.0)
    _ := image.DrawGlyphStyled(img, a, 300.0, 40.0, black, font, style)
    _ := image.DrawCodepointStyled(img, 1600, 340.0, 40.0, black, font, style)
    _ := image.DrawTextCentered(img, 200.0, 60.0, "middle", black, font, style)
    _ := image.DrawTextCenteredIn(img, "middle", black, font, style)
    _ := image.DrawTextInBox(img, 0.0, 0.0, 200.0, 60.0, "box", black, font, style, image.TextAlignRight, image.TextVAlignMiddle)
    _ := image.DrawTextFitBox(img, 0.0, 60.0, 200.0, 60.0, "fit", black, font, style, 0.8, 64.0)
    _ := image.DrawTextFitImage(img, "سلام", black, font, style, 0.9, 120.0)
    println image.TextAlignLeft, image.TextAlignCenter, image.TextVAlignTop, image.TextVAlignBottom, image.TextVAlignBaseline
    _ := image.Save(img, "salam-text-en.png")

    data := io.ReadFile("Vazirmatn-Regular.ttf")
    mut f2 := image.ParseFont(data as void*, data.len(), ok)
    mut f3 := image.ParseFontIndex(data as void*, data.len(), 0, ok)
    mut f4 := image.LoadFontIndex("NotoSansCJK.ttc", 0, ok)
    println image.IsCFFFont(data as void*, data.len())
    image.FreeFont(f2)
    image.FreeFont(f3)
    image.FreeFont(f4)
    image.FreeFont(font)
    image.Free(img)
end

AreaResampler

struct AreaResampler
A shrinker that averages the area under each new pixel, computing exactly what libgd's gdImageCopyResampled (PHP's imagecopyresampled) gives. Source rows go in one at a time and only a few output rows of sums are kept, so a picture that is still being made, or is too large to hold, can be shrunk on the way. Alpha passes through gd's 7 bit alpha, so it comes out in 128 steps.
NameTypeDescription
src_wint = 0The source width in pixels.
src_hint = 0The source height in pixels.
dst_wint = 0The output width in pixels.
dst_hint = 0The output height in pixels.
outImageThe output RGBA image; each row is filled as soon as its last source row arrives, and rows not reached yet stay transparent. AreaResamplerFree leaves it, so the caller frees it with Free.
okbool = falseThe resampler was set up; false when a size is zero or less or the output could not be made, and after AreaResamplerFree.
next_rowint = 0The number of the next source row to push; it equals src_h when every row is in.
x_startvoid*Internal: for each output column, where its source spans start in x_src and x_part.
x_countvoid*Internal: how many source columns each output column covers.
x_srcvoid*Internal: the source column of each span.
x_partvoid*Internal: how much of that source column the span covers, from 0 to 1.
y_firstvoid*Internal: the first source row each output row covers.
y_lastvoid*Internal: the last source row each output row covers.
ringint = 0Internal: how many output rows of sums are kept at once.
accvoid*Internal: the running sums, seven 32 bit floats for every pixel of each kept output row.
ai-image-ResizeArea.salam
import ai.image
import compress

func main:
    mut img := image.NewFilled(6, 4, image.Gray(0))
    image.DrawRectFilled(img, 3, 0, 3, 4, image.Gray(255))
    mut small := image.ResizeArea(img, 2, 1)
    println small.width, small.height, image.ToHexRGB(image.GetPixel(small, 0, 0)), image.ToHexRGB(image.GetPixel(small, 1, 0))
    mut dot := image.ResizeArea(img, 1, 1)
    println image.ToHexRGB(image.GetPixel(dot, 0, 0))
    image.Free(dot)
    image.Free(small)
    image.Free(img)

    mut r := image.NewAreaResampler(6, 4, 3, 2)
    println r.ok, r.dst_w, r.dst_h, r.next_row
    mut row := compress.NewByteBuf()
    repeat 4 in y:
        compress.BufReset(row)
        repeat 6 in x:
            v := x < 3 ? 0 : 255
            compress.BufPush(row, v)
            compress.BufPush(row, y * 60)
            compress.BufPush(row, 100)
        end
        image.AreaResamplerPushRow(r, row.data as u8*, 3)
    end
    compress.BufFree(row)
    image.AreaResamplerFree(r)
    println r.next_row, r.ok
    repeat 2 in y:
        println image.ToHexRGB(image.GetPixel(r.out, 0, y)), image.ToHexRGB(image.GetPixel(r.out, 1, y)), image.ToHexRGB(image.GetPixel(r.out, 2, y))
    end
    image.Free(r.out)
end
Output2 1 #000000 #ffffff #808080 true 3 2 0 4 false #001e64 #801e64 #ff1e64 #009664 #809664 #ff9664

Font

struct Font
A TrueType or OpenType font.
NameTypeDescription
Fonttypeset.FontThe gui.typeset font this image font wraps; every field of it can also be read directly.
ai-image-Draw.salam
import ai.image
import os

func main:
    mut img := image.New(8, 6)
    println img.width, img.height, image.IsEmpty(img), image.InBounds(img, 7, 5), image.InBounds(img, 8, 0)
    image.Fill(img, image.RGB(255, 255, 255))
    image.FillHex(img, "#202040")
    image.SetPixel(img, 0, 0, image.RGB(255, 0, 0))
    image.BlendPixel(img, 1, 0, image.RGBA(255, 255, 255, 128))
    println image.ToHex(image.GetPixel(img, 0, 0)), image.ToHex(image.GetPixel(img, 1, 0)), image.ToHexRGB(image.GetPixel(img, 2, 0))
    image.DrawLine(img, 0, 5, 7, 5, image.Gray(200))
    image.DrawRect(img, 1, 1, 4, 3, image.ParseHex("#ffcc00"))
    image.DrawRectFilled(img, 2, 2, 2, 1, image.ParseHex("#00ff00"))
    image.DrawCircle(img, 6, 2, 1, image.Gray(255))
    image.DrawCircleFilled(img, 6, 2, 0, image.Gray(10))
    println image.ToHexRGB(image.GetPixel(img, 3, 2)), image.ToHexRGB(image.GetPixel(img, 4, 5))

    color := image.ParseHex("#336699")
    println color.r, color.g, color.b, color.a, image.Luminance(color)
    println image.Equals(color, image.RGB(51, 102, 153)), image.ToHex(image.Blend(color, image.RGBA(255, 255, 255, 0)))
    println image.ToHexRGB(image.LerpColor(image.Gray(0), image.Gray(200), 0.5))

    mut labelled := image.NewFilled(40, 10, image.Gray(0))
    image.DrawText(labelled, 1, 1, "SALAM", image.Gray(255), 1)
    println image.TextWidth("SALAM", 1), image.FontWidth, image.FontHeight

    dir := os.TempDir()
    println image.Save(img, dir + "/salam_en.png"), image.SavePNG(img, dir + "/salam2_en.png"), image.SaveBMP(img, dir + "/salam_en.bmp"), image.SaveJPEG(img, dir + "/salam_en.jpg", 90)
    println image.SaveQuality(img, dir + "/salam2_en.jpg", 50), image.SaveWebP(img, dir + "/salam_en.webp")
    mut ok := false
    read := image.Open(dir + "/salam_en.png", ok)
    println ok, read.width, image.Equals(image.GetPixel(read, 0, 0), image.GetPixel(img, 0, 0))
    png := image.OpenPNG(dir + "/salam2_en.png", ok)
    bmp := image.OpenBMP(dir + "/salam_en.bmp", ok)
    jpg := image.OpenJPEG(dir + "/salam_en.jpg", ok)
    println ok, png.width, bmp.height, jpg.width
    println image.FormatFromExt("a.jpeg") == image.FormatJPEG, image.FormatFromExt("a.png") == image.FormatPNG, image.FormatFromExt("a.txt") == image.FormatUnknown

    buf := image.EncodePNG(img)
    println image.DetectFormat(buf.data, buf.len) == image.FormatPNG, image.IsWebP(buf.data, buf.len)
    from_buf := image.DecodePNG(buf.data, buf.len, ok)
    generic := image.Decode(buf.data, buf.len, ok)
    println ok, from_buf.width, generic.height
    b := image.EncodeBMP(img)
    b2 := image.DecodeBMP(b.data, b.len, ok)
    j := image.EncodeJPEG(img, 80)
    j2 := image.DecodeJPEG(j.data, j.len, ok)
    println image.DetectFormat(b.data, b.len) == image.FormatBMP, image.DetectFormat(j.data, j.len) == image.FormatJPEG, b2.width, j2.width
    any := image.Encode(img, image.FormatBMP, 90)
    web := image.EncodeWebP(img)
    lossy := image.EncodeWebPQuality(img, 75)
    println any.len == b.len, web.len > 0, image.FormatWebP
    clear := image.NewFilled(1, 1, image.RGBA(0, 0, 0, 0))
    println image.ToHex(image.GetPixel(image.FlattenAlpha(clear, image.Gray(255)), 0, 0))
    converted := image.Convert(img, image.FormatJPEG)
    println converted.width
    webp := image.DecodeWebP(web.data, web.len, ok)
    println ok, webp.width, image.Equals(image.GetPixel(webp, 1, 0), image.GetPixel(img, 1, 0))
    webp3 := image.DecodeWebP(lossy.data, lossy.len, ok)
    println ok, webp3.width, webp3.height
    webp2 := image.OpenWebP(dir + "/salam_en.webp", ok)
    println image.SaveGIF(img, dir + "/salam_en.gif"), image.FormatFromExt("a.gif") == image.FormatGIF
    gif := image.OpenGIF(dir + "/salam_en.gif", ok)
    g := image.EncodeGIF(img)
    gif2 := image.DecodeGIF(g.data, g.len, ok)
    println ok, gif.width, gif2.height, image.IsGIF(g.data, g.len), image.Equals(image.GetPixel(gif, 0, 0), image.GetPixel(img, 0, 0))
    println ok, webp2.height
    mut copy := image.Clone(img)
    image.Free(copy)
    image.Free(img)
end
Output8 6 false true false #ff0000ff #8f8f9fff #202040 #00ff00 #c8c8c8 51 102 153 255 92 true #336699ff #646464 30 5 7 true true true true true true true 8 true true 8 6 8 true true true true false true 8 6 true true 8 8 true true 4 #ffffffff 8 true 8 true true 8 6 true true true 8 6 true true true 6

JPEGOptions

struct JPEGOptions
Settings for the streaming JPEG writer and for EncodeJPEGOptions and SaveJPEGOptions: quality, chroma subsampling, the JFIF pixel density and an optional comment. The output is a baseline JPEG with the same coded data libjpeg writes for the same settings.
NameTypeDescription
qualityint = 90The quality from 1 to 100, 90 by default; values outside that range are clamped. It scales the standard quantization tables the way libjpeg does.
subsamplebool = trueTrue (the default) stores the color at half width and half height (4:2:0), which makes the file smaller; false keeps full color resolution (4:4:4) for sharper color edges.
density_unitint = 0The JFIF density unit: 0 means the densities only give the pixel aspect ratio (the default), 1 is dots per inch and 2 is dots per centimeter.
x_densityint = 1The horizontal density in density_unit, 1 by default; 300 with unit 1 marks a 300 DPI print.
y_densityint = 1The vertical density in density_unit, 1 by default.
commentstr = ""A text stored in a JPEG comment (COM) segment; empty (the default) writes no comment, and a comment of 65000 bytes or more is left out.
ai-image-JPEGStream.salam
import ai.image
import compress
import os

func main:
    opts := image.JPEGOptions { quality = 80, subsample = true, density_unit = 1, x_density = 300, y_density = 300, comment = "made with Salam" }
    mut img := image.NewFilled(40, 24, image.RGB(30, 120, 200))
    image.DrawRectFilled(img, 10, 6, 20, 12, image.RGB(250, 200, 40))

    mut s := image.NewJPEGStream(40, 24, opts)
    println s.ok, s.mcu_w, s.mcu_h, s.mcus_x, s.mcu_rows
    mut top := image.Crop(img, 0, 0, 40, 16)
    image.JPEGStreamWrite(s, top)
    image.Free(top)
    println s.rows_written, s.mcu_row
    mut row := compress.NewByteBuf()
    repeat 8 in y:
        compress.BufReset(row)
        repeat 40 in x:
            c := image.GetPixel(img, x, 16 + y)
            compress.BufPush(row, c.r as int)
            compress.BufPush(row, c.g as int)
            compress.BufPush(row, c.b as int)
        end
        image.JPEGStreamWriteRow(s, row.data as u8*, 3)
    end
    compress.BufFree(row)
    println image.JPEGStreamFinish(s), s.rows_written
    println compress.BufGet(s.out, 0), compress.BufGet(s.out, 1), compress.BufGet(s.out, 13), compress.BufGet(s.out, 14) * 256 + compress.BufGet(s.out, 15)

    mut ok := false
    mut back := image.DecodeJPEG(s.out.data, s.out.len, ok)
    println ok, back.width, back.height
    image.Free(back)
    mut whole := image.EncodeJPEGOptions(img, opts)
    println compress.BufEquals(whole, s.out)
    compress.BufFree(whole)
    compress.BufFree(s.out)

    println image.SaveJPEGOptions(img, "card.jpg", image.JPEGOptions { quality = 95, subsample = false }), os.FileSize("card.jpg") > 0
    os.Remove("card.jpg")
    image.Free(img)
end
Outputtrue 16 16 3 2 16 1 true 24 255 216 1 300 true 40 24 true true true

JPEGStream

struct JPEGStream
A JPEG encoder that takes the picture a row at a time, so the input pixels never have to be in memory all at once: only one strip of 16 rows (8 without subsampling) is held. The encoded file itself still builds up in memory. Start it with NewJPEGStream, feed rows with JPEGStreamWriteRow or JPEGStreamWrite, then call JPEGStreamFinish; the file is in out.
NameTypeDescription
widthint = 0The picture width in pixels, 1 to 65535.
heightint = 0The picture height in pixels, 1 to 65535.
rows_writtenint = 0How many rows have been fed so far; the picture is complete when it equals height.
okbool = falseThe stream was set up and is still open. It is false for a bad size or when memory ran out, and JPEGStreamFinish sets it to false.
outcompress.ByteBufThe encoded bytes: the headers right after NewJPEGStream, the whole file after JPEGStreamFinish. The caller frees it with compress.BufFree.
hsint = 2The horizontal sampling factor of the brightness channel: 2 with subsampling, 1 without.
vsint = 2The vertical sampling factor of the brightness channel: 2 with subsampling, 1 without.
mcu_wint = 16The width of one MCU (minimum coded unit) in pixels: 16 with subsampling, 8 without.
mcu_hint = 16The height of one MCU in pixels, which is also how many rows are buffered before a strip is encoded.
mcus_xint = 0How many MCUs make up one row of the picture.
full_wint = 0The row width rounded up to whole MCUs; the last pixel of each row is repeated to fill it.
y_wibint = 0The picture width in 8 by 8 brightness blocks, rounded up; blocks past it are padding.
y_hibint = 0The picture height in 8 by 8 brightness blocks, rounded up.
c_wint = 0The width of the color planes after subsampling, in samples.
mcu_rowint = 0The number of the next strip (MCU row) to encode.
mcu_rowsint = 0How many strips the whole picture has.
bufferedint = 0How many rows of the current strip are waiting to be encoded.
ybvoid*Internal: the brightness (Y) samples of the current strip.
cbbvoid*Internal: the blue difference (Cb) samples of the current strip at full resolution.
crbvoid*Internal: the red difference (Cr) samples of the current strip at full resolution.
cbdvoid*Internal: the Cb samples of the current strip after subsampling.
crdvoid*Internal: the Cr samples of the current strip after subsampling.
lqvoid*Internal: the brightness quantization table, scaled for the quality.
cqvoid*Internal: the color quantization table, scaled for the quality.
hcvoid*Internal: the Huffman codes of the four standard tables.
hlvoid*Internal: the lengths of those Huffman codes.
workvoid*Internal: the 64 value block the DCT works in.
acci64 = 0Internal: the bit accumulator of the entropy coder.
nbitsint = 0Internal: how many bits are waiting in acc.
dc_yint = 0Internal: the last brightness DC value; each block stores only the difference from it.
dc_cbint = 0Internal: the last Cb DC value.
dc_crint = 0Internal: the last Cr DC value.

The example for this item is shown with the ones above: ai-image-JPEGStream.salam

Histogram

struct Histogram
A histogram: how many pixels have each value from 0 to 255.
NameTypeDescription
rvoid*The red histogram.
gvoid*The green histogram.
bvoid*The blue histogram.
lumavoid*The brightness histogram.
ai-image-Edit.salam
import ai.image

func size(name: str, img: image.Image):
    println name, "" + img.width + "x" + img.height
end

func main:
    mut img := image.NewFilled(8, 4, image.Gray(100))
    image.SetPixel(img, 0, 0, image.RGB(255, 0, 0))
    size("nearest", image.ResizeNearestNeighbor(img, 4, 2))
    size("bilinear", image.ResizeBilinearFilter(img, 16, 8))
    size("resize", image.Resize(img, 2, 2, image.ResizeBilinear))
    size("near", image.Resize(img, 2, 2, image.ResizeNearest))
    size("scale", image.Scale(img, 0.5))
    size("crop", image.Crop(img, 2, 1, 3, 2))
    clockwise := image.RotateCW(img)
    size("clockwise", clockwise)
    println image.ToHexRGB(image.GetPixel(clockwise, 3, 0))
    size("counterclockwise", image.RotateCCW(img))
    println image.ToHexRGB(image.GetPixel(image.Rotate180(img), 7, 3))
    println image.ToHexRGB(image.GetPixel(image.FlipHorizontal(img), 7, 0)), image.ToHexRGB(image.GetPixel(image.FlipVertical(img), 0, 3))
    size("fit", image.ResizeFit(img, 4, 4))
    size("fill", image.ResizeFill(img, 4, 4))
    size("thumbnail", image.Thumbnail(img, 2))

    mut c := image.NewFilled(2, 1, image.RGB(200, 100, 50))
    image.Grayscale(c)
    println image.ToHexRGB(image.GetPixel(c, 0, 0))
    image.Invert(c)
    image.Brightness(c, 10)
    image.Contrast(c, 1.5)
    println image.ToHexRGB(image.GetPixel(c, 0, 0))
    image.Threshold(c, 128)
    println image.ToHexRGB(image.GetPixel(c, 0, 0))
    mut dot := image.NewFilled(5, 5, image.Gray(0))
    image.SetPixel(dot, 2, 2, image.Gray(255))
    blurred := image.Blurred(dot, 1)
    println image.GetPixel(blurred, 2, 2).r < 255, image.GetPixel(blurred, 1, 2).r > 0
    println image.GetPixel(image.Sharpened(dot, 1.0), 2, 2).r
    mut base := image.NewFilled(2, 2, image.Gray(0))
    image.Overlay(base, image.NewFilled(1, 1, image.Gray(200)), 1, 1, 0.5)
    println image.ToHexRGB(image.GetPixel(base, 1, 1)), image.ToHexRGB(image.GetPixel(base, 0, 0))

    mut hist := image.ComputeHistogram(dot)
    println image.HistogramGet(hist.luma, 0), image.HistogramGet(hist.luma, 255), image.HistogramGet(hist.r, 255), image.HistogramGet(hist.g, 0), image.HistogramGet(hist.b, 0)
    image.HistogramFree(hist)
    black := image.NewFilled(5, 5, image.Gray(0))
    diff := image.Diff(dot, black)
    println image.GetPixel(diff, 2, 2).r, image.GetPixel(diff, 0, 0).r
    println (image.MeanAbsError(dot, black) * 100.0 + 0.5) as i64, (image.PSNR(dot, black) + 0.5) as i64
end
Outputnearest 4x2 bilinear 16x8 resize 2x2 near 2x2 scale 4x2 crop 3x2 clockwise 4x8 #ff0000 counterclockwise 4x8 #ff0000 #ff0000 #ff0000 fit 4x4 fill 4x4 thumbnail 2x1 #7c7c7c #939393 #ffffff true true 251 #636363 #000000 24 1 1 24 24 255 0 1020 14

Image

struct Image
An 8 bit RGBA image.
NameTypeDescription
widthint = 0The width in pixels.
heightint = 0The height.
pixelsvoid*The pixels, four bytes each, row by row.

The example for this item is shown with the ones above: ai-image-Draw.salam

Color

struct Color
One color.
NameTypeDescription
ru8 = 0Red, 0 to 255.
gu8 = 0Green.
bu8 = 0Blue.
au8 = 255Alpha, that is opacity; 255 is fully opaque.

The example for this item is shown with the ones above: ai-image-Draw.salam

Constants and variables

FormatUnknown

const FormatUnknown: i32 = 0
Format: unknown.

The example for this item is shown with the ones above: ai-image-Draw.salam

FormatPNG

const FormatPNG: i32 = 1
Format: PNG.

The example for this item is shown with the ones above: ai-image-Draw.salam

FormatBMP

const FormatBMP: i32 = 2
Format: BMP.

The example for this item is shown with the ones above: ai-image-Draw.salam

FormatJPEG

const FormatJPEG: i32 = 3
Format: JPEG.

The example for this item is shown with the ones above: ai-image-Draw.salam

FormatWebP

const FormatWebP: i32 = 4
Format: WebP.

The example for this item is shown with the ones above: ai-image-Draw.salam

FormatGIF

const FormatGIF: i32 = 5
Format: GIF.

The example for this item is shown with the ones above: ai-image-Draw.salam

FontWidth

const FontWidth: i32 = 5
The width of each character of the pixel font.

The example for this item is shown with the ones above: ai-image-Draw.salam

FontHeight

const FontHeight: i32 = 7
The height of the pixel font.

The example for this item is shown with the ones above: ai-image-Draw.salam

TextDirAuto

const TextDirAuto: i32 = 0
Text direction: automatic, from the first letter.
ai-image-Bidi.salam
import ai.image

func main:
    println image.IsRTLText("سلام"), image.IsRTLText("hello")
    println image.BaseDirection("سلام hello") == image.TextDirRTL, image.BaseDirection("hello سلام") == image.TextDirLTR
    println image.TextDirAuto
    visual := image.ToVisualOrder("abc", image.TextDirLTR)
    println visual
    shaped := image.ShapeArabic("سلام")
    println shaped.len() > 0, shaped != "سلام"
    println image.ToVisualOrder("سلام", image.TextDirRTL) != "سلام"
end
Outputtrue false true true 0 abc true true true

TextDirLTR

const TextDirLTR: i32 = 1
Direction: left to right.

The example for this item is shown with the ones above: ai-image-Bidi.salam

TextDirRTL

const TextDirRTL: i32 = 2
Direction: right to left.

The example for this item is shown with the ones above: ai-image-Bidi.salam

TextAlignLeft

const TextAlignLeft: i32 = 0
Horizontal alignment: left.

The example for this item is shown with the ones above: ai-image-Font.salam

TextAlignCenter

const TextAlignCenter: i32 = 1
Horizontal alignment: center.

The example for this item is shown with the ones above: ai-image-Font.salam

TextAlignRight

const TextAlignRight: i32 = 2
Horizontal alignment: right.

The example for this item is shown with the ones above: ai-image-Font.salam

TextVAlignTop

const TextVAlignTop: i32 = 0
Vertical alignment: top.

The example for this item is shown with the ones above: ai-image-Font.salam

TextVAlignMiddle

const TextVAlignMiddle: i32 = 1
Vertical alignment: middle.

The example for this item is shown with the ones above: ai-image-Font.salam

TextVAlignBottom

const TextVAlignBottom: i32 = 2
Vertical alignment: bottom.

The example for this item is shown with the ones above: ai-image-Font.salam

TextVAlignBaseline

const TextVAlignBaseline: i32 = 3
Vertical alignment: the baseline.

The example for this item is shown with the ones above: ai-image-Font.salam

ResizeNearest

const ResizeNearest: i32 = 0
Resizing method: nearest neighbor, sharp and fast.

The example for this item is shown with the ones above: ai-image-Edit.salam

ResizeBilinear

const ResizeBilinear: i32 = 1
Resizing method: bilinear, smooth.

The example for this item is shown with the ones above: ai-image-Edit.salam

Functions

Grayscale

func Grayscale(img &: Image)
Makes it gray in place.

The example for this item is shown with the ones above: ai-image-Edit.salam

Invert

func Invert(img &: Image)
Inverts the colors in place.

The example for this item is shown with the ones above: ai-image-Edit.salam

Brightness

func Brightness(img &: Image, delta: int)
Makes it lighter or darker in place.

The example for this item is shown with the ones above: ai-image-Edit.salam

Contrast

func Contrast(img &: Image, factor: f64)
Changes the contrast by a factor in place.

The example for this item is shown with the ones above: ai-image-Edit.salam

Threshold

func Threshold(img &: Image, level: int)
Black and white with a threshold, in place.

The example for this item is shown with the ones above: ai-image-Edit.salam

Blurred

func Blurred(img: Image, radius: int): Image
A blurred version with a radius.

The example for this item is shown with the ones above: ai-image-Edit.salam

Sharpened

func Sharpened(img: Image, amount: f64): Image
A sharper version.

The example for this item is shown with the ones above: ai-image-Edit.salam

Overlay

func Overlay(base &: Image, mark: Image, x: int, y: int, opacity: f64)
Puts another image on top with an opacity; a watermark, for instance.

The example for this item is shown with the ones above: ai-image-Edit.salam

DecodeWebP

func DecodeWebP(p: void*, n: int, ok &: bool): Image
Reads WebP from bytes, both lossy and lossless, with the transparency. From an animated WebP it returns the first frame. For broken data, ok becomes false.

The example for this item is shown with the ones above: ai-image-Draw.salam

EncodeWebP

func EncodeWebP(img: Image): compress.ByteBuf
Encodes the image as lossless WebP; every pixel's color and alpha stays exact. For an empty image, or one larger than 16384 pixels, it returns an empty buffer.

The example for this item is shown with the ones above: ai-image-Draw.salam

EncodeWebPQuality

func EncodeWebPQuality(img: Image, quality: int): compress.ByteBuf
Encodes the image as WebP with a quality from 0 to 100; quality 100 is the lossless WebP and anything lower makes a lossy WebP, which is much smaller for a photo. The transparency stays exact either way.

The example for this item is shown with the ones above: ai-image-Draw.salam

EncodePNG

func EncodePNG(img: Image): compress.ByteBuf
The image as PNG.

The example for this item is shown with the ones above: ai-image-Draw.salam

SavePNG

func SavePNG(img: Image, path: str): bool
Saves a PNG.

The example for this item is shown with the ones above: ai-image-Draw.salam

DecodePNG

func DecodePNG(p: void*, n: int, ok &: bool): Image
Reads a PNG from bytes: every bit depth from 1 to 16, palette and gray images, tRNS transparency and interlaced PNG. 16 bits comes down to 8 by rounding. A file with a broken signature or CRC is refused.

The example for this item is shown with the ones above: ai-image-Draw.salam

OpenPNG

func OpenPNG(path: str, ok &: bool): Image
Reads a PNG file.

The example for this item is shown with the ones above: ai-image-Draw.salam

DetectFormat

func DetectFormat(p: void*, n: int): int
Works the format out from the first bytes.

The example for this item is shown with the ones above: ai-image-Draw.salam

FormatFromExt

func FormatFromExt(path: str): int
The format from a file extension.

The example for this item is shown with the ones above: ai-image-Draw.salam

Decode

func Decode(p: void*, n: int, ok &: bool): Image
Reads any supported format from bytes.

The example for this item is shown with the ones above: ai-image-Draw.salam

Open

func Open(path: str, ok &: bool): Image
Reads any supported format from a file.

The example for this item is shown with the ones above: ai-image-Draw.salam

FlattenAlpha

func FlattenAlpha(img: Image, bg: Color): Image
Flattens the transparency onto a background color, before saving a JPEG.

The example for this item is shown with the ones above: ai-image-Draw.salam

Convert

func Convert(img: Image, format: int): Image
Prepares the image for a format; for JPEG it takes the transparency away.

The example for this item is shown with the ones above: ai-image-Draw.salam

Encode

func Encode(img: Image, format: int, quality: int): compress.ByteBuf
Turns the image into bytes in a format with a quality.

The example for this item is shown with the ones above: ai-image-Draw.salam

SaveQuality

func SaveQuality(img: Image, path: str, quality: int): bool
Saves with a quality; the format comes from the extension. For WebP, quality 100 is lossless and anything lower is lossy.

The example for this item is shown with the ones above: ai-image-Draw.salam

Save

func Save(img: Image, path: str): bool
Saves; the format comes from the file extension. JPEG and WebP are saved at quality 90.

The example for this item is shown with the ones above: ai-image-Draw.salam

DrawGlyphStyled

func DrawGlyphStyled(img &: Image, glyph: int, x: f64, y: f64, col: Color, f: Font, st: TextStyle)
One glyph by its number.

The example for this item is shown with the ones above: ai-image-Font.salam

DrawCodepointStyled

func DrawCodepointStyled(img &: Image, codepoint: int, x: f64, y: f64, col: Color, f: Font, st: TextStyle): f64
One glyph by its code point.

The example for this item is shown with the ones above: ai-image-Font.salam

DrawTextStyled

func DrawTextStyled(img &: Image, x: f64, y: f64, text: str, col: Color, f: Font, st: TextStyle): f64
Text with a style; Persian is shaped and laid out right to left.

The example for this item is shown with the ones above: ai-image-Font.salam

DrawTextTTF

func DrawTextTTF(img &: Image, x: f64, y: f64, text: str, col: Color, f: Font, size: f64): f64
Text with a font and a size; it returns the advance.

The example for this item is shown with the ones above: ai-image-Font.salam

TextWidthStyled

func TextWidthStyled(f: Font, text: str, st: TextStyle): f64
The width of a text with a style.

The example for this item is shown with the ones above: ai-image-Font.salam

TextWidthTTF

func TextWidthTTF(f: Font, text: str, size: f64): f64
The width of a text in a font.

The example for this item is shown with the ones above: ai-image-Font.salam

FindSystemFont

func FindSystemFont(): str
The path of a system font.

The example for this item is shown with the ones above: ai-image-Font.salam

FindArabicFont

func FindArabicFont(): str
The path of a font with Arabic and Persian letters.

The example for this item is shown with the ones above: ai-image-Font.salam

LoadSystemFont

func LoadSystemFont(ok &: bool): Font
Loads a system font.

The example for this item is shown with the ones above: ai-image-Font.salam

NewAreaResampler

func NewAreaResampler(src_w: int, src_h: int, dst_w: int, dst_h: int): AreaResampler
Prepares a resampler from src_w by src_h to dst_w by dst_h and allocates the output image. If a size is zero or less, ok is false.

The example for this item is shown with the ones above: ai-image-ResizeArea.salam

AreaResamplerPushRow

func AreaResamplerPushRow(r &: AreaResampler, p: u8*, step: int)
Feeds the next source row: src_w pixels whose red, green, blue and alpha bytes start at p, step bytes apart; with step 4 the fourth byte is alpha, with step 3 the row counts as opaque. Rows past src_h are ignored.

The example for this item is shown with the ones above: ai-image-ResizeArea.salam

AreaResamplerFree

func AreaResamplerFree(r &: AreaResampler)
Frees the work tables and sets ok to false; the output image in out stays and is freed with Free.

The example for this item is shown with the ones above: ai-image-ResizeArea.salam

ResizeArea

func ResizeArea(img: Image, new_width: int, new_height: int): Image
Resizes the whole image by area averaging, with the same pixels as PHP's imagecopyresampled; best for shrinking photos without the aliasing of nearest neighbor. A size of zero or less gives an empty image, and an empty source gives a transparent image of the new size. The caller frees the result with Free.

The example for this item is shown with the ones above: ai-image-ResizeArea.salam

DrawLine

func DrawLine(img &: Image, x0: int, y0: int, x1: int, y1: int, c: Color)
A line.

The example for this item is shown with the ones above: ai-image-Draw.salam

DrawRect

func DrawRect(img &: Image, x: int, y: int, w: int, h: int, c: Color)
An empty rectangle.

The example for this item is shown with the ones above: ai-image-Draw.salam

DrawRectFilled

func DrawRectFilled(img &: Image, x: int, y: int, w: int, h: int, c: Color)
A filled rectangle.

The example for this item is shown with the ones above: ai-image-Draw.salam

DrawCircle

func DrawCircle(img &: Image, cx: int, cy: int, radius: int, c: Color)
An empty circle.

The example for this item is shown with the ones above: ai-image-Draw.salam

DrawCircleFilled

func DrawCircleFilled(img &: Image, cx: int, cy: int, radius: int, c: Color)
A filled circle.

The example for this item is shown with the ones above: ai-image-Draw.salam

DrawText

func DrawText(img &: Image, x: int, y: int, text: str, c: Color, scale: int)
Text with the simple pixel font and a magnification factor; it needs no font file and is only for Latin characters.

The example for this item is shown with the ones above: ai-image-Draw.salam

TextWidth

func TextWidth(text: str, scale: int): int
The width of a text in the pixel font.

The example for this item is shown with the ones above: ai-image-Draw.salam

ParseFontIndex

func ParseFontIndex(p: void*, n: int, index: int, ok &: bool): Font
Font number i of a TTC collection.

The example for this item is shown with the ones above: ai-image-Font.salam

ParseFont

func ParseFont(p: void*, n: int, ok &: bool): Font
A font from bytes.

The example for this item is shown with the ones above: ai-image-Font.salam

LoadFont

func LoadFont(path: str, ok &: bool): Font
A font from a .ttf or .otf file.

The example for this item is shown with the ones above: ai-image-Font.salam

LoadFontIndex

func LoadFontIndex(path: str, index: int, ok &: bool): Font
Font number i of a TTC file.

The example for this item is shown with the ones above: ai-image-Font.salam

FreeFont

func FreeFont(f &: Font)
Frees the font.

The example for this item is shown with the ones above: ai-image-Font.salam

FontValid

func FontValid(f: Font): bool
The font is valid.

The example for this item is shown with the ones above: ai-image-Font.salam

IsCFFFont

func IsCFFFont(p: void*, n: int): bool
The font has CFF outlines; that kind is not supported.

The example for this item is shown with the ones above: ai-image-Font.salam

UnitsPerEm

func UnitsPerEm(f: Font): int
The units per em.

The example for this item is shown with the ones above: ai-image-Font.salam

NumGlyphs

func NumGlyphs(f: Font): int
The number of glyphs.

The example for this item is shown with the ones above: ai-image-Font.salam

GlyphIndex

func GlyphIndex(f: Font, codepoint: int): int
The glyph number for a Unicode code point.

The example for this item is shown with the ones above: ai-image-Font.salam

ScaleFactor

func ScaleFactor(f: Font, size: f64): f64
The factor that turns font units into pixels at a size.

The example for this item is shown with the ones above: ai-image-Font.salam

AscentPixels

func AscentPixels(f: Font, size: f64): f64
The ascent in pixels.

The example for this item is shown with the ones above: ai-image-Font.salam

DescentPixels

func DescentPixels(f: Font, size: f64): f64
The descent in pixels; negative.

The example for this item is shown with the ones above: ai-image-Font.salam

LineHeightPixels

func LineHeightPixels(f: Font, size: f64): f64
The line height in pixels.

The example for this item is shown with the ones above: ai-image-Font.salam

GlyphAdvance

func GlyphAdvance(f: Font, glyph: int): int
A glyph's advance in font units.

The example for this item is shown with the ones above: ai-image-Font.salam

KernAdvance

func KernAdvance(f: Font, glyph1: int, glyph2: int): int
The spacing adjustment of two glyphs, like AV.

The example for this item is shown with the ones above: ai-image-Font.salam

GlyphBox

func GlyphBox(f: Font, glyph: int, x0 &: int, y0 &: int, x1 &: int, y1 &: int): bool
A glyph's box in font units.

The example for this item is shown with the ones above: ai-image-Font.salam

GlyphHasOutline

func GlyphHasOutline(f: Font, glyph: int): bool
The glyph has an outline; it is not a space.

The example for this item is shown with the ones above: ai-image-Font.salam

ShapeArabic

func ShapeArabic(text: str): str
Turns the Persian and Arabic letters into their connected initial, medial and final shapes.

The example for this item is shown with the ones above: ai-image-Bidi.salam

IsRTLText

func IsRTLText(text: str): bool
The text has a right to left character.

The example for this item is shown with the ones above: ai-image-Bidi.salam

BaseDirection

func BaseDirection(text: str): int
A text's base direction from its first strong letter, by the Unicode bidirectional algorithm.

The example for this item is shown with the ones above: ai-image-Bidi.salam

ToVisualOrder

func ToVisualOrder(text: str, dir: int): str
Puts the text in display order, for drawing.

The example for this item is shown with the ones above: ai-image-Bidi.salam

DrawTextCentered

func DrawTextCentered(img &: Image, cx: f64, cy: f64, text: str, col: Color, f: Font, st: TextStyle): f64
Text centered on a point.

The example for this item is shown with the ones above: ai-image-Font.salam

DrawTextCenteredIn

func DrawTextCenteredIn(img &: Image, text: str, col: Color, f: Font, st: TextStyle): f64
Text in the middle of the image.

The example for this item is shown with the ones above: ai-image-Font.salam

DrawTextInBox

func DrawTextInBox(img &: Image, x: f64, y: f64, w: f64, h: f64, text: str, col: Color, f: Font, st: TextStyle, halign: int, valign: int): f64
Text in a box with a horizontal and a vertical alignment.

The example for this item is shown with the ones above: ai-image-Font.salam

DrawTextFitBox

func DrawTextFitBox(img &: Image, x: f64, y: f64, w: f64, h: f64, text: str, col: Color, f: Font, st: TextStyle, fill: f64, max_size: f64): f64
Writes the text at the largest size that fits in a box, for titles and labels.

The example for this item is shown with the ones above: ai-image-Font.salam

DrawTextFitImage

func DrawTextFitImage(img &: Image, text: str, col: Color, f: Font, st: TextStyle, fill: f64, max_size: f64): f64
Writes the text at the largest size over the whole image.

The example for this item is shown with the ones above: ai-image-Font.salam

EncodeBMP

func EncodeBMP(img: Image): compress.ByteBuf
Encodes the image as a 32 bit BMP with a version 5 header, so the transparency is seen in other programs too.

The example for this item is shown with the ones above: ai-image-Draw.salam

SaveBMP

func SaveBMP(img: Image, path: str): bool
Saves a BMP.

The example for this item is shown with the ones above: ai-image-Draw.salam

DecodeBMP

func DecodeBMP(p: void*, n: int, ok &: bool): Image
Reads a BMP from bytes: 1 to 8 bit palette, RLE, 16, 24 and 32 bit with color masks, OS/2 and Windows headers and a BMP with a JPEG or a PNG inside. The pixels RLE does not write stay transparent.

The example for this item is shown with the ones above: ai-image-Draw.salam

OpenBMP

func OpenBMP(path: str, ok &: bool): Image
Reads a BMP file.

The example for this item is shown with the ones above: ai-image-Draw.salam

TextBounds

func TextBounds(f: Font, text: str, st: TextStyle, x0 &: f64, y0 &: f64, x1 &: f64, y1 &: f64): bool
The ink box of a text.

The example for this item is shown with the ones above: ai-image-Font.salam

TextInkWidth

func TextInkWidth(f: Font, text: str, st: TextStyle): f64
The ink width.

The example for this item is shown with the ones above: ai-image-Font.salam

TextInkHeight

func TextInkHeight(f: Font, text: str, st: TextStyle): f64
The ink height.

The example for this item is shown with the ones above: ai-image-Font.salam

TextInkSize

func TextInkSize(f: Font, text: str, st: TextStyle, w &: f64, h &: f64): bool
The ink width and height.

The example for this item is shown with the ones above: ai-image-Font.salam

FitSizeToWidth

func FitSizeToWidth(f: Font, text: str, st: TextStyle, target_w: f64, max_size: f64): f64
The largest size at which the text fits in a width.

The example for this item is shown with the ones above: ai-image-Font.salam

FitSizeToBox

func FitSizeToBox(f: Font, text: str, st: TextStyle, target_w: f64, target_h: f64, max_size: f64): f64
The largest size at which the text fits in a box.

The example for this item is shown with the ones above: ai-image-Font.salam

EncodeJPEG

func EncodeJPEG(img: Image, quality: int): compress.ByteBuf
The image as JPEG with a quality from 1 to 100.

The example for this item is shown with the ones above: ai-image-Draw.salam

SaveJPEG

func SaveJPEG(img: Image, path: str, quality: int): bool
Saves a JPEG.

The example for this item is shown with the ones above: ai-image-Draw.salam

DecodeJPEG

func DecodeJPEG(p: void*, n: int, ok &: bool): Image
Reads a JPEG from bytes: baseline and progressive JPEG, gray, color and CMYK, with any chroma subsampling. The pixels are the ones libjpeg gives.

The example for this item is shown with the ones above: ai-image-Draw.salam

OpenJPEG

func OpenJPEG(path: str, ok &: bool): Image
Reads a JPEG file.

The example for this item is shown with the ones above: ai-image-Draw.salam

IsWebP

func IsWebP(p: void*, n: int): bool
The bytes are WebP.

The example for this item is shown with the ones above: ai-image-Draw.salam

SaveWebP

func SaveWebP(img: Image, path: str): bool
Saves the image in a lossless WebP file; it returns true if the writing worked.

The example for this item is shown with the ones above: ai-image-Draw.salam

OpenWebP

func OpenWebP(path: str, ok &: bool): Image
Reads a WebP file, both lossy and lossless.

The example for this item is shown with the ones above: ai-image-Draw.salam

NewJPEGStream

func NewJPEGStream(width: int, height: int, opts: JPEGOptions): JPEGStream
Starts a streaming JPEG for a picture of width by height pixels and writes the headers into out. If a side is not between 1 and 65535 or memory runs out, ok is false and nothing else works on the stream.

The example for this item is shown with the ones above: ai-image-JPEGStream.salam

JPEGStreamWriteRow

func JPEGStreamWriteRow(s &: JPEGStream, p: u8*, step: int)
Feeds the next row: width pixels whose red, green and blue bytes are at p[0], p[1] and p[2], step bytes apart (3 for RGB, 4 for RGBA). Alpha is ignored, so flatten transparency first with FlattenAlpha. A full strip is encoded at once; rows past the height are ignored.

The example for this item is shown with the ones above: ai-image-JPEGStream.salam

JPEGStreamWrite

func JPEGStreamWrite(s &: JPEGStream, strip: Image)
Feeds every row of an RGBA image strip of any height. The strip must be as wide as the stream; otherwise nothing is written.

The example for this item is shown with the ones above: ai-image-JPEGStream.salam

JPEGStreamFinish

func JPEGStreamFinish(s &: JPEGStream): bool
Encodes the last partial strip (repeating its last row), writes the end marker and frees the work buffers; the finished file is in out, which the caller frees with compress.BufFree. It returns false when fewer than height rows were fed, and the file is then incomplete.

The example for this item is shown with the ones above: ai-image-JPEGStream.salam

EncodeJPEGOptions

func EncodeJPEGOptions(img: Image, opts: JPEGOptions): compress.ByteBuf
The image as JPEG bytes with options; the bytes are the same as feeding it through a JPEGStream. Alpha is ignored. For an empty image or a side larger than 65535 it returns an empty buffer. The caller frees the buffer with compress.BufFree.

The example for this item is shown with the ones above: ai-image-JPEGStream.salam

SaveJPEGOptions

func SaveJPEGOptions(img: Image, path: str, opts: JPEGOptions): bool
Saves the image as a JPEG file with options; it returns true when the writing worked.

The example for this item is shown with the ones above: ai-image-JPEGStream.salam

IsGIF

func IsGIF(p: void*, n: int): bool
The bytes are GIF.

The example for this item is shown with the ones above: ai-image-Draw.salam

DecodeGIF

func DecodeGIF(p: void*, n: int, ok &: bool): Image
Reads a GIF from bytes. From an animated GIF it returns the first frame, and the transparent pixels get an alpha of zero. For broken data, ok becomes false.

The example for this item is shown with the ones above: ai-image-Draw.salam

OpenGIF

func OpenGIF(path: str, ok &: bool): Image
Reads a GIF file.

The example for this item is shown with the ones above: ai-image-Draw.salam

EncodeGIF

func EncodeGIF(img: Image): compress.ByteBuf
Encodes the image as GIF. If the image has 256 colors or fewer the colors stay exact; otherwise the best 256 colors are picked and put in their place with error diffusion. Pixels with an alpha below 128 become transparent.

The example for this item is shown with the ones above: ai-image-Draw.salam

SaveGIF

func SaveGIF(img: Image, path: str): bool
Saves the image in a GIF file; it returns true if the writing worked.

The example for this item is shown with the ones above: ai-image-Draw.salam

ComputeHistogram

func ComputeHistogram(img: Image): Histogram
The image's histogram.

The example for this item is shown with the ones above: ai-image-Edit.salam

HistogramGet

func HistogramGet(channel: void*, bucket: int): int
How many have one value in one channel.

The example for this item is shown with the ones above: ai-image-Edit.salam

HistogramFree

func HistogramFree(h &: Histogram)
Frees it.

The example for this item is shown with the ones above: ai-image-Edit.salam

Diff

func Diff(a: Image, b: Image): Image
The absolute pixel by pixel difference.

The example for this item is shown with the ones above: ai-image-Edit.salam

MeanAbsError

func MeanAbsError(a: Image, b: Image): f64
The mean absolute error of two images.

The example for this item is shown with the ones above: ai-image-Edit.salam

PSNR

func PSNR(a: Image, b: Image): f64
The signal to noise ratio in decibels; higher means more alike.

The example for this item is shown with the ones above: ai-image-Edit.salam

ResizeNearestNeighbor

func ResizeNearestNeighbor(img: Image, new_width: int, new_height: int): Image
Resizing with the nearest neighbor.

The example for this item is shown with the ones above: ai-image-Edit.salam

ResizeBilinearFilter

func ResizeBilinearFilter(img: Image, new_width: int, new_height: int): Image
Bilinear resizing.

The example for this item is shown with the ones above: ai-image-Edit.salam

Resize

func Resize(img: Image, new_width: int, new_height: int, method: int): Image
Resizing with a method.

The example for this item is shown with the ones above: ai-image-Edit.salam

Scale

func Scale(img: Image, factor: f64): Image
Growing or shrinking by a factor.

The example for this item is shown with the ones above: ai-image-Edit.salam

Crop

func Crop(img: Image, x: int, y: int, w: int, h: int): Image
Cuts a rectangle out.

The example for this item is shown with the ones above: ai-image-Edit.salam

RotateCW

func RotateCW(img: Image): Image
A ninety degree clockwise turn.

The example for this item is shown with the ones above: ai-image-Edit.salam

RotateCCW

func RotateCCW(img: Image): Image
A ninety degree counterclockwise turn.

The example for this item is shown with the ones above: ai-image-Edit.salam

Rotate180

func Rotate180(img: Image): Image
A hundred and eighty degree turn.

The example for this item is shown with the ones above: ai-image-Edit.salam

FlipHorizontal

func FlipHorizontal(img: Image): Image
A horizontal mirror.

The example for this item is shown with the ones above: ai-image-Edit.salam

FlipVertical

func FlipVertical(img: Image): Image
A vertical mirror.

The example for this item is shown with the ones above: ai-image-Edit.salam

ResizeFit

func ResizeFit(img: Image, box_w: int, box_h: int): Image
The whole image inside a box keeping its ratio, centered with a transparent edge; the output is the size of the box.

The example for this item is shown with the ones above: ai-image-Edit.salam

ResizeFill

func ResizeFill(img: Image, box_w: int, box_h: int): Image
Fills the box keeping the ratio and cuts the rest off.

The example for this item is shown with the ones above: ai-image-Edit.salam

Thumbnail

func Thumbnail(img: Image, max_size: int): Image
A small image whose longest side is at most this; a smaller image is left alone.

The example for this item is shown with the ones above: ai-image-Edit.salam

RGB

func RGB(r: int, g: int, b: int): Color
A color from red, green and blue.

The example for this item is shown with the ones above: ai-image-Draw.salam

RGBA

func RGBA(r: int, g: int, b: int, a: int): Color
A color with alpha.

The example for this item is shown with the ones above: ai-image-Draw.salam

Gray

func Gray(v: int): Color
A gray with one value.

The example for this item is shown with the ones above: ai-image-Draw.salam

Equals

func Equals(a: Color, b: Color): bool
The two colors are the same.

The example for this item is shown with the ones above: ai-image-Draw.salam

Luminance

func Luminance(c: Color): int
A color's perceived brightness, 0 to 255.

The example for this item is shown with the ones above: ai-image-Draw.salam

ParseHex

func ParseHex(hex: str): Color
A color from hex, with three, six or eight digits.

The example for this item is shown with the ones above: ai-image-Draw.salam

ToHex

func ToHex(c: Color): str
Hex with alpha, like #336699ff.

The example for this item is shown with the ones above: ai-image-Draw.salam

ToHexRGB

func ToHexRGB(c: Color): str
Hex without alpha.

The example for this item is shown with the ones above: ai-image-Draw.salam

Blend

func Blend(dst: Color, src: Color): Color
Blends the source color with its alpha onto the destination.

The example for this item is shown with the ones above: ai-image-Draw.salam

LerpColor

func LerpColor(a: Color, b: Color, t: f64): Color
A linear interpolation of two colors.

The example for this item is shown with the ones above: ai-image-Draw.salam

New

func New(width: int, height: int): Image
A new transparent image.

The example for this item is shown with the ones above: ai-image-Draw.salam

NewFilled

func NewFilled(width: int, height: int, c: Color): Image
An image filled with one color.

The example for this item is shown with the ones above: ai-image-Draw.salam

Free

func Free(img &: Image)
Frees the image.

The example for this item is shown with the ones above: ai-image-Draw.salam

Clone

func Clone(img: Image): Image
An independent copy.

The example for this item is shown with the ones above: ai-image-Draw.salam

IsEmpty

func IsEmpty(img: Image): bool
The image has no pixels.

The example for this item is shown with the ones above: ai-image-Draw.salam

InBounds

func InBounds(img: Image, x: int, y: int): bool
The point is inside the image.

The example for this item is shown with the ones above: ai-image-Draw.salam

GetPixel

func GetPixel(img: Image, x: int, y: int): Color
A pixel's color.

The example for this item is shown with the ones above: ai-image-Draw.salam

SetPixel

func SetPixel(img &: Image, x: int, y: int, c: Color)
Sets a pixel's color.

The example for this item is shown with the ones above: ai-image-Draw.salam

BlendPixel

func BlendPixel(img &: Image, x: int, y: int, c: Color)
Blends a color with its alpha onto a pixel.

The example for this item is shown with the ones above: ai-image-Draw.salam

Fill

func Fill(img &: Image, c: Color)
Makes everything one color.

The example for this item is shown with the ones above: ai-image-Draw.salam

FillHex

func FillHex(img &: Image, hex: str)
Fills everything with a hex color, like #202040.

The example for this item is shown with the ones above: ai-image-Draw.salam