Skip to content

Commit

Permalink
perf(kjua): use library locally & with ts (#95)
Browse files Browse the repository at this point in the history
Co-authored-by: Raphaël Balet <raphael@megaphone.info>
  • Loading branch information
rbalet and Raphaël Balet authored May 28, 2024
1 parent bf402d9 commit c6ad86c
Show file tree
Hide file tree
Showing 12 changed files with 968 additions and 14 deletions.
20 changes: 9 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
"@angular/language-service": "^18.0.0",
"@angular/platform-browser": "^18.0.0",
"@angular/platform-browser-dynamic": "^18.0.0",
"kjua-svg": "^1.13.1",
"tslib": "^2.6.2",
"zone.js": "~0.14.6"
},
Expand All @@ -55,6 +54,7 @@
"jest": "^29.7.0",
"jest-preset-angular": "^14.1.0",
"ng-packagr": "^18.0.0",
"qrcode-generator": "^1.4.4",
"rxjs": "~7.8.1",
"ts-node": "~10.9.2",
"tslint": "~6.1.3",
Expand Down
91 changes: 91 additions & 0 deletions projects/ngx-kjua/src/lib/kjua/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
export interface KjuaOptions {
/**
* Render the image as either SVG, canvas or PNG-image
*/
render?: "image" | "svg" | "canvas";

/**
* render pixel-perfect lines
*/
crisp?: boolean;

/**
* minimum version: 1..40
*/
minVersion?: number;

/**
* error correction level: 'L', 'M', 'Q' or 'H'
*/
ecLevel?: "L" | "M" | "Q" | "H";

/**
* size in pixel
*/
size?: number;

/**
* pixel-ratio, null for devicePixelRatio
*/
ratio?: number | null;

/**
* code color
*/
fill?: string;

/**
* background color
*/
back?: string;

/**
* content
*/
text?: string;

/**
* roundend corners in pc: 0..100
*/
rounded?: number;

/**
* quiet zone in modules
*/
quiet?: number;

/**
* modes: 'plain', 'label', 'image', 'imagelabel' or 'labelimage'
*/
mode?: "plain" | "label" | "image" | "imagelabel" | "labelimage";

/**
* label/image size and pos in pc: 0..100
*/
mSize?: number | number[];
mPosX?: number | number[];
mPosY?: number | number[];

/**
* label
*/
label?: string;
fontname?: string;
fontcolor?: string;
fontoutline?: boolean;

/**
* image element
*/
image?: null | HTMLImageElement | string;

/**
* draw the image as part of the code
*/
imageAsCode?: boolean;

/**
* an optional HTML-ID-attribute for the element (works only with render-mode SVG and image)
*/
elementId?: string;
}
25 changes: 25 additions & 0 deletions projects/ngx-kjua/src/lib/kjua/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { create_canvas_qrcode } from "./lib/create_canvas_qrcode";
import { create_svg_qrcode } from "./lib/create_svg_qrcode";
import { defaults } from "./lib/defaults";
import { quiet_qrcode } from "./lib/qrcode";

export const kjua = (options: any): any => {
const settings = Object.assign({}, defaults, options);
const qr = quiet_qrcode(
settings.text,
settings.ecLevel,
settings.minVersion,
settings.quiet
);

if (typeof settings.image === "string") {
const image = new Image();
image.src = "data:image/png;base64," + settings.image;
image.crossOrigin = "anonymous";
settings.image = image;
}
if (settings.render === "svg") {
return create_svg_qrcode(qr, settings);
}
return create_canvas_qrcode(qr, settings, settings.render === "image");
};
85 changes: 85 additions & 0 deletions projects/ngx-kjua/src/lib/kjua/lib/create_canvas_qrcode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import * as dom from "./dom";
import { draw_mode } from "./draw_mode";
import { draw_module_rounded } from "./draw_rounded";

const draw_background = (ctx: any, settings: any) => {
if (settings.back) {
ctx.fillStyle = settings.back;
ctx.fillRect(0, 0, settings.size, settings.size);
}
};

const draw_module_default = (
qr: any,
ctx: any,
settings: any,
width: any,
row: any,
col: any
) => {
if (qr.is_dark(row, col)) {
ctx.rect(col * width, row * width, width, width);
}
};

export const draw_modules = (qr: any, ctx: any, settings: any) => {
if (!qr) {
return;
}

const draw_module =
settings.rounded > 0 && settings.rounded <= 100
? draw_module_rounded
: draw_module_default;
const mod_count = qr.module_count;

let mod_size = settings.size / mod_count;
let offset = 0;
if (settings.crisp) {
mod_size = Math.floor(mod_size);
offset = Math.floor((settings.size - mod_size * mod_count) / 2);
}

ctx.translate(offset, offset);
ctx.beginPath();
for (let row = 0; row < mod_count; row += 1) {
for (let col = 0; col < mod_count; col += 1) {
draw_module(qr, ctx, settings, mod_size, row, col);
}
}
ctx.fillStyle = settings.fill;
ctx.fill();
ctx.translate(-offset, -offset);
};

const draw = (qr: any, ctx: any, settings: any) => {
draw_background(ctx, settings);
draw_modules(qr, ctx, settings);
draw_mode(ctx, settings);
};

export const create_canvas_qrcode = (qr: any, settings: any, as_image: any) => {
const ratio = settings.ratio || dom.dpr;
const canvas = dom.create_canvas(settings.size, ratio);
const context = canvas.getContext("2d");

if (settings.imageAsCode) {
const canvas = dom.create_canvas(settings.size, ratio);
const ctx2 = canvas.getContext("2d");
draw_modules(qr, ctx2, settings);
const imagePos = dom.calc_image_pos(settings);
ctx2.globalCompositeOperation = "source-in";
ctx2.drawImage(
settings.image,
imagePos.x,
imagePos.y,
imagePos.iw,
imagePos.ih
);
settings = Object.assign({}, settings, { image: ctx2.canvas });
}

context.scale(ratio, ratio);
draw(qr, context, settings);
return as_image ? dom.canvas_to_img(canvas, settings.elementId) : canvas;
};
Loading

0 comments on commit c6ad86c

Please sign in to comment.