refactor: convert repository to monorepo with npm workspaces
Restructured the repository into a monorepo to better organize application code and maintenance scripts. ## Workspace Structure - web-app: Next.js application (all app code moved from root) - housekeeping: Database backup and maintenance scripts ## Key Changes - Moved all application code to web-app/ using git mv - Moved database scripts to housekeeping/ workspace - Updated Dockerfile for monorepo build process - Updated docker-compose files (volume paths: ./web-app/etc/hosts/) - Updated .gitignore for workspace-level node_modules - Updated documentation (README.md, CLAUDE.md, CHANGELOG.md) ## Migration Impact - Root package.json now manages workspaces - Build commands delegate to web-app workspace - All file history preserved via git mv - Docker build process updated for workspace structure 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
408
web-app/app/lib/pdf/barcodeDecoderWasm.ts
Normal file
408
web-app/app/lib/pdf/barcodeDecoderWasm.ts
Normal file
@@ -0,0 +1,408 @@
|
||||
import { PDFPageProxy } from 'pdfjs-dist';
|
||||
import { readBarcodes, prepareZXingModule, type ReaderOptions } from 'zxing-wasm/reader';
|
||||
|
||||
// Configure WASM file location (similar to how pdf.worker.min.mjs is configured)
|
||||
prepareZXingModule({
|
||||
overrides: {
|
||||
locateFile: (path, prefix) => {
|
||||
if (path.endsWith('.wasm')) {
|
||||
return window.location.origin + '/zxing_reader.wasm';
|
||||
}
|
||||
return prefix + path;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export type BillInfo = {
|
||||
header: string,
|
||||
currency: string,
|
||||
amount: number,
|
||||
payerName: string,
|
||||
payerAddress: string,
|
||||
payerTown: string,
|
||||
payeeName: string,
|
||||
payeeAddress: string,
|
||||
payeeTown: string,
|
||||
IBAN: string,
|
||||
model: string,
|
||||
reference: string,
|
||||
code: string,
|
||||
description: string,
|
||||
};
|
||||
|
||||
/** Breaks current microtask execution and gives the UI thread a chance to do a re-paint */
|
||||
const yieldToBrowser = (_label: string) => new Promise<boolean>((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(true);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
/**
|
||||
* Decodes a PDF417 barcode
|
||||
* @param text
|
||||
* @returns
|
||||
* @description
|
||||
* Example text: "HRVHUB30\nEUR\n000000000012422\nDEREŽIĆ NIKOLA\nULICA DIVKA BUDAKA 17/17\n10000 ZAGREB\nGPZ-Opskrba d.o.o.\nRadnička cesta 1\n10000 Zagreb\nHR3623400091110343158\nHR05\n02964686-0307\nGASB\nAkontacijska rata za 01.2024.\n"
|
||||
*
|
||||
* Decoded into:
|
||||
* header: HRVHUB30
|
||||
* currency:EUR
|
||||
* amount:000000000012422
|
||||
* payerName:DEREŽIĆ NIKOLA
|
||||
* payerAddress:ULICA DIVKA BUDAKA 17/17
|
||||
* payerTown:10000 ZAGREB
|
||||
* payeeName:GPZ-Opskrba d.o.o.
|
||||
* payeeAddress:Radnička cesta 1
|
||||
* payeeTown:10000 Zagreb
|
||||
* IBAN:HR3623400091110343158
|
||||
* model:HR05
|
||||
* reference:02964686-0307
|
||||
* code:GASB
|
||||
* description:Akontacijska rata za 01.2024.
|
||||
*
|
||||
*/
|
||||
const parseHubText = (text: string): BillInfo => {
|
||||
const [
|
||||
header,
|
||||
currency,
|
||||
amount,
|
||||
payerName,
|
||||
payerAddress,
|
||||
payerTown,
|
||||
payeeName,
|
||||
payeeAddress,
|
||||
payeeTown,
|
||||
IBAN,
|
||||
model,
|
||||
reference,
|
||||
code,
|
||||
description,
|
||||
] = text.split('\n');
|
||||
|
||||
return {
|
||||
header,
|
||||
currency,
|
||||
amount: parseInt(amount, 10),
|
||||
payerName,
|
||||
payerAddress,
|
||||
payerTown,
|
||||
payeeName,
|
||||
payeeAddress,
|
||||
payeeTown,
|
||||
IBAN,
|
||||
model,
|
||||
reference,
|
||||
code,
|
||||
description,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an image from the given file onto a canvas.
|
||||
* @param {File} imageFile - a file containing an image
|
||||
* @return {Promise<HTMLCanvasElement>} the canvas with the image rendered onto it
|
||||
*/
|
||||
const file2canvas = async function (imageFile: File): Promise<HTMLCanvasElement> {
|
||||
|
||||
const reader = new FileReader();
|
||||
|
||||
const canvas = await new Promise<HTMLCanvasElement>((resolve, reject) => {
|
||||
reader.onload = (progressEvent: ProgressEvent<FileReader>) => {
|
||||
const img = new Image();
|
||||
|
||||
img.onload = () => {
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
|
||||
if (!ctx) {
|
||||
reject(new Error("Context is not set"))
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.drawImage(img, 0, 0);
|
||||
|
||||
resolve(canvas);
|
||||
};
|
||||
|
||||
const result = (progressEvent.target as FileReader).result;
|
||||
|
||||
img.src = result as string;
|
||||
};
|
||||
|
||||
reader.onerror = (e) => reject(e);
|
||||
reader.readAsDataURL(imageFile);
|
||||
});
|
||||
|
||||
return (canvas);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an image from onto a canvas.
|
||||
* @param {String} imageBase64 - base64 encoded image string
|
||||
* @return {Promise<HTMLCanvasElement>} the canvas with the image rendered onto it
|
||||
*/
|
||||
const image2canvas = async function (imageBase64: string): Promise<HTMLCanvasElement> {
|
||||
|
||||
const canvas = await new Promise<HTMLCanvasElement>((resolve, reject) => {
|
||||
const img = new Image();
|
||||
|
||||
img.onload = () => {
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
|
||||
if (!ctx) {
|
||||
reject("Context is not set")
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.drawImage(img, 0, 0);
|
||||
|
||||
resolve(canvas);
|
||||
};
|
||||
|
||||
img.src = imageBase64;
|
||||
});
|
||||
|
||||
return (canvas);
|
||||
};
|
||||
|
||||
/**
|
||||
* Render the first page of a PDF document onto a new canvas.
|
||||
* @param {File} pdfFile - a file containing a PDF document
|
||||
* @return {Promise<HTMLCanvasElement>} the canvas with the first page of the PDF
|
||||
*/
|
||||
const pdf2canvas = async function (pdfFile: File): Promise<Array<HTMLCanvasElement>> {
|
||||
|
||||
const reader = new FileReader();
|
||||
const data = await new Promise<Uint8Array>((resolve, reject) => {
|
||||
reader.onload = (e) => resolve(new Uint8Array((e.target as FileReader).result as ArrayBuffer));
|
||||
reader.onerror = (e) => reject(e);
|
||||
reader.readAsArrayBuffer(pdfFile);
|
||||
});
|
||||
|
||||
const pdfJS = await import('pdfjs-dist');
|
||||
|
||||
// worker file was manually copied to the `public` folder
|
||||
pdfJS.GlobalWorkerOptions.workerSrc = window.location.origin + '/pdf.worker.min.mjs';
|
||||
|
||||
const pdf = await pdfJS.getDocument(data).promise;
|
||||
|
||||
const canvases: Array<HTMLCanvasElement> = [];
|
||||
|
||||
for (let i = 0; i < pdf.numPages; i++) {
|
||||
const page: PDFPageProxy = await pdf.getPage(i + 1);
|
||||
|
||||
const scale = 4;
|
||||
const viewport = page.getViewport({ scale });
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
const context = canvas.getContext('2d');
|
||||
canvas.height = viewport.height;
|
||||
canvas.width = viewport.width;
|
||||
|
||||
await page.render({ canvasContext: context as CanvasRenderingContext2D, viewport }).promise;
|
||||
|
||||
canvases.push(canvas);
|
||||
}
|
||||
|
||||
return (canvases);
|
||||
}
|
||||
|
||||
export type DecodeResult = {
|
||||
hub3aText: string,
|
||||
billInfo: BillInfo,
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert canvas to ImageData for zxing-wasm
|
||||
* @param canvas - HTMLCanvasElement to convert
|
||||
* @returns ImageData object
|
||||
*/
|
||||
const canvasToImageData = (canvas: HTMLCanvasElement): ImageData => {
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) {
|
||||
throw new Error('Failed to get canvas context');
|
||||
}
|
||||
return ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
};
|
||||
|
||||
/**
|
||||
* Searches the given canvas for all PDF417 codes and decodes them.
|
||||
* Uses a slicing strategy to improve detection when multiple barcodes are present.
|
||||
* @param {HTMLCanvasElement} canvas - the canvas to search for PDF417 codes
|
||||
* @return {Promise<Array<DecodeResult> | null>} - an array of decoded results
|
||||
* */
|
||||
const decodeFromCanvas = async (canvas: HTMLCanvasElement): Promise<Array<DecodeResult> | null> => {
|
||||
try {
|
||||
const readerOptions: ReaderOptions = {
|
||||
tryHarder: true,
|
||||
formats: ['PDF417'],
|
||||
maxNumberOfSymbols: 1, // Decode one barcode per slice
|
||||
};
|
||||
|
||||
const width = canvas.width;
|
||||
const height = canvas.height;
|
||||
|
||||
// Canvas can contain multiple PDF417 codes, so we need to try to find them all
|
||||
// We will try splitting the canvas into different numbers of horizontal subsections
|
||||
// and decode each subsection separately. The best result will be the one with the most codes found.
|
||||
const splits = [5, 4, 3, 2, 1, 0];
|
||||
|
||||
// Pre-allocate canvas pool (max 6 canvases needed for split=5)
|
||||
const canvasPool = Array.from({ length: 6 }, () => {
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) {
|
||||
throw new Error('Failed to get canvas context');
|
||||
}
|
||||
return { canvas, ctx };
|
||||
});
|
||||
|
||||
let bestResult: Array<DecodeResult> | null = null;
|
||||
|
||||
for (let splitIx = 0; splitIx < splits.length; splitIx++) {
|
||||
const split = splits[splitIx];
|
||||
const sectionsNeeded = split + 1;
|
||||
|
||||
// Add overlap to ensure we don't miss codes at section boundaries
|
||||
const overlap = split === 0 ? 0 : Math.round(height / 50); // 2% overlap
|
||||
const sectionHeight = split === 0 ? height : (Math.floor(Math.floor(height / split) + overlap));
|
||||
|
||||
// Prepare canvases from pool
|
||||
for (let i = 0; i < canvasPool.length; i++) {
|
||||
const { canvas: sectionCanvas, ctx: sectionContext } = canvasPool[i];
|
||||
|
||||
if (i < sectionsNeeded) {
|
||||
// Resize and use this canvas
|
||||
sectionCanvas.width = width;
|
||||
sectionCanvas.height = sectionHeight;
|
||||
|
||||
// Calculate the starting Y position for each section
|
||||
const startY = i === 0 ? 0 : i * sectionHeight - overlap;
|
||||
|
||||
// Draw the section of the original canvas onto this section canvas
|
||||
sectionContext.drawImage(canvas, 0, startY, width, sectionHeight, 0, 0, width, sectionHeight);
|
||||
} else {
|
||||
// Free unused canvases for this strategy
|
||||
sectionCanvas.width = 0;
|
||||
sectionCanvas.height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const codesFoundInSection: Array<DecodeResult> = [];
|
||||
|
||||
// Try to decode each section (only the ones we're using)
|
||||
for (let i = 0; i < sectionsNeeded; i++) {
|
||||
const { canvas: sectionCanvas } = canvasPool[i];
|
||||
|
||||
try {
|
||||
// give browser a chance to re-paint
|
||||
// this is needed to avoid UI freezing when decoding large images
|
||||
await yieldToBrowser('decodeFromCanvas');
|
||||
|
||||
const imageData = canvasToImageData(sectionCanvas);
|
||||
const results = await readBarcodes(imageData, readerOptions);
|
||||
|
||||
if (results.length > 0 && results[0].text) {
|
||||
const hub3aText = results[0].text;
|
||||
codesFoundInSection.push({
|
||||
hub3aText,
|
||||
billInfo: parseHubText(hub3aText),
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
// If no code was found in the current section, continue to next section
|
||||
}
|
||||
}
|
||||
|
||||
await yieldToBrowser('after decodeFromCanvas');
|
||||
|
||||
// If in this iteration we found fewer or equal codes than in the previous best result,
|
||||
// we can return the best result. This is an optimization.
|
||||
if (bestResult && codesFoundInSection.length <= bestResult.length) {
|
||||
return bestResult;
|
||||
}
|
||||
|
||||
bestResult = codesFoundInSection;
|
||||
}
|
||||
|
||||
return bestResult;
|
||||
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Finds PDF417 code within a base64 encoded image and decodes it */
|
||||
export const decodeFromImage = async (imageBase64: string): Promise<DecodeResult | null> => {
|
||||
const canvas = await image2canvas(imageBase64);
|
||||
|
||||
const readerOptions: ReaderOptions = {
|
||||
tryHarder: true,
|
||||
formats: ['PDF417'],
|
||||
maxNumberOfSymbols: 1,
|
||||
};
|
||||
|
||||
const imageData = canvasToImageData(canvas);
|
||||
const results = await readBarcodes(imageData, readerOptions);
|
||||
|
||||
if (results.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const hub3aText = results[0].text;
|
||||
|
||||
return ({
|
||||
hub3aText,
|
||||
billInfo: parseHubText(hub3aText)
|
||||
});
|
||||
}
|
||||
|
||||
/** Finds PDF417 code within a file and decodes it */
|
||||
const decodeFromFile = async (file: File): Promise<DecodeResult[] | null> => {
|
||||
switch (file.type) {
|
||||
case 'image/png':
|
||||
case 'image/jpeg':
|
||||
return (await decodeFromCanvas(await file2canvas(file)));
|
||||
case 'application/pdf':
|
||||
const pageCanvas = await pdf2canvas(file);
|
||||
// go through each page of the PDF and decode the PDF417 codes
|
||||
// if there are multiple pages, we will decode each page separately
|
||||
// and return the results from all pages
|
||||
const results = (await Promise.all(pageCanvas.map(async (canvas) => {
|
||||
await yieldToBrowser('decodeFromCanvas');
|
||||
return await decodeFromCanvas(canvas);
|
||||
})))
|
||||
// remove null results (pages with no PDF417 codes)
|
||||
.filter((result) => result !== null)
|
||||
// flatten the array of arrays into a single array
|
||||
.flat() as DecodeResult[];
|
||||
|
||||
return (results);
|
||||
default:
|
||||
console.error(file.name, 'is not a .pdf file.');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the first page of a PDF document onto a new canvas.
|
||||
* @param {Event} event - The change event from an HTMLInputElement.
|
||||
* @return {Promise<HTMLCanvasElement | null>} The canvas with the first page of the PDF, or null if the document is not a PDF.
|
||||
*/
|
||||
export async function findDecodePdf417(event: React.ChangeEvent<HTMLInputElement>): Promise<Array<DecodeResult> | null> {
|
||||
const file = (event.target as HTMLInputElement).files?.[0];
|
||||
|
||||
if (!file) {
|
||||
console.error('No file was selected.');
|
||||
return null;
|
||||
}
|
||||
|
||||
return (await decodeFromFile(file));
|
||||
}
|
||||
957
web-app/app/lib/pdf/bcmath.ts
Normal file
957
web-app/app/lib/pdf/bcmath.ts
Normal file
@@ -0,0 +1,957 @@
|
||||
/**
|
||||
* Binary Calculator (BC) Arbitrary Precision Mathematics Lib v0.10 (LGPL)
|
||||
* Copy of libbcmath included in PHP5 src
|
||||
* supports bcadd, bcsub, bcmul, bcdiv, bccomp, bcscale, and new function bcround(val, precision)
|
||||
* See PHP Manual for parameters.. functions work identical to the PHP5 funcions
|
||||
* Feel free to use how-ever you want, just email any bug-fixes/improvements to the sourceforge project:
|
||||
* https://sourceforge.net/projects/bcmath-js/
|
||||
*
|
||||
* Ported from the PHP5 bcmath extension source code,
|
||||
* which uses the libbcmath package...
|
||||
* Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2000 Philip A. Nelson
|
||||
* The Free Software Foundation, Inc.
|
||||
* 59 Temple Place, Suite 330
|
||||
* Boston, MA 02111-1307 USA.
|
||||
* e-mail: philnelson@acm.org
|
||||
* us-mail: Philip A. Nelson
|
||||
* Computer Science Department, 9062
|
||||
* Western Washington University
|
||||
* Bellingham, WA 98226-9062
|
||||
*/
|
||||
|
||||
interface BCNum {
|
||||
n_sign: string | null;
|
||||
n_len: number | null;
|
||||
n_scale: number | null;
|
||||
n_value: number[] | null;
|
||||
toString(): string;
|
||||
setScale(scale: number): BCNum;
|
||||
}
|
||||
|
||||
type BCNumValue = string | number;
|
||||
|
||||
const libbcmath = {
|
||||
PLUS: "+" as const,
|
||||
MINUS: "-" as const,
|
||||
BASE: 10,
|
||||
scale: 0,
|
||||
bc_num: function (this: BCNum): void {
|
||||
this.n_sign = null;
|
||||
this.n_len = null;
|
||||
this.n_scale = null;
|
||||
this.n_value = null;
|
||||
this.toString = function (): string {
|
||||
let b: string, a: string;
|
||||
a = this.n_value!.join("");
|
||||
b =
|
||||
(this.n_sign === libbcmath.PLUS ? "" : this.n_sign) +
|
||||
a.substr(0, this.n_len!);
|
||||
if (this.n_scale! > 0) {
|
||||
b += "." + a.substr(this.n_len!, this.n_scale!);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
this.setScale = function (a: number): BCNum {
|
||||
while (this.n_scale! < a) {
|
||||
this.n_value!.push(0);
|
||||
this.n_scale!++;
|
||||
}
|
||||
while (this.n_scale! > a) {
|
||||
this.n_value!.pop();
|
||||
this.n_scale!--;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
} as any as { new (): BCNum },
|
||||
bc_new_num: function (b: number, c: number): BCNum {
|
||||
const a = new libbcmath.bc_num();
|
||||
a.n_sign = libbcmath.PLUS;
|
||||
a.n_len = b;
|
||||
a.n_scale = c;
|
||||
a.n_value = libbcmath.safe_emalloc(1, b + c, 0);
|
||||
libbcmath.memset(a.n_value, 0, 0, b + c);
|
||||
return a;
|
||||
},
|
||||
safe_emalloc: function (c: number, b: number, a: number): number[] {
|
||||
return Array(c * b + a);
|
||||
},
|
||||
bc_init_num: function (): BCNum {
|
||||
return libbcmath.bc_new_num(1, 0);
|
||||
},
|
||||
_bc_rm_leading_zeros: function (a: BCNum): void {
|
||||
while (a.n_value![0] === 0 && a.n_len! > 1) {
|
||||
a.n_value!.shift();
|
||||
a.n_len!--;
|
||||
}
|
||||
},
|
||||
php_str2num: function (b: string): BCNum {
|
||||
const a = b.indexOf(".");
|
||||
if (a === -1) {
|
||||
return libbcmath.bc_str2num(b, 0);
|
||||
} else {
|
||||
return libbcmath.bc_str2num(b, b.length - a);
|
||||
}
|
||||
},
|
||||
CH_VAL: function (a: string): number {
|
||||
return parseInt(a, 10);
|
||||
},
|
||||
BCD_CHAR: function (a: number): string {
|
||||
return a + "0";
|
||||
},
|
||||
isdigit: function (a: string): boolean {
|
||||
return !isNaN(parseInt(a, 10));
|
||||
},
|
||||
bc_str2num: function (h: string, c: number): BCNum {
|
||||
const g = h.split("");
|
||||
let a = 0;
|
||||
let b = 0;
|
||||
let e = 0;
|
||||
let i = false;
|
||||
if (g[a] === "+" || g[a] === "-") {
|
||||
a++;
|
||||
}
|
||||
while (g[a] === "0") {
|
||||
a++;
|
||||
}
|
||||
while (g[a] && !isNaN(parseInt(g[a], 10))) {
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
if (g[a] === ".") {
|
||||
a++;
|
||||
}
|
||||
while (g[a] && !isNaN(parseInt(g[a], 10))) {
|
||||
a++;
|
||||
e++;
|
||||
}
|
||||
if (g[a] || b + e === 0) {
|
||||
return libbcmath.bc_init_num();
|
||||
}
|
||||
e = libbcmath.MIN(e, c);
|
||||
if (b === 0) {
|
||||
i = true;
|
||||
b = 1;
|
||||
}
|
||||
const f = libbcmath.bc_new_num(b, e);
|
||||
a = 0;
|
||||
if (g[a] === "-") {
|
||||
f.n_sign = libbcmath.MINUS;
|
||||
a++;
|
||||
} else {
|
||||
f.n_sign = libbcmath.PLUS;
|
||||
if (g[a] === "+") {
|
||||
a++;
|
||||
}
|
||||
}
|
||||
while (g[a] === "0") {
|
||||
a++;
|
||||
}
|
||||
let d = 0;
|
||||
if (i) {
|
||||
f.n_value![d++] = 0;
|
||||
b = 0;
|
||||
}
|
||||
for (; b > 0; b--) {
|
||||
f.n_value![d++] = libbcmath.CH_VAL(g[a++]);
|
||||
}
|
||||
if (e > 0) {
|
||||
a++;
|
||||
for (; e > 0; e--) {
|
||||
f.n_value![d++] = libbcmath.CH_VAL(g[a++]);
|
||||
}
|
||||
}
|
||||
return f;
|
||||
},
|
||||
cint: function (b?: number): number {
|
||||
if (typeof b === "undefined") {
|
||||
b = 0;
|
||||
}
|
||||
const a = parseInt(b.toString(), 10);
|
||||
if (isNaN(a)) {
|
||||
return 0;
|
||||
}
|
||||
return a;
|
||||
},
|
||||
MIN: function (d: number, c: number): number {
|
||||
return d > c ? c : d;
|
||||
},
|
||||
MAX: function (d: number, c: number): number {
|
||||
return d > c ? d : c;
|
||||
},
|
||||
ODD: function (b: number): number {
|
||||
return b & 1;
|
||||
},
|
||||
memset: function (d: number[], e: number, c: number, a: number): void {
|
||||
for (let b = 0; b < a; b++) {
|
||||
d[e + b] = c;
|
||||
}
|
||||
},
|
||||
memcpy: function (
|
||||
b: number[],
|
||||
f: number,
|
||||
e: number[],
|
||||
d: number,
|
||||
a: number
|
||||
): boolean {
|
||||
for (let c = 0; c < a; c++) {
|
||||
b[f + c] = e[d + c];
|
||||
}
|
||||
return true;
|
||||
},
|
||||
bc_is_zero: function (a: BCNum): boolean {
|
||||
let b = a.n_len! + a.n_scale!;
|
||||
let c = 0;
|
||||
while (b > 0 && a.n_value![c++] === 0) {
|
||||
b--;
|
||||
}
|
||||
return b === 0;
|
||||
},
|
||||
bc_out_of_memory: function (): never {
|
||||
throw new Error("(BC) Out of memory");
|
||||
},
|
||||
bc_add: function (f: BCNum, d: BCNum, c: number): BCNum {
|
||||
let e: BCNum;
|
||||
if (f.n_sign === d.n_sign) {
|
||||
e = libbcmath._bc_do_add(f, d, c);
|
||||
e.n_sign = f.n_sign;
|
||||
} else {
|
||||
const b = libbcmath._bc_do_compare(f, d, false, false);
|
||||
switch (b) {
|
||||
case -1:
|
||||
e = libbcmath._bc_do_sub(d, f, c);
|
||||
e.n_sign = d.n_sign;
|
||||
break;
|
||||
case 0:
|
||||
const a = libbcmath.MAX(c, libbcmath.MAX(f.n_scale!, d.n_scale!));
|
||||
e = libbcmath.bc_new_num(1, a);
|
||||
libbcmath.memset(e.n_value!, 0, 0, a + 1);
|
||||
break;
|
||||
case 1:
|
||||
e = libbcmath._bc_do_sub(f, d, c);
|
||||
e.n_sign = f.n_sign;
|
||||
break;
|
||||
default:
|
||||
e = libbcmath.bc_init_num();
|
||||
}
|
||||
}
|
||||
return e;
|
||||
},
|
||||
bc_compare: function (b: BCNum, a: BCNum): number {
|
||||
return libbcmath._bc_do_compare(b, a, true, false);
|
||||
},
|
||||
_bc_do_compare: function (
|
||||
e: BCNum,
|
||||
d: BCNum,
|
||||
c: boolean,
|
||||
b: boolean
|
||||
): number {
|
||||
if (c && e.n_sign !== d.n_sign) {
|
||||
if (e.n_sign === libbcmath.PLUS) {
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (e.n_len !== d.n_len) {
|
||||
if (e.n_len! > d.n_len!) {
|
||||
if (!c || e.n_sign === libbcmath.PLUS) {
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (!c || e.n_sign === libbcmath.PLUS) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
let f = e.n_len! + Math.min(e.n_scale!, d.n_scale!);
|
||||
let g = 0;
|
||||
let a = 0;
|
||||
while (f > 0 && e.n_value![g] === d.n_value![a]) {
|
||||
g++;
|
||||
a++;
|
||||
f--;
|
||||
}
|
||||
if (b && f === 1 && e.n_scale === d.n_scale) {
|
||||
return 0;
|
||||
}
|
||||
if (f !== 0) {
|
||||
if (e.n_value![g] > d.n_value![a]) {
|
||||
if (!c || e.n_sign === libbcmath.PLUS) {
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (!c || e.n_sign === libbcmath.PLUS) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (e.n_scale !== d.n_scale) {
|
||||
if (e.n_scale! > d.n_scale!) {
|
||||
for (f = e.n_scale! - d.n_scale!; f > 0; f--) {
|
||||
if (e.n_value![g++] !== 0) {
|
||||
if (!c || e.n_sign === libbcmath.PLUS) {
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (f = d.n_scale! - e.n_scale!; f > 0; f--) {
|
||||
if (d.n_value![a++] !== 0) {
|
||||
if (!c || e.n_sign === libbcmath.PLUS) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
_one_mult: function (
|
||||
d: number[],
|
||||
e: number,
|
||||
i: number,
|
||||
f: number,
|
||||
j: number[],
|
||||
c: number
|
||||
): void {
|
||||
if (f === 0) {
|
||||
libbcmath.memset(j, 0, 0, i);
|
||||
} else {
|
||||
if (f === 1) {
|
||||
libbcmath.memcpy(j, c, d, e, i);
|
||||
} else {
|
||||
let b = e + i - 1;
|
||||
let a = c + i - 1;
|
||||
let h = 0;
|
||||
while (i-- > 0) {
|
||||
const g = d[b--] * f + h;
|
||||
j[a--] = g % libbcmath.BASE;
|
||||
h = Math.floor(g / libbcmath.BASE);
|
||||
}
|
||||
if (h !== 0) {
|
||||
j[a] = h;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
bc_divide: function (l: BCNum, k: BCNum, z: number): BCNum | -1 {
|
||||
if (libbcmath.bc_is_zero(k)) {
|
||||
return -1;
|
||||
}
|
||||
if (libbcmath.bc_is_zero(l)) {
|
||||
return libbcmath.bc_new_num(1, z);
|
||||
}
|
||||
let w: BCNum | undefined;
|
||||
if (k.n_scale === 0) {
|
||||
if (k.n_len === 1 && k.n_value![0] === 1) {
|
||||
w = libbcmath.bc_new_num(l.n_len!, z);
|
||||
w.n_sign = l.n_sign === k.n_sign ? libbcmath.PLUS : libbcmath.MINUS;
|
||||
libbcmath.memset(w.n_value!, l.n_len!, 0, z);
|
||||
libbcmath.memcpy(
|
||||
w.n_value!,
|
||||
0,
|
||||
l.n_value!,
|
||||
0,
|
||||
l.n_len! + libbcmath.MIN(l.n_scale!, z)
|
||||
);
|
||||
return w;
|
||||
}
|
||||
}
|
||||
let s = k.n_scale!;
|
||||
let h = k.n_len! + s - 1;
|
||||
while (s > 0 && k.n_value![h--] === 0) {
|
||||
s--;
|
||||
}
|
||||
const j = l.n_len! + s;
|
||||
const u = l.n_scale! - s;
|
||||
let a: number;
|
||||
if (u < z) {
|
||||
a = z - u;
|
||||
} else {
|
||||
a = 0;
|
||||
}
|
||||
const c = libbcmath.safe_emalloc(1, l.n_len! + l.n_scale!, a + 2);
|
||||
if (c === null) {
|
||||
libbcmath.bc_out_of_memory();
|
||||
}
|
||||
libbcmath.memset(c, 0, 0, l.n_len! + l.n_scale! + a + 2);
|
||||
libbcmath.memcpy(c, 1, l.n_value!, 0, l.n_len! + l.n_scale!);
|
||||
let i = k.n_len! + s;
|
||||
const b = libbcmath.safe_emalloc(1, i, 1);
|
||||
if (b === null) {
|
||||
libbcmath.bc_out_of_memory();
|
||||
}
|
||||
libbcmath.memcpy(b, 0, k.n_value!, 0, i);
|
||||
b[i] = 0;
|
||||
h = 0;
|
||||
while (b[h] === 0) {
|
||||
h++;
|
||||
i--;
|
||||
}
|
||||
let q: number;
|
||||
let n: boolean;
|
||||
if (i > j + z) {
|
||||
q = z + 1;
|
||||
n = true;
|
||||
} else {
|
||||
n = false;
|
||||
if (i > j) {
|
||||
q = z + 1;
|
||||
} else {
|
||||
q = j - i + z + 1;
|
||||
}
|
||||
}
|
||||
w = libbcmath.bc_new_num(q - z, z);
|
||||
libbcmath.memset(w.n_value!, 0, 0, q);
|
||||
const e = libbcmath.safe_emalloc(1, i, 1);
|
||||
if (e === null) {
|
||||
libbcmath.bc_out_of_memory();
|
||||
}
|
||||
if (!n) {
|
||||
const f = Math.floor(10 / (k.n_value![h] + 1));
|
||||
if (f !== 1) {
|
||||
libbcmath._one_mult(c, 0, j + u + a + 1, f, c, 0);
|
||||
libbcmath._one_mult(k.n_value!, h, i, f, k.n_value!, h);
|
||||
}
|
||||
let r = 0;
|
||||
let x: number;
|
||||
if (i > j) {
|
||||
x = i - j;
|
||||
} else {
|
||||
x = 0;
|
||||
}
|
||||
while (r <= j + z - i) {
|
||||
let m: number;
|
||||
if (k.n_value![h] === c[r]) {
|
||||
m = 9;
|
||||
} else {
|
||||
m = Math.floor((c[r] * 10 + c[r + 1]) / k.n_value![h]);
|
||||
}
|
||||
if (
|
||||
k.n_value![h + 1] * m >
|
||||
(c[r] * 10 + c[r + 1] - k.n_value![h] * m) * 10 + c[r + 2]
|
||||
) {
|
||||
m--;
|
||||
if (
|
||||
k.n_value![h + 1] * m >
|
||||
(c[r] * 10 + c[r + 1] - k.n_value![h] * m) * 10 + c[r + 2]
|
||||
) {
|
||||
m--;
|
||||
}
|
||||
}
|
||||
let t = 0;
|
||||
if (m !== 0) {
|
||||
e[0] = 0;
|
||||
libbcmath._one_mult(k.n_value!, h, i, m, e, 1);
|
||||
let p = r + i;
|
||||
let o = i;
|
||||
for (let g = 0; g < i + 1; g++) {
|
||||
let A: number;
|
||||
if (o < 0) {
|
||||
A = c[p] - 0 - t;
|
||||
} else {
|
||||
A = c[p] - e[o--] - t;
|
||||
}
|
||||
if (A < 0) {
|
||||
A += 10;
|
||||
t = 1;
|
||||
} else {
|
||||
t = 0;
|
||||
}
|
||||
c[p--] = A;
|
||||
}
|
||||
}
|
||||
if (t === 1) {
|
||||
m--;
|
||||
let p = r + i;
|
||||
let o = i - 1;
|
||||
let v = 0;
|
||||
for (let g = 0; g < i; g++) {
|
||||
let A: number;
|
||||
if (o < 0) {
|
||||
A = c[p] + 0 + v;
|
||||
} else {
|
||||
A = c[p] + k.n_value![o--] + v;
|
||||
}
|
||||
if (A > 9) {
|
||||
A -= 10;
|
||||
v = 1;
|
||||
} else {
|
||||
v = 0;
|
||||
}
|
||||
c[p--] = A;
|
||||
}
|
||||
if (v === 1) {
|
||||
c[p] = (c[p] + 1) % 10;
|
||||
}
|
||||
}
|
||||
w.n_value![x++] = m;
|
||||
r++;
|
||||
}
|
||||
}
|
||||
w.n_sign = l.n_sign === k.n_sign ? libbcmath.PLUS : libbcmath.MINUS;
|
||||
if (libbcmath.bc_is_zero(w)) {
|
||||
w.n_sign = libbcmath.PLUS;
|
||||
}
|
||||
libbcmath._bc_rm_leading_zeros(w);
|
||||
return w;
|
||||
},
|
||||
_bc_do_add: function (h: BCNum, g: BCNum, i: number): BCNum {
|
||||
const c = libbcmath.MAX(h.n_scale!, g.n_scale!);
|
||||
const b = libbcmath.MAX(h.n_len!, g.n_len!) + 1;
|
||||
const f = libbcmath.bc_new_num(b, libbcmath.MAX(c, i));
|
||||
let l = h.n_scale!;
|
||||
let a = g.n_scale!;
|
||||
let k = h.n_len! + l - 1;
|
||||
let e = g.n_len! + a - 1;
|
||||
let j = c + b - 1;
|
||||
if (l !== a) {
|
||||
if (l > a) {
|
||||
while (l > a) {
|
||||
f.n_value![j--] = h.n_value![k--];
|
||||
l--;
|
||||
}
|
||||
} else {
|
||||
while (a > l) {
|
||||
f.n_value![j--] = g.n_value![e--];
|
||||
a--;
|
||||
}
|
||||
}
|
||||
}
|
||||
l += h.n_len!;
|
||||
a += g.n_len!;
|
||||
let m = 0;
|
||||
while (l > 0 && a > 0) {
|
||||
let d = h.n_value![k--] + g.n_value![e--] + m;
|
||||
if (d >= libbcmath.BASE) {
|
||||
m = 1;
|
||||
d -= libbcmath.BASE;
|
||||
} else {
|
||||
m = 0;
|
||||
}
|
||||
f.n_value![j] = d;
|
||||
j--;
|
||||
l--;
|
||||
a--;
|
||||
}
|
||||
if (l === 0) {
|
||||
while (a-- > 0) {
|
||||
let d = g.n_value![e--] + m;
|
||||
if (d >= libbcmath.BASE) {
|
||||
m = 1;
|
||||
d -= libbcmath.BASE;
|
||||
} else {
|
||||
m = 0;
|
||||
}
|
||||
f.n_value![j--] = d;
|
||||
}
|
||||
} else {
|
||||
while (l-- > 0) {
|
||||
let d = h.n_value![k--] + m;
|
||||
if (d >= libbcmath.BASE) {
|
||||
m = 1;
|
||||
d -= libbcmath.BASE;
|
||||
} else {
|
||||
m = 0;
|
||||
}
|
||||
f.n_value![j--] = d;
|
||||
}
|
||||
}
|
||||
if (m === 1) {
|
||||
f.n_value![j] += 1;
|
||||
}
|
||||
libbcmath._bc_rm_leading_zeros(f);
|
||||
return f;
|
||||
},
|
||||
_bc_do_sub: function (h: BCNum, g: BCNum, i: number): BCNum {
|
||||
const a = libbcmath.MAX(h.n_len!, g.n_len!);
|
||||
const m = libbcmath.MAX(h.n_scale!, g.n_scale!);
|
||||
const f = libbcmath.MIN(h.n_len!, g.n_len!);
|
||||
const d = libbcmath.MIN(h.n_scale!, g.n_scale!);
|
||||
const l = libbcmath.bc_new_num(a, libbcmath.MAX(m, i));
|
||||
let k = h.n_len! + h.n_scale! - 1;
|
||||
let c = g.n_len! + g.n_scale! - 1;
|
||||
let n = a + m - 1;
|
||||
let j = 0;
|
||||
if (h.n_scale !== d) {
|
||||
for (let e = h.n_scale! - d; e > 0; e--) {
|
||||
l.n_value![n--] = h.n_value![k--];
|
||||
}
|
||||
} else {
|
||||
for (let e = g.n_scale! - d; e > 0; e--) {
|
||||
let b = 0 - g.n_value![c--] - j;
|
||||
if (b < 0) {
|
||||
b += libbcmath.BASE;
|
||||
j = 1;
|
||||
} else {
|
||||
j = 0;
|
||||
}
|
||||
l.n_value![n--] = b;
|
||||
}
|
||||
}
|
||||
for (let e = 0; e < f + d; e++) {
|
||||
let b = h.n_value![k--] - g.n_value![c--] - j;
|
||||
if (b < 0) {
|
||||
b += libbcmath.BASE;
|
||||
j = 1;
|
||||
} else {
|
||||
j = 0;
|
||||
}
|
||||
l.n_value![n--] = b;
|
||||
}
|
||||
if (a !== f) {
|
||||
for (let e = a - f; e > 0; e--) {
|
||||
let b = h.n_value![k--] - j;
|
||||
if (b < 0) {
|
||||
b += libbcmath.BASE;
|
||||
j = 1;
|
||||
} else {
|
||||
j = 0;
|
||||
}
|
||||
l.n_value![n--] = b;
|
||||
}
|
||||
}
|
||||
libbcmath._bc_rm_leading_zeros(l);
|
||||
return l;
|
||||
},
|
||||
MUL_BASE_DIGITS: 80,
|
||||
MUL_SMALL_DIGITS: 0,
|
||||
bc_multiply: function (f: BCNum, d: BCNum, h: number): BCNum {
|
||||
const b = f.n_len! + f.n_scale!;
|
||||
const a = d.n_len! + d.n_scale!;
|
||||
const g = f.n_scale! + d.n_scale!;
|
||||
const e = libbcmath.MIN(
|
||||
g,
|
||||
libbcmath.MAX(h, libbcmath.MAX(f.n_scale!, d.n_scale!))
|
||||
);
|
||||
const c = libbcmath._bc_rec_mul(f, b, d, a, g);
|
||||
c.n_sign = f.n_sign === d.n_sign ? libbcmath.PLUS : libbcmath.MINUS;
|
||||
c.n_len = a + b + 1 - g;
|
||||
c.n_scale = e;
|
||||
libbcmath._bc_rm_leading_zeros(c);
|
||||
if (libbcmath.bc_is_zero(c)) {
|
||||
c.n_sign = libbcmath.PLUS;
|
||||
}
|
||||
return c;
|
||||
},
|
||||
new_sub_num: function (b: number, d: number, c: number[]): BCNum {
|
||||
const a = new libbcmath.bc_num();
|
||||
a.n_sign = libbcmath.PLUS;
|
||||
a.n_len = b;
|
||||
a.n_scale = d;
|
||||
a.n_value = c;
|
||||
return a;
|
||||
},
|
||||
_bc_simp_mul: function (
|
||||
i: BCNum,
|
||||
b: number,
|
||||
h: BCNum,
|
||||
m: number,
|
||||
a: number
|
||||
): BCNum {
|
||||
const d = b + m + 1;
|
||||
const j = libbcmath.bc_new_num(d, 0);
|
||||
const n = b - 1;
|
||||
const l = m - 1;
|
||||
let f = d - 1;
|
||||
let g = 0;
|
||||
for (let e = 0; e < d - 1; e++) {
|
||||
const k = n - libbcmath.MAX(0, e - m + 1);
|
||||
const c = l - libbcmath.MIN(e, m - 1);
|
||||
let kIdx = k;
|
||||
let cIdx = c;
|
||||
while (kIdx >= 0 && cIdx <= l) {
|
||||
g += i.n_value![kIdx--] * h.n_value![cIdx++];
|
||||
}
|
||||
j.n_value![f--] = Math.floor(g % libbcmath.BASE);
|
||||
g = Math.floor(g / libbcmath.BASE);
|
||||
}
|
||||
j.n_value![f] = g;
|
||||
return j;
|
||||
},
|
||||
_bc_shift_addsub: function (
|
||||
b: BCNum,
|
||||
g: BCNum,
|
||||
a: number,
|
||||
d: boolean
|
||||
): boolean {
|
||||
let e = g.n_len!;
|
||||
if (g.n_value![0] === 0) {
|
||||
e--;
|
||||
}
|
||||
if (!(b.n_len! + b.n_scale! >= a + e)) {
|
||||
throw new Error("len + scale < shift + count");
|
||||
}
|
||||
let c = b.n_len! + b.n_scale! - a - 1;
|
||||
let h = g.n_len! - 1;
|
||||
let f = 0;
|
||||
if (d) {
|
||||
while (e--) {
|
||||
b.n_value![c] -= g.n_value![h--] + f;
|
||||
if (b.n_value![c] < 0) {
|
||||
f = 1;
|
||||
b.n_value![c--] += libbcmath.BASE;
|
||||
} else {
|
||||
f = 0;
|
||||
c--;
|
||||
}
|
||||
}
|
||||
while (f) {
|
||||
b.n_value![c] -= f;
|
||||
if (b.n_value![c] < 0) {
|
||||
b.n_value![c--] += libbcmath.BASE;
|
||||
} else {
|
||||
f = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (e--) {
|
||||
b.n_value![c] += g.n_value![h--] + f;
|
||||
if (b.n_value![c] > libbcmath.BASE - 1) {
|
||||
f = 1;
|
||||
b.n_value![c--] -= libbcmath.BASE;
|
||||
} else {
|
||||
f = 0;
|
||||
c--;
|
||||
}
|
||||
}
|
||||
while (f) {
|
||||
b.n_value![c] += f;
|
||||
if (b.n_value![c] > libbcmath.BASE - 1) {
|
||||
b.n_value![c--] -= libbcmath.BASE;
|
||||
} else {
|
||||
f = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
_bc_rec_mul: function (
|
||||
m: BCNum,
|
||||
i: number,
|
||||
l: BCNum,
|
||||
j: number,
|
||||
c: number
|
||||
): BCNum {
|
||||
if (
|
||||
i + j < libbcmath.MUL_BASE_DIGITS ||
|
||||
i < libbcmath.MUL_SMALL_DIGITS ||
|
||||
j < libbcmath.MUL_SMALL_DIGITS
|
||||
) {
|
||||
return libbcmath._bc_simp_mul(m, i, l, j, c);
|
||||
}
|
||||
const o = Math.floor((libbcmath.MAX(i, j) + 1) / 2);
|
||||
let r: BCNum, s: BCNum;
|
||||
if (i < o) {
|
||||
r = libbcmath.bc_init_num();
|
||||
s = libbcmath.new_sub_num(i, 0, m.n_value!);
|
||||
} else {
|
||||
r = libbcmath.new_sub_num(i - o, 0, m.n_value!);
|
||||
s = libbcmath.new_sub_num(o, 0, m.n_value!.slice(i - o));
|
||||
}
|
||||
let g: BCNum, h: BCNum;
|
||||
if (j < o) {
|
||||
g = libbcmath.bc_init_num();
|
||||
h = libbcmath.new_sub_num(j, 0, l.n_value!);
|
||||
} else {
|
||||
g = libbcmath.new_sub_num(j - o, 0, l.n_value!);
|
||||
h = libbcmath.new_sub_num(o, 0, l.n_value!.slice(j - o));
|
||||
}
|
||||
libbcmath._bc_rm_leading_zeros(r);
|
||||
libbcmath._bc_rm_leading_zeros(s);
|
||||
const f = s.n_len!;
|
||||
libbcmath._bc_rm_leading_zeros(g);
|
||||
libbcmath._bc_rm_leading_zeros(h);
|
||||
const p = h.n_len!;
|
||||
const e = libbcmath.bc_is_zero(r) || libbcmath.bc_is_zero(g);
|
||||
const y = libbcmath.bc_sub(r, s, 0);
|
||||
const q = y.n_len!;
|
||||
const x = libbcmath.bc_sub(h, g, 0);
|
||||
const t = x.n_len!;
|
||||
let d: BCNum;
|
||||
if (e) {
|
||||
d = libbcmath.bc_init_num();
|
||||
} else {
|
||||
d = libbcmath._bc_rec_mul(r, r.n_len!, g, g.n_len!, 0);
|
||||
}
|
||||
let b: BCNum;
|
||||
if (libbcmath.bc_is_zero(y) || libbcmath.bc_is_zero(x)) {
|
||||
b = libbcmath.bc_init_num();
|
||||
} else {
|
||||
b = libbcmath._bc_rec_mul(y, q, x, t, 0);
|
||||
}
|
||||
let a: BCNum;
|
||||
if (libbcmath.bc_is_zero(s) || libbcmath.bc_is_zero(h)) {
|
||||
a = libbcmath.bc_init_num();
|
||||
} else {
|
||||
a = libbcmath._bc_rec_mul(s, s.n_len!, h, h.n_len!, 0);
|
||||
}
|
||||
const w = i + j + 1;
|
||||
const k = libbcmath.bc_new_num(w, 0);
|
||||
if (!e) {
|
||||
libbcmath._bc_shift_addsub(k, d, 2 * o, false);
|
||||
libbcmath._bc_shift_addsub(k, d, o, false);
|
||||
}
|
||||
libbcmath._bc_shift_addsub(k, a, o, false);
|
||||
libbcmath._bc_shift_addsub(k, a, 0, false);
|
||||
libbcmath._bc_shift_addsub(k, b, o, y.n_sign !== x.n_sign);
|
||||
return k;
|
||||
},
|
||||
bc_sub: function (e: BCNum, d: BCNum, c: number): BCNum {
|
||||
let f: BCNum;
|
||||
if (e.n_sign !== d.n_sign) {
|
||||
f = libbcmath._bc_do_add(e, d, c);
|
||||
f.n_sign = e.n_sign;
|
||||
} else {
|
||||
const b = libbcmath._bc_do_compare(e, d, false, false);
|
||||
switch (b) {
|
||||
case -1:
|
||||
f = libbcmath._bc_do_sub(d, e, c);
|
||||
f.n_sign =
|
||||
d.n_sign === libbcmath.PLUS ? libbcmath.MINUS : libbcmath.PLUS;
|
||||
break;
|
||||
case 0:
|
||||
const a = libbcmath.MAX(c, libbcmath.MAX(e.n_scale!, d.n_scale!));
|
||||
f = libbcmath.bc_new_num(1, a);
|
||||
libbcmath.memset(f.n_value!, 0, 0, a + 1);
|
||||
break;
|
||||
case 1:
|
||||
f = libbcmath._bc_do_sub(e, d, c);
|
||||
f.n_sign = e.n_sign;
|
||||
break;
|
||||
default:
|
||||
f = libbcmath.bc_init_num();
|
||||
}
|
||||
}
|
||||
return f;
|
||||
},
|
||||
};
|
||||
|
||||
libbcmath.MUL_SMALL_DIGITS = libbcmath.MUL_BASE_DIGITS / 4;
|
||||
|
||||
export function bcadd(b: BCNumValue, d: BCNumValue, f?: number): string {
|
||||
if (typeof f === "undefined") {
|
||||
f = libbcmath.scale;
|
||||
}
|
||||
f = f < 0 ? 0 : f;
|
||||
let e = libbcmath.php_str2num(b.toString());
|
||||
let c = libbcmath.php_str2num(d.toString());
|
||||
if (e.n_scale! > c.n_scale!) {
|
||||
c.setScale(e.n_scale!);
|
||||
}
|
||||
if (c.n_scale! > e.n_scale!) {
|
||||
e.setScale(c.n_scale!);
|
||||
}
|
||||
let a = libbcmath.bc_add(e, c, f);
|
||||
if (a.n_scale! > f) {
|
||||
a.n_scale = f;
|
||||
}
|
||||
return a.toString();
|
||||
}
|
||||
|
||||
export function bcsub(b: BCNumValue, d: BCNumValue, f?: number): string {
|
||||
if (typeof f === "undefined") {
|
||||
f = libbcmath.scale;
|
||||
}
|
||||
f = f < 0 ? 0 : f;
|
||||
let e = libbcmath.php_str2num(b.toString());
|
||||
let c = libbcmath.php_str2num(d.toString());
|
||||
if (e.n_scale! > c.n_scale!) {
|
||||
c.setScale(e.n_scale!);
|
||||
}
|
||||
if (c.n_scale! > e.n_scale!) {
|
||||
e.setScale(c.n_scale!);
|
||||
}
|
||||
let a = libbcmath.bc_sub(e, c, f);
|
||||
if (a.n_scale! > f) {
|
||||
a.n_scale = f;
|
||||
}
|
||||
return a.toString();
|
||||
}
|
||||
|
||||
export function bccomp(a: BCNumValue, c: BCNumValue, e?: number): number {
|
||||
if (typeof e === "undefined") {
|
||||
e = libbcmath.scale;
|
||||
}
|
||||
e = e < 0 ? 0 : e;
|
||||
const d = libbcmath.bc_str2num(a.toString(), e);
|
||||
const b = libbcmath.bc_str2num(c.toString(), e);
|
||||
return libbcmath.bc_compare(d, b);
|
||||
}
|
||||
|
||||
export function bcscale(a: number): boolean {
|
||||
const parsedScale = parseInt(a.toString(), 10);
|
||||
if (isNaN(parsedScale)) {
|
||||
return false;
|
||||
}
|
||||
if (parsedScale < 0) {
|
||||
return false;
|
||||
}
|
||||
libbcmath.scale = parsedScale;
|
||||
return true;
|
||||
}
|
||||
|
||||
export function bcdiv(b: BCNumValue, d: BCNumValue, f?: number): string {
|
||||
if (typeof f === "undefined") {
|
||||
f = libbcmath.scale;
|
||||
}
|
||||
f = f < 0 ? 0 : f;
|
||||
let e = libbcmath.php_str2num(b.toString());
|
||||
let c = libbcmath.php_str2num(d.toString());
|
||||
if (e.n_scale! > c.n_scale!) {
|
||||
c.setScale(e.n_scale!);
|
||||
}
|
||||
if (c.n_scale! > e.n_scale!) {
|
||||
e.setScale(c.n_scale!);
|
||||
}
|
||||
const a = libbcmath.bc_divide(e, c, f);
|
||||
if (a === -1) {
|
||||
throw new Error("(BC) Division by zero");
|
||||
}
|
||||
if (a.n_scale! > f) {
|
||||
a.n_scale = f;
|
||||
}
|
||||
return a.toString();
|
||||
}
|
||||
|
||||
export function bcmul(b: BCNumValue, d: BCNumValue, f?: number): string {
|
||||
if (typeof f === "undefined") {
|
||||
f = libbcmath.scale;
|
||||
}
|
||||
f = f < 0 ? 0 : f;
|
||||
let e = libbcmath.php_str2num(b.toString());
|
||||
let c = libbcmath.php_str2num(d.toString());
|
||||
if (e.n_scale! > c.n_scale!) {
|
||||
c.setScale(e.n_scale!);
|
||||
}
|
||||
if (c.n_scale! > e.n_scale!) {
|
||||
e.setScale(c.n_scale!);
|
||||
}
|
||||
let a = libbcmath.bc_multiply(e, c, f);
|
||||
if (a.n_scale! > f) {
|
||||
a.n_scale = f;
|
||||
}
|
||||
return a.toString();
|
||||
}
|
||||
|
||||
export function bcround(d: BCNumValue, b: number): string {
|
||||
let a = "0." + Array(b + 1).join("0") + "5";
|
||||
if (d.toString().substring(0, 1) === "-") {
|
||||
a = "-" + a;
|
||||
}
|
||||
const c = bcadd(d, a, b);
|
||||
return c;
|
||||
}
|
||||
1053
web-app/app/lib/pdf/pdf417.ts
Normal file
1053
web-app/app/lib/pdf/pdf417.ts
Normal file
File diff suppressed because it is too large
Load Diff
4030
web-app/app/lib/pdf/pdf417LookupTables.ts
Normal file
4030
web-app/app/lib/pdf/pdf417LookupTables.ts
Normal file
File diff suppressed because it is too large
Load Diff
51
web-app/app/lib/pdf/renderBarcode.ts
Normal file
51
web-app/app/lib/pdf/renderBarcode.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { BarcodeArray } from './pdf417';
|
||||
|
||||
/**
|
||||
* Renders a PDF417 barcode matrix to a canvas and returns it as a data URL.
|
||||
*
|
||||
* This function creates an HTML canvas element, draws the barcode by iterating through
|
||||
* the barcode matrix, and converts the canvas to a base64-encoded PNG data URL that
|
||||
* can be used as an image source.
|
||||
*
|
||||
* @param barcodeMatrix - The barcode array generated by the PDF417 encoder containing
|
||||
* the barcode matrix data with dimensions and binary code values
|
||||
* @param blockWidth - The width in pixels of each individual barcode module (bar/space unit)
|
||||
* @param blockHeight - The height in pixels of each individual barcode module (bar/space unit)
|
||||
*
|
||||
* @returns A data URL string (base64-encoded PNG) representing the rendered barcode image,
|
||||
* suitable for use in an HTML img src attribute
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const pdf417 = createPDF417();
|
||||
* pdf417.init("Hello World", 2, 2);
|
||||
* const barcodeArray = pdf417.getBarcodeArray();
|
||||
* const dataUrl = renderBarcode(barcodeArray, 2, 4);
|
||||
* // dataUrl can now be used: <img src={dataUrl} />
|
||||
* ```
|
||||
*/
|
||||
export function renderBarcode(barcodeMatrix: BarcodeArray, blockWidth: number, blockHeight: number) {
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = barcodeMatrix.num_cols * blockWidth;
|
||||
canvas.height = barcodeMatrix.num_rows * blockHeight;
|
||||
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
|
||||
|
||||
let positionY = 0;
|
||||
for (let row = 0; row < barcodeMatrix.num_rows; row += 1) {
|
||||
let positionX = 0;
|
||||
|
||||
for (let col = 0; col < barcodeMatrix.num_cols; col += 1) {
|
||||
if (barcodeMatrix.bcode[row][col] === 1) {
|
||||
ctx.fillStyle = '#000';
|
||||
} else {
|
||||
ctx.fillStyle = '#FFF';
|
||||
}
|
||||
ctx.fillRect(positionX, positionY, blockWidth, blockHeight);
|
||||
positionX += blockWidth;
|
||||
}
|
||||
positionY += blockHeight;
|
||||
}
|
||||
|
||||
return canvas.toDataURL();
|
||||
}
|
||||
Reference in New Issue
Block a user