A fast QR code generator with logo embedding support, built with Rust and native node packages for best performance while avoiding additional modules (example: canvas).
- Fast: Built with Rust (for logos) for maximum performance and caching 🚀
- Fast SVG: High performance SVG support via
QrCodewhen no logo is needed - Cross-platform: Works on iOS, Windows, Linux, and macOS
- Logo embedding: Add custom logos to your QR codes with no need for node canvas!
- Customizable: Custom colors, sizes, and margins
- Multiple formats: Generate SVG, PNG, and JPEG outputs
- Scalable: With caching you can also use a secondary store for persistence
- Well-tested: Comprehensive test coverage with Vitest
- Maintained: Actively maintained with regular updates
npm install qrbit- Node.js >= 18
- Supported platforms: Windows (x86, x64), macOS (Arm, Intel), Linux (x64)
const qr = new QrBit({ text: "https://github.com/jaredwray/qrbit", size: 200 });
const svg = await qr.toSvg();
console.log(svg); // here is the svg!Here is how you add a logo:
const qr = new QrBit({
text: "https://github.com/jaredwray/qrbit",
logo: '/path/to/logo.png',
size: 200 });
const svg = await qr.toSvg();
console.log(svg); // here is the svg with an embedded logo!const qr = new QrBit({
text: "https://github.com/jaredwray/qrbit",
logo: '/path/to/logo.png',
size: 200 });
const png = await qr.toPng(); // buffer of the png!Creates a new QrBit instance with the specified options.
Parameters:
options(QrOptions): Configuration object for the QR code
interface QrOptions {
text: string; // The text content to encode
size?: number; // Size in pixels (default: 200)
margin?: number; // Margin in pixels (default: undefined)
logo?: string | Buffer; // Logo file path or buffer
logoSizeRatio?: number; // Logo size ratio (default: 0.2)
backgroundColor?: string; // Background color (default: "#FFFFFF")
foregroundColor?: string; // Foreground color (default: "#000000")
cache?: Cacheable | boolean; // Caching configuration (default: true)
}
interface toOptions {
cache?: boolean; // Enable/disable caching (default: true)
quality?: number; // JPEG quality 1-100 (default: 90) - only for toJpg methods
}Example:
import { QrBit } from 'qrbit';
const qr = new QrBit({
text: "https://github.com/jaredwray/qrbit",
size: 300,
margin: 20,
logo: "./logo.png",
logoSizeRatio: 0.25,
backgroundColor: "#FFFFFF",
foregroundColor: "#000000"
});Get or set the text content for the QR code.
const qr = new QrBit({ text: "Hello World" });
console.log(qr.text); // "Hello World"
qr.text = "New content";Get or set the size of the QR code in pixels.
const qr = new QrBit({ text: "Hello World" });
console.log(qr.size); // 200 (default)
qr.size = 400;Get or set the margin around the QR code in pixels.
const qr = new QrBit({ text: "Hello World" });
console.log(qr.margin); // undefined (default)
qr.margin = 20;Get or set the logo as a file path or buffer.
const qr = new QrBit({ text: "Hello World" });
qr.logo = "./path/to/logo.png";
// or
qr.logo = fs.readFileSync("./logo.png");Get or set the logo size ratio relative to QR code size (0.0 to 1.0).
const qr = new QrBit({ text: "Hello World" });
qr.logoSizeRatio = 0.3; // 30% of QR code sizeGet or set the background color in hex format.
const qr = new QrBit({ text: "Hello World" });
qr.backgroundColor = "#FF0000"; // Red backgroundGet or set the foreground color in hex format.
const qr = new QrBit({ text: "Hello World" });
qr.foregroundColor = "#FFFFFF"; // White foregroundGet or set the cache instance for performance optimization.
import { Cacheable } from 'cacheable';
const qr = new QrBit({ text: "Hello World" });
qr.cache = new Cacheable(); // Custom cache instance
qr.cache = false; // Disable cachingGenerate SVG QR code with optional caching. Uses native QRCode library for simple cases, Rust implementation for logos.
Parameters:
options.cache?: boolean- Whether to use caching (default: true)
Returns: Promise - The SVG string
const qr = new QrBit({ text: "Hello World" });
const svg = await qr.toSvg();
console.log(svg); // <svg xmlns="http://www.w3.org/2000/svg"...
// Without caching
const svgNoCache = await qr.toSvg({ cache: false });Generate SVG QR code and save it to a file. Creates directories if they don't exist.
Parameters:
filePath: string- The file path where to save the SVGoptions.cache?: boolean- Whether to use caching (default: true)
Returns: Promise
const qr = new QrBit({ text: "Hello World" });
await qr.toSvgFile("./output/qr-code.svg");
// With options
await qr.toSvgFile("./output/qr-code.svg", { cache: false });Generate PNG QR code with optional caching. Uses high-performance SVG to PNG conversion.
Parameters:
options.cache?: boolean- Whether to use caching (default: true)
Returns: Promise - The PNG buffer
const qr = new QrBit({ text: "Hello World" });
const pngBuffer = await qr.toPng();
// Save to file
fs.writeFileSync("qr-code.png", pngBuffer);
// Without caching
const pngNoCache = await qr.toPng({ cache: false });Generate PNG QR code and save it to a file. Creates directories if they don't exist.
Parameters:
filePath: string- The file path where to save the PNGoptions.cache?: boolean- Whether to use caching (default: true)
Returns: Promise
const qr = new QrBit({ text: "Hello World" });
await qr.toPngFile("./output/qr-code.png");
// With options
await qr.toPngFile("./output/qr-code.png", { cache: false });Generate JPEG QR code with optional caching and quality control. Uses high-performance SVG to JPEG conversion.
Parameters:
options.cache?: boolean- Whether to use caching (default: true)options.quality?: number- JPEG quality from 1-100 (default: 90)
Returns: Promise - The JPEG buffer
const qr = new QrBit({ text: "Hello World" });
const jpgBuffer = await qr.toJpg();
// With high quality
const jpgHigh = await qr.toJpg({ quality: 95 });
// With compression for smaller file size
const jpgCompressed = await qr.toJpg({ quality: 70 });
// Save to file
fs.writeFileSync("qr-code.jpg", jpgBuffer);
// Without caching
const jpgNoCache = await qr.toJpg({ cache: false, quality: 85 });Generate JPEG QR code and save it to a file. Creates directories if they don't exist.
Parameters:
filePath: string- The file path where to save the JPEGoptions.cache?: boolean- Whether to use caching (default: true)options.quality?: number- JPEG quality from 1-100 (default: 90)
Returns: Promise
const qr = new QrBit({ text: "Hello World" });
await qr.toJpgFile("./output/qr-code.jpg");
// With high quality
await qr.toJpgFile("./output/qr-code.jpg", { quality: 95 });
// With compression
await qr.toJpgFile("./output/qr-code.jpg", { quality: 70, cache: false });Convert SVG content to PNG buffer using the native Rust implementation.
Parameters:
svgContent: string- The SVG content as a stringwidth?: number- Optional width for the PNG outputheight?: number- Optional height for the PNG output
Returns: Buffer - The PNG buffer
const svg = '<svg>...</svg>';
const pngBuffer = QrBit.convertSvgToPng(svg, 400, 400);Convert SVG content to JPEG buffer using the native Rust implementation.
Parameters:
svgContent: string- The SVG content as a stringwidth?: number- Optional width for the JPEG outputheight?: number- Optional height for the JPEG outputquality?: number- JPEG quality from 1-100 (default: 90)
Returns: Buffer - The JPEG buffer
const svg = '<svg>...</svg>';
const jpegBuffer = QrBit.convertSvgToJpeg(svg, 400, 400, 85);| name | summary | ops/sec | time/op | margin | samples |
|---|---|---|---|---|---|
| QRCode toString (v1.5.4) | 🥇 | 6K | 162µs | ±0.37% | 6K |
| QrBit toSvg (Native) (v1.0.0) | -3.2% | 6K | 172µs | ±0.92% | 6K |
| QrBit toSvg (Rust) (v1.0.0) | -85% | 945 | 1ms | ±1.17% | 912 |
| styled-qr-code-node toBuffer (v1.5.2) | -89% | 709 | 1ms | ±1.07% | 701 |
Rust is there for performance and when doing heavy image processing without needing node canvas installed. If you do not add a logo then the Native version is what you will get for SVG.
| name | summary | ops/sec | time/op | margin | samples |
|---|---|---|---|---|---|
| QrBit toPng (v1.0.0) | 🥇 | 2K | 647µs | ±0.68% | 2K |
| QRCode toBuffer (v1.5.4) | -49% | 804 | 1ms | ±0.77% | 794 |
| styled-qr-code-node toBuffer (v1.5.2) | -85% | 238 | 4ms | ±0.74% | 238 |
| name | summary | ops/sec | time/op | margin | samples |
|---|---|---|---|---|---|
| QrBit toJpg (v1.2.0) | 🥇 | 663 | 2ms | ±0.37% | 662 |
| styled-qr-code-node toBuffer (v1.5.2) | -36% | 424 | 2ms | ±2.13% | 418 |
Rust is used for toPng() and toJpg to optimize performance for image generation and heavy image processing without needing node canvas installed.
| name | summary | ops/sec | time/op | margin | samples |
|---|---|---|---|---|---|
| QrBit SVG (Path) (v1.0.0) | 🥇 | 819 | 1ms | ±1.04% | 794 |
| QrBit SVG (Buffer) (v1.0.0) | -58% | 341 | 3ms | ±1.08% | 339 |
| QrBit PNG (Path) (v1.0.0) | -61% | 319 | 3ms | ±1.95% | 314 |
| styled-qr-code-node PNG (v1.5.2) | -81% | 159 | 6ms | ±0.75% | 159 |
| QrBit PNG (Buffer) (v1.0.0) | -81% | 154 | 7ms | ±1.05% | 154 |
| styled-qr-code-node SVG (v1.5.2) | -84% | 134 | 7ms | ±0.59% | 135 |
Buffer is much slower as we have to push the stream across to the rust module. For fastest performance provide the path of the image.
| name | summary | ops/sec | time/op | margin | samples |
|---|---|---|---|---|---|
| QrBit toSvg (Native) (v1.0.0) | 🥇 | 95K | 94µs | ±2.08% | 11K |
| QRCode toString (v1.5.4) | -93% | 6K | 161µs | ±0.37% | 6K |
| QrBit toSvg (Rust) (v1.0.0) | -99% | 938 | 1ms | ±1.12% | 907 |
| styled-qr-code-node toBuffer (v1.5.2) | -99% | 710 | 1ms | ±1.10% | 700 |
| name | summary | ops/sec | time/op | margin | samples |
|---|---|---|---|---|---|
| QrBit toPng (v1.0.0) | 🥇 | 13K | 584µs | ±1.84% | 2K |
| QRCode toBuffer (v1.5.4) | -94% | 760 | 1ms | ±1.54% | 741 |
| styled-qr-code-node toBuffer (v1.5.2) | -98% | 233 | 4ms | ±2.10% | 231 |
The examples/ directory contains various QR code examples showcasing different features and use cases. You can generate these examples by running:
pnpm generate-examplesSimple QR code with default settings.
const qr = new QrBit({ text: "Hello World!" });
await qr.toPngFile("01_basic.png");QR code encoding a GitHub URL.
const qr = new QrBit({ text: "https://github.com/jaredwray/qrbit", size: 200 });
await qr.toSvgFile("02_url.svg");QR code with increased size for better scanning.
const qr = new QrBit({ text: "Large QR", size: 400 });
await qr.toPngFile("03_large_size.png");Black background with white foreground.
const qr = new QrBit({
text: "Inverted Colors",
backgroundColor: "#000000",
foregroundColor: "#FFFFFF"
});
await qr.toSvgFile("04_inverted.svg");Custom red background theme.
const qr = new QrBit({
text: "Red Theme",
backgroundColor: "#FF0000",
foregroundColor: "#FFFFFF"
});
await qr.toPngFile("05_red_theme.png");QR code with a small embedded logo.
const qr = new QrBit({
text: "logo small",
logo: "./logo.png",
logoSizeRatio: 0.2
});
await qr.toPngFile("06_logo_small.png");Large logo with red background theme.
const qr = new QrBit({
text: "logo large red",
logo: "./logo.png",
size: 400,
logoSizeRatio: 0.3,
backgroundColor: "#FF0000",
foregroundColor: "#FFFFFF"
});
await qr.toSvgFile("07_logo_large_red.svg");QR code for WiFi network connection.
const qr = new QrBit({
text: "WIFI:T:WPA;S:MyNetwork;P:MyPassword;;"
});
await qr.toPngFile("08_wifi.png");Custom margin and blue color scheme.
const qr = new QrBit({
text: "https://github.com/jaredwray/qrbit",
size: 300,
margin: 40,
backgroundColor: "#0000FF",
foregroundColor: "#FFFFFF"
});
await qr.toSvgFile("09_large_margin_blue.svg");Using a logo loaded from a Buffer instead of file path.
const logoBuffer = fs.readFileSync("./logo.png");
const qr = new QrBit({
text: "Buffer Logo",
logo: logoBuffer,
logoSizeRatio: 0.2,
backgroundColor: "#F0F0F0",
foregroundColor: "#333333"
});
await qr.toPngFile("10_buffer_logo.png");JPEG format with high quality setting.
const qr = new QrBit({
text: "High Quality JPEG",
size: 300
});
await qr.toJpgFile("11_jpg_high_quality.jpg", { quality: 95 });JPEG with embedded logo and custom blue background.
const qr = new QrBit({
text: "JPEG with Logo",
logo: "./logo.png",
size: 400,
logoSizeRatio: 0.25,
backgroundColor: "#2196F3",
foregroundColor: "#FFFFFF"
});
await qr.toJpgFile("12_jpg_logo_blue.jpg", { quality: 90 });JPEG with lower quality for smaller file size.
const qr = new QrBit({
text: "https://github.com/jaredwray/qrbit",
size: 300,
backgroundColor: "#4CAF50",
foregroundColor: "#FFFFFF"
});
await qr.toJpgFile("13_jpg_compressed_green.jpg", { quality: 70 });JPEG using buffer-based logo with orange background.
const logoBuffer = fs.readFileSync("./logo.png");
const qr = new QrBit({
text: "JPEG Buffer Logo",
logo: logoBuffer,
size: 350,
logoSizeRatio: 0.2,
backgroundColor: "#FF9800",
foregroundColor: "#FFFFFF"
});
await qr.toJpgFile("14_jpg_buffer_logo_orange.jpg", { quality: 85 });These examples demonstrate the versatility and capabilities of QrBit for generating QR codes with various customizations, from simple text encoding to complex styled codes with embedded logos, supporting SVG, PNG, and JPEG formats with quality control.
Please read our Contributing Guidelines and also our Code of Conduct.