@cj-tech-master/excelts 9.1.0 → 9.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -1
- package/dist/browser/modules/archive/compression/crc32.js +1 -1
- package/dist/browser/modules/archive/crypto/aes.d.ts +0 -8
- package/dist/browser/modules/archive/crypto/aes.js +1 -20
- package/dist/browser/modules/archive/crypto/index.d.ts +2 -1
- package/dist/browser/modules/archive/crypto/index.js +3 -1
- package/dist/browser/modules/csv/parse/row-processor.d.ts +1 -1
- package/dist/browser/modules/csv/worker/worker-script.generated.js +1 -1
- package/dist/browser/modules/excel/utils/cell-matrix.js +1 -0
- package/dist/browser/modules/excel/utils/encryptor.browser.d.ts +4 -5
- package/dist/browser/modules/excel/utils/encryptor.browser.js +7 -12
- package/dist/browser/modules/excel/utils/encryptor.d.ts +1 -1
- package/dist/browser/modules/excel/utils/encryptor.js +4 -7
- package/dist/browser/modules/pdf/builder/document-builder.d.ts +517 -0
- package/dist/browser/modules/pdf/builder/document-builder.js +1493 -0
- package/dist/browser/modules/pdf/builder/form-appearance.d.ts +56 -0
- package/dist/browser/modules/pdf/builder/form-appearance.js +140 -0
- package/dist/browser/modules/pdf/builder/image-utils.d.ts +39 -0
- package/dist/browser/modules/pdf/builder/image-utils.js +129 -0
- package/dist/browser/modules/pdf/builder/pdf-editor.d.ts +230 -0
- package/dist/browser/modules/pdf/builder/pdf-editor.js +1574 -0
- package/dist/browser/modules/pdf/builder/resource-merger.d.ts +41 -0
- package/dist/browser/modules/pdf/builder/resource-merger.js +258 -0
- package/dist/browser/modules/pdf/core/digital-signature.d.ts +109 -0
- package/dist/browser/modules/pdf/core/digital-signature.js +659 -0
- package/dist/browser/modules/pdf/core/encryption.js +8 -7
- package/dist/browser/modules/pdf/core/pdf-object.d.ts +11 -0
- package/dist/browser/modules/pdf/core/pdf-object.js +38 -0
- package/dist/browser/modules/pdf/core/pdf-stream.d.ts +32 -0
- package/dist/browser/modules/pdf/core/pdf-stream.js +66 -0
- package/dist/browser/modules/pdf/core/pdf-writer.d.ts +55 -1
- package/dist/browser/modules/pdf/core/pdf-writer.js +271 -6
- package/dist/browser/modules/pdf/core/pdfa.d.ts +62 -0
- package/dist/browser/modules/pdf/core/pdfa.js +261 -0
- package/dist/browser/modules/pdf/index.d.ts +11 -0
- package/dist/browser/modules/pdf/index.js +9 -0
- package/dist/browser/modules/pdf/reader/bookmark-extractor.d.ts +35 -0
- package/dist/browser/modules/pdf/reader/bookmark-extractor.js +324 -0
- package/dist/browser/modules/pdf/reader/pdf-decrypt.js +6 -5
- package/dist/browser/modules/pdf/reader/pdf-reader.d.ts +17 -0
- package/dist/browser/modules/pdf/reader/pdf-reader.js +26 -2
- package/dist/browser/modules/pdf/reader/table-extractor.d.ts +69 -0
- package/dist/browser/modules/pdf/reader/table-extractor.js +365 -0
- package/dist/browser/modules/pdf/render/layout-engine.d.ts +21 -1
- package/dist/browser/modules/pdf/render/layout-engine.js +112 -5
- package/dist/browser/modules/pdf/render/page-renderer.d.ts +2 -9
- package/dist/browser/modules/pdf/render/page-renderer.js +62 -103
- package/dist/browser/modules/pdf/render/pdf-exporter.js +2 -61
- package/dist/browser/modules/pdf/render/style-converter.d.ts +4 -0
- package/dist/browser/modules/pdf/render/style-converter.js +1 -1
- package/dist/browser/modules/pdf/types.d.ts +14 -1
- package/dist/browser/modules/stream/browser/readable.js +8 -2
- package/dist/browser/utils/crypto.browser.d.ts +64 -0
- package/dist/browser/{modules/pdf/core/crypto.js → utils/crypto.browser.js} +91 -101
- package/dist/browser/utils/crypto.d.ts +97 -0
- package/dist/browser/utils/crypto.js +209 -0
- package/dist/cjs/modules/archive/compression/crc32.js +1 -1
- package/dist/cjs/modules/archive/crypto/aes.js +2 -23
- package/dist/cjs/modules/archive/crypto/index.js +3 -1
- package/dist/cjs/modules/csv/worker/worker-script.generated.js +1 -1
- package/dist/cjs/modules/excel/utils/cell-matrix.js +1 -0
- package/dist/cjs/modules/excel/utils/encryptor.browser.js +7 -12
- package/dist/cjs/modules/excel/utils/encryptor.js +4 -10
- package/dist/cjs/modules/pdf/builder/document-builder.js +1532 -0
- package/dist/cjs/modules/pdf/builder/form-appearance.js +145 -0
- package/dist/cjs/modules/pdf/builder/image-utils.js +135 -0
- package/dist/cjs/modules/pdf/builder/pdf-editor.js +1612 -0
- package/dist/cjs/modules/pdf/builder/resource-merger.js +263 -0
- package/dist/cjs/modules/pdf/core/digital-signature.js +667 -0
- package/dist/cjs/modules/pdf/core/encryption.js +8 -7
- package/dist/cjs/modules/pdf/core/pdf-object.js +38 -0
- package/dist/cjs/modules/pdf/core/pdf-stream.js +66 -0
- package/dist/cjs/modules/pdf/core/pdf-writer.js +272 -6
- package/dist/cjs/modules/pdf/core/pdfa.js +266 -0
- package/dist/cjs/modules/pdf/index.js +19 -1
- package/dist/cjs/modules/pdf/reader/bookmark-extractor.js +327 -0
- package/dist/cjs/modules/pdf/reader/pdf-decrypt.js +6 -5
- package/dist/cjs/modules/pdf/reader/pdf-reader.js +26 -2
- package/dist/cjs/modules/pdf/reader/table-extractor.js +368 -0
- package/dist/cjs/modules/pdf/render/layout-engine.js +113 -4
- package/dist/cjs/modules/pdf/render/page-renderer.js +63 -105
- package/dist/cjs/modules/pdf/render/pdf-exporter.js +3 -62
- package/dist/cjs/modules/pdf/render/style-converter.js +1 -0
- package/dist/cjs/modules/stream/browser/readable.js +8 -2
- package/dist/cjs/{modules/pdf/core/crypto.js → utils/crypto.browser.js} +95 -102
- package/dist/cjs/utils/crypto.js +228 -0
- package/dist/esm/modules/archive/compression/crc32.js +1 -1
- package/dist/esm/modules/archive/crypto/aes.js +1 -20
- package/dist/esm/modules/archive/crypto/index.js +3 -1
- package/dist/esm/modules/csv/worker/worker-script.generated.js +1 -1
- package/dist/esm/modules/excel/utils/cell-matrix.js +1 -0
- package/dist/esm/modules/excel/utils/encryptor.browser.js +7 -12
- package/dist/esm/modules/excel/utils/encryptor.js +4 -7
- package/dist/esm/modules/pdf/builder/document-builder.js +1493 -0
- package/dist/esm/modules/pdf/builder/form-appearance.js +140 -0
- package/dist/esm/modules/pdf/builder/image-utils.js +129 -0
- package/dist/esm/modules/pdf/builder/pdf-editor.js +1574 -0
- package/dist/esm/modules/pdf/builder/resource-merger.js +258 -0
- package/dist/esm/modules/pdf/core/digital-signature.js +659 -0
- package/dist/esm/modules/pdf/core/encryption.js +8 -7
- package/dist/esm/modules/pdf/core/pdf-object.js +38 -0
- package/dist/esm/modules/pdf/core/pdf-stream.js +66 -0
- package/dist/esm/modules/pdf/core/pdf-writer.js +271 -6
- package/dist/esm/modules/pdf/core/pdfa.js +261 -0
- package/dist/esm/modules/pdf/index.js +9 -0
- package/dist/esm/modules/pdf/reader/bookmark-extractor.js +324 -0
- package/dist/esm/modules/pdf/reader/pdf-decrypt.js +6 -5
- package/dist/esm/modules/pdf/reader/pdf-reader.js +26 -2
- package/dist/esm/modules/pdf/reader/table-extractor.js +365 -0
- package/dist/esm/modules/pdf/render/layout-engine.js +112 -5
- package/dist/esm/modules/pdf/render/page-renderer.js +62 -103
- package/dist/esm/modules/pdf/render/pdf-exporter.js +2 -61
- package/dist/esm/modules/pdf/render/style-converter.js +1 -1
- package/dist/esm/modules/stream/browser/readable.js +8 -2
- package/dist/esm/{modules/pdf/core/crypto.js → utils/crypto.browser.js} +91 -101
- package/dist/esm/utils/crypto.js +209 -0
- package/dist/iife/excelts.iife.js +1248 -1074
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +53 -54
- package/dist/types/modules/archive/crypto/aes.d.ts +0 -8
- package/dist/types/modules/archive/crypto/index.d.ts +2 -1
- package/dist/types/modules/csv/parse/row-processor.d.ts +1 -1
- package/dist/types/modules/excel/utils/encryptor.browser.d.ts +4 -5
- package/dist/types/modules/excel/utils/encryptor.d.ts +1 -1
- package/dist/types/modules/pdf/builder/document-builder.d.ts +517 -0
- package/dist/types/modules/pdf/builder/form-appearance.d.ts +56 -0
- package/dist/types/modules/pdf/builder/image-utils.d.ts +39 -0
- package/dist/types/modules/pdf/builder/pdf-editor.d.ts +230 -0
- package/dist/types/modules/pdf/builder/resource-merger.d.ts +41 -0
- package/dist/types/modules/pdf/core/digital-signature.d.ts +109 -0
- package/dist/types/modules/pdf/core/pdf-object.d.ts +11 -0
- package/dist/types/modules/pdf/core/pdf-stream.d.ts +32 -0
- package/dist/types/modules/pdf/core/pdf-writer.d.ts +55 -1
- package/dist/types/modules/pdf/core/pdfa.d.ts +62 -0
- package/dist/types/modules/pdf/index.d.ts +11 -0
- package/dist/types/modules/pdf/reader/bookmark-extractor.d.ts +35 -0
- package/dist/types/modules/pdf/reader/pdf-reader.d.ts +17 -0
- package/dist/types/modules/pdf/reader/table-extractor.d.ts +69 -0
- package/dist/types/modules/pdf/render/layout-engine.d.ts +21 -1
- package/dist/types/modules/pdf/render/page-renderer.d.ts +2 -9
- package/dist/types/modules/pdf/render/style-converter.d.ts +4 -0
- package/dist/types/modules/pdf/types.d.ts +14 -1
- package/dist/types/utils/crypto.browser.d.ts +64 -0
- package/dist/types/utils/crypto.d.ts +97 -0
- package/package.json +110 -111
- package/dist/browser/modules/pdf/core/crypto.d.ts +0 -65
- package/dist/types/modules/pdf/core/crypto.d.ts +0 -65
|
@@ -12,6 +12,15 @@
|
|
|
12
12
|
import { PdfContentStream } from "../core/pdf-stream.js";
|
|
13
13
|
import { resolvePdfFontName } from "../font/font-manager.js";
|
|
14
14
|
import { CELL_PADDING_H, CELL_PADDING_V, LINE_HEIGHT_FACTOR, INDENT_WIDTH } from "./constants.js";
|
|
15
|
+
import { parseImageDimensions } from "../builder/image-utils.js";
|
|
16
|
+
function computeCellPadding(cell, scaleFactor = 1) {
|
|
17
|
+
return {
|
|
18
|
+
left: (CELL_PADDING_H + cell.borderInsets.left) * scaleFactor,
|
|
19
|
+
right: (CELL_PADDING_H + cell.borderInsets.right) * scaleFactor,
|
|
20
|
+
top: (CELL_PADDING_V + cell.borderInsets.top) * scaleFactor,
|
|
21
|
+
bottom: (CELL_PADDING_V + cell.borderInsets.bottom) * scaleFactor
|
|
22
|
+
};
|
|
23
|
+
}
|
|
15
24
|
/**
|
|
16
25
|
* Render a single page to a PDF content stream.
|
|
17
26
|
*/
|
|
@@ -187,10 +196,9 @@ function drawCellText(stream, cell, fontManager, alphaValues, scaleFactor = 1) {
|
|
|
187
196
|
if (!text && !cell.richText) {
|
|
188
197
|
return;
|
|
189
198
|
}
|
|
190
|
-
const
|
|
191
|
-
const
|
|
192
|
-
const
|
|
193
|
-
const availHeight = rect.height - padV * 2;
|
|
199
|
+
const pad = computeCellPadding(cell, scaleFactor);
|
|
200
|
+
const availWidth = rect.width - pad.left - pad.right;
|
|
201
|
+
const availHeight = rect.height - pad.top - pad.bottom;
|
|
194
202
|
if (availWidth <= 0 || availHeight <= 0) {
|
|
195
203
|
return;
|
|
196
204
|
}
|
|
@@ -248,7 +256,7 @@ function drawCellText(stream, cell, fontManager, alphaValues, scaleFactor = 1) {
|
|
|
248
256
|
const lineHeight = fontSize * LINE_HEIGHT_FACTOR;
|
|
249
257
|
const ascent = fontManager.getFontAscent(resourceName, fontSize);
|
|
250
258
|
const totalTextHeight = lines.length * lineHeight;
|
|
251
|
-
const textStartY = computeTextStartY(verticalAlign, rect, totalTextHeight, ascent,
|
|
259
|
+
const textStartY = computeTextStartY(verticalAlign, rect, totalTextHeight, ascent, pad.top, pad.bottom);
|
|
252
260
|
stream.setFillColor(cell.textColor);
|
|
253
261
|
stream.beginText();
|
|
254
262
|
stream.setFont(resourceName, fontSize);
|
|
@@ -256,7 +264,7 @@ function drawCellText(stream, cell, fontManager, alphaValues, scaleFactor = 1) {
|
|
|
256
264
|
const line = lines[i];
|
|
257
265
|
const lineY = textStartY - i * lineHeight;
|
|
258
266
|
const textWidth = measure(line);
|
|
259
|
-
const textX = computeTextX(horizontalAlign, rect, textWidth, indentPts,
|
|
267
|
+
const textX = computeTextX(horizontalAlign, rect, textWidth, indentPts, pad.left, pad.right);
|
|
260
268
|
stream.setTextMatrix(1, 0, 0, 1, textX, lineY);
|
|
261
269
|
const hexEncoded = fontManager.encodeText(line, resourceName);
|
|
262
270
|
if (hexEncoded) {
|
|
@@ -267,7 +275,7 @@ function drawCellText(stream, cell, fontManager, alphaValues, scaleFactor = 1) {
|
|
|
267
275
|
}
|
|
268
276
|
}
|
|
269
277
|
stream.endText();
|
|
270
|
-
drawTextDecorations(stream, cell, lines, lineHeight, textStartY, measure, resourceName, fontManager, indentPts);
|
|
278
|
+
drawTextDecorations(stream, cell, lines, lineHeight, textStartY, measure, resourceName, fontManager, indentPts, pad);
|
|
271
279
|
stream.restore();
|
|
272
280
|
}
|
|
273
281
|
// =============================================================================
|
|
@@ -276,8 +284,7 @@ function drawCellText(stream, cell, fontManager, alphaValues, scaleFactor = 1) {
|
|
|
276
284
|
function drawRichText(stream, cell, fontManager, indentPts, scaleFactor = 1) {
|
|
277
285
|
const { rect, horizontalAlign, verticalAlign, wrapText } = cell;
|
|
278
286
|
const runs = cell.richText;
|
|
279
|
-
const
|
|
280
|
-
const padV = CELL_PADDING_V * scaleFactor;
|
|
287
|
+
const pad = computeCellPadding(cell, scaleFactor);
|
|
281
288
|
// Use the largest font size across all runs for line height calculation
|
|
282
289
|
let maxFontSize = cell.fontSize;
|
|
283
290
|
for (const run of runs) {
|
|
@@ -294,7 +301,7 @@ function drawRichText(stream, cell, fontManager, indentPts, scaleFactor = 1) {
|
|
|
294
301
|
: fontManager.ensureFont(resolvePdfFontName(run.fontFamily, run.bold, run.italic));
|
|
295
302
|
// --- Wrapping path ---
|
|
296
303
|
if (wrapText) {
|
|
297
|
-
const availWidth = rect.width -
|
|
304
|
+
const availWidth = rect.width - pad.left - pad.right - indentPts;
|
|
298
305
|
if (availWidth <= 0) {
|
|
299
306
|
return;
|
|
300
307
|
}
|
|
@@ -313,7 +320,7 @@ function drawRichText(stream, cell, fontManager, indentPts, scaleFactor = 1) {
|
|
|
313
320
|
const primaryResourceName = runResource(runs[0]);
|
|
314
321
|
const ascent = fontManager.getFontAscent(primaryResourceName, primaryFontSize);
|
|
315
322
|
const totalTextHeight = lines.length * lineHeight;
|
|
316
|
-
const textStartY = computeTextStartY(verticalAlign, rect, totalTextHeight, ascent,
|
|
323
|
+
const textStartY = computeTextStartY(verticalAlign, rect, totalTextHeight, ascent, pad.top, pad.bottom);
|
|
317
324
|
let charPos = 0;
|
|
318
325
|
for (let li = 0; li < lines.length; li++) {
|
|
319
326
|
const lineY = textStartY - li * lineHeight;
|
|
@@ -351,7 +358,7 @@ function drawRichText(stream, cell, fontManager, indentPts, scaleFactor = 1) {
|
|
|
351
358
|
for (const seg of segments) {
|
|
352
359
|
lineWidth += fontManager.measureText(seg.text, seg.resourceName, seg.run.fontSize);
|
|
353
360
|
}
|
|
354
|
-
let textX = computeTextX(horizontalAlign, rect, lineWidth, indentPts,
|
|
361
|
+
let textX = computeTextX(horizontalAlign, rect, lineWidth, indentPts, pad.left, pad.right);
|
|
355
362
|
for (const seg of segments) {
|
|
356
363
|
const { run, text, resourceName } = seg;
|
|
357
364
|
const segWidth = fontManager.measureText(text, resourceName, run.fontSize);
|
|
@@ -394,8 +401,8 @@ function drawRichText(stream, cell, fontManager, indentPts, scaleFactor = 1) {
|
|
|
394
401
|
}
|
|
395
402
|
const primaryResourceName = runMetrics[0]?.resourceName ?? "F1";
|
|
396
403
|
const ascent = fontManager.getFontAscent(primaryResourceName, primaryFontSize);
|
|
397
|
-
const textStartY = computeTextStartY(verticalAlign, rect, lineHeight, ascent,
|
|
398
|
-
let textX = computeTextX(horizontalAlign, rect, totalWidth, indentPts,
|
|
404
|
+
const textStartY = computeTextStartY(verticalAlign, rect, lineHeight, ascent, pad.top, pad.bottom);
|
|
405
|
+
let textX = computeTextX(horizontalAlign, rect, totalWidth, indentPts, pad.left, pad.right);
|
|
399
406
|
for (let i = 0; i < runs.length; i++) {
|
|
400
407
|
const run = runs[i];
|
|
401
408
|
const { resourceName } = runMetrics[i];
|
|
@@ -432,8 +439,7 @@ function drawRichText(stream, cell, fontManager, indentPts, scaleFactor = 1) {
|
|
|
432
439
|
function drawRotatedText(stream, cell, fontManager, indentPts, scaleFactor = 1) {
|
|
433
440
|
const { rect, wrapText } = cell;
|
|
434
441
|
let { fontSize } = cell;
|
|
435
|
-
const
|
|
436
|
-
const padV = CELL_PADDING_V * scaleFactor;
|
|
442
|
+
const pad = computeCellPadding(cell, scaleFactor);
|
|
437
443
|
const isEmbedded = fontManager.hasEmbeddedFont();
|
|
438
444
|
const resourceName = isEmbedded
|
|
439
445
|
? fontManager.getEmbeddedResourceName()
|
|
@@ -445,8 +451,8 @@ function drawRotatedText(stream, cell, fontManager, indentPts, scaleFactor = 1)
|
|
|
445
451
|
const sin = Math.sin(radians);
|
|
446
452
|
const absSin = Math.abs(sin);
|
|
447
453
|
const absCos = Math.abs(cos);
|
|
448
|
-
const maxWidth = rect.width -
|
|
449
|
-
const maxHeight = rect.height -
|
|
454
|
+
const maxWidth = rect.width - pad.left - pad.right;
|
|
455
|
+
const maxHeight = rect.height - pad.top - pad.bottom;
|
|
450
456
|
// Available length along the text flow direction for wrapping
|
|
451
457
|
let availTextLength;
|
|
452
458
|
if (absSin > 0.01 && absCos > 0.01) {
|
|
@@ -494,11 +500,11 @@ function drawRotatedText(stream, cell, fontManager, indentPts, scaleFactor = 1)
|
|
|
494
500
|
stream.setFillColor(cell.textColor);
|
|
495
501
|
if (is90) {
|
|
496
502
|
// Text reads bottom-to-top. Each line becomes a column drawn left-to-right.
|
|
497
|
-
drawRotated90(stream, cell, lines, fontManager, resourceName, fontSize, scaledLineHeight, ascent,
|
|
503
|
+
drawRotated90(stream, cell, lines, fontManager, resourceName, fontSize, scaledLineHeight, ascent, pad);
|
|
498
504
|
}
|
|
499
505
|
else if (isMinus90) {
|
|
500
506
|
// Text reads top-to-bottom. Each line becomes a column drawn right-to-left.
|
|
501
|
-
drawRotatedMinus90(stream, cell, lines, fontManager, resourceName, fontSize, scaledLineHeight, ascent,
|
|
507
|
+
drawRotatedMinus90(stream, cell, lines, fontManager, resourceName, fontSize, scaledLineHeight, ascent, pad);
|
|
502
508
|
}
|
|
503
509
|
else {
|
|
504
510
|
// General rotation — center multi-line text block in cell
|
|
@@ -506,7 +512,7 @@ function drawRotatedText(stream, cell, fontManager, indentPts, scaleFactor = 1)
|
|
|
506
512
|
}
|
|
507
513
|
}
|
|
508
514
|
/** 90° CCW: text reads bottom-to-top, lines stack left-to-right. */
|
|
509
|
-
function drawRotated90(stream, cell, lines, fontManager, resourceName, fontSize, lineHeight, ascent,
|
|
515
|
+
function drawRotated90(stream, cell, lines, fontManager, resourceName, fontSize, lineHeight, ascent, pad) {
|
|
510
516
|
const { rect, horizontalAlign, verticalAlign } = cell;
|
|
511
517
|
const totalColumnsWidth = lines.length * lineHeight;
|
|
512
518
|
// horizontalAlign controls X placement of line columns (same visual axis)
|
|
@@ -515,11 +521,11 @@ function drawRotated90(stream, cell, lines, fontManager, resourceName, fontSize,
|
|
|
515
521
|
startX = rect.x + rect.width / 2 - totalColumnsWidth / 2 + ascent;
|
|
516
522
|
}
|
|
517
523
|
else if (horizontalAlign === "right") {
|
|
518
|
-
startX = rect.x + rect.width -
|
|
524
|
+
startX = rect.x + rect.width - pad.right - totalColumnsWidth + ascent;
|
|
519
525
|
}
|
|
520
526
|
else {
|
|
521
527
|
// left (default)
|
|
522
|
-
startX = rect.x +
|
|
528
|
+
startX = rect.x + pad.left + ascent;
|
|
523
529
|
}
|
|
524
530
|
for (let i = 0; i < lines.length; i++) {
|
|
525
531
|
const line = lines[i];
|
|
@@ -530,16 +536,16 @@ function drawRotated90(stream, cell, lines, fontManager, resourceName, fontSize,
|
|
|
530
536
|
let ty;
|
|
531
537
|
if (verticalAlign === "top") {
|
|
532
538
|
// text at top → text end near top → ty starts at bottom so text reaches top
|
|
533
|
-
ty = rect.y + rect.height -
|
|
539
|
+
ty = rect.y + rect.height - pad.top - lineWidth;
|
|
534
540
|
}
|
|
535
541
|
else if (verticalAlign === "middle") {
|
|
536
542
|
ty = rect.y + (rect.height - lineWidth) / 2;
|
|
537
543
|
}
|
|
538
544
|
else {
|
|
539
545
|
// bottom (default) → text at bottom → ty near bottom
|
|
540
|
-
ty = rect.y +
|
|
546
|
+
ty = rect.y + pad.bottom;
|
|
541
547
|
}
|
|
542
|
-
ty = Math.max(ty, rect.y +
|
|
548
|
+
ty = Math.max(ty, rect.y + pad.bottom);
|
|
543
549
|
stream.beginText();
|
|
544
550
|
stream.setFont(resourceName, fontSize);
|
|
545
551
|
stream.setTextMatrix(0, 1, -1, 0, colX, ty);
|
|
@@ -548,7 +554,7 @@ function drawRotated90(stream, cell, lines, fontManager, resourceName, fontSize,
|
|
|
548
554
|
}
|
|
549
555
|
}
|
|
550
556
|
/** -90° (270° CW): text reads top-to-bottom, lines stack right-to-left. */
|
|
551
|
-
function drawRotatedMinus90(stream, cell, lines, fontManager, resourceName, fontSize, lineHeight, ascent,
|
|
557
|
+
function drawRotatedMinus90(stream, cell, lines, fontManager, resourceName, fontSize, lineHeight, ascent, pad) {
|
|
552
558
|
const { rect, horizontalAlign, verticalAlign } = cell;
|
|
553
559
|
const totalColumnsWidth = lines.length * lineHeight;
|
|
554
560
|
// horizontalAlign controls X placement: lines stack right-to-left
|
|
@@ -557,11 +563,11 @@ function drawRotatedMinus90(stream, cell, lines, fontManager, resourceName, font
|
|
|
557
563
|
startX = rect.x + rect.width / 2 + totalColumnsWidth / 2 - lineHeight + ascent;
|
|
558
564
|
}
|
|
559
565
|
else if (horizontalAlign === "right") {
|
|
560
|
-
startX = rect.x + rect.width -
|
|
566
|
+
startX = rect.x + rect.width - pad.right - lineHeight + ascent;
|
|
561
567
|
}
|
|
562
568
|
else {
|
|
563
569
|
// left (default)
|
|
564
|
-
startX = rect.x +
|
|
570
|
+
startX = rect.x + pad.left + totalColumnsWidth - lineHeight + ascent;
|
|
565
571
|
}
|
|
566
572
|
for (let i = 0; i < lines.length; i++) {
|
|
567
573
|
const line = lines[i];
|
|
@@ -572,16 +578,16 @@ function drawRotatedMinus90(stream, cell, lines, fontManager, resourceName, font
|
|
|
572
578
|
let ty;
|
|
573
579
|
if (verticalAlign === "top") {
|
|
574
580
|
// text at top → ty near top (high PDF y)
|
|
575
|
-
ty = rect.y + rect.height -
|
|
581
|
+
ty = rect.y + rect.height - pad.top;
|
|
576
582
|
}
|
|
577
583
|
else if (verticalAlign === "middle") {
|
|
578
584
|
ty = rect.y + (rect.height + lineWidth) / 2;
|
|
579
585
|
}
|
|
580
586
|
else {
|
|
581
587
|
// bottom (default) → text at bottom → ty so text ends at bottom
|
|
582
|
-
ty = rect.y +
|
|
588
|
+
ty = rect.y + pad.bottom + lineWidth;
|
|
583
589
|
}
|
|
584
|
-
ty = Math.min(ty, rect.y + rect.height -
|
|
590
|
+
ty = Math.min(ty, rect.y + rect.height - pad.top);
|
|
585
591
|
stream.beginText();
|
|
586
592
|
stream.setFont(resourceName, fontSize);
|
|
587
593
|
stream.setTextMatrix(0, -1, 1, 0, colX, ty);
|
|
@@ -592,8 +598,8 @@ function drawRotatedMinus90(stream, cell, lines, fontManager, resourceName, font
|
|
|
592
598
|
/** General rotation — center a multi-line text block in the cell. */
|
|
593
599
|
function drawRotatedGeneral(stream, cell, lines, fontManager, resourceName, fontSize, lineHeight, ascent, cos, sin, indentPts) {
|
|
594
600
|
const { rect, horizontalAlign, verticalAlign } = cell;
|
|
595
|
-
|
|
596
|
-
const
|
|
601
|
+
// Use border-aware padding (no scaleFactor — font size is already scaled by caller)
|
|
602
|
+
const pad = computeCellPadding(cell);
|
|
597
603
|
// Compute the rotated bounding box of the text block
|
|
598
604
|
let maxLineWidth = 0;
|
|
599
605
|
for (const line of lines) {
|
|
@@ -613,10 +619,10 @@ function drawRotatedGeneral(stream, cell, lines, fontManager, resourceName, font
|
|
|
613
619
|
const indentOffset = horizontalAlign === "left" ? indentPts / 2 : horizontalAlign === "right" ? -indentPts / 2 : 0;
|
|
614
620
|
let cy;
|
|
615
621
|
if (verticalAlign === "top") {
|
|
616
|
-
cy = rect.y + rect.height -
|
|
622
|
+
cy = rect.y + rect.height - pad.top - rotatedHeight / 2;
|
|
617
623
|
}
|
|
618
624
|
else if (verticalAlign === "bottom") {
|
|
619
|
-
cy = rect.y +
|
|
625
|
+
cy = rect.y + pad.bottom + rotatedHeight / 2;
|
|
620
626
|
}
|
|
621
627
|
else {
|
|
622
628
|
// middle (default)
|
|
@@ -629,10 +635,10 @@ function drawRotatedGeneral(stream, cell, lines, fontManager, resourceName, font
|
|
|
629
635
|
const slantAtCy = slantShift * 2 * verticalRatio; // slantShift*2 = full slantOffset
|
|
630
636
|
let cx;
|
|
631
637
|
if (horizontalAlign === "right") {
|
|
632
|
-
cx = rect.x + rect.width -
|
|
638
|
+
cx = rect.x + rect.width - pad.right - rotatedWidth / 2 + indentOffset + slantAtCy;
|
|
633
639
|
}
|
|
634
640
|
else if (horizontalAlign === "left") {
|
|
635
|
-
cx = rect.x +
|
|
641
|
+
cx = rect.x + pad.left + rotatedWidth / 2 + indentOffset + slantAtCy;
|
|
636
642
|
}
|
|
637
643
|
else {
|
|
638
644
|
// center (default for rotated)
|
|
@@ -669,8 +675,7 @@ function emitText(stream, fontManager, text, resourceName) {
|
|
|
669
675
|
*/
|
|
670
676
|
function drawVerticalStackedText(stream, cell, fontManager, _indentPts, scaleFactor = 1) {
|
|
671
677
|
const { rect, text, fontSize, horizontalAlign, verticalAlign } = cell;
|
|
672
|
-
const
|
|
673
|
-
const padV = CELL_PADDING_V * scaleFactor;
|
|
678
|
+
const pad = computeCellPadding(cell, scaleFactor);
|
|
674
679
|
const isEmbedded = fontManager.hasEmbeddedFont();
|
|
675
680
|
const resourceName = isEmbedded
|
|
676
681
|
? fontManager.getEmbeddedResourceName()
|
|
@@ -687,11 +692,11 @@ function drawVerticalStackedText(stream, cell, fontManager, _indentPts, scaleFac
|
|
|
687
692
|
startX = rect.x + rect.width / 2 - totalColumnsWidth / 2 + columnWidth / 2;
|
|
688
693
|
}
|
|
689
694
|
else if (horizontalAlign === "right") {
|
|
690
|
-
startX = rect.x + rect.width -
|
|
695
|
+
startX = rect.x + rect.width - pad.right - totalColumnsWidth + columnWidth / 2;
|
|
691
696
|
}
|
|
692
697
|
else {
|
|
693
698
|
// left (default)
|
|
694
|
-
startX = rect.x +
|
|
699
|
+
startX = rect.x + pad.left + columnWidth / 2;
|
|
695
700
|
}
|
|
696
701
|
stream.setFillColor(cell.textColor);
|
|
697
702
|
for (let colIdx = 0; colIdx < columns.length; colIdx++) {
|
|
@@ -704,14 +709,14 @@ function drawVerticalStackedText(stream, cell, fontManager, _indentPts, scaleFac
|
|
|
704
709
|
currentY = rect.y + rect.height / 2 + totalTextHeight / 2 - ascent;
|
|
705
710
|
}
|
|
706
711
|
else if (verticalAlign === "bottom") {
|
|
707
|
-
currentY = rect.y +
|
|
712
|
+
currentY = rect.y + pad.bottom + totalTextHeight - ascent;
|
|
708
713
|
}
|
|
709
714
|
else {
|
|
710
715
|
// top (default)
|
|
711
|
-
currentY = rect.y + rect.height -
|
|
716
|
+
currentY = rect.y + rect.height - pad.top - ascent;
|
|
712
717
|
}
|
|
713
718
|
for (const ch of colText) {
|
|
714
|
-
if (currentY < rect.y +
|
|
719
|
+
if (currentY < rect.y + pad.bottom) {
|
|
715
720
|
break;
|
|
716
721
|
}
|
|
717
722
|
const charWidth = fontManager.measureText(ch, resourceName, fontSize);
|
|
@@ -738,60 +743,60 @@ export function alphaGsName(alpha) {
|
|
|
738
743
|
// =============================================================================
|
|
739
744
|
// Text Layout Helpers
|
|
740
745
|
// =============================================================================
|
|
741
|
-
export function computeTextStartY(verticalAlign, rect, totalTextHeight, ascent,
|
|
746
|
+
export function computeTextStartY(verticalAlign, rect, totalTextHeight, ascent, padVTop = CELL_PADDING_V, padVBottom = padVTop) {
|
|
742
747
|
let y;
|
|
743
748
|
switch (verticalAlign) {
|
|
744
749
|
case "top":
|
|
745
|
-
y = rect.y + rect.height -
|
|
750
|
+
y = rect.y + rect.height - padVTop - ascent;
|
|
746
751
|
break;
|
|
747
752
|
case "middle":
|
|
748
753
|
y = rect.y + rect.height / 2 + totalTextHeight / 2 - ascent;
|
|
749
754
|
break;
|
|
750
755
|
case "bottom":
|
|
751
756
|
default:
|
|
752
|
-
y = rect.y +
|
|
757
|
+
y = rect.y + padVBottom + (totalTextHeight - ascent);
|
|
753
758
|
break;
|
|
754
759
|
}
|
|
755
760
|
// Clamp: ensure text ascent doesn't exceed the cell top
|
|
756
|
-
const maxY = rect.y + rect.height -
|
|
761
|
+
const maxY = rect.y + rect.height - padVTop - ascent;
|
|
757
762
|
if (y > maxY) {
|
|
758
763
|
y = maxY;
|
|
759
764
|
}
|
|
760
765
|
// Clamp: ensure text descent doesn't go below cell bottom
|
|
761
|
-
const minY = rect.y +
|
|
766
|
+
const minY = rect.y + padVBottom;
|
|
762
767
|
if (y < minY) {
|
|
763
768
|
y = minY;
|
|
764
769
|
}
|
|
765
770
|
return y;
|
|
766
771
|
}
|
|
767
|
-
export function computeTextX(align, rect, textWidth, indentPts = 0,
|
|
772
|
+
export function computeTextX(align, rect, textWidth, indentPts = 0, padHLeft = CELL_PADDING_H, padHRight = padHLeft) {
|
|
768
773
|
let x;
|
|
769
774
|
switch (align) {
|
|
770
775
|
case "center":
|
|
771
776
|
x = rect.x + (rect.width - textWidth) / 2;
|
|
772
777
|
break;
|
|
773
778
|
case "right":
|
|
774
|
-
x = rect.x + rect.width -
|
|
779
|
+
x = rect.x + rect.width - padHRight - textWidth;
|
|
775
780
|
break;
|
|
776
781
|
default:
|
|
777
|
-
x = rect.x +
|
|
782
|
+
x = rect.x + padHLeft + indentPts;
|
|
778
783
|
break;
|
|
779
784
|
}
|
|
780
785
|
// Clamp: don't start before cell left edge
|
|
781
|
-
const minX = rect.x +
|
|
786
|
+
const minX = rect.x + padHLeft;
|
|
782
787
|
if (x < minX) {
|
|
783
788
|
x = minX;
|
|
784
789
|
}
|
|
785
790
|
return x;
|
|
786
791
|
}
|
|
787
|
-
function drawTextDecorations(stream, cell, lines, lineHeight, textStartY, measure, resourceName, fontManager, indentPts) {
|
|
792
|
+
function drawTextDecorations(stream, cell, lines, lineHeight, textStartY, measure, resourceName, fontManager, indentPts, pad) {
|
|
788
793
|
if (cell.strike) {
|
|
789
794
|
const descent = fontManager.getFontDescent(resourceName, cell.fontSize);
|
|
790
795
|
const strikeY = textStartY + descent + cell.fontSize * 0.3;
|
|
791
796
|
for (let i = 0; i < lines.length; i++) {
|
|
792
797
|
const lineY = strikeY - i * lineHeight;
|
|
793
798
|
const lw = measure(lines[i]);
|
|
794
|
-
const startX = computeTextX(cell.horizontalAlign, cell.rect, lw, indentPts);
|
|
799
|
+
const startX = computeTextX(cell.horizontalAlign, cell.rect, lw, indentPts, pad?.left, pad?.right);
|
|
795
800
|
stream.drawLine(startX, lineY, startX + lw, lineY, cell.textColor, 0.5);
|
|
796
801
|
}
|
|
797
802
|
}
|
|
@@ -801,7 +806,7 @@ function drawTextDecorations(stream, cell, lines, lineHeight, textStartY, measur
|
|
|
801
806
|
for (let i = 0; i < lines.length; i++) {
|
|
802
807
|
const lineY = textStartY - i * lineHeight + underlineOffset;
|
|
803
808
|
const lw = measure(lines[i]);
|
|
804
|
-
const startX = computeTextX(cell.horizontalAlign, cell.rect, lw, indentPts);
|
|
809
|
+
const startX = computeTextX(cell.horizontalAlign, cell.rect, lw, indentPts, pad?.left, pad?.right);
|
|
805
810
|
stream.drawLine(startX, lineY, startX + lw, lineY, cell.textColor, 0.5);
|
|
806
811
|
}
|
|
807
812
|
}
|
|
@@ -1070,52 +1075,6 @@ function renderImageWatermark(stream, page, watermark) {
|
|
|
1070
1075
|
/**
|
|
1071
1076
|
* Parse image dimensions from raw JPEG or PNG data without a full decode.
|
|
1072
1077
|
*/
|
|
1073
|
-
export function parseImageDimensions(data, format) {
|
|
1074
|
-
if (format === "png") {
|
|
1075
|
-
return parsePngDimensions(data);
|
|
1076
|
-
}
|
|
1077
|
-
return parseJpegDimensions(data);
|
|
1078
|
-
}
|
|
1079
|
-
/** Read width/height from a PNG IHDR chunk (bytes 16-23). */
|
|
1080
|
-
function parsePngDimensions(data) {
|
|
1081
|
-
// PNG header: 8 byte signature, then IHDR chunk: 4 byte length, 4 byte type, 4 byte width, 4 byte height
|
|
1082
|
-
if (data.length >= 24 &&
|
|
1083
|
-
data[12] === 0x49 &&
|
|
1084
|
-
data[13] === 0x48 &&
|
|
1085
|
-
data[14] === 0x44 &&
|
|
1086
|
-
data[15] === 0x52) {
|
|
1087
|
-
const width = (data[16] << 24) | (data[17] << 16) | (data[18] << 8) | data[19];
|
|
1088
|
-
const height = (data[20] << 24) | (data[21] << 16) | (data[22] << 8) | data[23];
|
|
1089
|
-
return { width, height };
|
|
1090
|
-
}
|
|
1091
|
-
return { width: 1, height: 1 };
|
|
1092
|
-
}
|
|
1093
|
-
/** Read width/height from JPEG SOF marker. */
|
|
1094
|
-
function parseJpegDimensions(data) {
|
|
1095
|
-
let offset = 2; // skip SOI marker
|
|
1096
|
-
while (offset < data.length - 1) {
|
|
1097
|
-
while (offset < data.length && data[offset] === 0xff && data[offset + 1] === 0xff) {
|
|
1098
|
-
offset++;
|
|
1099
|
-
}
|
|
1100
|
-
if (offset >= data.length - 1 || data[offset] !== 0xff) {
|
|
1101
|
-
break;
|
|
1102
|
-
}
|
|
1103
|
-
const marker = data[offset + 1];
|
|
1104
|
-
const isSof = marker >= 0xc0 && marker <= 0xcf && marker !== 0xc4 && marker !== 0xc8 && marker !== 0xcc;
|
|
1105
|
-
if (isSof && offset + 8 < data.length) {
|
|
1106
|
-
return {
|
|
1107
|
-
width: (data[offset + 7] << 8) | data[offset + 8],
|
|
1108
|
-
height: (data[offset + 5] << 8) | data[offset + 6]
|
|
1109
|
-
};
|
|
1110
|
-
}
|
|
1111
|
-
if (offset + 3 >= data.length) {
|
|
1112
|
-
break;
|
|
1113
|
-
}
|
|
1114
|
-
const segLen = (data[offset + 2] << 8) | data[offset + 3];
|
|
1115
|
-
offset += 2 + segLen;
|
|
1116
|
-
}
|
|
1117
|
-
return { width: 1, height: 1 };
|
|
1118
|
-
}
|
|
1119
1078
|
/**
|
|
1120
1079
|
* Resolve the center position for a watermark on a given page.
|
|
1121
1080
|
*/
|
|
@@ -14,8 +14,8 @@ import { FontManager, resolvePdfFontName } from "../font/font-manager.js";
|
|
|
14
14
|
import { parseTtf } from "../font/ttf-parser.js";
|
|
15
15
|
import { initEncryption } from "../core/encryption.js";
|
|
16
16
|
import { layoutSheet } from "./layout-engine.js";
|
|
17
|
-
import { renderPage, alphaGsName, renderWatermark
|
|
18
|
-
import {
|
|
17
|
+
import { renderPage, alphaGsName, renderWatermark } from "./page-renderer.js";
|
|
18
|
+
import { writeImageXObject } from "../builder/image-utils.js";
|
|
19
19
|
import { PdfError, PdfRenderError } from "../errors.js";
|
|
20
20
|
import { PageSizes } from "../types.js";
|
|
21
21
|
import { argbToPdfColor } from "./style-converter.js";
|
|
@@ -500,62 +500,3 @@ function isWatermarkApplicable(watermark, page) {
|
|
|
500
500
|
}
|
|
501
501
|
return true;
|
|
502
502
|
}
|
|
503
|
-
// =============================================================================
|
|
504
|
-
// Image XObject
|
|
505
|
-
// =============================================================================
|
|
506
|
-
/**
|
|
507
|
-
* Write a JPEG or PNG image as a PDF XObject Image.
|
|
508
|
-
*/
|
|
509
|
-
function writeImageXObject(writer, data, format) {
|
|
510
|
-
if (format === "png") {
|
|
511
|
-
return writePngImageXObject(writer, data);
|
|
512
|
-
}
|
|
513
|
-
return writeJpegImageXObject(writer, data);
|
|
514
|
-
}
|
|
515
|
-
/**
|
|
516
|
-
* Write a JPEG image using DCTDecode (raw JPEG data embedded directly).
|
|
517
|
-
*/
|
|
518
|
-
function writeJpegImageXObject(writer, data) {
|
|
519
|
-
const objNum = writer.allocObject();
|
|
520
|
-
const dims = parseImageDimensions(data, "jpeg");
|
|
521
|
-
const dict = new PdfDict()
|
|
522
|
-
.set("Type", "/XObject")
|
|
523
|
-
.set("Subtype", "/Image")
|
|
524
|
-
.set("Width", pdfNumber(dims.width))
|
|
525
|
-
.set("Height", pdfNumber(dims.height))
|
|
526
|
-
.set("ColorSpace", "/DeviceRGB")
|
|
527
|
-
.set("BitsPerComponent", "8")
|
|
528
|
-
.set("Filter", "/DCTDecode");
|
|
529
|
-
writer.addStreamObject(objNum, dict, data);
|
|
530
|
-
return objNum;
|
|
531
|
-
}
|
|
532
|
-
/**
|
|
533
|
-
* Write a PNG image: decode to raw RGB, create SMask for alpha if needed.
|
|
534
|
-
*/
|
|
535
|
-
function writePngImageXObject(writer, data) {
|
|
536
|
-
const png = decodePng(data);
|
|
537
|
-
const objNum = writer.allocObject();
|
|
538
|
-
const dict = new PdfDict()
|
|
539
|
-
.set("Type", "/XObject")
|
|
540
|
-
.set("Subtype", "/Image")
|
|
541
|
-
.set("Width", pdfNumber(png.width))
|
|
542
|
-
.set("Height", pdfNumber(png.height))
|
|
543
|
-
.set("ColorSpace", "/DeviceRGB")
|
|
544
|
-
.set("BitsPerComponent", pdfNumber(png.bitsPerComponent));
|
|
545
|
-
// If the image has an alpha channel, create a soft mask XObject
|
|
546
|
-
if (png.alpha) {
|
|
547
|
-
const smaskObjNum = writer.allocObject();
|
|
548
|
-
const smaskDict = new PdfDict()
|
|
549
|
-
.set("Type", "/XObject")
|
|
550
|
-
.set("Subtype", "/Image")
|
|
551
|
-
.set("Width", pdfNumber(png.width))
|
|
552
|
-
.set("Height", pdfNumber(png.height))
|
|
553
|
-
.set("ColorSpace", "/DeviceGray")
|
|
554
|
-
.set("BitsPerComponent", "8");
|
|
555
|
-
writer.addStreamObject(smaskObjNum, smaskDict, png.alpha);
|
|
556
|
-
dict.set("SMask", pdfRef(smaskObjNum));
|
|
557
|
-
}
|
|
558
|
-
// RGB pixel data — compression handled by addStreamObject
|
|
559
|
-
writer.addStreamObject(objNum, dict, png.pixels);
|
|
560
|
-
return objNum;
|
|
561
|
-
}
|
|
@@ -53,6 +53,10 @@ export declare function extractFontProperties(font: Partial<PdfFontStyle> | unde
|
|
|
53
53
|
* Other patterns are approximated or ignored.
|
|
54
54
|
*/
|
|
55
55
|
export declare function excelFillToPdfColor(fill: PdfFillData | undefined): PdfColor | null;
|
|
56
|
+
/**
|
|
57
|
+
* Map border styles to PDF line widths.
|
|
58
|
+
*/
|
|
59
|
+
export declare function borderStyleToLineWidth(style: string): number;
|
|
56
60
|
/**
|
|
57
61
|
* Convert border data to PDF LayoutBorders.
|
|
58
62
|
*/
|
|
@@ -179,7 +179,7 @@ export function excelFillToPdfColor(fill) {
|
|
|
179
179
|
/**
|
|
180
180
|
* Map border styles to PDF line widths.
|
|
181
181
|
*/
|
|
182
|
-
function borderStyleToLineWidth(style) {
|
|
182
|
+
export function borderStyleToLineWidth(style) {
|
|
183
183
|
switch (style) {
|
|
184
184
|
case "thin":
|
|
185
185
|
return 0.25;
|
|
@@ -655,8 +655,21 @@ export interface LayoutCell {
|
|
|
655
655
|
verticalAlign: "top" | "middle" | "bottom";
|
|
656
656
|
/** Whether text wrapping is enabled */
|
|
657
657
|
wrapText: boolean;
|
|
658
|
-
/** Border definitions for this cell */
|
|
658
|
+
/** Border definitions for this cell (after shared-edge resolution: only edges this cell draws) */
|
|
659
659
|
borders: LayoutBorders;
|
|
660
|
+
/**
|
|
661
|
+
* Effective border insets in points for text padding.
|
|
662
|
+
*
|
|
663
|
+
* On a shared edge the border line is drawn by only one of the two cells,
|
|
664
|
+
* but it still visually intrudes into both. These values record the actual
|
|
665
|
+
* half-width intrusion on each side regardless of which cell draws the line.
|
|
666
|
+
*/
|
|
667
|
+
borderInsets: {
|
|
668
|
+
top: number;
|
|
669
|
+
right: number;
|
|
670
|
+
bottom: number;
|
|
671
|
+
left: number;
|
|
672
|
+
};
|
|
660
673
|
/** Number of columns this cell spans (for merged cells) */
|
|
661
674
|
colSpan: number;
|
|
662
675
|
/** Number of rows this cell spans (for merged cells) */
|
|
@@ -232,7 +232,10 @@ export class Readable extends EventEmitter {
|
|
|
232
232
|
err.code = "ERR_INVALID_ARG_TYPE";
|
|
233
233
|
throw err;
|
|
234
234
|
}
|
|
235
|
-
const readable = new Readable({
|
|
235
|
+
const readable = new Readable({
|
|
236
|
+
...options,
|
|
237
|
+
objectMode: options?.objectMode ?? true
|
|
238
|
+
});
|
|
236
239
|
const iter = iterable;
|
|
237
240
|
// Node.js treats strings as a single chunk, not as Iterable<char>.
|
|
238
241
|
// Match that behavior by wrapping strings in an array.
|
|
@@ -1738,7 +1741,10 @@ export class Readable extends EventEmitter {
|
|
|
1738
1741
|
}
|
|
1739
1742
|
}
|
|
1740
1743
|
else {
|
|
1741
|
-
for await (const item of _mapWithConcurrency(this, async (chunk) => ({
|
|
1744
|
+
for await (const item of _mapWithConcurrency(this, async (chunk) => ({
|
|
1745
|
+
chunk,
|
|
1746
|
+
match: await fn(chunk, { signal: innerSignal })
|
|
1747
|
+
}), concurrency, signal)) {
|
|
1742
1748
|
if (item.match) {
|
|
1743
1749
|
this.destroy();
|
|
1744
1750
|
return item.chunk;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cryptographic primitives — Browser version.
|
|
3
|
+
*
|
|
4
|
+
* Uses pure JavaScript for synchronous operations (SHA-256, MD5, AES-CBC, RC4)
|
|
5
|
+
* since Web Crypto API is async-only and cannot replace synchronous call sites.
|
|
6
|
+
*
|
|
7
|
+
* Uses Web Crypto API for:
|
|
8
|
+
* - `randomBytes` (crypto.getRandomValues — truly random)
|
|
9
|
+
* - `rsaVerify` / `rsaSign` (SubtleCrypto — hardware-accelerated)
|
|
10
|
+
*
|
|
11
|
+
* Exports the same API as `crypto.ts` (Node.js version).
|
|
12
|
+
*/
|
|
13
|
+
export declare function aesCbcEncrypt(plaintext: Uint8Array, key: Uint8Array, iv: Uint8Array): Uint8Array;
|
|
14
|
+
export declare function aesCbcDecrypt(ciphertext: Uint8Array, key: Uint8Array, iv: Uint8Array): Uint8Array;
|
|
15
|
+
export declare function aesCbcDecryptRaw(ciphertext: Uint8Array, key: Uint8Array, iv: Uint8Array): Uint8Array;
|
|
16
|
+
export declare function aesCbcEncryptRaw(plaintext: Uint8Array, key: Uint8Array, iv: Uint8Array): Uint8Array;
|
|
17
|
+
export declare function aesEcbEncrypt(block: Uint8Array, key: Uint8Array): Uint8Array;
|
|
18
|
+
export declare function sha256(input: Uint8Array): Uint8Array;
|
|
19
|
+
export declare function md5(input: Uint8Array): Uint8Array;
|
|
20
|
+
/**
|
|
21
|
+
* RC4 stream cipher.
|
|
22
|
+
* @deprecated Only used for reading legacy encrypted PDFs.
|
|
23
|
+
*/
|
|
24
|
+
export declare function rc4(key: Uint8Array, data: Uint8Array): Uint8Array;
|
|
25
|
+
/**
|
|
26
|
+
* Generate cryptographically secure random bytes.
|
|
27
|
+
* Uses crypto.getRandomValues (available in all modern browsers).
|
|
28
|
+
*/
|
|
29
|
+
export declare function randomBytes(length: number): Uint8Array;
|
|
30
|
+
/**
|
|
31
|
+
* Compute a hash digest using Web Crypto API.
|
|
32
|
+
*
|
|
33
|
+
* NOTE: In the browser, this is async. The Node.js version is sync.
|
|
34
|
+
* For callers that need sync hashing, use `sha256()` or `md5()` directly.
|
|
35
|
+
*
|
|
36
|
+
* @param algorithm - Hash algorithm name (e.g., "SHA-256", "SHA-512", "SHA-1").
|
|
37
|
+
* @param data - Data to hash
|
|
38
|
+
* @returns The digest bytes
|
|
39
|
+
*/
|
|
40
|
+
export declare function hashAsync(algorithm: string, data: Uint8Array): Promise<Uint8Array>;
|
|
41
|
+
/**
|
|
42
|
+
* Compute a hash digest synchronously (pure JS — SHA-256 and MD5 only).
|
|
43
|
+
*
|
|
44
|
+
* @param algorithm - "SHA-256" or "MD5" (case-insensitive, hyphens optional)
|
|
45
|
+
* @param data - Data to hash
|
|
46
|
+
* @returns The digest bytes
|
|
47
|
+
* @throws If algorithm is not SHA-256 or MD5
|
|
48
|
+
*/
|
|
49
|
+
export declare function hash(algorithm: string, data: Uint8Array): Uint8Array;
|
|
50
|
+
/**
|
|
51
|
+
* Verify an RSA PKCS#1 v1.5 signature.
|
|
52
|
+
*
|
|
53
|
+
* @param publicKeyDer - DER-encoded SubjectPublicKeyInfo
|
|
54
|
+
* @param signature - The signature bytes
|
|
55
|
+
* @param data - The signed data (will be hashed with SHA-256)
|
|
56
|
+
*/
|
|
57
|
+
export declare function rsaVerify(publicKeyDer: Uint8Array, signature: Uint8Array, data: Uint8Array): Promise<boolean>;
|
|
58
|
+
/**
|
|
59
|
+
* Create an RSA PKCS#1 v1.5 signature.
|
|
60
|
+
*
|
|
61
|
+
* @param privateKeyDer - DER-encoded PKCS#8 private key
|
|
62
|
+
* @param data - The data to sign (will be hashed with SHA-256)
|
|
63
|
+
*/
|
|
64
|
+
export declare function rsaSign(privateKeyDer: Uint8Array, data: Uint8Array): Promise<Uint8Array>;
|