Skip to content

Commit eab18a4

Browse files
committed
Fix: logo related issues
1 parent 9d49d52 commit eab18a4

File tree

7 files changed

+74
-57
lines changed

7 files changed

+74
-57
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## Ver. 2.1.2
4+
5+
- Fixed an issue where the QR codes were not drawing correctly if a logo image was set.
6+
- Fixed the incorrectly typed option `logoImage` in _Options_.
7+
- Optimized the style of logo in the QR code.
8+
39
## Ver. 2.1.1
410

511
- Fixed an issue on protectors drawing for alignment patterns.

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ An awesome but simple QR code generator written in JavaScript.
1111
<table>
1212
<tr>
1313
<td valign="top"><img src="art/gallery-1.png" width="350"></td>
14-
<td valign="top"><img src="art/gallery-2.png" width="350"></td>
15-
<td valign="top"><img src="art/gallery-3.gif" width="350"></td>
16-
</tr>
14+
<td valign="top"><img src="art/gallery-2.png" width="350"></td>
15+
<td valign="top"><img src="art/gallery-3.gif" width="350"></td>
16+
</tr>
1717
</table>
1818

1919
## Contents <!-- omit in toc -->
@@ -125,7 +125,6 @@ type Options = {
125125
correctLevel?: number;
126126
maskPattern?: number;
127127
version?: number;
128-
dotScale?: number;
129128
components?: ComponentOptions;
130129
colorDark?: string;
131130
colorLight?: string;
@@ -138,6 +137,7 @@ type Options = {
138137
logoScale?: number;
139138
logoMargin?: number;
140139
logoCornerRadius?: number;
140+
dotScale?: number;
141141
};
142142
```
143143

dist/awesome-qr.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/awesome-qr.d.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -167,16 +167,6 @@ export declare type Options = {
167167
* @defaultValue true
168168
*/
169169
whiteMargin?: boolean;
170-
/**
171-
* @deprecated
172-
*
173-
* Ratio of the real size to the full size of the blocks.
174-
*
175-
* This can be helpful when you want to make more parts of the background visible.
176-
*
177-
* @deafultValue 0.4
178-
*/
179-
dotScale?: number;
180170
/**
181171
* Logo image to be displayed at the center of the QR code.
182172
*
@@ -186,7 +176,7 @@ export declare type Options = {
186176
*
187177
* @defaultValue undefined
188178
*/
189-
logoImage?: string;
179+
logoImage?: string | Buffer;
190180
/**
191181
* Ratio of the logo size to the QR code size.
192182
*
@@ -205,6 +195,16 @@ export declare type Options = {
205195
* @defaultValue 8
206196
*/
207197
logoCornerRadius?: number;
198+
/**
199+
* @deprecated
200+
*
201+
* Ratio of the real size to the full size of the blocks.
202+
*
203+
* This can be helpful when you want to make more parts of the background visible.
204+
*
205+
* @deafultValue 0.4
206+
*/
207+
dotScale?: number;
208208
};
209209
export declare class AwesomeQR {
210210
private canvas;

lib/awesome-qr.js

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,10 @@ var AwesomeQR = /** @class */ (function () {
8585
}
8686
});
8787
}
88-
if (_options.dotScale) {
88+
if (_options.dotScale !== null && _options.dotScale !== undefined) {
89+
if (_options.dotScale <= 0 || _options.dotScale > 1) {
90+
throw new Error("dotScale should be in range (0, 1].");
91+
}
8992
_options.components.data.scale = _options.dotScale;
9093
_options.components.timing.scale = _options.dotScale;
9194
_options.components.alignment.scale = _options.dotScale;
@@ -170,8 +173,6 @@ var AwesomeQR = /** @class */ (function () {
170173
AwesomeQR._drawAlignProtector = function (canvasContext, centerX, centerY, nSize) {
171174
canvasContext.clearRect((centerX - 2) * nSize, (centerY - 2) * nSize, 5 * nSize, 5 * nSize);
172175
canvasContext.fillRect((centerX - 2) * nSize, (centerY - 2) * nSize, 5 * nSize, 5 * nSize);
173-
// canvasContext.clearRect((centerX - 2) * nWidth, (centerY - 2) * nHeight, 5 * nWidth, 5 * nHeight);
174-
// canvasContext.fillRect((centerX - 2) * nWidth, (centerY - 2) * nHeight, 5 * nWidth, 5 * nHeight);
175176
};
176177
AwesomeQR._drawAlign = function (canvasContext, centerX, centerY, nSize, xyOffset, dotScale, colorDark, hasProtector) {
177178
if (xyOffset === void 0) { xyOffset = 0; }
@@ -199,7 +200,7 @@ var AwesomeQR = /** @class */ (function () {
199200
AwesomeQR.prototype._draw = function () {
200201
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
201202
return __awaiter(this, void 0, void 0, function () {
202-
var nCount, rawSize, rawMargin, margin, rawViewportSize, whiteMargin, backgroundDimming, nSize, viewportSize, size, mainCanvas, mainCanvasContext, dotScale, 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, gifOutput_1, backgroundCanvas_1, backgroundCanvasContext_1, patchCanvas_1, patchCanvasContext_1, patchData_1, u8array, binary, outCanvas, outCanvasContext;
203+
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;
203204
return __generator(this, function (_v) {
204205
switch (_v.label) {
205206
case 0:
@@ -218,12 +219,8 @@ var AwesomeQR = /** @class */ (function () {
218219
size = viewportSize + 2 * margin;
219220
mainCanvas = canvas_1.createCanvas(size, size);
220221
mainCanvasContext = mainCanvas.getContext("2d");
221-
dotScale = this.options.dotScale;
222222
this._clear();
223-
if (dotScale <= 0 || dotScale > 1) {
224-
throw new Error("Scale should be in range (0, 1].");
225-
}
226-
// Leave room for margin
223+
// Translate to make the top and left margins off the viewport
227224
mainCanvasContext.save();
228225
mainCanvasContext.translate(margin, margin);
229226
backgroundCanvas = canvas_1.createCanvas(size, size);
@@ -389,7 +386,6 @@ var AwesomeQR = /** @class */ (function () {
389386
continue;
390387
}
391388
else {
392-
// mainCanvasContext.fillStyle = "rgba(0, 0, 0, .2)";
393389
AwesomeQR._drawAlign(mainCanvasContext, agnX, agnY, nSize, alignmentXyOffset, alignmentScale, this.options.colorDark, ((_u = (_t = this.options.components) === null || _t === void 0 ? void 0 : _t.alignment) === null || _u === void 0 ? void 0 : _u.protectors) || false);
394390
}
395391
}
@@ -418,21 +414,31 @@ var AwesomeQR = /** @class */ (function () {
418414
if (logoCornerRadius < 0) {
419415
logoCornerRadius = 0;
420416
}
421-
mainCanvasContext.restore();
422417
logoSize = viewportSize * logoScale;
423418
x = 0.5 * (size - logoSize);
424419
y = x;
420+
// Restore the canvas
421+
// After restoring, the top and left margins should be taken into account
422+
mainCanvasContext.restore();
423+
// Clean the area that the logo covers (including margins)
425424
mainCanvasContext.fillStyle = "#FFFFFF";
426425
mainCanvasContext.save();
427-
AwesomeQR._prepareRoundedCornerClip(mainCanvasContext, x - logoMargin, y - logoMargin, logoSize + 2 * logoMargin, logoSize + 2 * logoMargin, logoCornerRadius);
426+
AwesomeQR._prepareRoundedCornerClip(mainCanvasContext, x - logoMargin, y - logoMargin, logoSize + 2 * logoMargin, logoSize + 2 * logoMargin, logoCornerRadius + logoMargin);
428427
mainCanvasContext.clip();
428+
oldGlobalCompositeOperation = mainCanvasContext.globalCompositeOperation;
429+
mainCanvasContext.globalCompositeOperation = "destination-out";
429430
mainCanvasContext.fill();
431+
mainCanvasContext.globalCompositeOperation = oldGlobalCompositeOperation;
430432
mainCanvasContext.restore();
433+
// Draw logo image
431434
mainCanvasContext.save();
432435
AwesomeQR._prepareRoundedCornerClip(mainCanvasContext, x, y, logoSize, logoSize, logoCornerRadius);
433436
mainCanvasContext.clip();
434437
mainCanvasContext.drawImage(logoImage, x, y, logoSize, logoSize);
435438
mainCanvasContext.restore();
439+
// Re-translate the canvas to translate the top and left margins into invisible area
440+
mainCanvasContext.save();
441+
mainCanvasContext.translate(margin, margin);
436442
_v.label = 6;
437443
case 6:
438444
if (!!parsedGIFBackground) {
@@ -529,7 +535,7 @@ var AwesomeQR = /** @class */ (function () {
529535
backgroundDimming: "rgba(0,0,0,0)",
530536
logoImage: undefined,
531537
logoScale: 0.2,
532-
logoMargin: 6,
538+
logoMargin: 4,
533539
logoCornerRadius: 8,
534540
whiteMargin: true,
535541
components: AwesomeQR.defaultComponentOptions,

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "awesome-qr",
3-
"version": "2.1.1-rc.0",
3+
"version": "2.1.2-rc.0",
44
"description": "An awesome but simple QR code generator written in JavaScript.",
55
"main": "./lib/index.js",
66
"types": "./lib/index.d.ts",

src/awesome-qr.ts

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -194,17 +194,6 @@ export type Options = {
194194
*/
195195
whiteMargin?: boolean;
196196

197-
/**
198-
* @deprecated
199-
*
200-
* Ratio of the real size to the full size of the blocks.
201-
*
202-
* This can be helpful when you want to make more parts of the background visible.
203-
*
204-
* @deafultValue 0.4
205-
*/
206-
dotScale?: number;
207-
208197
/**
209198
* Logo image to be displayed at the center of the QR code.
210199
*
@@ -214,7 +203,7 @@ export type Options = {
214203
*
215204
* @defaultValue undefined
216205
*/
217-
logoImage?: string;
206+
logoImage?: string | Buffer;
218207

219208
/**
220209
* Ratio of the logo size to the QR code size.
@@ -236,6 +225,17 @@ export type Options = {
236225
* @defaultValue 8
237226
*/
238227
logoCornerRadius?: number;
228+
229+
/**
230+
* @deprecated
231+
*
232+
* Ratio of the real size to the full size of the blocks.
233+
*
234+
* This can be helpful when you want to make more parts of the background visible.
235+
*
236+
* @deafultValue 0.4
237+
*/
238+
dotScale?: number;
239239
};
240240

241241
export class AwesomeQR {
@@ -275,7 +275,7 @@ export class AwesomeQR {
275275
backgroundDimming: "rgba(0,0,0,0)",
276276
logoImage: undefined,
277277
logoScale: 0.2,
278-
logoMargin: 6,
278+
logoMargin: 4,
279279
logoCornerRadius: 8,
280280
whiteMargin: true,
281281
components: AwesomeQR.defaultComponentOptions,
@@ -311,7 +311,10 @@ export class AwesomeQR {
311311
});
312312
}
313313

314-
if (_options.dotScale) {
314+
if (_options.dotScale !== null && _options.dotScale !== undefined) {
315+
if (_options.dotScale! <= 0 || _options.dotScale! > 1) {
316+
throw new Error("dotScale should be in range (0, 1].");
317+
}
315318
_options.components.data!.scale = _options.dotScale;
316319
_options.components.timing!.scale = _options.dotScale;
317320
_options.components.alignment!.scale = _options.dotScale;
@@ -430,9 +433,6 @@ export class AwesomeQR {
430433
) {
431434
canvasContext.clearRect((centerX - 2) * nSize, (centerY - 2) * nSize, 5 * nSize, 5 * nSize);
432435
canvasContext.fillRect((centerX - 2) * nSize, (centerY - 2) * nSize, 5 * nSize, 5 * nSize);
433-
434-
// canvasContext.clearRect((centerX - 2) * nWidth, (centerY - 2) * nHeight, 5 * nWidth, 5 * nHeight);
435-
// canvasContext.fillRect((centerX - 2) * nWidth, (centerY - 2) * nHeight, 5 * nWidth, 5 * nHeight);
436436
}
437437

438438
private static _drawAlign(
@@ -487,14 +487,9 @@ export class AwesomeQR {
487487
const mainCanvas = createCanvas(size, size);
488488
const mainCanvasContext = mainCanvas.getContext("2d");
489489

490-
const dotScale = this.options.dotScale!;
491490
this._clear();
492491

493-
if (dotScale <= 0 || dotScale > 1) {
494-
throw new Error("Scale should be in range (0, 1].");
495-
}
496-
497-
// Leave room for margin
492+
// Translate to make the top and left margins off the viewport
498493
mainCanvasContext.save();
499494
mainCanvasContext.translate(margin, margin);
500495

@@ -701,7 +696,6 @@ export class AwesomeQR {
701696
} else if (agnX === cornerAlignmentCenter && agnY === cornerAlignmentCenter) {
702697
continue;
703698
} else {
704-
// mainCanvasContext.fillStyle = "rgba(0, 0, 0, .2)";
705699
AwesomeQR._drawAlign(
706700
mainCanvasContext,
707701
agnX,
@@ -741,12 +735,15 @@ export class AwesomeQR {
741735
logoCornerRadius = 0;
742736
}
743737

744-
mainCanvasContext.restore();
745-
746738
const logoSize = viewportSize * logoScale;
747739
const x = 0.5 * (size - logoSize);
748740
const y = x;
749741

742+
// Restore the canvas
743+
// After restoring, the top and left margins should be taken into account
744+
mainCanvasContext.restore();
745+
746+
// Clean the area that the logo covers (including margins)
750747
mainCanvasContext.fillStyle = "#FFFFFF";
751748
mainCanvasContext.save();
752749
AwesomeQR._prepareRoundedCornerClip(
@@ -755,17 +752,25 @@ export class AwesomeQR {
755752
y - logoMargin,
756753
logoSize + 2 * logoMargin,
757754
logoSize + 2 * logoMargin,
758-
logoCornerRadius
755+
logoCornerRadius + logoMargin
759756
);
760757
mainCanvasContext.clip();
758+
const oldGlobalCompositeOperation = mainCanvasContext.globalCompositeOperation;
759+
mainCanvasContext.globalCompositeOperation = "destination-out";
761760
mainCanvasContext.fill();
761+
mainCanvasContext.globalCompositeOperation = oldGlobalCompositeOperation;
762762
mainCanvasContext.restore();
763763

764+
// Draw logo image
764765
mainCanvasContext.save();
765766
AwesomeQR._prepareRoundedCornerClip(mainCanvasContext, x, y, logoSize, logoSize, logoCornerRadius);
766767
mainCanvasContext.clip();
767768
mainCanvasContext.drawImage(logoImage, x, y, logoSize, logoSize);
768769
mainCanvasContext.restore();
770+
771+
// Re-translate the canvas to translate the top and left margins into invisible area
772+
mainCanvasContext.save();
773+
mainCanvasContext.translate(margin, margin);
769774
}
770775

771776
if (!!parsedGIFBackground) {

0 commit comments

Comments
 (0)