Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/core/QRCodeStyling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ import drawTypes from "../constants/drawTypes";

import defaultOptions, { RequiredOptions } from "./QROptions";
import sanitizeOptions from "../tools/sanitizeOptions";
import { FileExtension, QRCode, Options, DownloadOptions, ExtensionFunction, Window } from "../types";
import { FileExtension, QRCode, Options, DownloadOptions, ExtensionFunction, Window, NodeCanvasElement } from "../types";
import qrcode from "qrcode-generator";
import getMimeType from "../tools/getMimeType";
import { Canvas as NodeCanvas, Image } from "canvas";

declare const window: Window;

Expand All @@ -18,7 +17,7 @@ export default class QRCodeStyling {
_window: Window;
_container?: HTMLElement;
_domCanvas?: HTMLCanvasElement;
_nodeCanvas?: NodeCanvas;
_nodeCanvas?: NodeCanvasElement;
_svg?: SVGElement;
_qr?: QRCode;
_extension?: ExtensionFunction;
Expand Down Expand Up @@ -79,7 +78,7 @@ export default class QRCodeStyling {
const image64 = `data:${getMimeType('svg')};base64,${svg64}`;

if (this._options.nodeCanvas?.loadImage) {
return this._options.nodeCanvas.loadImage(image64).then((image: Image) => {
return this._options.nodeCanvas.loadImage(image64).then((image) => {
// fix blurry svg
image.width = this._options.width;
image.height = this._options.height;
Expand Down
7 changes: 3 additions & 4 deletions src/core/QRSVG.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import QRCornerDot, { availableCornerDotTypes } from "../figures/cornerDot/QRCor
import { RequiredOptions } from "./QROptions";
import gradientTypes from "../constants/gradientTypes";
import shapeTypes from "../constants/shapeTypes";
import { DotType, QRCode, FilterFunction, Gradient, Window } from "../types";
import { Image } from "canvas";
import { DotType, QRCode, FilterFunction, Gradient, Window, NodeCanvasImage } from "../types";

const squareMask = [
[1, 1, 1, 1, 1, 1, 1],
Expand Down Expand Up @@ -40,7 +39,7 @@ export default class QRSVG {
_cornersDotClipPath?: SVGElement;
_options: RequiredOptions;
_qr?: QRCode;
_image?: HTMLImageElement | Image;
_image?: HTMLImageElement | NodeCanvasImage;
_imageUri?: string;
_instanceId: number;

Expand Down Expand Up @@ -457,7 +456,7 @@ export default class QRSVG {
if (options.nodeCanvas?.loadImage) {
options.nodeCanvas
.loadImage(options.image)
.then((image: Image) => {
.then((image) => {
this._image = image;
if (this._options.imageOptions.saveAsBlob) {
const canvas = options.nodeCanvas?.createCanvas( this._image.width, this._image.height);
Expand Down
46 changes: 40 additions & 6 deletions src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import { DOMWindow, JSDOM } from "jsdom";
import nodeCanvas from "canvas";

export interface UnknownObject {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
Expand All @@ -14,7 +11,44 @@ export type GradientType = "radial" | "linear";
export type DrawType = "canvas" | "svg";
export type ShapeType = "square" | "circle";

export type Window = DOMWindow;
// Minimal window-like interface — compatible with both browser Window and jsdom DOMWindow
export interface BrowserWindow {
document: Document;
XMLSerializer: typeof XMLSerializer;
Image: { new(): HTMLImageElement };
XMLHttpRequest: typeof XMLHttpRequest;
FileReader: typeof FileReader;
}

export type Window = BrowserWindow;

// Minimal node-canvas interfaces — avoids importing the "canvas" package in browser bundles
export interface NodeCanvasImage {
width: number;
height: number;
}

export interface NodeCanvasRenderingContext2D {
drawImage(image: NodeCanvasImage, dx: number, dy: number): void;
}

export interface NodeCanvasElement {
width: number;
height: number;
getContext(contextId: "2d"): NodeCanvasRenderingContext2D | null;
toBuffer(mimeType: string): Buffer;
toDataURL(type?: string): string;
}

export interface NodeCanvasFactory {
createCanvas(width: number, height: number): NodeCanvasElement;
loadImage(src: string): Promise<NodeCanvasImage>;
}

// Minimal jsdom constructor interface — avoids importing "jsdom" in browser bundles
export interface JSDOMConstructor {
new(html: string, options?: { resources?: string }): { window: BrowserWindow };
}

export type Gradient = {
type: GradientType;
Expand Down Expand Up @@ -116,8 +150,8 @@ export type Options = {
margin?: number;
data?: string;
image?: string;
nodeCanvas?: typeof nodeCanvas;
jsdom?: typeof JSDOM;
nodeCanvas?: NodeCanvasFactory;
jsdom?: JSDOMConstructor;
qrOptions?: {
typeNumber?: TypeNumber;
mode?: Mode;
Expand Down