Skip to content

Render text and an image into one label

renderText and renderImage both return LabelBitmaps, so combining them is just a matter of stacking. The interesting part is sizing: text scales by integer factors (scaleX, scaleY), images scale by RGBA-stage resampling.

Centred caption above an image

ts
import { padBitmap, renderImage, renderText, stackBitmaps } from '@mbtech-nl/bitmap';

const image = renderImage(productPhotoRgba, { dither: 'atkinson' });
const caption = renderText('SKU 4501', { scaleX: 2, scaleY: 2 });

const padding = Math.max(0, image.widthPx - caption.widthPx);
const left = Math.floor(padding / 2);
const right = padding - left;

const captionCentred = padBitmap(caption, { top: 6, bottom: 4, left, right });
const label = stackBitmaps([captionCentred, image], 'vertical');

Two-line text block

renderText does a single line — for multi-line, render each line separately and stack:

ts
const lines = [
  renderText('TO:',                { scaleX: 1, scaleY: 1 }),
  renderText('Acme Corp',          { scaleX: 2, scaleY: 2 }),
  renderText('123 Main Street',    { scaleX: 1, scaleY: 1 }),
  renderText('Springfield, USA',   { scaleX: 1, scaleY: 1 }),
];

// All lines share the bundled font's char height (8) × scaleY, but widths
// differ — pad each to the widest one.
const targetWidth = Math.max(...lines.map(l => l.widthPx));
const padded = lines.map(l =>
  padBitmap(l, { right: targetWidth - l.widthPx, bottom: 2 }),
);
const block = stackBitmaps(padded, 'vertical');

Inline text + image (horizontal)

ts
import { padBitmap, renderImage, renderText, stackBitmaps } from '@mbtech-nl/bitmap';

const icon = renderImage(iconRgba, { dither: false });   // already small
const label = renderText('FRAGILE', { scaleX: 2, scaleY: 2 });

// Pad the shorter element to match the taller one.
const tallest = Math.max(icon.heightPx, label.heightPx);
const align = (b: LabelBitmap) =>
  b.heightPx === tallest ? b : padBitmap(b, { bottom: tallest - b.heightPx });

const row = stackBitmaps(
  [align(icon), padBitmap(align(label), { left: 8 })],
  'horizontal',
);

For text-rich layouts that don't fit the bundled 8×8 font, render the text in a real font using a canvas (browser or @napi-rs/canvas) and feed the result to renderImage.

Released under the MIT License.