Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix browser image not rendered, set saveAsBlob=true by default, as it was before 1.6.0 version #250

Merged
merged 1 commit into from
Oct 21, 2024
Merged
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
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
3 changes: 3 additions & 0 deletions src/core/QRCodeStyling.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ describe("Test QRCodeStyling class", () => {
},
backgroundOptions: {
color: "#e9ebee"
},
imageOptions: {
saveAsBlob: false
}
});
qrCode.getRawData("svg").then((buffer) => {
Expand Down
2 changes: 1 addition & 1 deletion src/core/QROptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const defaultOptions: RequiredOptions = {
errorCorrectionLevel: errorCorrectionLevels.Q
},
imageOptions: {
saveAsBlob: false,
saveAsBlob: true,
hideBackgroundDots: true,
imageSize: 0.4,
crossOrigin: undefined,
Expand Down
36 changes: 9 additions & 27 deletions src/core/QRSVG.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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],
Expand All @@ -30,8 +31,6 @@ const dotMask = [
];

export default class QRSVG {
_domCanvas?: HTMLCanvasElement;
_nodeCanvas?: NodeCanvas;
_window: Window;
_element: SVGElement;
_defs: SVGElement;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
})
Expand All @@ -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();
};
Expand Down
8 changes: 5 additions & 3 deletions src/tools/toDataUrl.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
export default async function toDataURL(url: string): Promise<string> {
import { Window } from "../types";

export default async function toDataURL(url: string, window: Window): Promise<string> {
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);
};
Expand Down
Loading