Images
PNG and JPEG decoding is client-side and pure JS
(pngjs,
jpeg-js — no native modules). A
decoded Image is independent of any X connection; the first time it is
drawn it uploads to that server as a 32-bit ARGB pixmap and is cached, so
repeated draws cost a single server-side composite.
import { createClient, loadImage } from 'ntk';
const app = await createClient();
const wnd = app.createWindow({ width: 400, height: 300 });
const ctx = wnd.getContext('2d');
const img = await loadImage('photo.jpg'); // path, file URL or Buffer
ctx.drawImage(img, 0, 0); // natural size
ctx.drawImage(img, 0, 0, 200, 150); // scaled (server-side, bilinear)
ctx.drawImage(img, 10, 10, 80, 80, 220, 10, 160, 160); // source crop + scale
wnd.map();
API
loadImage(source)→Promise<Image>—sourceis a file path, a fileURL, or aBuffer/Uint8Arrayof encoded PNG/JPEG bytesdecodeImage(buffer)→Image— synchronous decode of in-memory bytes; the format is sniffed from magic bytesnew Image({ width, height, data })— wrap raw non-premultiplied RGBA pixels (width * height * 4bytes)
Image
image.width,image.height— pixel dimensionsimage.data— non-premultiplied RGBA bytes (Buffer)image.picture(app)→Picture— the cached server-side picture for that app's display (uploaded on first call).ctx.drawImageuses this internally; it is public for manual Render compositingimage.destroy()/Symbol.dispose— free the server-side copies (safe: the image re-uploads if drawn again). Client-side pixel data stays usable; the server resources are also reclaimed by GC as a fallback (see resource management)
Notes
- Alpha is handled correctly: pixels are premultiplied at upload, so
translucent PNGs blend with what is underneath (
Overcomposition). - Uploads are chunked to respect the server's maximum request length, so large images work over the wire.
- Drawing the same
Imageinto several windows/pixmaps of one app reuses one upload; using it with several apps (rare) keeps one upload per app.