Skip to content
View source

imageGenerated

Category: Packages · Manifest: use "kernels/";

What Entelechy does to a picture, knowing nothing of the world it shows.

What Entelechy does to a picture, knowing nothing of the world it shows: color spaces, blending and masks, two pictures compared, filters, tone and its curves, scaling and sharpening, antialiasing within a frame, histograms, distance fields, mipmaps, pixel art and sprite sheets. Each is a word a kernel calls on a pixel, its kernel a thin pass.

Layer: Graphics. Uses: random.

use "image.entpkg";
  • kernels/antialias.ent — Antialiasing within one frame (FXAA, fxaa). Kernels: image.fxaa@1.
  • kernels/blend.ent — Blending, and any picture kept to part of another by a mask. Kernels: image.blend@1, image.masked@1.
  • kernels/color.ent — Color as numbers. Kernels: image.encode@1, image.decode@1.
  • kernels/distance.ent — Distance. Kernels: image.seeds@1, image.first_step@1, image.next_step@1, image.flood@1, image.distance@1.
  • kernels/compare.ent — Two pictures compared: each pixel’s difference (color_apart), and how far apart they are as a whole, the most a pixel differs and how many differ by more than a step. Kernels: image.difference@1, image.apart_rows@1, image.apart@1.
  • kernels/filter.ent — Filters. Kernels: image.blur@1, image.shrink@1, image.convolve@1, image.sharpen@1, image.edges@1, image.morph@1, image.resize@1.
  • kernels/histogram.ent — Histograms. Kernels: image.histogram@1, image.cumulate@1, image.equalize@1.
  • kernels/mipmap.ent — A mip strip. Kernels: image.mip_first@1, image.mip_next@1, image.mip_halve@1.
  • kernels/pixel_art.ent — Pixel effects. Kernels: image.pixelate@1, image.palette@2, image.ramp@1, image.dither@1, image.outline@1, image.shadow@1.
  • kernels/sprite_sheet.ent — Sheets.
  • kernels/tone.ent — Tone and color grading. Kernels: image.adjust@1, image.levels@1, image.curve@1, image.neutral@1, image.lut@1.
  • kernels/tone_map.ent — Tone curves, ACES’s fit and AgX, light of any brightness to 0..1 (tone_curve), sharpened against its neighbors (tone_sharpened), made vivid and warm (tone_warmth).
  • kernels/upscale.ent — A picture scaled to another size, edge-aware (FSR 1’s EASU, upscaled) or nearest-neighbor (upscaled_near), and a sharpening that cannot overshoot (RCAS). Kernels: image.upscale@1, image.contrast_sharpen@1.
  • kernels/wrap.ent — Wrap addressing for a linear read.
  • graphs/blur.esn — A Gaussian blur, both ways, as a sub-graph.
  • graphs/compare.esn — Two pictures compared: the difference to look at and how far apart, as a test holds a scene to another’s picture or a person sees where two renders part (two pictures read as inputs, then entelechy replay with show apart.apart[0]).
  • graphs/distance.esn — The signed distance from every pixel to a shape, in pixels, negative inside.
  • graphs/equalize.esn — Histogram equalization as a sub-graph.
  • graphs/flood.esn — Jump flooding as a sub-graph.
  • graphs/flood_pass.esn — One jump-flooding pass and the step after it.
  • graphs/mipmap.esn — The mip strip of a square texture, as a sub- graph.
  • graphs/mipmap_level.esn — One halving of a mip strip.
  • graphs/sharpen.esn — Unsharp masking as a sub-graph.
  • graphs/upscale.esn — Scaled to the window and sharpened.

tests/ holds scenes and their replays, run on every backend: antialias.replay, compare.replay, looks.replay, operations.replay, upscale.replay. Every Kernel of the package is reached by one of them.

Used by the darkroom, image, mipmap, nebula examples.

Kernel Mode Brief
image.adjust@1 map The picture adjusted: exposure stops, contrast (1 none), saturation (1 none, 0 gray), hue turned (a whole turn is 1).
image.apart@1 map How far apart two pictures are as a whole (domain = 1): the most a pixel differs (x) and how many differ by more than the rows’ step (y), from image.apart_rows.
image.apart_rows@1 map Each row of a difference (image.difference’s), one cell a row: the most a pixel differs (x) and how many differ by more than over (y). A node sets domain = size(difference) * vec2(0, 1) + vec2(1, 0).
image.blend@1 map top composited over base, as the W3C’s compositing spec does it: where top covers (its alpha times opacity), its color is blended with base’s by mode, as much as base is there; then laid over base, the alphas joined as one sheet over another, the color weighed by both. space is where the arithmetic is done: on sRGB’s stored values (Encoded), as painting programs blend and the modes are defined, or on light itself (Linear). top is stretched over base whatever its size.
image.blur@1 map A Gaussian blur along axis (one pass of the two a blur takes, graphs/blur.esn): sigma measured in the output’s pixels, taps one output pixel apart out to three sigmas.
image.contrast_sharpen@1 map Sharpened once (amount 0 not at all, 1 the most): pulled from its four neighbors by an amount held between the darkest and brightest of the five, never past 0 to 1, with no white rims.
image.convolve@1 map Any convolution: weights holds n by n numbers, row by row, centered on the pixel (n odd). The weights are used as given, not normalized.
image.cumulate@1 prefix with sum The cumulative count: at each bin, the pixels in it and below.
image.curve@1 map Curves: each channel looked up in curve, rows of the output for inputs spread evenly from 0 to 1 (x for red, y green, z blue), blended between rows.
image.decode@1 map
image.difference@1 map The difference of a and b (domain = size(a); b read at the same place across the picture, whatever its size): each channel’s, and in w the most of them.
image.distance@1 map The signed distance, in pixels, from each pixel’s center to the shape’s edge: from the nearest pixel of the shape when outside it (inside’s flood), less the distance to the nearest pixel outside it when within (outside’s flood); half a pixel taken off each, so the edge lies between the pixels either side. Where a flood found no seed, reach.
image.dither@1 map Each pixel held to colors with ordered dithering (dithered_color): a gradient becomes a pattern of two colors.
image.edges@1 map Edges: the strength of the Sobel gradient, gray, opaque.
image.encode@1 map Linear light to sRGB’s stored values (for a window or a file), and back; alpha kept.
image.equalize@1 map The picture equalized: each pixel’s lightness moved to the share of the pixels darker than it (cumulative, from image.cumulate), read between the counts below and through its bin by where in the bin it falls, so a smooth gradient stays smooth. The color is scaled to reach it: lightness grows as the cube root of a scale, so the cube of the ratio, which keeps the hue. amount mixes it with the source.
image.first_step@1 map The first step: half the picture’s longer side, as a power of two.
image.flood@1 map One pass: the nearest seed among this pixel’s and the eight a step away.
image.fxaa@1 map The HDR picture image antialiased (the same size, fxaa); on 0 leaves it as it is.
image.histogram@1 scatter into input 1 with sum How many pixels of the source fall in each bin.
image.levels@1 map Levels: black to 0 and white to 1, clamped, then bent by gamma (above 1 brightens the middle).
image.lut@1 map The picture through a 3D LUT (lut_at), its values taken 0 to 1.
image.masked@1 map top over base as far as mask says: 0 base, 1 top, between them mixed (domain = size(base); top and mask any size, read smoothly across the picture). Any pass kept to part of a picture: a grade, an outline, a blur, laid only where a mask asks.
image.mip_first@1 map The strip before any halving: the texture in the top square and nothing under it.
image.mip_halve@1 map One halving: four texels of the level above averaged into one of the level named, everything else carried over.
image.mip_next@1 map
image.morph@1 map Dilation (each channel the greatest within radius pixels, a disc) or erosion (the least): bright shapes grown or worn away.
image.neutral@1 map The neutral LUT of side n (domain = vec2(n * n, n)): each color itself. Grade it as a picture and image.lut applies that grade.
image.next_step@1 map The next step: half this one, never below one.
image.outline@1 map A line of color round what is drawn: each pixel not drawn beside one that is, across a side, or across a corner too (corners).
image.palette@2 map Each pixel the color of colors nearest it.
image.pixelate@1 map Cells of cell pixels, each the color at its center.
image.ramp@1 map Each pixel the color of colors, rows from dark to light, its lightness falls to (ramp_color).
image.resize@1 map The source at the node’s domain, by bicubic (Catmull-Rom) interpolation: sharper than at_linear when enlarging. For halving and beyond, image.shrink.
image.seeds@1 map Seeds: where the mask is on (its luminance times alpha past threshold, or not past it when inside is false), the pixel’s own center, else none. A seed is (x, y, 1, 0); none is all zeros.
image.shadow@1 map A shadow of color cast by what is drawn, offset pixels away, under it: each pixel not drawn whose pixel offset back is.
image.sharpen@1 map Unsharp masking: the source pushed away from its blurred copy by amount; alpha kept. graphs/sharpen.esn places it with its blur.
image.shrink@1 map The source smaller: each output pixel the mean of the source pixels it covers (a box filter, exact at whole ratios).
image.upscale@1 map Scaled to domain: edge-aware (upscaled), nearest-neighbor when near is 1 (upscaled_near).
Function Brief
fxaa_luma(c: Vec3) -> Float How bright it looks (0 to 1): brightness pressed into 0 to 1 and square-rooted, so a step in the dark counts as one in the light.
fxaa_at(image: Image, q: Vec2) -> Float
fxaa_stride(i: Int) -> Float How far the ith step along an edge goes (pixels): a pixel at a time first, longer strides further on.
fxaa_walk(image: Image, q: Vec2, across: Vec2, dir: Vec2, edge: Float, gradient: Float) -> Vec2 From pixel q along dir, each step reading the mean brightness of this row and the row across (the brightness on the edge’s middle), until it differs from edge by a quarter of gradient: how far it went (x), and the difference in brightness there (y).
fxaa(image: Image, q: Vec2, threshold: Float, least: Float, subpixel: Float) -> Vec4 Pixel q of the HDR picture image antialiased: where the contrast is under threshold (of the brightest, at least least) it is left; subpixel is how much of what is finer than a pixel is smoothed (0 none).
blend_channel(mode: Blend, base: Float, top: Float) -> Float One channel of top laid over base by mode.
blend(mode: Blend, base: Vec3, top: Vec3) -> Vec3 top laid over base by mode, channel by channel.
luminance(c: Vec3) -> Float How bright a linear color looks (Rec. 709’s weights).
srgb_decode(v: Float) -> Float One channel of sRGB’s transfer: a stored value to linear light, and back.
srgb_encode(v: Float) -> Float
srgb_to_linear(c: Vec3) -> Vec3
linear_to_srgb(c: Vec3) -> Vec3
rgb_to_hsv(c: Vec3) -> Vec3 Hue (0 up to 1, red at 0), saturation and value, and back.
hsv_to_rgb(c: Vec3) -> Vec3
cbrt(v: Float) -> Float A cube root that keeps the sign: pow’s answer, which a device may give a few units off, made exact by one step of Newton’s method.
linear_to_oklab(c: Vec3) -> Vec3 Linear light to Oklab (Ottosson): lightness, then the green-red and blue-yellow axes; equal steps in it look equal. And back.
oklab_to_linear(c: Vec3) -> Vec3
blackbody(heat: Float) -> Vec3 Glowing matter by how hot it is, 0 to 1: deep red, orange, yellow, white.
hue(h: Float) -> Vec3 A vivid hue round the wheel, 0 to 1: red, yellow, green, cyan, blue, magenta, and red again.
color_apart(a: Vec4, b: Vec4) -> Float How far apart two colors are: the most any of red, green and blue differs.
sobel(source: Image, c: Vec2) -> Vec2 The Sobel gradient of the source’s luminance at c: how fast it grows along x and along y.
cubic_weights(t: Float) -> Vec4 Catmull-Rom’s weights for the four taps round a fraction t.
lightness(c: Vec3) -> Float How bright a linear color looks, 0 for black to 1 for white.
bin_of(c: Vec3, bins: Int) -> Int The bin a color falls in, of bins.
mip_start(k: Int, side: Int) -> Float
mip_level(strip: Grid<Vec4>, uv: Vec2, k: Int, side: Int) -> Vec4
mip_wanted(du: Vec2, dv: Vec2, side: Int, levels: Int) -> Float
mip_at(strip: Grid<Vec4>, uv: Vec2, wanted: Float, side: Int, levels: Int) -> Vec4
nearest_color(c: Vec3, colors: Rows<Vec3>) -> Vec3 The color of colors nearest c in Oklab, where equal distances look equal; the first of two as near.
ramp_color(c: Vec3, colors: Rows<Vec3>) -> Vec3 The color of colors, rows from dark to light, that c’s Oklab lightness falls to: lightness 0 to 1 cut into as many equal steps as there are rows, so a picture keeps its light and dark in any tint.
bayer4(p: IVec2) -> Float The threshold of pixel p in a 4 by 4 Bayer matrix, from 1/32 to 31/32: neighbors apart, so a share of pixels over it spreads evenly.
dithered_color(c: Vec3, colors: Rows<Vec3>, p: IVec2) -> Vec3 c held to colors with ordered dithering at pixel p: of the two colors nearest it in Oklab, the farther is taken at the pixels whose threshold the share of the way c lies toward it passes.
drawn(source: Image, p: IVec2) -> Bool Whether pixel p of source is drawn: its alpha at least a half.
sheet_cell(k: Int, columns: Int) -> IVec2 The cell of frame k in a sheet columns cells across.
sheet_texel(k: Int, columns: Int, cell: IVec2, p: IVec2) -> IVec2 The texel of a sheet of cells of cell pixels that pixel p of frame k is.
sheet_place(t: IVec2, columns: Int, cell: IVec2) -> SheetPlace Which frame texel t of a sheet is in, and where in it: what a Kernel drawing a whole sheet asks of each texel.
sheet_pixel(sheet: Image, k: Int, columns: Int, cell: IVec2, p: IVec2) -> Vec4 Pixel p of frame k of sheet.
frame_at(seconds: Float, fps: Float, frames: Int, loops: Bool) -> Int The frame of an animation of frames frames at fps frames a second that shows seconds after it starts: round again (loops) or held at its last.
adjusted(c: Vec3, exposure: Float, contrast: Float, saturation: Float, hue: Float) -> Vec3 Exposure in stops; contrast round middle gray (0.18), as a power of the light, so it suits light brighter than white too; saturation and hue turned in Oklab, so a change looks even across colors.
lut_at(lut: Image, c: Vec3) -> Vec3 A 3D LUT’s color for c: the LUT is a strip of n squares side by side, n*n wide and n high, red across each square, green down it, blue square by square; blended between squares and within them.
aces(x: Vec3) -> Vec3 ACES tone mapping, the fitted curve: light of any brightness to 0..1, as film takes it.
agx(x: Vec3) -> Vec3 AgX tone mapping (Troy Sobotka’s), in its minimal fitted form: light of any brightness to 0..1 (linear), taken into AgX’s inset primaries, its log2 between -12.47 and 4.03 stops eased by the fitted sigmoid, and out again; bright colors desaturate toward white as film’s do, rather than turning hue.
tone_sharpened(hdr: Image, p: Vec2, c: Vec3, amount: Float) -> Vec3 Light c at p of hdr sharpened amount (0 not at all): pulled apart from the mean of its four neighbors, less where the contrast is already high (no white rims).
tone_curve(c: Vec3, curve: Int) -> Vec3 Light c through a tone curve: 0 ACES’s fit, 1 none (light past 1 clipped, as a standard clip-to-1 view), 2 AgX.
tone_warmth(c: Vec3, vivid: Float, warmth: Float, shadow_tint: Vec3, light_tint: Vec3) -> Vec3 A toned color c made vivid (1 as it is) and tinted warmth of the way from shadow_tint in its shadows to light_tint in its lights.
upscaled_near(image: Image, q: Vec2, dst: Vec2) -> Vec4 What lies at pixel q when image is scaled to dst, nearest-neighbor: each pixel made a block, nothing interpolated (pixel art’s look). With a whole multiple (camera.extent’s whole) the blocks are one size; the window’s edge of less than a block repeats the last column and row.
upscale_light(c: Vec4) -> Float
upscale_tap(image: Image, p: Vec2) -> Vec4
upscale_edge(w: Float, la: Float, lb: Float, lc: Float, ld: Float, le: Float) -> Vec3
upscale_weight(off: Vec2, dir: Vec2, stretch: Vec2, lob: Float, clip: Float) -> Float
upscaled(image: Image, q: Vec2, dst: Vec2) -> Vec4 What lies at pixel q when image is scaled to dst: twelve points of the source (the nearest four and their cross neighbors), the edge’s direction and strength found by brightness, a Lanczos-shaped kernel stretched along the edge and narrowed across it; the result held between the darkest and brightest of the nearest four, so edges do not ring. At one size it is left as it is. A Kernel drawing at the window’s size and reading a picture drawn smaller reads it this way (image.upscale does only this). Where the picture is larger than dst (supersampled), the block of it falling in this pixel (at most four points a side) is averaged.
at_linear_wrapped(tile: Grid<Vec4>, q: Vec2) -> Vec4
Name Syntax
Blend type Blend = enum { Normal, Multiply, Screen, Overlay, SoftLight, Add, Difference, Darken, Lighten };
Space type Space = enum { Encoded, Linear };
Weighed struct Weighed { sum: Vec4; weight: Float; }
Morph type Morph = enum { Dilate, Erode };
DitherPair struct DitherPair { near: Vec3; near_d: Float; next: Vec3; next_d: Float; }
SheetPlace struct SheetPlace { frame: Int; at: IVec2; }
Name Interface Description
blur input source: Image
param sigma: Float = 2.0
output result <- down.result
A Gaussian blur, both ways, as a sub-graph. sigma is in the output’s pixels; domain smaller than the source shrinks as it blurs. Place it with node soft: graph “image.entpkg/graphs/blur.esn” { source <- x.result; sigma = 3.0; }
compare input a: Image
input b: Image
param over: Float = 0.0078125
output difference <- difference.result
output apart <- apart.result
Two pictures compared: difference, each pixel’s (w the most a channel differs), and apart, the most any pixel differs (x) and how many differ by more than over (y). Placed: node apart: graph “image.entpkg/graphs/compare.esn” { a <- before; b <- after.result; }
distance input mask: Image
param threshold: Float = 0.5
param passes: Int = 11
output result <- signed.result
The signed distance from every pixel to a shape, in pixels, negative inside: the shape is where mask is on (see image.seeds). Place it with node field: graph “image.entpkg/graphs/distance.esn” { mask <- shape.result; }
equalize input source: Image
param bins: Int = 256
param amount: Float = 1.0
output result <- even.result
output counts <- counts.result
Histogram equalization as a sub-graph: the pixels counted into bins by brightness, the counts accumulated, and each pixel moved to its rank. Place it with node even: graph “image.entpkg/graphs/equalize.esn” { source <- x.result; amount = 0.7; }
flood input seeds: Image
param passes: Int = 11
output result <- flooded.result
Jump flooding as a sub-graph: every pixel given the nearest of seeds (from image.seeds). passes covers a picture whose longer side is up to 2^(passes - 1) pixels, with one pass at a step of one to spare. Place it with node near: graph “image.entpkg/graphs/flood.esn” { seeds <- s.result; passes = 11; }
flood_pass input seeds: Image
input step: Rows<Int>
output result <- pass.result
output step <- next.result
One jump-flooding pass and the step after it. flood.esn places this passes times.
mipmap input source: Image
param side: Int = 256
param levels: Int = 7
output result <- halved.result
The mip strip of a square texture, as a sub-graph. Place it with node strip: graph “image.entpkg/graphs/mipmap.esn” { source <- texture.result; side = 256; levels = 7; } and read it with the functions in mipmap.ent. A placement does not know which repetition it is, so the level being written rides beside the strip as a row of one Int and is carried on with it.
mipmap_level input strip: Image
input step: Rows<Int>
param side: Int = 256
output result <- result.result
output step <- next.result
One halving of a mip strip: the level the counter names is written from the level above it, every other texel carried over unchanged. mipmap.esn places this levels times.
sharpen input source: Image
param sigma: Float = 1.5
param amount: Float = 0.6
output result <- crisp.result
Unsharp masking as a sub-graph: the source pushed away from its blur of sigma pixels by amount. Place it with node crisp: graph “image.entpkg/graphs/sharpen.esn” { source <- x.result; amount = 0.8; }
upscale input picture: Image
param amount: Float = 0.8
param near: Int = 0
output result <- sharp.result
A finished picture (tone-mapped, sRGB) scaled to the window’s size: an edge-aware upscale (image.upscale), sharpened once more without overshoot (image.contrast_sharpen), each frame stable on its own, nothing carried between frames. A picture already the window’s size passes through as it is. Placed: node shown: graph “image.entpkg/graphs/upscale.esn” { picture <- view.result; amount = 0.8; }

The picture adjusted: exposure stops, contrast (1 none), saturation (1 none, 0 gray), hue turned (a whole turn is 1).

Mode map
Requires field.read, field.write
Inputs source: Image
Params exposure: Float = 0.0, contrast: Float = 1.0, saturation: Float = 1.0, hue: Float = 0.0
Outputs result: Image
Source packages/image.entpkg/kernels/tone.ent

How far apart two pictures are as a whole (domain = 1): the most a pixel differs (x) and how many differ by more than the rows’ step (y), from image.apart_rows.

Mode map
Requires field.read, field.write
Inputs rows: Grid<Vec2>
Params —
Outputs result: Rows<Vec2>
Source packages/image.entpkg/kernels/compare.ent

Each row of a difference (image.difference’s), one cell a row: the most a pixel differs (x) and how many differ by more than over (y). A node sets domain = size(difference) * vec2(0, 1) + vec2(1, 0).

Mode map
Requires field.read, field.write
Inputs difference: Image
Params over: Float = 0.0078125
Outputs result: Grid<Vec2>
Source packages/image.entpkg/kernels/compare.ent

top composited over base, as the W3C’s compositing spec does it: where top covers (its alpha times opacity), its color is blended with base’s by mode, as much as base is there; then laid over base, the alphas joined as one sheet over another, the color weighed by both. space is where the arithmetic is done: on sRGB’s stored values (Encoded), as painting programs blend and the modes are defined, or on light itself (Linear). top is stretched over base whatever its size.

Mode map
Requires field.read, field.write
Inputs base: Image, top: Image
Params mode: Int = 0, opacity: Float = 1.0, space: Int = 0
Outputs result: Image
Source packages/image.entpkg/kernels/blend.ent

A Gaussian blur along axis (one pass of the two a blur takes, graphs/blur.esn): sigma measured in the output’s pixels, taps one output pixel apart out to three sigmas.

Mode map
Requires field.read, field.write
Inputs source: Image
Params axis: Vec2 = [1.0, 0.0], sigma: Float = 2.0
Outputs result: Image
Source packages/image.entpkg/kernels/filter.ent

Sharpened once (amount 0 not at all, 1 the most): pulled from its four neighbors by an amount held between the darkest and brightest of the five, never past 0 to 1, with no white rims.

Mode map
Requires field.read, field.write
Inputs image: Image
Params amount: Float = 0.8
Outputs result: Image
Source packages/image.entpkg/kernels/upscale.ent

Any convolution: weights holds n by n numbers, row by row, centered on the pixel (n odd). The weights are used as given, not normalized.

Mode map
Requires field.read, field.write
Inputs source: Image, weights: Rows<Float>
Params —
Outputs result: Image
Source packages/image.entpkg/kernels/filter.ent

The cumulative count: at each bin, the pixels in it and below.

Mode prefix with sum
Requires field.read, field.write
Inputs counts: Rows<Int>
Params —
Outputs result: Rows<Int>
Source packages/image.entpkg/kernels/histogram.ent

Curves: each channel looked up in curve, rows of the output for inputs spread evenly from 0 to 1 (x for red, y green, z blue), blended between rows.

Mode map
Requires field.read, field.write
Inputs source: Image, curve: Rows<Vec4>
Params —
Outputs result: Image
Source packages/image.entpkg/kernels/tone.ent
Mode map
Requires field.read, field.write
Inputs source: Image
Params —
Outputs result: Image
Source packages/image.entpkg/kernels/color.ent

The difference of a and b (domain = size(a); b read at the same place across the picture, whatever its size): each channel’s, and in w the most of them.

Mode map
Requires field.read, field.write
Inputs a: Image, b: Image
Params —
Outputs result: Image
Source packages/image.entpkg/kernels/compare.ent

The signed distance, in pixels, from each pixel’s center to the shape’s edge: from the nearest pixel of the shape when outside it (inside’s flood), less the distance to the nearest pixel outside it when within (outside’s flood); half a pixel taken off each, so the edge lies between the pixels either side. Where a flood found no seed, reach.

Mode map
Requires field.read, field.write
Inputs inside: Image, outside: Image
Params reach: Float = 1000.0
Outputs result: Grid<Float>

Each pixel held to colors with ordered dithering (dithered_color): a gradient becomes a pattern of two colors.

Mode map
Requires field.read, field.write
Inputs source: Image, colors: Rows<Vec3>
Params —
Outputs result: Image
Source packages/image.entpkg/kernels/pixel_art.ent

Edges: the strength of the Sobel gradient, gray, opaque.

Mode map
Requires field.read, field.write
Inputs source: Image
Params —
Outputs result: Image
Source packages/image.entpkg/kernels/filter.ent

Linear light to sRGB’s stored values (for a window or a file), and back; alpha kept.

Mode map
Requires field.read, field.write
Inputs source: Image
Params —
Outputs result: Image
Source packages/image.entpkg/kernels/color.ent

The picture equalized: each pixel’s lightness moved to the share of the pixels darker than it (cumulative, from image.cumulate), read between the counts below and through its bin by where in the bin it falls, so a smooth gradient stays smooth. The color is scaled to reach it: lightness grows as the cube root of a scale, so the cube of the ratio, which keeps the hue. amount mixes it with the source.

Mode map
Requires field.read, field.write
Inputs source: Image, cumulative: Rows<Int>
Params amount: Float = 1.0
Outputs result: Image
Source packages/image.entpkg/kernels/histogram.ent

The first step: half the picture’s longer side, as a power of two.

Mode map
Requires field.read, field.write
Inputs source: Image
Params —
Outputs result: Rows<Int>

One pass: the nearest seed among this pixel’s and the eight a step away.

Mode map
Requires field.read, field.write
Inputs seeds: Image, step: Rows<Int>
Params —
Outputs result: Image

The HDR picture image antialiased (the same size, fxaa); on 0 leaves it as it is.

Mode map
Requires field.read, field.write
Inputs image: Image
Params threshold: Float = 0.125, least: Float = 0.04, subpixel: Float = 0.6, on: Int = 1
Outputs result: Image
Source packages/image.entpkg/kernels/antialias.ent

How many pixels of the source fall in each bin.

Mode scatter into input 1 with sum
Requires field.read, field.write
Inputs source: Image, bins: Rows<Int>
Params —
Outputs result: Rows<Int>
Source packages/image.entpkg/kernels/histogram.ent

Levels: black to 0 and white to 1, clamped, then bent by gamma (above 1 brightens the middle).

Mode map
Requires field.read, field.write
Inputs source: Image
Params black: Float = 0.0, white: Float = 1.0, gamma: Float = 1.0
Outputs result: Image
Source packages/image.entpkg/kernels/tone.ent

The picture through a 3D LUT (lut_at), its values taken 0 to 1.

Mode map
Requires field.read, field.write
Inputs source: Image, lut: Image
Params —
Outputs result: Image
Source packages/image.entpkg/kernels/tone.ent

top over base as far as mask says: 0 base, 1 top, between them mixed (domain = size(base); top and mask any size, read smoothly across the picture). Any pass kept to part of a picture: a grade, an outline, a blur, laid only where a mask asks.

Mode map
Requires field.read, field.write
Inputs base: Image, top: Image, mask: Grid<Float>
Params —
Outputs result: Image
Source packages/image.entpkg/kernels/blend.ent

The strip before any halving: the texture in the top square and nothing under it.

Mode map
Requires field.read, field.write
Inputs source: Image
Params side: Int = 256
Outputs result: Image
Source packages/image.entpkg/kernels/mipmap.ent

One halving: four texels of the level above averaged into one of the level named, everything else carried over.

Mode map
Requires field.read, field.write
Inputs strip: Image, step: Rows<Int>
Params side: Int = 256
Outputs result: Image
Source packages/image.entpkg/kernels/mipmap.ent
Mode map
Requires field.read, field.write
Inputs previous: Rows<Int>
Params —
Outputs result: Rows<Int>
Source packages/image.entpkg/kernels/mipmap.ent

Dilation (each channel the greatest within radius pixels, a disc) or erosion (the least): bright shapes grown or worn away.

Mode map
Requires field.read, field.write
Inputs source: Image
Params radius: Int = 1, mode: Int = 0
Outputs result: Image
Source packages/image.entpkg/kernels/filter.ent

The neutral LUT of side n (domain = vec2(n * n, n)): each color itself. Grade it as a picture and image.lut applies that grade.

Mode map
Requires field.write
Inputs —
Params n: Int = 33
Outputs result: Image
Source packages/image.entpkg/kernels/tone.ent

The next step: half this one, never below one.

Mode map
Requires field.read, field.write
Inputs step: Rows<Int>
Params —
Outputs result: Rows<Int>

A line of color round what is drawn: each pixel not drawn beside one that is, across a side, or across a corner too (corners).

Mode map
Requires field.read, field.write
Inputs source: Image
Params color: Vec4 = [0.0, 0.0, 0.0, 1.0], corners: Bool = False
Outputs result: Image
Source packages/image.entpkg/kernels/pixel_art.ent

Each pixel the color of colors nearest it.

Mode map
Requires field.read, field.write
Inputs source: Image, colors: Rows<Vec3>
Params —
Outputs result: Image
Source packages/image.entpkg/kernels/pixel_art.ent

Cells of cell pixels, each the color at its center.

Mode map
Requires field.read, field.write
Inputs source: Image
Params cell: Float = 8.0
Outputs result: Image
Source packages/image.entpkg/kernels/pixel_art.ent

Each pixel the color of colors, rows from dark to light, its lightness falls to (ramp_color).

Mode map
Requires field.read, field.write
Inputs source: Image, colors: Rows<Vec3>
Params —
Outputs result: Image
Source packages/image.entpkg/kernels/pixel_art.ent

The source at the node’s domain, by bicubic (Catmull-Rom) interpolation: sharper than at_linear when enlarging. For halving and beyond, image.shrink.

Mode map
Requires field.read, field.write
Inputs source: Image
Params —
Outputs result: Image
Source packages/image.entpkg/kernels/filter.ent

Seeds: where the mask is on (its luminance times alpha past threshold, or not past it when inside is false), the pixel’s own center, else none. A seed is (x, y, 1, 0); none is all zeros.

Mode map
Requires field.read, field.write
Inputs mask: Image
Params threshold: Float = 0.5, inside: Bool = True
Outputs result: Image

A shadow of color cast by what is drawn, offset pixels away, under it: each pixel not drawn whose pixel offset back is.

Mode map
Requires field.read, field.write
Inputs source: Image
Params offset: Vec2 = [1.0, 1.0], color: Vec4 = [0.0, 0.0, 0.0, 0.5]
Outputs result: Image
Source packages/image.entpkg/kernels/pixel_art.ent

Unsharp masking: the source pushed away from its blurred copy by amount; alpha kept. graphs/sharpen.esn places it with its blur.

Mode map
Requires field.read, field.write
Inputs source: Image, blurred: Image
Params amount: Float = 0.6
Outputs result: Image
Source packages/image.entpkg/kernels/filter.ent

The source smaller: each output pixel the mean of the source pixels it covers (a box filter, exact at whole ratios).

Mode map
Requires field.read, field.write
Inputs source: Image
Params —
Outputs result: Image
Source packages/image.entpkg/kernels/filter.ent

Scaled to domain: edge-aware (upscaled), nearest-neighbor when near is 1 (upscaled_near).

Mode map
Requires field.read, field.write
Inputs image: Image
Params near: Int = 0
Outputs result: Image
Source packages/image.entpkg/kernels/upscale.ent

antialias.replay, compare.replay, looks.replay, operations.replay, upscale.replay