nativeImage
Load, query, encode, resize, and crop tray/dock/window icons from PNG or JPEG, backed by Cocoa on macOS and GdkPixbuf on Linux.
The nativeImage module loads, queries, and encodes system images - the icons you hand to a Tray, a window, or a Menu. It is a deliberate subset of Electron’s module: decoding and pixel work happen behind a per-platform native backend (Cocoa NSBitmapImageRep on macOS, GdkPixbuf on Linux), while the NativeImage class itself is plain TypeScript.
A bad path or undecodable bytes never throw - they yield an empty image (isEmpty() is true, size 0×0), matching Electron’s “empty and transparent image” behavior.
Process: Main. The module is exported from
bunmaska/bunmaska/main, notbunmaska/renderer. As in Electron, if you need an image in a renderer, build it in your preload/main and pass it across - there is no renderer-sidenativeImagefactory.
Static methods
These live on the nativeImage object and each return a NativeImage.
nativeImage.createFromPath(path)
createFromPath(path: string): NativeImage
Loads an image from a filesystem path (PNG or JPEG). An unreadable path or non-image file returns an empty image rather than throwing.
import { nativeImage } from 'bunmaska';
const icon = nativeImage.createFromPath('/Users/somebody/images/icon.png');
console.log(icon.isEmpty(), icon.getSize()); // false { width: 32, height: 32 }
nativeImage.createFromBuffer(buffer)
createFromBuffer(buffer: Uint8Array): NativeImage
Decodes in-memory PNG or JPEG bytes. Undecodable bytes return an empty image.
import { readFileSync } from 'node:fs';
import { nativeImage } from 'bunmaska';
const bytes = readFileSync('/Users/somebody/images/icon.png');
const image = nativeImage.createFromBuffer(bytes);
Note: unlike Electron, this takes no options argument - there is no raw-bitmap path here (see Not in Bunmaska). It always decodes encoded image bytes.
nativeImage.createFromDataURL(dataURL)
createFromDataURL(dataURL: string): NativeImage
Decodes a data: URL. Both base64 (;base64,) and URL-encoded payloads are handled. A string that is not a data: URL returns an empty image.
import { nativeImage } from 'bunmaska';
const image = nativeImage.createFromDataURL(
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAB...',
);
nativeImage.createEmpty()
createEmpty(): NativeImage
Creates an empty, transparent image with no native decode. Handy as a placeholder.
import { nativeImage } from 'bunmaska';
const blank = nativeImage.createEmpty();
console.log(blank.isEmpty()); // true
Instance methods
Available on any NativeImage returned by the factory. The class is never constructed directly.
image.getSize()
getSize(): { width: number; height: number }
Returns the image’s pixel dimensions, or { width: 0, height: 0 } when empty.
Implementation aside:
bun:ffican’t return a struct by value, so Electron’sNSImage.size(anNSSize) is unreadable across the boundary. Each backend instead reports width/height via scalar getters at decode time. The practical upshot for you:getSize()takes noscaleFactorargument.
import { nativeImage } from 'bunmaska';
const { width, height } = nativeImage.createFromPath('./icon.png').getSize();
image.isEmpty()
isEmpty(): boolean
Whether the image has no usable contents (bad path, undecodable bytes, or created empty).
import { nativeImage } from 'bunmaska';
if (nativeImage.createFromPath('./missing.png').isEmpty()) {
console.warn('icon failed to load; falling back to a default');
}
image.getAspectRatio()
getAspectRatio(): number
The image’s width-to-height ratio, or 0 when empty / zero-height.
import { nativeImage } from 'bunmaska';
const ratio = nativeImage.createFromPath('./banner.png').getAspectRatio(); // e.g. 1.777...
Note: unlike Electron this takes no scaleFactor argument (Bunmaska images carry a single representation).
image.toPNG()
toPNG(): Uint8Array
Encodes the image to PNG bytes. An empty image returns a zero-length buffer.
import { writeFileSync } from 'node:fs';
import { nativeImage } from 'bunmaska';
const png = nativeImage.createFromPath('./icon.jpg').toPNG();
writeFileSync('./icon.png', png);
Note: takes no options - there is no scaleFactor parameter.
image.toJPEG(quality)
toJPEG(quality?: number): Uint8Array
Encodes the image to JPEG bytes. quality is 0-100 and defaults to 92. An empty image returns a zero-length buffer.
import { writeFileSync } from 'node:fs';
import { nativeImage } from 'bunmaska';
const jpeg = nativeImage.createFromPath('./photo.png').toJPEG(80);
writeFileSync('./photo.jpg', jpeg);
Platform note:
qualityis honored on macOS (viaNSImageCompressionFactor). On Linux, GdkPixbuf is currently saved with default quality and thequalityargument is ignored. The default value differs from Electron’s API too: Electron requiresquality; Bunmaska defaults it to92.
image.toDataURL()
toDataURL(): string
Returns the image as a data:image/png;base64,... URL (PNG-encoded). An empty image produces a URL with an empty payload.
import { nativeImage } from 'bunmaska';
const url = nativeImage.createFromPath('./icon.png').toDataURL();
// 'data:image/png;base64,iVBORw0KGgo...'
Note: always PNG; takes no options / scaleFactor.
image.resize(options)
resize(options: { width?: number; height?: number; quality?: 'good' | 'better' | 'best' }): NativeImage
Returns a new image resized to the given dimensions. Omitting one dimension preserves the aspect ratio; omitting both returns an unchanged-size copy. Resizing an empty image yields an empty image.
import { nativeImage } from 'bunmaska';
const big = nativeImage.createFromPath('./icon.png');
const thumb = big.resize({ width: 64 }); // height derived to keep aspect ratio
const square = big.resize({ width: 32, height: 32 });
qualityis accepted for Electron source-compatibility but is best-effort: the macOS backend redraws via a CoreGraphics offscreen bitmap and Linux uses GdkPixbuf bilinear scaling, so the'good' | 'better' | 'best'hint does not currently select distinct algorithms.
image.crop(rect)
crop(rect: { x: number; y: number; width: number; height: number }): NativeImage
Returns a new image containing the sub-rectangle (pixels, top-left origin). A rect that is empty or entirely outside the image yields an empty image; a partially-overflowing rect is clamped to bounds.
import { nativeImage } from 'bunmaska';
const full = nativeImage.createFromPath('./sprite.png');
const tile = full.crop({ x: 0, y: 0, width: 16, height: 16 });
image.setTemplateImage(option)
setTemplateImage(option: boolean): void
Marks (or unmarks) the image as a template - a monochrome icon the OS recolors for light/dark UI. This is plain JS metadata on the image, mirroring Electron’s own model: the macOS NSImage setTemplate: flag is applied when the image is realized for a Tray or menu, not on the decoded representation here.
import { nativeImage } from 'bunmaska';
const trayIcon = nativeImage.createFromPath('./iconTemplate.png');
trayIcon.setTemplateImage(true);
Practically meaningful on macOS menu-bar/tray rendering; on Linux it is carried but has no recoloring effect.
image.isTemplateImage()
isTemplateImage(): boolean
Whether the image is currently marked as a template image.
import { nativeImage } from 'bunmaska';
const img = nativeImage.createFromPath('./iconTemplate.png');
img.setTemplateImage(true);
console.log(img.isTemplateImage()); // true
Events
The nativeImage module and NativeImage class emit no events.
Properties
NativeImage exposes no public data properties. (Electron’s isMacTemplateImage property is replaced here by the setTemplateImage() / isTemplateImage() method pair.)
Not in Bunmaska (yet)
Comparing against Electron’s nativeImage, the following are not implemented. Most reflect the single-representation, scalar-metadata design and the macOS-specific AppKit surface.
createFromBitmap(buffer, options)- no raw ARGB/bitmap ingestion path; only encoded PNG/JPEG bytes decode.createThumbnailFromPath(path, size)- no OS thumbnail service is wired (Electron ships it macOS/Windows only anyway).createFromNamedImage(imageName, options)- macOSNSImage/SF Symbols by name, plushslShift/pointSize/weight/scale, are not exposed.createMenuSymbol(imageName)- macOS SF Symbol menu icons are not implemented.getBitmap(options)/toBitmap(options)- no raw pixel-buffer readback (no struct/buffer round-trip across the FFI for this).getNativeHandle()- the native handle is held internally but not surfaced as aBufferpointer.getScaleFactors()and the@2x/@3xmulti-representation, high-DPI model - images carry a single representation; explicitly deferred in the source.addRepresentation(options)- follows from the above; there is no representation list to append to.scaleFactoroptions ongetSize,getAspectRatio,toPNG,toBitmap,toDataURL- omitted along with multi-rep support.colorSpaceoption on bitmap output - no bitmap output exists to color-manage.- The
isMacTemplateImageproperty - covered instead bysetTemplateImage()/isTemplateImage(). - Windows
ICOloading - Bunmaska targets macOS and Linux only; there is no Windows backend.