Skip to content

JPEG Buffer renderer

Use QRCodeJPEGRenderer when Node.js-compatible code must deliver a JPEG file, for example to a form, print service, or upload field that only accepts JPEG images. JPEG also suits QR codes with a photographic center image, where lossy compression keeps the photo small.

Prefer the PNG or WebP renderer otherwise:

  • Lossy. JPEG blurs sharp edges slightly. QR codes still scan, but pixels near module edges shift a little.
  • No transparency. Transparent pixels are blended onto a solid matte color.
  • Larger files. For a plain QR code with a few flat colors, PNG and lossless WebP are much smaller. A default QR code for https://qrcodesdk.dev is about 9.7 KB as JPEG, 1.1 KB as PNG, and 310 bytes as WebP. A block-aligned module size closes most of that gap.
import {qrcode} from '@qrcodesdk/core';
import {QRCodeJPEGRenderer} from '@qrcodesdk/node';
const jpeg = qrcode('https://qrcodesdk.dev').render(QRCodeJPEGRenderer());
import {qrcode} from '@qrcodesdk/core';
import {QRCodeJPEGRenderer} from '@qrcodesdk/node';
const jpeg = qrcode('https://qrcodesdk.dev').render(
QRCodeJPEGRenderer({
style: {moduleSize: 8, background: '#ffffff00'},
quality: 85,
transparency: {matte: '#f8fafc'},
}),
);

See Customize appearance for every color, shape, and finder option.

The renderer synchronously returns a Node.js Buffer containing a complete baseline JPEG (JFIF) file. Its pixel width and height are style.moduleSize × (matrix width + 2 × style.quietZone). Output above 8192 × 8192 pixels (67,108,864 pixels) throws QRCodeError with code INVALID_OPTIONS before any pixels are allocated.

QRCodeJPEGRendererOptions accepts style, centerImage, quality, and transparency. TypeScript rejects every other key; the renderer does not repeat that check at runtime.

Option Type Default Effect
style QRCodeVisualStyle shared defaults Applies graphical dimensions, colors, and shapes
quality integer 1–100 92 Trades file size for detail
transparency.matte opaque QRCodeColor '#ffffff' Color that transparent pixels are blended onto
centerImage QRCodeRasterCenterImage undefined Draws a center image from rasterCenterImage()

The default quality of 92 keeps module edges sharp enough for reliable scanning. Lower values make smaller files with blurrier edges; test the result with the scanners you target before going below about 75.

  • Baseline JPEG. The file is a single-pass JFIF image. Every JPEG decoder can read it.
  • Optimized Huffman tables. The encoder counts the symbols of each image first and fits its Huffman tables to them, which makes files 10–50% smaller than the standard tables at no cost in quality.
  • No chroma subsampling. Color is stored at full resolution, so colored module edges stay crisp.
  • Grayscale output. When every pixel is gray, such as the default black-on-white style, the file stores one grayscale channel. It is smaller and has no color fringes.
  • Transparency. JPEG has no alpha channel. Every pixel is blended onto transparency.matte, including partially transparent module colors and antialiased edges. Pick the color of the page or print medium behind the QR code.
  • Identical output everywhere. The encoder uses integer arithmetic only, so the same pixels produce the same bytes in Node.js and in every browser.

JPEG compresses the image in blocks of 8 × 8 pixels. When module edges fall inside a block, the block has to store sharp detail, which costs most of the file size and causes the slight blur around modules. Choose a style.moduleSize that is a multiple of 8 so every block covers a single module and is one flat color:

import {qrcode} from '@qrcodesdk/core';
import {QRCodeJPEGRenderer} from '@qrcodesdk/node';
const jpeg = qrcode('https://qrcodesdk.dev').render(QRCodeJPEGRenderer({style: {moduleSize: 8}}));
style.moduleSize Image size JPEG size
4 132 × 132 pixels 3.0 KB
5 165 × 165 pixels 9.7 KB
8 264 × 264 pixels 870 bytes

Sizes are for https://qrcodesdk.dev at the default quality and quiet zone. A module size of 8, 16, or 24 gives the smallest files and keeps square module edges exact. Sizes that divide 8, such as 4 or 2, also align modules with the blocks and help less. Rounded or circular module shapes, center images, and antialiased edges still add detail within blocks.

Create the center image with rasterCenterImage() from PNG bytes, as for the PNG renderer. One center image can be reused across the PNG, WebP, GIF, and JPEG renderers:

import {readFile} from 'node:fs/promises';
import {qrcode} from '@qrcodesdk/core';
import {QRCodeJPEGRenderer, rasterCenterImage} from '@qrcodesdk/node';
const centerImage = rasterCenterImage(await readFile('./photo.png'), {size: 0.3});
const jpeg = qrcode('https://qrcodesdk.dev')
.errorCorrection('H')
.render(QRCodeJPEGRenderer({centerImage}));
  • quality must be a safe integer from 1 through 100. Other values throw QRCodeError with code INVALID_OPTIONS when QRCodeJPEGRenderer() is called.
  • transparency.matte must be an opaque #rrggbb color, or #rrggbbff. Other values throw QRCodeError with code INVALID_OPTIONS when QRCodeJPEGRenderer() is called.
  • The center-image source must contain PNG bytes, even for JPEG output. See the PNG renderer constraints for its limits.
  • Option values are copied when QRCodeJPEGRenderer() is called.

Support QRCodeSDK

If you find QRCodeSDK useful, please consider sponsoring the project!