diff --git a/README.md b/README.md index 2e8a5d57..5e9c6722 100644 --- a/README.md +++ b/README.md @@ -127,13 +127,13 @@ errorCorrectionLevel|string (`'L' 'M' 'Q' 'H'`) |`'Q'` `options.imageOptions` structure -Property |Type |Default Value|Description -------------------|---------------------------------------|-------------|------------------------------------------------------------------------------ -hideBackgroundDots|boolean |`true` |Hide all dots covered by the image -imageSize |number |`0.4` |Coefficient of the image size. Not recommended to use ove 0.5. Lower is better -margin |number |`0` |Margin of the image in px -crossOrigin |string(`'anonymous' 'use-credentials'`)| |Set "anonymous" if you want to download QR code from other origins. -saveAsBlob |boolean |`false` |Saves image as base64 blob in svg type, see bellow +Property |Type | Default Value |Description +------------------|---------------------------------------|---------------|------------------------------------------------------------------------------ +hideBackgroundDots|boolean | `true` |Hide all dots covered by the image +imageSize |number | `0.4` |Coefficient of the image size. Not recommended to use ove 0.5. Lower is better +margin |number | `0` |Margin of the image in px +crossOrigin |string(`'anonymous' 'use-credentials'`)| |Set "anonymous" if you want to download QR code from other origins. +saveAsBlob |boolean | `true` |Saves image as base64 blob in svg type, see bellow When QR type is svg, the image may not load in certain applications as it is saved as a url, and some svg applications will not render url images for security reasons. Setting `saveAsBlob` to true will instead save the image as a blob, allowing it to render correctly in more places, but will also increase the file size. diff --git a/src/core/QRCodeStyling.test.js b/src/core/QRCodeStyling.test.js index 93672e3d..fa3c9a6e 100644 --- a/src/core/QRCodeStyling.test.js +++ b/src/core/QRCodeStyling.test.js @@ -87,6 +87,9 @@ describe("Test QRCodeStyling class", () => { }, backgroundOptions: { color: "#e9ebee" + }, + imageOptions: { + saveAsBlob: false } }); qrCode.getRawData("svg").then((buffer) => { diff --git a/src/core/QROptions.ts b/src/core/QROptions.ts index 902caa26..93234397 100644 --- a/src/core/QROptions.ts +++ b/src/core/QROptions.ts @@ -49,7 +49,7 @@ const defaultOptions: RequiredOptions = { errorCorrectionLevel: errorCorrectionLevels.Q }, imageOptions: { - saveAsBlob: false, + saveAsBlob: true, hideBackgroundDots: true, imageSize: 0.4, crossOrigin: undefined, diff --git a/src/core/QRSVG.ts b/src/core/QRSVG.ts index 52297fc7..1e447190 100644 --- a/src/core/QRSVG.ts +++ b/src/core/QRSVG.ts @@ -1,4 +1,5 @@ import calculateImageSize from "../tools/calculateImageSize"; +import toDataUrl from "../tools/toDataUrl"; import errorCorrectionPercents from "../constants/errorCorrectionPercents"; import QRDot from "../figures/dot/QRDot"; import QRCornerSquare from "../figures/cornerSquare/QRCornerSquare"; @@ -7,7 +8,7 @@ import { RequiredOptions } from "./QROptions"; import gradientTypes from "../constants/gradientTypes"; import shapeTypes from "../constants/shapeTypes"; import { QRCode, FilterFunction, Gradient, Window } from "../types"; -import { Canvas as NodeCanvas, Image } from "canvas"; +import { Image } from "canvas"; const squareMask = [ [1, 1, 1, 1, 1, 1, 1], @@ -30,8 +31,6 @@ const dotMask = [ ]; export default class QRSVG { - _domCanvas?: HTMLCanvasElement; - _nodeCanvas?: NodeCanvas; _window: Window; _element: SVGElement; _defs: SVGElement; @@ -60,18 +59,6 @@ export default class QRSVG { this._element.setAttribute("viewBox", `0 0 ${options.width} ${options.height}`); this._defs = this._window.document.createElementNS("http://www.w3.org/2000/svg", "defs"); this._element.appendChild(this._defs); - - if (options.imageOptions.saveAsBlob) { - if (options.nodeCanvas?.createCanvas) { - this._nodeCanvas = options.nodeCanvas.createCanvas(options.width, options.height); - this._nodeCanvas.width = options.width; - this._nodeCanvas.height = options.height; - } else { - this._domCanvas = document.createElement("canvas"); - this._domCanvas.width = options.width; - this._domCanvas.height = options.height; - } - } this._imageUri = options.image; this._instanceId = QRSVG.instanceCount++; this._options = options; @@ -471,15 +458,11 @@ export default class QRSVG { options.nodeCanvas .loadImage(options.image) .then((image: Image) => { - // fix blurry svg - if (/(\.svg$)|(^data:image\/svg)/.test(options.image ?? "")) { - image.width = this._options.width; - image.height = this._options.height; - } this._image = image; - if (this._options.imageOptions.saveAsBlob && this._nodeCanvas) { - this._nodeCanvas.getContext('2d')?.drawImage(image, 0, 0, this._nodeCanvas.width, this._nodeCanvas.height); - this._imageUri = this._nodeCanvas.toDataURL('image/png'); + if (this._options.imageOptions.saveAsBlob) { + const canvas = options.nodeCanvas?.createCanvas( this._image.width, this._image.height); + canvas?.getContext('2d')?.drawImage(image, 0, 0); + this._imageUri = canvas?.toDataURL(); } resolve(); }) @@ -492,10 +475,9 @@ export default class QRSVG { } this._image = image; - image.onload = (): void => { - if (this._options.imageOptions.saveAsBlob && this._domCanvas) { - this._domCanvas.getContext('2d')?.drawImage(image, 0, 0, this._domCanvas.width, this._domCanvas.height); - this._imageUri = this._domCanvas.toDataURL('image/png'); + image.onload = async () => { + if (this._options.imageOptions.saveAsBlob) { + this._imageUri = await toDataUrl(options.image || "", this._window); } resolve(); }; diff --git a/src/tools/toDataUrl.ts b/src/tools/toDataUrl.ts index d07fdd8c..22492cb4 100644 --- a/src/tools/toDataUrl.ts +++ b/src/tools/toDataUrl.ts @@ -1,8 +1,10 @@ -export default async function toDataURL(url: string): Promise { +import { Window } from "../types"; + +export default async function toDataURL(url: string, window: Window): Promise { return new Promise((resolve) => { - const xhr = new XMLHttpRequest(); + const xhr = new window.XMLHttpRequest(); xhr.onload = function () { - const reader = new FileReader(); + const reader = new window.FileReader(); reader.onloadend = function () { resolve(reader.result as string); };