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

🐛 fixes utf-8 encoding #54

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion dist/awesome-qr.js

Large diffs are not rendered by default.

45 changes: 23 additions & 22 deletions lib/awesome-qr.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AwesomeQR = void 0;
var canvas_1 = require("canvas");
var skia_canvas_1 = require("skia-canvas");
var gifuct_js_1 = require("./gifuct-js");
var qrcode_1 = require("./qrcode");
var GIFEncoder_1 = __importDefault(require("./gif.js/GIFEncoder"));
Expand Down Expand Up @@ -94,7 +94,7 @@ var AwesomeQR = /** @class */ (function () {
_options.components.alignment.scale = _options.dotScale;
}
this.options = _options;
this.canvas = canvas_1.createCanvas(options.size, options.size);
this.canvas = new skia_canvas_1.Canvas(options.size, options.size);
this.canvasContext = this.canvas.getContext("2d");
this.qrCode = new qrcode_1.QRCodeModel(-1, this.options.correctLevel);
if (Number.isInteger(this.options.maskPattern)) {
Expand Down Expand Up @@ -139,7 +139,7 @@ var AwesomeQR = /** @class */ (function () {
var count = 0;
height = image.naturalHeight || image.height;
width = image.naturalWidth || image.width;
var canvas = canvas_1.createCanvas(width, height);
var canvas = new skia_canvas_1.Canvas(width, height);
var context = canvas.getContext("2d");
if (!context) {
return defaultRGB;
Expand Down Expand Up @@ -200,7 +200,7 @@ var AwesomeQR = /** @class */ (function () {
AwesomeQR.prototype._draw = function () {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
return __awaiter(this, void 0, void 0, function () {
var nCount, rawSize, rawMargin, margin, rawViewportSize, whiteMargin, backgroundDimming, nSize, viewportSize, size, mainCanvas, mainCanvasContext, backgroundCanvas, backgroundCanvasContext, parsedGIFBackground, gifFrames, gif, r, g, b, count, i, c, backgroundImage, avgRGB, alignmentPatternCenters, dataScale, dataXyOffset, row, col, bIsDark, isBlkPosCtr, isTiming, isProtected, i, nLeft, nTop, inAgnRange, cornerAlignmentCenter, protectorStyle, i, j, agnX, agnY, timingScale, timingXyOffset, i, cornerAlignmentScale, cornerAlignmentXyOffset, alignmentScale, alignmentXyOffset, i, j, agnX, agnY, logoImage, logoScale, logoMargin, logoCornerRadius, logoSize, x, y, oldGlobalCompositeOperation, gifOutput_1, backgroundCanvas_1, backgroundCanvasContext_1, patchCanvas_1, patchCanvasContext_1, patchData_1, u8array, binary, outCanvas, outCanvasContext;
var nCount, rawSize, rawMargin, margin, rawViewportSize, whiteMargin, backgroundDimming, nSize, viewportSize, size, mainCanvas, mainCanvasContext, backgroundCanvas, backgroundCanvasContext, parsedGIFBackground, gifFrames, gif, r, g, b, count, i, c, backgroundImage, avgRGB, alignmentPatternCenters, dataScale, dataXyOffset, row, col, bIsDark, isBlkPosCtr, isTiming, isProtected, i, nLeft, nTop, inAgnRange, cornerAlignmentCenter, protectorStyle, i, j, agnX, agnY, timingScale, timingXyOffset, i, cornerAlignmentScale, cornerAlignmentXyOffset, alignmentScale, alignmentXyOffset, i, j, agnX, agnY, logoImage, logoScale, logoMargin, logoCornerRadius, logoSize, x, y, oldGlobalCompositeOperation, gifOutput_1, backgroundCanvas_1, backgroundCanvasContext_1, patchCanvas_1, patchCanvasContext_1, patchData_1, u8array, binary, outCanvas, outCanvasContext, format;
return __generator(this, function (_v) {
switch (_v.label) {
case 0:
Expand All @@ -217,13 +217,13 @@ var AwesomeQR = /** @class */ (function () {
nSize = Math.ceil(rawViewportSize / nCount);
viewportSize = nSize * nCount;
size = viewportSize + 2 * margin;
mainCanvas = canvas_1.createCanvas(size, size);
mainCanvas = new skia_canvas_1.Canvas(size, size);
mainCanvasContext = mainCanvas.getContext("2d");
this._clear();
// Translate to make the top and left margins off the viewport
mainCanvasContext.save();
mainCanvasContext.translate(margin, margin);
backgroundCanvas = canvas_1.createCanvas(size, size);
backgroundCanvas = new skia_canvas_1.Canvas(size, size);
backgroundCanvasContext = backgroundCanvas.getContext("2d");
parsedGIFBackground = null;
gifFrames = [];
Expand Down Expand Up @@ -253,7 +253,7 @@ var AwesomeQR = /** @class */ (function () {
return [3 /*break*/, 4];
case 1:
if (!!!this.options.backgroundImage) return [3 /*break*/, 3];
return [4 /*yield*/, canvas_1.loadImage(this.options.backgroundImage)];
return [4 /*yield*/, skia_canvas_1.loadImage(this.options.backgroundImage)];
case 2:
backgroundImage = _v.sent();
if (this.options.autoColor) {
Expand Down Expand Up @@ -399,7 +399,7 @@ var AwesomeQR = /** @class */ (function () {
mainCanvasContext.fillRect(-margin, -margin, margin, size);
}
if (!!!this.options.logoImage) return [3 /*break*/, 6];
return [4 /*yield*/, canvas_1.loadImage(this.options.logoImage)];
return [4 /*yield*/, skia_canvas_1.loadImage(this.options.logoImage)];
case 5:
logoImage = _v.sent();
logoScale = this.options.logoScale;
Expand Down Expand Up @@ -450,31 +450,31 @@ var AwesomeQR = /** @class */ (function () {
}
var _a = frame.dims, width = _a.width, height = _a.height;
if (!backgroundCanvas_1) {
backgroundCanvas_1 = canvas_1.createCanvas(width, height);
backgroundCanvas_1 = new skia_canvas_1.Canvas(width, height);
backgroundCanvasContext_1 = backgroundCanvas_1.getContext("2d");
backgroundCanvasContext_1.rect(0, 0, backgroundCanvas_1.width, backgroundCanvas_1.height);
backgroundCanvasContext_1.fillStyle = "#ffffff";
backgroundCanvasContext_1.fill();
}
if (!patchCanvas_1 || !patchData_1 || width !== patchCanvas_1.width || height !== patchCanvas_1.height) {
patchCanvas_1 = canvas_1.createCanvas(width, height);
patchCanvas_1 = new skia_canvas_1.Canvas(width, height);
patchCanvasContext_1 = patchCanvas_1.getContext("2d");
patchData_1 = patchCanvasContext_1.createImageData(width, height);
}
patchData_1.data.set(frame.patch);
patchCanvasContext_1.putImageData(patchData_1, 0, 0);
backgroundCanvasContext_1.drawImage(patchCanvas_1, frame.dims.left, frame.dims.top);
var unscaledCanvas = canvas_1.createCanvas(size, size);
backgroundCanvasContext_1.drawImage(patchCanvas_1.getContext('2d').canvas, frame.dims.left, frame.dims.top);
var unscaledCanvas = new skia_canvas_1.Canvas(size, size);
var unscaledCanvasContext = unscaledCanvas.getContext("2d");
unscaledCanvasContext.drawImage(backgroundCanvas_1, 0, 0, size, size);
unscaledCanvasContext.drawImage(backgroundCanvas_1.getContext('2d').canvas, 0, 0, size, size);
unscaledCanvasContext.rect(0, 0, size, size);
unscaledCanvasContext.fillStyle = backgroundDimming;
unscaledCanvasContext.fill();
unscaledCanvasContext.drawImage(mainCanvas, 0, 0, size, size);
unscaledCanvasContext.drawImage(mainCanvas.getContext('2d').canvas, 0, 0, size, size);
// Scale the final image
var outCanvas = canvas_1.createCanvas(rawSize, rawSize);
var outCanvas = new skia_canvas_1.Canvas(rawSize, rawSize);
var outCanvasContext = outCanvas.getContext("2d");
outCanvasContext.drawImage(unscaledCanvas, 0, 0, rawSize, rawSize);
outCanvasContext.drawImage(unscaledCanvas.getContext('2d').canvas, 0, 0, rawSize, rawSize);
gifOutput_1.addFrame(outCanvasContext.getImageData(0, 0, outCanvas.width, outCanvas.height).data);
});
if (!gifOutput_1) {
Expand All @@ -490,16 +490,17 @@ var AwesomeQR = /** @class */ (function () {
}
else {
// Swap and merge the foreground and the background
backgroundCanvasContext.drawImage(mainCanvas, 0, 0, size, size);
mainCanvasContext.drawImage(backgroundCanvas, -margin, -margin, size, size);
outCanvas = canvas_1.createCanvas(rawSize, rawSize);
backgroundCanvasContext.drawImage(mainCanvas.getContext('2d').canvas, 0, 0, size, size);
mainCanvasContext.drawImage(backgroundCanvas.getContext('2d').canvas, -margin, -margin, size, size);
outCanvas = new skia_canvas_1.Canvas(rawSize, rawSize);
outCanvasContext = outCanvas.getContext("2d");
outCanvasContext.drawImage(mainCanvas, 0, 0, rawSize, rawSize);
outCanvasContext.drawImage(mainCanvas.getContext('2d').canvas, 0, 0, rawSize, rawSize);
this.canvas = outCanvas;
format = this.options.gifBackground ? "gif" : "png";
if (isElement(this.canvas)) {
return [2 /*return*/, Promise.resolve(this.canvas.toDataURL())];
return [2 /*return*/, Promise.resolve(this.canvas.toDataURL(format))];
}
return [2 /*return*/, Promise.resolve(this.canvas.toBuffer())];
return [2 /*return*/, Promise.resolve(this.canvas.toBuffer(format))];
}
return [2 /*return*/];
}
Expand Down
2 changes: 1 addition & 1 deletion lib/qrcode.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export declare class QRUtil {
static getPatternPosition(typeNumber: number): number[];
static getMask(maskPattern: number, i: number, j: number): boolean;
static getErrorCorrectPolynomial(errorCorrectLength: number): QRPolynomial;
static getLengthInBits(mode: number, type: number): 14 | 11 | 12 | 8 | 10 | 9 | 16 | 13;
static getLengthInBits(mode: number, type: number): 14 | 11 | 12 | 10 | 8 | 9 | 16 | 13;
static getLostPoint(qrCode: QRCodeModel): number;
}
export declare class QRMath {
Expand Down
33 changes: 14 additions & 19 deletions lib/qrcode.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,32 +84,27 @@ var QR8bitByte = /** @class */ (function () {
for (var i = 0, l = this.data.length; i < l; i++) {
var byteArray = [];
var code = this.data.charCodeAt(i);
if (code > 0x10000) {
byteArray[0] = 0xf0 | ((code & 0x1c0000) >>> 18);
byteArray[1] = 0x80 | ((code & 0x3f000) >>> 12);
byteArray[2] = 0x80 | ((code & 0xfc0) >>> 6);
byteArray[3] = 0x80 | (code & 0x3f);
if (code < 0x80)
byteArray.push(code);
else if (code < 0x800) {
byteArray.push(0xc0 | (code >> 6), 0x80 | (code & 0x3f));
}
else if (code > 0x800) {
byteArray[0] = 0xe0 | ((code & 0xf000) >>> 12);
byteArray[1] = 0x80 | ((code & 0xfc0) >>> 6);
byteArray[2] = 0x80 | (code & 0x3f);
}
else if (code > 0x80) {
byteArray[0] = 0xc0 | ((code & 0x7c0) >>> 6);
byteArray[1] = 0x80 | (code & 0x3f);
else if (code < 0xd800 || code >= 0xe000) {
byteArray.push(0xe0 | (code >> 12), 0x80 | ((code >> 6) & 0x3f), 0x80 | (code & 0x3f));
}
// surrogate pair
else {
byteArray[0] = code;
i++;
// UTF-16 encodes 0x10000-0x10FFFF by
// subtracting 0x10000 and splitting the
// 20 bits of 0x0-0xFFFFF into two halves
var codePoint = 0x10000 + (((code & 0x3ff) << 10)
| (this.data.charCodeAt(i) & 0x3ff));
byteArray.push(0xf0 | (codePoint >> 18), 0x80 | ((codePoint >> 12) & 0x3f), 0x80 | ((codePoint >> 6) & 0x3f), 0x80 | (codePoint & 0x3f));
}
byteArrays.push(byteArray);
}
this.parsedData = Array.prototype.concat.apply([], byteArrays);
if (this.parsedData.length != this.data.length) {
this.parsedData.unshift(191);
this.parsedData.unshift(187);
this.parsedData.unshift(239);
}
}
QR8bitByte.prototype.getLength = function () {
return this.parsedData.length;
Expand Down
42 changes: 22 additions & 20 deletions src/qrcode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,32 +95,34 @@ class QR8bitByte {
const byteArray: number[] = [];
const code = this.data.charCodeAt(i);

if (code > 0x10000) {
byteArray[0] = 0xf0 | ((code & 0x1c0000) >>> 18);
byteArray[1] = 0x80 | ((code & 0x3f000) >>> 12);
byteArray[2] = 0x80 | ((code & 0xfc0) >>> 6);
byteArray[3] = 0x80 | (code & 0x3f);
} else if (code > 0x800) {
byteArray[0] = 0xe0 | ((code & 0xf000) >>> 12);
byteArray[1] = 0x80 | ((code & 0xfc0) >>> 6);
byteArray[2] = 0x80 | (code & 0x3f);
} else if (code > 0x80) {
byteArray[0] = 0xc0 | ((code & 0x7c0) >>> 6);
byteArray[1] = 0x80 | (code & 0x3f);
} else {
byteArray[0] = code;
if (code < 0x80) byteArray.push(code);
else if (code < 0x800) {
byteArray.push(0xc0 | (code >> 6),
0x80 | (code & 0x3f));
}
else if (code < 0xd800 || code >= 0xe000) {
byteArray.push(0xe0 | (code >> 12),
0x80 | ((code >> 6) & 0x3f),
0x80 | (code & 0x3f));
}
// surrogate pair
else {
i++;
// UTF-16 encodes 0x10000-0x10FFFF by
// subtracting 0x10000 and splitting the
// 20 bits of 0x0-0xFFFFF into two halves
const codePoint = 0x10000 + (((code & 0x3ff) << 10)
| (this.data.charCodeAt(i) & 0x3ff));
byteArray.push(0xf0 | (codePoint >> 18),
0x80 | ((codePoint >> 12) & 0x3f),
0x80 | ((codePoint >> 6) & 0x3f),
0x80 | (codePoint & 0x3f));
}

byteArrays.push(byteArray);
}

this.parsedData = Array.prototype.concat.apply([], byteArrays);

if (this.parsedData.length != this.data.length) {
this.parsedData.unshift(191);
this.parsedData.unshift(187);
this.parsedData.unshift(239);
}
}

getLength() {
Expand Down
2 changes: 1 addition & 1 deletion test/qr.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe("Common tests", () => {
it("Should draw and decode QR code without errors", (done) => {
(async () => {
try {
const expected = "Awesome-qr.js";
const expected = "Awesome-qr.js🧡";
const qr = new AwesomeQR({ text: expected, size: 400, margin: 10 });
const buf = (await qr.draw()) as Buffer;
const image = await Jimp.read(buf);
Expand Down