mirror of
https://github.com/foliojs/pdfkit.git
synced 2025-12-08 20:15:54 +00:00
* Fix further LineWrapper precision issues * add test of bounded text precision issue * add rowSpanning table example * add failure threshold * implement toContainText jest matcher * create a unit test for bounded text precision * remove round up rounding code path --------- Co-authored-by: Luiz Américo Pereira Câmara <blikblum@users.noreply.github.com>
143 lines
3.6 KiB
JavaScript
143 lines
3.6 KiB
JavaScript
const fArray = new Float32Array(1);
|
|
const uArray = new Uint32Array(fArray.buffer);
|
|
|
|
export function PDFNumber(n) {
|
|
// PDF numbers are strictly 32bit
|
|
// so convert this number to a 32bit number
|
|
// @see ISO 32000-1 Annex C.2 (real numbers)
|
|
const rounded = Math.fround(n);
|
|
if (rounded <= n) return rounded;
|
|
|
|
// Will have to perform 32bit float truncation
|
|
fArray[0] = n;
|
|
|
|
// Get the 32-bit representation as integer and shift bits
|
|
if (n <= 0) {
|
|
uArray[0] += 1;
|
|
} else {
|
|
uArray[0] -= 1;
|
|
}
|
|
|
|
// Return the float value
|
|
return fArray[0];
|
|
}
|
|
|
|
/**
|
|
* Measurement of size
|
|
*
|
|
* @typedef {number | `${number}` | `${number}${'em' | 'in' | 'px' | 'cm' | 'mm' | 'pc' | 'ex' | 'ch' | 'rem' | 'vw' | 'vmin' | 'vmax' | '%' | 'pt'}`} Size
|
|
*/
|
|
|
|
/**
|
|
* @typedef {Array<PDFTilingPattern | PDFColor> | string | Array<number>} PDFColor
|
|
*/
|
|
|
|
/** @typedef {string | Buffer | Uint8Array | ArrayBuffer} PDFFontSource */
|
|
/**
|
|
* Side definitions
|
|
* - To define all sides, use a single value
|
|
* - To define up-down left-right, use a `[Y, X]` array
|
|
* - To define each side, use `[top, right, bottom, left]` array
|
|
* - Or `{vertical: SideValue, horizontal: SideValue}`
|
|
* - Or `{top: SideValue, right: SideValue, bottom: SideValue, left: SideValue}`
|
|
*
|
|
* @template T
|
|
* @typedef {T | [T, T] | [T, T, T, T] | { vertical: T; horizontal: T } | ExpandedSideDefinition<T>} SideDefinition<T>
|
|
**/
|
|
|
|
/**
|
|
* @template T
|
|
* @typedef {{ top: T; right: T; bottom: T; left: T }} ExpandedSideDefinition<T>
|
|
*/
|
|
|
|
/**
|
|
* Convert any side definition into a static structure
|
|
*
|
|
* @template S
|
|
* @template D
|
|
* @template O
|
|
* @template {S | D} T
|
|
* @param {SideDefinition<S>} sides - The sides to convert
|
|
* @param {SideDefinition<D>} defaultDefinition - The value to use when no definition is provided
|
|
* @param {function(T): O} transformer - The transformation to apply to the sides once normalized
|
|
* @returns {ExpandedSideDefinition<O>}
|
|
*/
|
|
export function normalizeSides(
|
|
sides,
|
|
defaultDefinition = undefined,
|
|
transformer = (v) => v,
|
|
) {
|
|
if (
|
|
sides == null ||
|
|
(typeof sides === 'object' && Object.keys(sides).length === 0)
|
|
) {
|
|
sides = defaultDefinition;
|
|
}
|
|
if (sides == null || typeof sides !== 'object') {
|
|
sides = { top: sides, right: sides, bottom: sides, left: sides };
|
|
} else if (Array.isArray(sides)) {
|
|
if (sides.length === 2) {
|
|
sides = { vertical: sides[0], horizontal: sides[1] };
|
|
} else {
|
|
sides = {
|
|
top: sides[0],
|
|
right: sides[1],
|
|
bottom: sides[2],
|
|
left: sides[3],
|
|
};
|
|
}
|
|
}
|
|
|
|
if ('vertical' in sides || 'horizontal' in sides) {
|
|
sides = {
|
|
top: sides.vertical,
|
|
right: sides.horizontal,
|
|
bottom: sides.vertical,
|
|
left: sides.horizontal,
|
|
};
|
|
}
|
|
|
|
return {
|
|
top: transformer(sides.top),
|
|
right: transformer(sides.right),
|
|
bottom: transformer(sides.bottom),
|
|
left: transformer(sides.left),
|
|
};
|
|
}
|
|
|
|
export const MM_TO_CM = 1 / 10; // 1MM = 1CM
|
|
export const CM_TO_IN = 1 / 2.54; // 1CM = 1/2.54 IN
|
|
export const PX_TO_IN = 1 / 96; // 1 PX = 1/96 IN
|
|
export const IN_TO_PT = 72; // 1 IN = 72 PT
|
|
export const PC_TO_PT = 12; // 1 PC = 12 PT
|
|
|
|
/**
|
|
* Get cosine in degrees of a
|
|
*
|
|
* Rounding errors are handled
|
|
* @param a
|
|
* @returns {number}
|
|
*/
|
|
export function cosine(a) {
|
|
if (a === 0) return 1;
|
|
if (a === 90) return 0;
|
|
if (a === 180) return -1;
|
|
if (a === 270) return 0;
|
|
return Math.cos((a * Math.PI) / 180);
|
|
}
|
|
|
|
/**
|
|
* Get sine in degrees of a
|
|
*
|
|
* Rounding errors are handled
|
|
* @param a
|
|
* @returns {number}
|
|
*/
|
|
export function sine(a) {
|
|
if (a === 0) return 0;
|
|
if (a === 90) return 1;
|
|
if (a === 180) return 0;
|
|
if (a === 270) return -1;
|
|
return Math.sin((a * Math.PI) / 180);
|
|
}
|