Liking cljdoc? Tell your friends :D

com.blockether.imaging

Clojure imaging WITHOUT java.desktop — decoding, encoding, transforms, vector drawing, text, SVG rasterisation and plotting, all in-process through the JDK Foreign Function & Memory API over a first-party Rust cdylib (native/imaging-c: the image crate + resvg/usvg/tiny-skia).

Why it exists: javax.imageio, java.awt.image.BufferedImage and Graphics2D drag the whole AWT/Java2D/ImageIO subgraph — service loaders, sun.java2d.loops JNI blit primitives, the font manager — into a GraalVM native image, which is both huge and, on a headless server, pointless. This library replaces that surface with a ~5 MB cdylib and zero JNI: pure downcalls, no subprocess, no -Djava.awt.headless, no fontconfig.

Everything is bytes in, bytes out. An Img is an opaque handle on the Rust side; it is AutoCloseable (use with-open for tight loops) AND registered with a java.lang.ref.Cleaner, so forgetting to close leaks nothing permanently.

Run the JVM with --enable-native-access=ALL-UNNAMED so the foreign linker may load the library without a restricted-method warning.

The library is resolved ONCE, lazily, the first time it's needed:

  1. IMAGING_NATIVE_PATH env / com.blockether.imaging.native.path system property — an explicit path to the cdylib (used verbatim).
  2. A bundled classpath resource prebuilds/<platform>/<lib>, shipped by com.blockether/imaging-native-<platform>. This is the native-image path.
  3. A runtime download: the imaging-native-<platform> jar resolved through clojure.tools.deps (honouring Maven repos/mirrors/settings.xml), extracted + cached. Disable with IMAGING_DISABLE_DOWNLOAD=1.

<platform> in { linux-x64 linux-arm64 darwin-arm64 darwin-x64 windows-x64 }.

Clojure imaging WITHOUT `java.desktop` — decoding, encoding, transforms,
vector drawing, text, SVG rasterisation and plotting, all in-process through
the JDK Foreign Function & Memory API over a first-party Rust cdylib
(`native/imaging-c`: the `image` crate + `resvg`/`usvg`/`tiny-skia`).

Why it exists: `javax.imageio`, `java.awt.image.BufferedImage` and
`Graphics2D` drag the whole AWT/Java2D/ImageIO subgraph — service loaders,
`sun.java2d.loops` JNI blit primitives, the font manager — into a GraalVM
native image, which is both huge and, on a headless server, pointless. This
library replaces that surface with a ~5 MB cdylib and zero JNI: pure
downcalls, no subprocess, no `-Djava.awt.headless`, no fontconfig.

Everything is bytes in, bytes out. An `Img` is an opaque handle on the Rust
side; it is `AutoCloseable` (use `with-open` for tight loops) AND registered
with a `java.lang.ref.Cleaner`, so forgetting to close leaks nothing
permanently.

Run the JVM with `--enable-native-access=ALL-UNNAMED` so the foreign linker
may load the library without a restricted-method warning.

The library is resolved ONCE, lazily, the first time it's needed:
  1. IMAGING_NATIVE_PATH env / `com.blockether.imaging.native.path` system
     property — an explicit path to the cdylib (used verbatim).
  2. A bundled classpath resource `prebuilds/<platform>/<lib>`, shipped by
     `com.blockether/imaging-native-<platform>`. This is the native-image path.
  3. A runtime download: the `imaging-native-<platform>` jar resolved through
     `clojure.tools.deps` (honouring Maven repos/mirrors/settings.xml),
     extracted + cached. Disable with IMAGING_DISABLE_DOWNLOAD=1.

`<platform>` in { linux-x64 linux-arm64 darwin-arm64 darwin-x64 windows-x64 }.
raw docstring

com.blockether.imaging.plot

A small, opinionated plotting DSL over com.blockether.imaging/plot.

The renderer lives in the Rust cdylib (native/imaging-c/src/plot.rs, drawn with tiny-skia and text-shaped through usvg), so plotting needs NO java.desktop, no headless AWT and no fonts on the host — four Noto faces are embedded in the library.

Everything here is DATA: a figure is a map, a panel is a map, a series is a map. This namespace only builds those maps (and hands them to the renderer), so anything the DSL doesn't wrap yet you can still express by assoc'ing the raw key — unknown keys are passed straight through to the renderer.

(require '[com.blockether.imaging.plot :as plot])

(plot/save! "cpu.png"
  (plot/figure {:title "CPU" :theme :dark :width 900 :height 400}
    (plot/lines {:x-label "minute" :y-label "%"}
      {:name "user" :x (range 60) :y user-samples}
      {:name "sys"  :x (range 60) :y sys-samples})))

Panel constructors: lines areas bars hbars stacked-bars scatter steps histogram pie donut heatmap. Each takes an optional option map first, then series maps (or plain sequences of numbers). figure composes panels into a grid; a bare panel is itself a valid figure.

A small, opinionated plotting DSL over `com.blockether.imaging/plot`.

The renderer lives in the Rust cdylib (`native/imaging-c/src/plot.rs`, drawn
with tiny-skia and text-shaped through usvg), so plotting needs NO
`java.desktop`, no headless AWT and no fonts on the host — four Noto faces are
embedded in the library.

Everything here is DATA: a figure is a map, a panel is a map, a series is a
map. This namespace only builds those maps (and hands them to the renderer),
so anything the DSL doesn't wrap yet you can still express by assoc'ing the
raw key — unknown keys are passed straight through to the renderer.

```clojure
(require '[com.blockether.imaging.plot :as plot])

(plot/save! "cpu.png"
  (plot/figure {:title "CPU" :theme :dark :width 900 :height 400}
    (plot/lines {:x-label "minute" :y-label "%"}
      {:name "user" :x (range 60) :y user-samples}
      {:name "sys"  :x (range 60) :y sys-samples})))
```

Panel constructors: `lines` `areas` `bars` `hbars` `stacked-bars` `scatter`
`steps` `histogram` `pie` `donut` `heatmap`. Each takes an optional option map
first, then series maps (or plain sequences of numbers). `figure` composes
panels into a grid; a bare panel is itself a valid figure.
raw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close