Comparing version 9.5.2 to 9.6.0
import { BitMatrix, Data, EcLevel, Matrix } from "./typing/types"; | ||
export declare function init(version: number): Matrix; | ||
export declare function fillFinders(matrix: Matrix): void; | ||
export declare function zeroFillFinders(matrix: BitMatrix): void; | ||
export declare function fillAlignAndTiming(matrix: Matrix): void; | ||
@@ -11,2 +10,1 @@ export declare function fillStub(matrix: Matrix): void; | ||
export declare function getMatrix(data: Data): BitMatrix; | ||
export declare function clearMatrixCenter(matrix: BitMatrix, widthPct: number, heightPct: number): BitMatrix; |
@@ -231,22 +231,2 @@ (function (global, factory) { | ||
} | ||
function zeroFillFinders(matrix) { | ||
const N = matrix.length; | ||
const zeroPixel = 0; | ||
for (let i = -3; i <= 3; i++) { | ||
for (let j = -3; j <= 3; j++) { | ||
matrix[3 + i][3 + j] = zeroPixel; | ||
matrix[3 + i][N - 4 + j] = zeroPixel; | ||
matrix[N - 4 + i][3 + j] = zeroPixel; | ||
} | ||
} | ||
for (let i = 0; i < 8; i++) { | ||
matrix[7][i] = | ||
matrix[i][7] = | ||
matrix[7][N - i - 1] = | ||
matrix[i][N - 8] = | ||
matrix[N - 8][i] = | ||
matrix[N - 1 - i][7] = | ||
zeroPixel; | ||
} | ||
} | ||
function fillAlignAndTiming(matrix) { | ||
@@ -565,17 +545,2 @@ const N = matrix.length; | ||
} | ||
function clearMatrixCenter(matrix, widthPct, heightPct) { | ||
matrix = matrix.map((x) => x.slice()); | ||
const mW = matrix.length; | ||
const cW = Math.ceil(((mW * widthPct) / 100 + (mW % 2)) / 2) * 2 - (mW % 2); | ||
const mH = matrix[0]?.length ?? 0; | ||
const cH = Math.ceil(((mH * heightPct) / 100 + (mH % 2)) / 2) * 2 - (mH % 2); | ||
const clearStartX = Math.round((mW - cW) / 2); | ||
const clearStartY = Math.round((mH - cH) / 2); | ||
for (let x = clearStartX; x < clearStartX + cW; x += 1) { | ||
for (let y = clearStartY; y < clearStartY + cH; y += 1) { | ||
matrix[x][y] = 0; | ||
} | ||
} | ||
return matrix; | ||
} | ||
@@ -1570,7 +1535,45 @@ const EC_LEVELS = ["L", "M", "Q", "H"]; | ||
function zeroFillFinders(matrix) { | ||
matrix = structuredClone(matrix); | ||
const N = matrix.length; | ||
const zeroPixel = 0; | ||
for (let i = -3; i <= 3; i++) { | ||
for (let j = -3; j <= 3; j++) { | ||
matrix[3 + i][3 + j] = zeroPixel; | ||
matrix[3 + i][N - 4 + j] = zeroPixel; | ||
matrix[N - 4 + i][3 + j] = zeroPixel; | ||
} | ||
} | ||
for (let i = 0; i < 8; i++) { | ||
matrix[7][i] = | ||
matrix[i][7] = | ||
matrix[7][N - i - 1] = | ||
matrix[i][N - 8] = | ||
matrix[N - 8][i] = | ||
matrix[N - 1 - i][7] = | ||
zeroPixel; | ||
} | ||
return matrix; | ||
} | ||
function clearMatrixCenter(matrix, widthPct, heightPct) { | ||
matrix = structuredClone(matrix); | ||
const mW = matrix.length; | ||
const cW = Math.ceil(((mW * widthPct) / 100 + (mW % 2)) / 2) * 2 - (mW % 2); | ||
const mH = matrix[0]?.length ?? 0; | ||
const cH = Math.ceil(((mH * heightPct) / 100 + (mH % 2)) / 2) * 2 - (mH % 2); | ||
const clearStartX = Math.round((mW - cW) / 2); | ||
const clearStartY = Math.round((mH - cH) / 2); | ||
for (let x = clearStartX; x < clearStartX + cW; x += 1) { | ||
for (let y = clearStartY; y < clearStartY + cH; y += 1) { | ||
matrix[x][y] = 0; | ||
} | ||
} | ||
return matrix; | ||
} | ||
async function getPNG(text, inOptions) { | ||
const options = getOptions(inOptions); | ||
let matrix = QR(text, options.ec_level, options.parse_url); | ||
zeroFillFinders(matrix); | ||
if (options.logo && options.logoWidth && options.logoHeight) { | ||
matrix = zeroFillFinders(matrix); | ||
if (options.logo && options.logoWidth && options.logoHeight && !options.noExcavate) { | ||
matrix = clearMatrixCenter(matrix, options.logoWidth, options.logoHeight); | ||
@@ -1577,0 +1580,0 @@ } |
import { ImageOptions, Matrix } from "./typing/types"; | ||
export declare function getSVG(text: string, inOptions?: ImageOptions): Promise<Uint8Array>; | ||
export declare function getSVG(text: string, inOptions?: ImageOptions): Uint8Array; | ||
export declare function createSVG({ matrix, margin, size, logo, logoWidth, logoHeight, color, bgColor, imageWidth, imageHeight, borderRadius, }: ImageOptions & { | ||
@@ -7,2 +7,2 @@ matrix: Matrix; | ||
imageHeight?: number; | ||
}): Promise<Uint8Array>; | ||
}): Uint8Array; |
@@ -7,2 +7,236 @@ (function (global, factory) { | ||
function zeroFillFinders(matrix) { | ||
matrix = structuredClone(matrix); | ||
const N = matrix.length; | ||
const zeroPixel = 0; | ||
for (let i = -3; i <= 3; i++) { | ||
for (let j = -3; j <= 3; j++) { | ||
matrix[3 + i][3 + j] = zeroPixel; | ||
matrix[3 + i][N - 4 + j] = zeroPixel; | ||
matrix[N - 4 + i][3 + j] = zeroPixel; | ||
} | ||
} | ||
for (let i = 0; i < 8; i++) { | ||
matrix[7][i] = | ||
matrix[i][7] = | ||
matrix[7][N - i - 1] = | ||
matrix[i][N - 8] = | ||
matrix[N - 8][i] = | ||
matrix[N - 1 - i][7] = | ||
zeroPixel; | ||
} | ||
return matrix; | ||
} | ||
function clearMatrixCenter(matrix, widthPct, heightPct) { | ||
matrix = structuredClone(matrix); | ||
const mW = matrix.length; | ||
const cW = Math.ceil(((mW * widthPct) / 100 + (mW % 2)) / 2) * 2 - (mW % 2); | ||
const mH = matrix[0]?.length ?? 0; | ||
const cH = Math.ceil(((mH * heightPct) / 100 + (mH % 2)) / 2) * 2 - (mH % 2); | ||
const clearStartX = Math.round((mW - cW) / 2); | ||
const clearStartY = Math.round((mH - cH) / 2); | ||
for (let x = clearStartX; x < clearStartX + cW; x += 1) { | ||
for (let y = clearStartY; y < clearStartY + cH; y += 1) { | ||
matrix[x][y] = 0; | ||
} | ||
} | ||
return matrix; | ||
} | ||
const enc = new TextEncoder(); | ||
const dec = new TextDecoder(); | ||
function encode$1(inData, parse_url) { | ||
let str; | ||
let data; | ||
if (typeof inData === "string" || typeof inData === "number") { | ||
str = `${inData}`; | ||
data = enc.encode(str); | ||
} | ||
else if (Array.isArray(inData)) { | ||
data = new Uint8Array(inData); | ||
str = dec.decode(inData); | ||
} | ||
else { | ||
throw new Error("Bad data: " + typeof inData); | ||
} | ||
if (/^[0-9]+$/.test(str)) { | ||
if (data.byteLength > 7089) { | ||
throw new Error("Too much data"); | ||
} | ||
return encode_numeric(str); | ||
} | ||
if (/^[0-9A-Z \$%\*\+\.\/\:\-]+$/.test(str)) { | ||
if (data.byteLength > 4296) { | ||
throw new Error("Too much data"); | ||
} | ||
return encode_alphanum(str); | ||
} | ||
if (parse_url && /^https?:/i.test(str)) { | ||
return encode_url(str); | ||
} | ||
if (data.byteLength > 2953) { | ||
throw new Error("Too much data"); | ||
} | ||
return encode_8bit(new Uint8Array(data)); | ||
} | ||
function pushBits(arr, n, value) { | ||
for (let bit = 1 << (n - 1); bit; bit >>>= 1) { | ||
arr.push(bit & value ? 1 : 0); | ||
} | ||
} | ||
function encode_8bit(data) { | ||
const len = data.byteLength; | ||
const bits = []; | ||
for (let i = 0; i < len; i++) { | ||
pushBits(bits, 8, data[i]); | ||
} | ||
const res = {}; | ||
let d = [0, 1, 0, 0]; | ||
pushBits(d, 16, len); | ||
res.data10 = res.data27 = d.concat(bits); | ||
if (len < 256) { | ||
let d = [0, 1, 0, 0]; | ||
pushBits(d, 8, len); | ||
res.data1 = d.concat(bits); | ||
} | ||
return res; | ||
} | ||
const ALPHANUM = (function (s) { | ||
const res = {}; | ||
for (let i = 0; i < s.length; i++) { | ||
res[s[i]] = i; | ||
} | ||
return res; | ||
})("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"); | ||
function encode_alphanum(str) { | ||
const len = str.length; | ||
const bits = []; | ||
for (let i = 0; i < len; i += 2) { | ||
let b = 6; | ||
let n = ALPHANUM[str[i]]; | ||
if (str[i + 1]) { | ||
b = 11; | ||
n = n * 45 + ALPHANUM[str[i + 1]]; | ||
} | ||
pushBits(bits, b, n); | ||
} | ||
const res = {}; | ||
let d = [0, 0, 1, 0]; | ||
pushBits(d, 13, len); | ||
res.data27 = d.concat(bits); | ||
if (len < 2048) { | ||
let d = [0, 0, 1, 0]; | ||
pushBits(d, 11, len); | ||
res.data10 = d.concat(bits); | ||
} | ||
if (len < 512) { | ||
let d = [0, 0, 1, 0]; | ||
pushBits(d, 9, len); | ||
res.data1 = d.concat(bits); | ||
} | ||
return res; | ||
} | ||
function encode_numeric(str) { | ||
const len = str.length; | ||
const bits = []; | ||
for (let i = 0; i < len; i += 3) { | ||
const s = str.substr(i, 3); | ||
const b = Math.ceil((s.length * 10) / 3); | ||
pushBits(bits, b, parseInt(s, 10)); | ||
} | ||
const res = {}; | ||
let d = [0, 0, 0, 1]; | ||
pushBits(d, 14, len); | ||
res.data27 = d.concat(bits); | ||
if (len < 4096) { | ||
let d = [0, 0, 0, 1]; | ||
pushBits(d, 12, len); | ||
res.data10 = d.concat(bits); | ||
} | ||
if (len < 1024) { | ||
let d = [0, 0, 0, 1]; | ||
pushBits(d, 10, len); | ||
res.data1 = d.concat(bits); | ||
} | ||
return res; | ||
} | ||
function encode_url(str) { | ||
const slash = str.indexOf("/", 8) + 1 || str.length; | ||
const res = encode$1(str.slice(0, slash).toUpperCase(), false); | ||
if (slash >= str.length) { | ||
return res; | ||
} | ||
const path_res = encode$1(str.slice(slash), false); | ||
res.data27 = res.data27.concat(path_res.data27); | ||
if (res.data10 && path_res.data10) { | ||
res.data10 = res.data10.concat(path_res.data10); | ||
} | ||
if (res.data1 && path_res.data1) { | ||
res.data1 = res.data1.concat(path_res.data1); | ||
} | ||
return res; | ||
} | ||
function calculateEC(msg, ec_len) { | ||
msg = [].slice.call(msg); | ||
const poly = generatorPolynomial(ec_len); | ||
for (let i = 0; i < ec_len; i++) | ||
msg.push(0); | ||
while (msg.length > ec_len) { | ||
if (!msg[0]) { | ||
msg.shift(); | ||
continue; | ||
} | ||
const log_k = log(msg[0]); | ||
for (let i = 0; i <= ec_len; i++) { | ||
msg[i] = msg[i] ^ exp(poly[i] + log_k); | ||
} | ||
msg.shift(); | ||
} | ||
return new Uint8Array(msg); | ||
} | ||
const GF256_BASE = 285; | ||
const EXP_TABLE = [1]; | ||
const LOG_TABLE = []; | ||
for (let i = 1; i < 256; i++) { | ||
let n = EXP_TABLE[i - 1] << 1; | ||
if (n > 255) | ||
n ^= GF256_BASE; | ||
EXP_TABLE[i] = n; | ||
} | ||
for (let i = 0; i < 255; i++) { | ||
LOG_TABLE[EXP_TABLE[i]] = i; | ||
} | ||
function exp(k) { | ||
while (k < 0) | ||
k += 255; | ||
while (k > 255) | ||
k -= 255; | ||
return EXP_TABLE[k]; | ||
} | ||
function log(k) { | ||
if (k < 1 || k > 255) { | ||
throw Error(`Bad log(${k})`); | ||
} | ||
return LOG_TABLE[k]; | ||
} | ||
const POLYNOMIALS = [ | ||
[0], | ||
[0, 0], | ||
[0, 25, 1], | ||
]; | ||
function generatorPolynomial(num) { | ||
if (POLYNOMIALS[num]) { | ||
return POLYNOMIALS[num]; | ||
} | ||
const prev = generatorPolynomial(num - 1); | ||
const res = []; | ||
res[0] = prev[0]; | ||
for (let i = 1; i <= num; i++) { | ||
res[i] = log(exp(prev[i]) ^ exp(prev[i - 1] + num - 1)); | ||
} | ||
POLYNOMIALS[num] = res; | ||
return res; | ||
} | ||
function init(version) { | ||
@@ -36,22 +270,2 @@ const N = (version << 2) + 0b10001; | ||
} | ||
function zeroFillFinders(matrix) { | ||
const N = matrix.length; | ||
const zeroPixel = 0; | ||
for (let i = -3; i <= 3; i++) { | ||
for (let j = -3; j <= 3; j++) { | ||
matrix[3 + i][3 + j] = zeroPixel; | ||
matrix[3 + i][N - 4 + j] = zeroPixel; | ||
matrix[N - 4 + i][3 + j] = zeroPixel; | ||
} | ||
} | ||
for (let i = 0; i < 8; i++) { | ||
matrix[7][i] = | ||
matrix[i][7] = | ||
matrix[7][N - i - 1] = | ||
matrix[i][N - 8] = | ||
matrix[N - 8][i] = | ||
matrix[N - 1 - i][7] = | ||
zeroPixel; | ||
} | ||
} | ||
function fillAlignAndTiming(matrix) { | ||
@@ -370,214 +584,3 @@ const N = matrix.length; | ||
} | ||
function clearMatrixCenter(matrix, widthPct, heightPct) { | ||
matrix = matrix.map((x) => x.slice()); | ||
const mW = matrix.length; | ||
const cW = Math.ceil(((mW * widthPct) / 100 + (mW % 2)) / 2) * 2 - (mW % 2); | ||
const mH = matrix[0]?.length ?? 0; | ||
const cH = Math.ceil(((mH * heightPct) / 100 + (mH % 2)) / 2) * 2 - (mH % 2); | ||
const clearStartX = Math.round((mW - cW) / 2); | ||
const clearStartY = Math.round((mH - cH) / 2); | ||
for (let x = clearStartX; x < clearStartX + cW; x += 1) { | ||
for (let y = clearStartY; y < clearStartY + cH; y += 1) { | ||
matrix[x][y] = 0; | ||
} | ||
} | ||
return matrix; | ||
} | ||
const enc = new TextEncoder(); | ||
const dec = new TextDecoder(); | ||
function encode$1(inData, parse_url) { | ||
let str; | ||
let data; | ||
if (typeof inData === "string" || typeof inData === "number") { | ||
str = `${inData}`; | ||
data = enc.encode(str); | ||
} | ||
else if (Array.isArray(inData)) { | ||
data = new Uint8Array(inData); | ||
str = dec.decode(inData); | ||
} | ||
else { | ||
throw new Error("Bad data: " + typeof inData); | ||
} | ||
if (/^[0-9]+$/.test(str)) { | ||
if (data.byteLength > 7089) { | ||
throw new Error("Too much data"); | ||
} | ||
return encode_numeric(str); | ||
} | ||
if (/^[0-9A-Z \$%\*\+\.\/\:\-]+$/.test(str)) { | ||
if (data.byteLength > 4296) { | ||
throw new Error("Too much data"); | ||
} | ||
return encode_alphanum(str); | ||
} | ||
if (parse_url && /^https?:/i.test(str)) { | ||
return encode_url(str); | ||
} | ||
if (data.byteLength > 2953) { | ||
throw new Error("Too much data"); | ||
} | ||
return encode_8bit(new Uint8Array(data)); | ||
} | ||
function pushBits(arr, n, value) { | ||
for (let bit = 1 << (n - 1); bit; bit >>>= 1) { | ||
arr.push(bit & value ? 1 : 0); | ||
} | ||
} | ||
function encode_8bit(data) { | ||
const len = data.byteLength; | ||
const bits = []; | ||
for (let i = 0; i < len; i++) { | ||
pushBits(bits, 8, data[i]); | ||
} | ||
const res = {}; | ||
let d = [0, 1, 0, 0]; | ||
pushBits(d, 16, len); | ||
res.data10 = res.data27 = d.concat(bits); | ||
if (len < 256) { | ||
let d = [0, 1, 0, 0]; | ||
pushBits(d, 8, len); | ||
res.data1 = d.concat(bits); | ||
} | ||
return res; | ||
} | ||
const ALPHANUM = (function (s) { | ||
const res = {}; | ||
for (let i = 0; i < s.length; i++) { | ||
res[s[i]] = i; | ||
} | ||
return res; | ||
})("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"); | ||
function encode_alphanum(str) { | ||
const len = str.length; | ||
const bits = []; | ||
for (let i = 0; i < len; i += 2) { | ||
let b = 6; | ||
let n = ALPHANUM[str[i]]; | ||
if (str[i + 1]) { | ||
b = 11; | ||
n = n * 45 + ALPHANUM[str[i + 1]]; | ||
} | ||
pushBits(bits, b, n); | ||
} | ||
const res = {}; | ||
let d = [0, 0, 1, 0]; | ||
pushBits(d, 13, len); | ||
res.data27 = d.concat(bits); | ||
if (len < 2048) { | ||
let d = [0, 0, 1, 0]; | ||
pushBits(d, 11, len); | ||
res.data10 = d.concat(bits); | ||
} | ||
if (len < 512) { | ||
let d = [0, 0, 1, 0]; | ||
pushBits(d, 9, len); | ||
res.data1 = d.concat(bits); | ||
} | ||
return res; | ||
} | ||
function encode_numeric(str) { | ||
const len = str.length; | ||
const bits = []; | ||
for (let i = 0; i < len; i += 3) { | ||
const s = str.substr(i, 3); | ||
const b = Math.ceil((s.length * 10) / 3); | ||
pushBits(bits, b, parseInt(s, 10)); | ||
} | ||
const res = {}; | ||
let d = [0, 0, 0, 1]; | ||
pushBits(d, 14, len); | ||
res.data27 = d.concat(bits); | ||
if (len < 4096) { | ||
let d = [0, 0, 0, 1]; | ||
pushBits(d, 12, len); | ||
res.data10 = d.concat(bits); | ||
} | ||
if (len < 1024) { | ||
let d = [0, 0, 0, 1]; | ||
pushBits(d, 10, len); | ||
res.data1 = d.concat(bits); | ||
} | ||
return res; | ||
} | ||
function encode_url(str) { | ||
const slash = str.indexOf("/", 8) + 1 || str.length; | ||
const res = encode$1(str.slice(0, slash).toUpperCase(), false); | ||
if (slash >= str.length) { | ||
return res; | ||
} | ||
const path_res = encode$1(str.slice(slash), false); | ||
res.data27 = res.data27.concat(path_res.data27); | ||
if (res.data10 && path_res.data10) { | ||
res.data10 = res.data10.concat(path_res.data10); | ||
} | ||
if (res.data1 && path_res.data1) { | ||
res.data1 = res.data1.concat(path_res.data1); | ||
} | ||
return res; | ||
} | ||
function calculateEC(msg, ec_len) { | ||
msg = [].slice.call(msg); | ||
const poly = generatorPolynomial(ec_len); | ||
for (let i = 0; i < ec_len; i++) | ||
msg.push(0); | ||
while (msg.length > ec_len) { | ||
if (!msg[0]) { | ||
msg.shift(); | ||
continue; | ||
} | ||
const log_k = log(msg[0]); | ||
for (let i = 0; i <= ec_len; i++) { | ||
msg[i] = msg[i] ^ exp(poly[i] + log_k); | ||
} | ||
msg.shift(); | ||
} | ||
return new Uint8Array(msg); | ||
} | ||
const GF256_BASE = 285; | ||
const EXP_TABLE = [1]; | ||
const LOG_TABLE = []; | ||
for (let i = 1; i < 256; i++) { | ||
let n = EXP_TABLE[i - 1] << 1; | ||
if (n > 255) | ||
n ^= GF256_BASE; | ||
EXP_TABLE[i] = n; | ||
} | ||
for (let i = 0; i < 255; i++) { | ||
LOG_TABLE[EXP_TABLE[i]] = i; | ||
} | ||
function exp(k) { | ||
while (k < 0) | ||
k += 255; | ||
while (k > 255) | ||
k -= 255; | ||
return EXP_TABLE[k]; | ||
} | ||
function log(k) { | ||
if (k < 1 || k > 255) { | ||
throw Error(`Bad log(${k})`); | ||
} | ||
return LOG_TABLE[k]; | ||
} | ||
const POLYNOMIALS = [ | ||
[0], | ||
[0, 0], | ||
[0, 25, 1], | ||
]; | ||
function generatorPolynomial(num) { | ||
if (POLYNOMIALS[num]) { | ||
return POLYNOMIALS[num]; | ||
} | ||
const prev = generatorPolynomial(num - 1); | ||
const res = []; | ||
res[0] = prev[0]; | ||
for (let i = 1; i <= num; i++) { | ||
res[i] = log(exp(prev[i]) ^ exp(prev[i - 1] + num - 1)); | ||
} | ||
POLYNOMIALS[num] = res; | ||
return res; | ||
} | ||
const EC_LEVELS = ["L", "M", "Q", "H"]; | ||
@@ -1571,7 +1574,7 @@ function getTemplate(message, ec_level) { | ||
async function getSVG(text, inOptions = {}) { | ||
function getSVG(text, inOptions = {}) { | ||
const options = getOptions({ ...inOptions, type: "svg" }); | ||
let matrix = QR(text, options.ec_level, options.parse_url); | ||
zeroFillFinders(matrix); | ||
if (options.logo && options.logoWidth && options.logoHeight) { | ||
matrix = zeroFillFinders(matrix); | ||
if (options.logo && options.logoWidth && options.logoHeight && !options.noExcavate) { | ||
matrix = clearMatrixCenter(matrix, options.logoWidth, options.logoHeight); | ||
@@ -1582,3 +1585,3 @@ } | ||
const te = new TextEncoder(); | ||
async function createSVG({ matrix, margin, size, logo, logoWidth, logoHeight, color, bgColor, imageWidth, imageHeight, borderRadius, }) { | ||
function createSVG({ matrix, margin, size, logo, logoWidth, logoHeight, color, bgColor, imageWidth, imageHeight, borderRadius, }) { | ||
const actualBlockSize = size || 9; | ||
@@ -1585,0 +1588,0 @@ const matrixSizePx = matrix.length * actualBlockSize; |
@@ -26,2 +26,3 @@ export type MatrixValue = 0 | 1 | 128 | 129; | ||
logoHeight?: number; | ||
noExcavate?: boolean; | ||
color?: number | string; | ||
@@ -28,0 +29,0 @@ bgColor?: number | string; |
@@ -11,2 +11,3 @@ import { ImageOptions, ImageType, Matrix } from "./typing/types"; | ||
logoHeight?: number; | ||
noExcavate?: boolean; | ||
color?: string | number; | ||
@@ -13,0 +14,0 @@ bgColor?: string | number; |
import { BitMatrix, Data, EcLevel, Matrix } from "./typing/types"; | ||
export declare function init(version: number): Matrix; | ||
export declare function fillFinders(matrix: Matrix): void; | ||
export declare function zeroFillFinders(matrix: BitMatrix): void; | ||
export declare function fillAlignAndTiming(matrix: Matrix): void; | ||
@@ -11,2 +10,1 @@ export declare function fillStub(matrix: Matrix): void; | ||
export declare function getMatrix(data: Data): BitMatrix; | ||
export declare function clearMatrixCenter(matrix: BitMatrix, widthPct: number, heightPct: number): BitMatrix; |
@@ -29,22 +29,2 @@ export function init(version) { | ||
} | ||
export function zeroFillFinders(matrix) { | ||
const N = matrix.length; | ||
const zeroPixel = 0; | ||
for (let i = -3; i <= 3; i++) { | ||
for (let j = -3; j <= 3; j++) { | ||
matrix[3 + i][3 + j] = zeroPixel; | ||
matrix[3 + i][N - 4 + j] = zeroPixel; | ||
matrix[N - 4 + i][3 + j] = zeroPixel; | ||
} | ||
} | ||
for (let i = 0; i < 8; i++) { | ||
matrix[7][i] = | ||
matrix[i][7] = | ||
matrix[7][N - i - 1] = | ||
matrix[i][N - 8] = | ||
matrix[N - 8][i] = | ||
matrix[N - 1 - i][7] = | ||
zeroPixel; | ||
} | ||
} | ||
export function fillAlignAndTiming(matrix) { | ||
@@ -363,17 +343,2 @@ const N = matrix.length; | ||
} | ||
export function clearMatrixCenter(matrix, widthPct, heightPct) { | ||
matrix = matrix.map((x) => x.slice()); | ||
const mW = matrix.length; | ||
const cW = Math.ceil(((mW * widthPct) / 100 + (mW % 2)) / 2) * 2 - (mW % 2); | ||
const mH = matrix[0]?.length ?? 0; | ||
const cH = Math.ceil(((mH * heightPct) / 100 + (mH % 2)) / 2) * 2 - (mH % 2); | ||
const clearStartX = Math.round((mW - cW) / 2); | ||
const clearStartY = Math.round((mH - cH) / 2); | ||
for (let x = clearStartX; x < clearStartX + cW; x += 1) { | ||
for (let y = clearStartY; y < clearStartY + cH; y += 1) { | ||
matrix[x][y] = 0; | ||
} | ||
} | ||
return matrix; | ||
} | ||
//# sourceMappingURL=matrix.js.map |
@@ -5,3 +5,3 @@ import { PDFDocument, PDFOperator, PDFOperatorNames, rgb } from "pdf-lib"; | ||
import colorString from "color-string"; | ||
import { clearMatrixCenter, zeroFillFinders } from "./matrix.js"; | ||
import { clearMatrixCenter, zeroFillFinders } from "./bitMatrix.js"; | ||
const textDec = new TextDecoder(); | ||
@@ -11,4 +11,4 @@ export async function getPDF(text, inOptions) { | ||
let matrix = QR(text, options.ec_level, options.parse_url); | ||
zeroFillFinders(matrix); | ||
if (options.logo && options.logoWidth && options.logoHeight) { | ||
matrix = zeroFillFinders(matrix); | ||
if (options.logo && options.logoWidth && options.logoHeight && !options.noExcavate) { | ||
matrix = clearMatrixCenter(matrix, options.logoWidth, options.logoHeight); | ||
@@ -15,0 +15,0 @@ } |
import { QR } from "./qr-base.js"; | ||
import { colorToHex, getOptions, getDotsSVGPath, getFindersSVGPath } from "./utils.js"; | ||
import { Base64 } from "js-base64"; | ||
import { clearMatrixCenter, zeroFillFinders } from "./matrix.js"; | ||
import { clearMatrixCenter, zeroFillFinders } from "./bitMatrix.js"; | ||
export async function getPNG(text, inOptions) { | ||
const options = getOptions(inOptions); | ||
let matrix = QR(text, options.ec_level, options.parse_url); | ||
zeroFillFinders(matrix); | ||
if (options.logo && options.logoWidth && options.logoHeight) { | ||
matrix = zeroFillFinders(matrix); | ||
if (options.logo && options.logoWidth && options.logoHeight && !options.noExcavate) { | ||
matrix = clearMatrixCenter(matrix, options.logoWidth, options.logoHeight); | ||
@@ -11,0 +11,0 @@ } |
@@ -5,8 +5,8 @@ import { QR } from "./qr-base.js"; | ||
import sharp from "sharp"; | ||
import { clearMatrixCenter, zeroFillFinders } from "./matrix.js"; | ||
import { clearMatrixCenter, zeroFillFinders } from "./bitMatrix.js"; | ||
export async function getPNG(text, inOptions = {}) { | ||
const options = getOptions({ ...inOptions, type: "png" }); | ||
let matrix = QR(text, options.ec_level, options.parse_url); | ||
zeroFillFinders(matrix); | ||
if (options.logo && options.logoWidth && options.logoHeight) { | ||
matrix = zeroFillFinders(matrix); | ||
if (options.logo && options.logoWidth && options.logoHeight && !options.noExcavate) { | ||
matrix = clearMatrixCenter(matrix, options.logoWidth, options.logoHeight); | ||
@@ -23,3 +23,3 @@ } | ||
} | ||
const svg = await createSVG({ | ||
const svg = createSVG({ | ||
matrix, | ||
@@ -26,0 +26,0 @@ size, |
import { ImageOptions, Matrix } from "./typing/types"; | ||
export declare function getSVG(text: string, inOptions?: ImageOptions): Promise<Uint8Array>; | ||
export declare function getSVG(text: string, inOptions?: ImageOptions): Uint8Array; | ||
export declare function createSVG({ matrix, margin, size, logo, logoWidth, logoHeight, color, bgColor, imageWidth, imageHeight, borderRadius, }: ImageOptions & { | ||
@@ -7,2 +7,2 @@ matrix: Matrix; | ||
imageHeight?: number; | ||
}): Promise<Uint8Array>; | ||
}): Uint8Array; |
@@ -1,10 +0,10 @@ | ||
import { clearMatrixCenter, zeroFillFinders } from "./matrix.js"; | ||
import { clearMatrixCenter, zeroFillFinders } from "./bitMatrix.js"; | ||
import { QR } from "./qr-base.js"; | ||
import { colorToHex, getOptions, getDotsSVGPath, getFindersSVGPath } from "./utils.js"; | ||
import { Base64 } from "js-base64"; | ||
export async function getSVG(text, inOptions = {}) { | ||
export function getSVG(text, inOptions = {}) { | ||
const options = getOptions({ ...inOptions, type: "svg" }); | ||
let matrix = QR(text, options.ec_level, options.parse_url); | ||
zeroFillFinders(matrix); | ||
if (options.logo && options.logoWidth && options.logoHeight) { | ||
matrix = zeroFillFinders(matrix); | ||
if (options.logo && options.logoWidth && options.logoHeight && !options.noExcavate) { | ||
matrix = clearMatrixCenter(matrix, options.logoWidth, options.logoHeight); | ||
@@ -15,3 +15,3 @@ } | ||
const te = new TextEncoder(); | ||
export async function createSVG({ matrix, margin, size, logo, logoWidth, logoHeight, color, bgColor, imageWidth, imageHeight, borderRadius, }) { | ||
export function createSVG({ matrix, margin, size, logo, logoWidth, logoHeight, color, bgColor, imageWidth, imageHeight, borderRadius, }) { | ||
const actualBlockSize = size || 9; | ||
@@ -18,0 +18,0 @@ const matrixSizePx = matrix.length * actualBlockSize; |
@@ -12,2 +12,3 @@ import test from "ava"; | ||
window.globalThis.TextDecoder = TextDecoder; | ||
window.globalThis.structuredClone = structuredClone; | ||
window.globalThis.Path2D = Path2D; | ||
@@ -14,0 +15,0 @@ for (const scriptType of ['png', 'svg', 'pdf']) { |
@@ -7,2 +7,3 @@ import test from "ava"; | ||
import { assertEqual, generatedImageDir, goldenDir } from "./_common.js"; | ||
import { readFileSync } from "node:fs"; | ||
const text = "I \u2764\uFE0F QR code!"; | ||
@@ -14,2 +15,9 @@ const defaultParams = { | ||
}; | ||
const logoJPEG = readFileSync(`${goldenDir}/logo.jpg`).buffer; | ||
const turnedLogo = readFileSync(`${goldenDir}/logo_45deg.png`).buffer; | ||
const generatorByType = { | ||
pdf: getPDF, | ||
png: getPNG, | ||
svg: getSVG, | ||
}; | ||
[ | ||
@@ -180,3 +188,3 @@ { | ||
params: { | ||
logo: (await readFile(`${goldenDir}/logo.jpg`)).buffer, | ||
logo: logoJPEG, | ||
}, | ||
@@ -222,3 +230,3 @@ }, | ||
params: { | ||
logo: (await readFile(`${goldenDir}/logo.jpg`)).buffer, | ||
logo: logoJPEG, | ||
}, | ||
@@ -237,4 +245,21 @@ }, | ||
params: { size: 199, margin: 10 }, | ||
} | ||
].forEach((testData) => { | ||
}, | ||
["pdf", "png", "svg"].map(fileType => [{ | ||
name: `${fileType} noExcavate`, | ||
fn: generatorByType[fileType], | ||
filename: `qr_noexcavate.${fileType}`, | ||
params: { | ||
logo: turnedLogo, | ||
noExcavate: true, | ||
} | ||
}, { | ||
name: `${fileType} excavate`, | ||
fn: generatorByType[fileType], | ||
filename: `qr_excavate.${fileType}`, | ||
params: { | ||
logo: turnedLogo, | ||
noExcavate: false, | ||
} | ||
}]) | ||
].flat(2).forEach((testData) => { | ||
test.serial(testData.name, async (t) => { | ||
@@ -241,0 +266,0 @@ const image = await testData.fn(text, { |
@@ -26,2 +26,3 @@ export type MatrixValue = 0 | 1 | 128 | 129; | ||
logoHeight?: number; | ||
noExcavate?: boolean; | ||
color?: number | string; | ||
@@ -28,0 +29,0 @@ bgColor?: number | string; |
@@ -11,2 +11,3 @@ import { ImageOptions, ImageType, Matrix } from "./typing/types"; | ||
logoHeight?: number; | ||
noExcavate?: boolean; | ||
color?: string | number; | ||
@@ -13,0 +14,0 @@ bgColor?: string | number; |
{ | ||
"name": "qreator", | ||
"version": "9.5.2", | ||
"version": "9.6.0", | ||
"description": "QR Code generator for browser and node.js with tree shaking and logo support", | ||
@@ -40,2 +40,6 @@ "homepage": "https://github.com/Short-io/qreator", | ||
"default": "./lib/pdf.js" | ||
}, | ||
"./lib/react": { | ||
"types": "./lib/react.d.ts", | ||
"default": "./lib/react.js" | ||
} | ||
@@ -69,2 +73,3 @@ }, | ||
"@types/pixelmatch": "^5.2.6", | ||
"@types/react": "^18.3.1", | ||
"@types/sharp": "^0.31.1", | ||
@@ -85,2 +90,3 @@ "@types/svg-path-parser": "^1.1.6", | ||
"pixelmatch": "^5.3.0", | ||
"react": "^18.3.1", | ||
"rollup": "^4.18.0", | ||
@@ -93,5 +99,7 @@ "size-limit": "^11.1.4", | ||
"dependencies": { | ||
"@types/react-dom": "^18.3.1", | ||
"color-string": "^1.9.1", | ||
"js-base64": "^3.7.7", | ||
"pdf-lib": "^1.17.1", | ||
"react-dom": "^18.3.1", | ||
"sharp": "^0.33.5" | ||
@@ -98,0 +106,0 @@ }, |
@@ -78,3 +78,5 @@ # qreator | ||
| `borderRadius` | border-radius (in pixels) | number | 0 - `size / 2` | `0` | | ||
| `noExcavate` | don't remove partially covered modules | boolean | `true`, `false` | `false` | | ||
## Benchmarks | ||
@@ -81,0 +83,0 @@ |
@@ -36,29 +36,3 @@ import { BitMatrix, Data, EcLevel, Matrix } from "./typing/types"; | ||
/** | ||
* Finders require different UI representation, so we zero-fill finders and draw them later | ||
*/ | ||
export function zeroFillFinders(matrix: BitMatrix) { | ||
const N = matrix.length; | ||
const zeroPixel = 0; | ||
// squares | ||
for (let i = -3; i <= 3; i++) { | ||
for (let j = -3; j <= 3; j++) { | ||
matrix[3 + i][3 + j] = zeroPixel; | ||
matrix[3 + i][N - 4 + j] = zeroPixel; | ||
matrix[N - 4 + i][3 + j] = zeroPixel; | ||
} | ||
} | ||
// border | ||
for (let i = 0; i < 8; i++) { | ||
matrix[7][i] = | ||
matrix[i][7] = | ||
matrix[7][N - i - 1] = | ||
matrix[i][N - 8] = | ||
matrix[N - 8][i] = | ||
matrix[N - 1 - i][7] = | ||
zeroPixel; | ||
} | ||
} | ||
// {{{1 Put align and timinig | ||
@@ -416,26 +390,2 @@ export function fillAlignAndTiming(matrix: Matrix) { | ||
return matrix.map((row) => row.map((cell) => (cell & 1) as 0 | 1)); | ||
} | ||
/** | ||
* Before we insert logo in the QR we need to clear pixels under the logo. This function clears pixels | ||
*/ | ||
export function clearMatrixCenter(matrix: BitMatrix, widthPct: number, heightPct: number): BitMatrix { | ||
matrix = matrix.map((x) => x.slice()); // avoid mutating input arg | ||
// TODO: Here's a homegrown formula, perhaps could be simplified | ||
const mW = matrix.length; | ||
const cW = Math.ceil(((mW * widthPct) / 100 + (mW % 2)) / 2) * 2 - (mW % 2); | ||
const mH = matrix[0]?.length ?? 0; | ||
const cH = Math.ceil(((mH * heightPct) / 100 + (mH % 2)) / 2) * 2 - (mH % 2); | ||
// Given the formula, these must be whole numbers, but round anyway to account for js EPSILON | ||
const clearStartX = Math.round((mW - cW) / 2); | ||
const clearStartY = Math.round((mH - cH) / 2); | ||
for (let x = clearStartX; x < clearStartX + cW; x += 1) { | ||
for (let y = clearStartY; y < clearStartY + cH; y += 1) { | ||
matrix[x][y] = 0; | ||
} | ||
} | ||
return matrix; | ||
} | ||
} |
@@ -6,3 +6,3 @@ import { PDFDocument, PDFImage, PDFOperator, PDFOperatorNames, PDFPage, rgb } from "pdf-lib"; | ||
import colorString from "color-string"; | ||
import { clearMatrixCenter, zeroFillFinders } from "./matrix.js"; | ||
import { clearMatrixCenter, zeroFillFinders } from "./bitMatrix.js"; | ||
@@ -15,4 +15,4 @@ const textDec = new TextDecoder(); | ||
let matrix = QR(text, options.ec_level, options.parse_url); | ||
zeroFillFinders(matrix) | ||
if (options.logo && options.logoWidth && options.logoHeight) { | ||
matrix = zeroFillFinders(matrix) | ||
if (options.logo && options.logoWidth && options.logoHeight && !options.noExcavate) { | ||
matrix = clearMatrixCenter(matrix, options.logoWidth, options.logoHeight); | ||
@@ -19,0 +19,0 @@ } |
@@ -5,3 +5,3 @@ import { QR } from "./qr-base.js"; | ||
import { Base64 } from "js-base64"; | ||
import { clearMatrixCenter, zeroFillFinders } from "./matrix.js"; | ||
import { clearMatrixCenter, zeroFillFinders } from "./bitMatrix.js"; | ||
@@ -12,4 +12,4 @@ export async function getPNG(text: string, inOptions: ImageOptions) { | ||
let matrix = QR(text, options.ec_level, options.parse_url); | ||
zeroFillFinders(matrix) | ||
if (options.logo && options.logoWidth && options.logoHeight) { | ||
matrix = zeroFillFinders(matrix) | ||
if (options.logo && options.logoWidth && options.logoHeight && !options.noExcavate) { | ||
matrix = clearMatrixCenter(matrix, options.logoWidth, options.logoHeight); | ||
@@ -16,0 +16,0 @@ } |
@@ -6,3 +6,3 @@ import { ImageOptions, Matrix } from "./typing/types"; | ||
import sharp from "sharp"; | ||
import { clearMatrixCenter, zeroFillFinders } from "./matrix.js"; | ||
import { clearMatrixCenter, zeroFillFinders } from "./bitMatrix.js"; | ||
@@ -13,4 +13,4 @@ export async function getPNG(text: string, inOptions: ImageOptions = {}) { | ||
let matrix = QR(text, options.ec_level, options.parse_url); | ||
zeroFillFinders(matrix) | ||
if (options.logo && options.logoWidth && options.logoHeight) { | ||
matrix = zeroFillFinders(matrix) | ||
if (options.logo && options.logoWidth && options.logoHeight && !options.noExcavate) { | ||
matrix = clearMatrixCenter(matrix, options.logoWidth, options.logoHeight); | ||
@@ -41,3 +41,3 @@ } | ||
const svg = await createSVG({ | ||
const svg = createSVG({ | ||
matrix, | ||
@@ -44,0 +44,0 @@ size, |
@@ -1,2 +0,2 @@ | ||
import { clearMatrixCenter, zeroFillFinders } from "./matrix.js"; | ||
import { clearMatrixCenter, zeroFillFinders } from "./bitMatrix.js"; | ||
import { QR } from "./qr-base.js"; | ||
@@ -11,8 +11,8 @@ import { ImageOptions, Matrix } from "./typing/types"; | ||
export async function getSVG(text: string, inOptions: ImageOptions = {}) { | ||
export function getSVG(text: string, inOptions: ImageOptions = {}) { | ||
const options = getOptions({ ...inOptions, type: "svg" }); | ||
let matrix = QR(text, options.ec_level, options.parse_url); | ||
zeroFillFinders(matrix) | ||
if (options.logo && options.logoWidth && options.logoHeight) { | ||
matrix = zeroFillFinders(matrix) | ||
if (options.logo && options.logoWidth && options.logoHeight && !options.noExcavate) { | ||
matrix = clearMatrixCenter(matrix, options.logoWidth, options.logoHeight); | ||
@@ -26,3 +26,3 @@ } | ||
export async function createSVG({ | ||
export function createSVG({ | ||
matrix, | ||
@@ -43,3 +43,3 @@ margin, | ||
imageHeight?: number; | ||
}): Promise<Uint8Array> { | ||
}): Uint8Array { | ||
const actualBlockSize = size || 9; | ||
@@ -46,0 +46,0 @@ const matrixSizePx = matrix.length * actualBlockSize; |
@@ -16,2 +16,3 @@ import test from "ava"; | ||
window.globalThis.TextDecoder = TextDecoder; | ||
window.globalThis.structuredClone = structuredClone; | ||
window.globalThis.Path2D = Path2D; | ||
@@ -18,0 +19,0 @@ |
@@ -9,2 +9,3 @@ import test from "ava"; | ||
import { assertEqual, generatedImageDir, goldenDir } from "./_common.js"; | ||
import { readFileSync } from "node:fs"; | ||
@@ -20,2 +21,11 @@ const text = "I \u2764\uFE0F QR code!"; | ||
const logoJPEG = readFileSync(`${goldenDir}/logo.jpg`).buffer; | ||
const turnedLogo = readFileSync(`${goldenDir}/logo_45deg.png`).buffer; | ||
const generatorByType = { | ||
pdf: getPDF, | ||
png: getPNG, | ||
svg: getSVG, | ||
} | ||
interface TestParams { | ||
@@ -193,3 +203,3 @@ name: string; | ||
params: { | ||
logo: (await readFile(`${goldenDir}/logo.jpg`)).buffer, | ||
logo: logoJPEG, | ||
}, | ||
@@ -235,3 +245,3 @@ }, | ||
params: { | ||
logo: (await readFile(`${goldenDir}/logo.jpg`)).buffer, | ||
logo: logoJPEG, | ||
}, | ||
@@ -250,4 +260,21 @@ }, | ||
params: { size: 199, margin: 10 }, | ||
} | ||
] as TestParams[]).forEach((testData) => { | ||
}, | ||
(["pdf", "png", "svg"] as const).map(fileType => [{ | ||
name: `${fileType} noExcavate`, | ||
fn: generatorByType[fileType], | ||
filename: `qr_noexcavate.${fileType}`, | ||
params: { | ||
logo: turnedLogo, | ||
noExcavate: true, | ||
} | ||
}, { | ||
name: `${fileType} excavate`, | ||
fn: generatorByType[fileType], | ||
filename: `qr_excavate.${fileType}`, | ||
params: { | ||
logo: turnedLogo, | ||
noExcavate: false, | ||
} | ||
}]) as TestParams[][] | ||
] as TestParams[]).flat(2).forEach((testData) => { | ||
test.serial(testData.name, async (t) => { | ||
@@ -254,0 +281,0 @@ const image = await testData.fn(text, { |
@@ -86,2 +86,6 @@ export type MatrixValue = 0 | 1 | 128 | 129; | ||
/** | ||
* by default we remove partially covered modules under the logo, this option disables such behaviour | ||
*/ | ||
noExcavate?: boolean; | ||
/** | ||
* Foreground color in RGBA format. | ||
@@ -88,0 +92,0 @@ * @default 0x000000FF |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
4395506
97
38155
95
6
32
+ Added@types/react-dom@^18.3.1
+ Addedreact-dom@^18.3.1
+ Added@types/prop-types@15.7.13(transitive)
+ Added@types/react@18.3.12(transitive)
+ Added@types/react-dom@18.3.1(transitive)
+ Addedcsstype@3.1.3(transitive)
+ Addedjs-tokens@4.0.0(transitive)
+ Addedloose-envify@1.4.0(transitive)
+ Addedreact@18.3.1(transitive)
+ Addedreact-dom@18.3.1(transitive)
+ Addedscheduler@0.23.2(transitive)