@bendyline/squisq-formats 2.7.2 → 2.7.4
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 +1 -1
- package/THIRD_PARTY_LICENSES.txt +192 -0
- package/dist/{chunk-YERFQ2SB.js → chunk-32AQL6I6.js} +219 -83
- package/dist/{chunk-YITBSNPM.js → chunk-5YYF3Z6C.js} +4 -2
- package/dist/{chunk-ETK2SKVQ.js → chunk-B6UQPW75.js} +7 -3
- package/dist/{chunk-PKFWF4FX.js → chunk-GESOAVYN.js} +5 -2
- package/dist/{chunk-RSU3V5IQ.js → chunk-JZR32FON.js} +14 -1
- package/dist/{chunk-52RXDH24.js → chunk-OOM2YMXU.js} +2 -2
- package/dist/{chunk-XCHIYF3A.js → chunk-RRULGPWV.js} +1 -1
- package/dist/{chunk-Z3QORA5G.js → chunk-VU7M3YV6.js} +1 -1
- package/dist/{chunk-YVCUNZB5.js → chunk-WMIDXNGR.js} +1 -1
- package/dist/docx/index.js +2 -2
- package/dist/epub/index.js +3 -3
- package/dist/html/index.js +3 -3
- package/dist/images-PQCYRJJ5.js +14 -0
- package/dist/index.js +9 -9
- package/dist/outside-in/index.js +2 -2
- package/dist/pdf/index.d.ts +38 -0
- package/dist/pdf/index.js +2 -2
- package/dist/pptx/index.js +3 -3
- package/dist/registry/index.js +1 -1
- package/dist/unicodeFontData.generated-YY6T2K5S.js +22 -0
- package/package.json +4 -3
- package/dist/images-CAWESWRF.js +0 -10
|
@@ -13,13 +13,14 @@ import {
|
|
|
13
13
|
fontAwesomeGlyph
|
|
14
14
|
} from "./chunk-LBXBRFBZ.js";
|
|
15
15
|
import {
|
|
16
|
+
authoredImageSize,
|
|
16
17
|
fitWithin,
|
|
17
18
|
readImageDimensions
|
|
18
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-JZR32FON.js";
|
|
19
20
|
|
|
20
21
|
// src/pdf/export.ts
|
|
21
22
|
import { PDFDocument, StandardFonts, rgb, PDFString } from "pdf-lib";
|
|
22
|
-
import
|
|
23
|
+
import fontkit2 from "@pdf-lib/fontkit";
|
|
23
24
|
import { contrastRatio } from "@bendyline/squisq/schemas";
|
|
24
25
|
import { docToMarkdown, resolveThemeForDoc } from "@bendyline/squisq/doc";
|
|
25
26
|
import { readFrontmatterThemeId, sanitizeUrl } from "@bendyline/squisq/markdown";
|
|
@@ -269,6 +270,10 @@ var WHITESPACE_LIKE = /* @__PURE__ */ new Set([
|
|
|
269
270
|
8288,
|
|
270
271
|
65279
|
|
271
272
|
]);
|
|
273
|
+
var INVISIBLE_OR_SPACE = /^[\p{Cc}\p{Cf}\p{Zl}\p{Zp}\p{Zs}]$/u;
|
|
274
|
+
function isInvisibleOrSpace(codePoint) {
|
|
275
|
+
return WHITESPACE_LIKE.has(codePoint) || INVISIBLE_OR_SPACE.test(String.fromCodePoint(codePoint));
|
|
276
|
+
}
|
|
272
277
|
var MAX_SAMPLES = 5;
|
|
273
278
|
var ASCII_ONLY = /^[\x20-\x7e]*$/;
|
|
274
279
|
var COMBINING_MARKS = /[̀-ͯ]/g;
|
|
@@ -320,13 +325,116 @@ var WinAnsiTracker = class {
|
|
|
320
325
|
get substitutions() {
|
|
321
326
|
return this.count;
|
|
322
327
|
}
|
|
323
|
-
/**
|
|
324
|
-
|
|
328
|
+
/**
|
|
329
|
+
* One-shot summary for the export, or undefined when nothing was lost.
|
|
330
|
+
* `unicodeFont` says an embedded Unicode font already drew what it could, so
|
|
331
|
+
* what remains is beyond it too (CJK and emoji, with the bundled faces).
|
|
332
|
+
*/
|
|
333
|
+
warning(options = {}) {
|
|
325
334
|
if (this.count === 0) return void 0;
|
|
335
|
+
if (options.unicodeFont) {
|
|
336
|
+
return `PDF export replaced ${this.count} character(s) that its fonts cannot draw (${this.samples.join(", ")}). Scripts such as CJK and emoji are not available in PDF export.`;
|
|
337
|
+
}
|
|
326
338
|
return `PDF export replaced ${this.count} character(s) that the standard PDF fonts cannot encode (${this.samples.join(", ")}). Scripts such as emoji, CJK and Cyrillic require an embedded Unicode font.`;
|
|
327
339
|
}
|
|
328
340
|
};
|
|
329
341
|
|
|
342
|
+
// src/pdf/unicodeText.ts
|
|
343
|
+
import fontkit from "@pdf-lib/fontkit";
|
|
344
|
+
async function loadBundledUnicodeFonts() {
|
|
345
|
+
const { dejaVuFontData } = await import("./unicodeFontData.generated-YY6T2K5S.js");
|
|
346
|
+
return dejaVuFontData();
|
|
347
|
+
}
|
|
348
|
+
function hasUnencodableText(value) {
|
|
349
|
+
for (const ch of value) {
|
|
350
|
+
const codePoint = ch.codePointAt(0);
|
|
351
|
+
if (!isWinAnsiEncodable(codePoint) && !isInvisibleOrSpace(codePoint)) return true;
|
|
352
|
+
}
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
function needsUnicodeFont(root) {
|
|
356
|
+
const pending = [root];
|
|
357
|
+
while (pending.length > 0) {
|
|
358
|
+
const value = pending.pop();
|
|
359
|
+
if (typeof value === "string") {
|
|
360
|
+
if (hasUnencodableText(value)) return true;
|
|
361
|
+
} else if (Array.isArray(value)) {
|
|
362
|
+
pending.push(...value);
|
|
363
|
+
} else if (value && typeof value === "object") {
|
|
364
|
+
pending.push(...Object.values(value));
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
function asBytes(data) {
|
|
370
|
+
return data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
371
|
+
}
|
|
372
|
+
async function embedUnicodeFaces(pdfDoc, fonts, standard) {
|
|
373
|
+
pdfDoc.registerFontkit(fontkit);
|
|
374
|
+
const faces = /* @__PURE__ */ new Map();
|
|
375
|
+
const faceFor = (data) => {
|
|
376
|
+
let face = faces.get(data);
|
|
377
|
+
if (!face) {
|
|
378
|
+
const bytes = asBytes(data);
|
|
379
|
+
const metrics = fontkit.create(bytes);
|
|
380
|
+
face = pdfDoc.embedFont(bytes, { subset: true }).then((font) => ({
|
|
381
|
+
font,
|
|
382
|
+
covers: (codePoint) => metrics.hasGlyphForCodePoint(codePoint)
|
|
383
|
+
}));
|
|
384
|
+
faces.set(data, face);
|
|
385
|
+
}
|
|
386
|
+
return face;
|
|
387
|
+
};
|
|
388
|
+
const [regular, bold, mono] = await Promise.all([
|
|
389
|
+
faceFor(fonts.regular),
|
|
390
|
+
faceFor(fonts.bold ?? fonts.regular),
|
|
391
|
+
faceFor(fonts.mono ?? fonts.regular)
|
|
392
|
+
]);
|
|
393
|
+
return /* @__PURE__ */ new Map([
|
|
394
|
+
[standard.regular, regular],
|
|
395
|
+
[standard.italic, regular],
|
|
396
|
+
[standard.bold, bold],
|
|
397
|
+
[standard.boldItalic, bold],
|
|
398
|
+
[standard.mono, mono],
|
|
399
|
+
[standard.monoBold, mono]
|
|
400
|
+
]);
|
|
401
|
+
}
|
|
402
|
+
var PdfTextRuns = class {
|
|
403
|
+
constructor(tracker, faces = /* @__PURE__ */ new Map()) {
|
|
404
|
+
this.tracker = tracker;
|
|
405
|
+
this.faces = faces;
|
|
406
|
+
}
|
|
407
|
+
split(text, font) {
|
|
408
|
+
const face = this.faces.get(font);
|
|
409
|
+
if (!face || !hasUnencodableText(text)) return [{ text: this.tracker.clean(text), font }];
|
|
410
|
+
const runs = [];
|
|
411
|
+
const push = (value, runFont) => {
|
|
412
|
+
if (value.length === 0) return;
|
|
413
|
+
const last = runs[runs.length - 1];
|
|
414
|
+
if (last && last.font === runFont) last.text += value;
|
|
415
|
+
else runs.push({ text: value, font: runFont });
|
|
416
|
+
};
|
|
417
|
+
const drawable = (codePoint) => !isInvisibleOrSpace(codePoint) && face.covers(codePoint);
|
|
418
|
+
for (const word of text.normalize("NFC").split(/(\s+)/u)) {
|
|
419
|
+
if (word.length === 0) continue;
|
|
420
|
+
const codePoints = Array.from(word, (ch) => ch.codePointAt(0));
|
|
421
|
+
if (codePoints.every(isWinAnsiEncodable)) {
|
|
422
|
+
push(word, font);
|
|
423
|
+
} else if (codePoints.every(drawable)) {
|
|
424
|
+
push(word, face.font);
|
|
425
|
+
} else {
|
|
426
|
+
for (const ch of word) {
|
|
427
|
+
const codePoint = ch.codePointAt(0);
|
|
428
|
+
if (isWinAnsiEncodable(codePoint)) push(ch, font);
|
|
429
|
+
else if (drawable(codePoint)) push(ch, face.font);
|
|
430
|
+
else push(this.tracker.clean(ch), font);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return runs.length > 0 ? runs : [{ text: "", font }];
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
|
|
330
438
|
// src/pdf/styles.ts
|
|
331
439
|
var PAGE_WIDTH_LETTER = 612;
|
|
332
440
|
var PAGE_HEIGHT_LETTER = 792;
|
|
@@ -401,7 +509,7 @@ async function markdownDocToPdf(doc, options = {}) {
|
|
|
401
509
|
const ctx = await createExportContext(pdfDoc, options, doc);
|
|
402
510
|
ctx.images = await embedDocumentImages(pdfDoc, doc, options.images);
|
|
403
511
|
renderBlocks(doc.children, ctx, 0);
|
|
404
|
-
const warning = ctx.text.warning();
|
|
512
|
+
const warning = ctx.text.warning({ unicodeFont: ctx.unicodeFont });
|
|
405
513
|
if (warning) {
|
|
406
514
|
if (options.onWarning) options.onWarning(warning);
|
|
407
515
|
else console.warn(warning);
|
|
@@ -455,10 +563,22 @@ async function createExportContext(pdfDoc, options, doc) {
|
|
|
455
563
|
pdfDoc.embedFont(StandardFonts.Courier),
|
|
456
564
|
pdfDoc.embedFont(StandardFonts.CourierBold)
|
|
457
565
|
]);
|
|
566
|
+
let unicodeFaces = /* @__PURE__ */ new Map();
|
|
567
|
+
if (options.unicodeFonts !== false && needsUnicodeFont(doc)) {
|
|
568
|
+
const faces = options.unicodeFonts ?? await loadBundledUnicodeFonts();
|
|
569
|
+
unicodeFaces = await embedUnicodeFaces(pdfDoc, faces, {
|
|
570
|
+
regular,
|
|
571
|
+
bold,
|
|
572
|
+
italic,
|
|
573
|
+
boldItalic,
|
|
574
|
+
mono,
|
|
575
|
+
monoBold
|
|
576
|
+
});
|
|
577
|
+
}
|
|
458
578
|
const icons = {};
|
|
459
579
|
const iconFamilies = collectInlineIconFamilies(doc);
|
|
460
580
|
if (iconFamilies.size > 0) {
|
|
461
|
-
pdfDoc.registerFontkit(
|
|
581
|
+
pdfDoc.registerFontkit(fontkit2);
|
|
462
582
|
await Promise.all(
|
|
463
583
|
fontAwesomeFaces(iconFamilies).map(async (face) => {
|
|
464
584
|
icons[face.family] = await pdfDoc.embedFont(face.data, { subset: true });
|
|
@@ -483,6 +603,7 @@ async function createExportContext(pdfDoc, options, doc) {
|
|
|
483
603
|
colorLink = paperInk(theme.colors.highlight || theme.colors.secondary, COLOR_LINK);
|
|
484
604
|
}
|
|
485
605
|
}
|
|
606
|
+
const text = new WinAnsiTracker();
|
|
486
607
|
return {
|
|
487
608
|
pdfDoc,
|
|
488
609
|
fonts: { regular, bold, italic, boldItalic, mono, monoBold, icons },
|
|
@@ -496,7 +617,9 @@ async function createExportContext(pdfDoc, options, doc) {
|
|
|
496
617
|
bottomY: margin,
|
|
497
618
|
colors: { text: colorText, heading: colorHeading, link: colorLink },
|
|
498
619
|
footnotes: new FootnoteIndex(doc),
|
|
499
|
-
text
|
|
620
|
+
text,
|
|
621
|
+
runs: new PdfTextRuns(text, unicodeFaces),
|
|
622
|
+
unicodeFont: unicodeFaces.size > 0,
|
|
500
623
|
signal: options.signal,
|
|
501
624
|
images: /* @__PURE__ */ new Map()
|
|
502
625
|
};
|
|
@@ -522,15 +645,15 @@ function flattenInlines(nodes, ctx, state) {
|
|
|
522
645
|
case "text": {
|
|
523
646
|
const font = state.code ? state.bold ? ctx.fonts.monoBold : ctx.fonts.mono : pickFont(ctx, state.bold, state.italic);
|
|
524
647
|
const baseSize = state.code ? CODE_FONT_SIZE : ctx.fontSize;
|
|
525
|
-
spans.push(
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
648
|
+
spans.push(
|
|
649
|
+
...textSpans(ctx, node.value, font, {
|
|
650
|
+
fontSize: state.vertAlign ? baseSize * VERT_ALIGN_SCALE : baseSize,
|
|
651
|
+
color: state.code ? COLOR_CODE_TEXT : state.color ?? ctx.colors.text,
|
|
652
|
+
link: state.link,
|
|
653
|
+
strikethrough: state.strikethrough,
|
|
654
|
+
...state.vertAlign ? { baselineShift: vertAlignShift(state.vertAlign, baseSize) } : {}
|
|
655
|
+
})
|
|
656
|
+
);
|
|
534
657
|
break;
|
|
535
658
|
}
|
|
536
659
|
case "strong":
|
|
@@ -561,13 +684,13 @@ function flattenInlines(nodes, ctx, state) {
|
|
|
561
684
|
);
|
|
562
685
|
break;
|
|
563
686
|
case "inlineCode": {
|
|
564
|
-
spans.push(
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
687
|
+
spans.push(
|
|
688
|
+
...textSpans(ctx, node.value, ctx.fonts.mono, {
|
|
689
|
+
fontSize: CODE_FONT_SIZE,
|
|
690
|
+
color: COLOR_CODE_TEXT,
|
|
691
|
+
link: state.link
|
|
692
|
+
})
|
|
693
|
+
);
|
|
571
694
|
break;
|
|
572
695
|
}
|
|
573
696
|
case "link": {
|
|
@@ -584,12 +707,12 @@ function flattenInlines(nodes, ctx, state) {
|
|
|
584
707
|
}
|
|
585
708
|
case "image": {
|
|
586
709
|
const imgNode = node;
|
|
587
|
-
spans.push(
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
710
|
+
spans.push(
|
|
711
|
+
...textSpans(ctx, imgNode.alt ? `[Image: ${imgNode.alt}]` : "[Image]", ctx.fonts.italic, {
|
|
712
|
+
fontSize: ctx.fontSize,
|
|
713
|
+
color: COLOR_BLOCKQUOTE_TEXT
|
|
714
|
+
})
|
|
715
|
+
);
|
|
593
716
|
break;
|
|
594
717
|
}
|
|
595
718
|
case "inlineIcon": {
|
|
@@ -606,14 +729,14 @@ function flattenInlines(nodes, ctx, state) {
|
|
|
606
729
|
strikethrough: state.strikethrough
|
|
607
730
|
});
|
|
608
731
|
} else {
|
|
609
|
-
spans.push(
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
732
|
+
spans.push(
|
|
733
|
+
...textSpans(ctx, `{[${iconNode.token}]}`, pickFont(ctx, state.bold, state.italic), {
|
|
734
|
+
fontSize: ctx.fontSize,
|
|
735
|
+
color: state.color ?? ctx.colors.text,
|
|
736
|
+
link: state.link,
|
|
737
|
+
strikethrough: state.strikethrough
|
|
738
|
+
})
|
|
739
|
+
);
|
|
617
740
|
}
|
|
618
741
|
break;
|
|
619
742
|
}
|
|
@@ -628,33 +751,33 @@ function flattenInlines(nodes, ctx, state) {
|
|
|
628
751
|
case "htmlInline": {
|
|
629
752
|
const html = node.rawHtml;
|
|
630
753
|
if (html) {
|
|
631
|
-
spans.push(
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
754
|
+
spans.push(
|
|
755
|
+
...textSpans(ctx, html, ctx.fonts.mono, {
|
|
756
|
+
fontSize: CODE_FONT_SIZE,
|
|
757
|
+
color: COLOR_CODE_TEXT
|
|
758
|
+
})
|
|
759
|
+
);
|
|
637
760
|
}
|
|
638
761
|
break;
|
|
639
762
|
}
|
|
640
763
|
case "inlineMath":
|
|
641
|
-
spans.push(
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
764
|
+
spans.push(
|
|
765
|
+
...textSpans(ctx, node.value, ctx.fonts.mono, {
|
|
766
|
+
fontSize: CODE_FONT_SIZE,
|
|
767
|
+
color: COLOR_CODE_TEXT
|
|
768
|
+
})
|
|
769
|
+
);
|
|
647
770
|
break;
|
|
648
771
|
case "footnoteReference": {
|
|
649
772
|
const ref = node;
|
|
650
773
|
const marker = ctx.footnotes ? String(ctx.footnotes.cite(ref.identifier).number) : ref.label ?? ref.identifier;
|
|
651
|
-
spans.push(
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
774
|
+
spans.push(
|
|
775
|
+
...textSpans(ctx, marker, ctx.fonts.regular, {
|
|
776
|
+
fontSize: ctx.fontSize * VERT_ALIGN_SCALE,
|
|
777
|
+
color: ctx.colors.link,
|
|
778
|
+
baselineShift: vertAlignShift("superscript", ctx.fontSize)
|
|
779
|
+
})
|
|
780
|
+
);
|
|
658
781
|
break;
|
|
659
782
|
}
|
|
660
783
|
// linkReference, imageReference, textDirective — render children or identifier
|
|
@@ -663,12 +786,12 @@ function flattenInlines(nodes, ctx, state) {
|
|
|
663
786
|
if (fallback.children) {
|
|
664
787
|
spans.push(...flattenInlines(fallback.children, ctx, state));
|
|
665
788
|
} else if (fallback.value) {
|
|
666
|
-
spans.push(
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
789
|
+
spans.push(
|
|
790
|
+
...textSpans(ctx, fallback.value, pickFont(ctx, state.bold, state.italic), {
|
|
791
|
+
fontSize: ctx.fontSize,
|
|
792
|
+
color: state.color ?? ctx.colors.text
|
|
793
|
+
})
|
|
794
|
+
);
|
|
672
795
|
}
|
|
673
796
|
break;
|
|
674
797
|
}
|
|
@@ -676,6 +799,23 @@ function flattenInlines(nodes, ctx, state) {
|
|
|
676
799
|
}
|
|
677
800
|
return spans;
|
|
678
801
|
}
|
|
802
|
+
function textSpans(ctx, text, font, style) {
|
|
803
|
+
return ctx.runs.split(text, font).map((run) => ({ ...style, text: run.text, font: run.font }));
|
|
804
|
+
}
|
|
805
|
+
function drawTextLine(ctx, text, font, at) {
|
|
806
|
+
let x = at.x;
|
|
807
|
+
for (const run of ctx.runs.split(text, font)) {
|
|
808
|
+
if (run.text.length === 0) continue;
|
|
809
|
+
ctx.page.drawText(run.text, {
|
|
810
|
+
x,
|
|
811
|
+
y: at.y,
|
|
812
|
+
size: at.size,
|
|
813
|
+
font: run.font,
|
|
814
|
+
color: rgb(at.color.r, at.color.g, at.color.b)
|
|
815
|
+
});
|
|
816
|
+
x += run.font.widthOfTextAtSize(run.text, at.size);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
679
819
|
function pickFont(ctx, bold, italic) {
|
|
680
820
|
if (bold && italic) return ctx.fonts.boldItalic;
|
|
681
821
|
if (bold) return ctx.fonts.bold;
|
|
@@ -880,9 +1020,10 @@ function renderImageParagraph(node, ctx, x0, width) {
|
|
|
880
1020
|
drawSpans(note, ctx, width, x0);
|
|
881
1021
|
continue;
|
|
882
1022
|
}
|
|
1023
|
+
const display = authoredImageSize(imageNode, embedded) ?? embedded;
|
|
883
1024
|
const size = fitWithin(
|
|
884
|
-
|
|
885
|
-
|
|
1025
|
+
display.width * POINTS_PER_CSS_PIXEL,
|
|
1026
|
+
display.height * POINTS_PER_CSS_PIXEL,
|
|
886
1027
|
width,
|
|
887
1028
|
maxHeight
|
|
888
1029
|
);
|
|
@@ -967,7 +1108,7 @@ function renderListItem(item, ctx, extraIndent, depth, ordered, counter) {
|
|
|
967
1108
|
function renderCodeBlock(node, ctx, extraIndent) {
|
|
968
1109
|
const x0 = ctx.margin + extraIndent;
|
|
969
1110
|
const _w = ctx.contentWidth - extraIndent;
|
|
970
|
-
const lines = node.value.split("\n")
|
|
1111
|
+
const lines = node.value.split("\n");
|
|
971
1112
|
const lineH = CODE_FONT_SIZE * LINE_HEIGHT_FACTOR;
|
|
972
1113
|
const totalHeight = lines.length * lineH + 12;
|
|
973
1114
|
ensureSpace(ctx, Math.min(totalHeight, ctx.y - ctx.bottomY));
|
|
@@ -977,12 +1118,11 @@ function renderCodeBlock(node, ctx, extraIndent) {
|
|
|
977
1118
|
for (const line of lines) {
|
|
978
1119
|
ensureSpace(ctx, lineH);
|
|
979
1120
|
if (line.length > 0) {
|
|
980
|
-
ctx.
|
|
1121
|
+
drawTextLine(ctx, line, ctx.fonts.mono, {
|
|
981
1122
|
x: x0 + 8,
|
|
982
1123
|
y: ctx.y - CODE_FONT_SIZE,
|
|
983
1124
|
size: CODE_FONT_SIZE,
|
|
984
|
-
|
|
985
|
-
color: rgb(COLOR_CODE_TEXT.r, COLOR_CODE_TEXT.g, COLOR_CODE_TEXT.b)
|
|
1125
|
+
color: COLOR_CODE_TEXT
|
|
986
1126
|
});
|
|
987
1127
|
}
|
|
988
1128
|
ctx.y -= lineH;
|
|
@@ -1083,36 +1223,34 @@ function renderThematicBreak(ctx, extraIndent) {
|
|
|
1083
1223
|
}
|
|
1084
1224
|
function renderHtmlBlock(node, ctx, extraIndent) {
|
|
1085
1225
|
if (!node.rawHtml) return;
|
|
1086
|
-
const lines = node.rawHtml.split("\n")
|
|
1226
|
+
const lines = node.rawHtml.split("\n");
|
|
1087
1227
|
const x0 = ctx.margin + extraIndent;
|
|
1088
1228
|
for (const line of lines) {
|
|
1089
1229
|
if (line.trim().length === 0) continue;
|
|
1090
1230
|
const lineH = CODE_FONT_SIZE * LINE_HEIGHT_FACTOR;
|
|
1091
1231
|
ensureSpace(ctx, lineH);
|
|
1092
|
-
ctx.
|
|
1232
|
+
drawTextLine(ctx, line, ctx.fonts.mono, {
|
|
1093
1233
|
x: x0,
|
|
1094
1234
|
y: ctx.y - CODE_FONT_SIZE,
|
|
1095
1235
|
size: CODE_FONT_SIZE,
|
|
1096
|
-
|
|
1097
|
-
color: rgb(COLOR_CODE_TEXT.r, COLOR_CODE_TEXT.g, COLOR_CODE_TEXT.b)
|
|
1236
|
+
color: COLOR_CODE_TEXT
|
|
1098
1237
|
});
|
|
1099
1238
|
ctx.y -= lineH;
|
|
1100
1239
|
}
|
|
1101
1240
|
ctx.y -= PARAGRAPH_SPACING;
|
|
1102
1241
|
}
|
|
1103
1242
|
function renderMathBlock(node, ctx, extraIndent) {
|
|
1104
|
-
const lines = node.value.split("\n")
|
|
1243
|
+
const lines = node.value.split("\n");
|
|
1105
1244
|
const x0 = ctx.margin + extraIndent;
|
|
1106
1245
|
for (const line of lines) {
|
|
1107
1246
|
const lineH = CODE_FONT_SIZE * LINE_HEIGHT_FACTOR;
|
|
1108
1247
|
ensureSpace(ctx, lineH);
|
|
1109
1248
|
if (line.length > 0) {
|
|
1110
|
-
ctx.
|
|
1249
|
+
drawTextLine(ctx, line, ctx.fonts.mono, {
|
|
1111
1250
|
x: x0,
|
|
1112
1251
|
y: ctx.y - CODE_FONT_SIZE,
|
|
1113
1252
|
size: CODE_FONT_SIZE,
|
|
1114
|
-
|
|
1115
|
-
color: rgb(COLOR_CODE_TEXT.r, COLOR_CODE_TEXT.g, COLOR_CODE_TEXT.b)
|
|
1253
|
+
color: COLOR_CODE_TEXT
|
|
1116
1254
|
});
|
|
1117
1255
|
}
|
|
1118
1256
|
ctx.y -= lineH;
|
|
@@ -1121,15 +1259,14 @@ function renderMathBlock(node, ctx, extraIndent) {
|
|
|
1121
1259
|
}
|
|
1122
1260
|
function renderFootnoteDefinition(node, ctx, extraIndent) {
|
|
1123
1261
|
const number = ctx.footnotes?.numberFor(node.identifier);
|
|
1124
|
-
const label =
|
|
1262
|
+
const label = number !== void 0 ? `${number}.` : `[${node.identifier}]`;
|
|
1125
1263
|
const lineH = ctx.fontSize * LINE_HEIGHT_FACTOR;
|
|
1126
1264
|
ensureSpace(ctx, lineH);
|
|
1127
|
-
ctx.
|
|
1265
|
+
drawTextLine(ctx, label, ctx.fonts.bold, {
|
|
1128
1266
|
x: ctx.margin + extraIndent,
|
|
1129
1267
|
y: ctx.y - ctx.fontSize * 0.75,
|
|
1130
1268
|
size: ctx.fontSize * 0.75,
|
|
1131
|
-
|
|
1132
|
-
color: rgb(ctx.colors.link.r, ctx.colors.link.g, ctx.colors.link.b)
|
|
1269
|
+
color: ctx.colors.link
|
|
1133
1270
|
});
|
|
1134
1271
|
renderBlocks(node.children, ctx, extraIndent + LIST_INDENT);
|
|
1135
1272
|
}
|
|
@@ -1163,12 +1300,11 @@ function renderFallbackBlock(node, ctx, extraIndent) {
|
|
|
1163
1300
|
} else if (fallback.value && typeof fallback.value === "string") {
|
|
1164
1301
|
const lineH = ctx.fontSize * LINE_HEIGHT_FACTOR;
|
|
1165
1302
|
ensureSpace(ctx, lineH);
|
|
1166
|
-
|
|
1303
|
+
drawTextLine(ctx, fallback.value, ctx.fonts.regular, {
|
|
1167
1304
|
x: ctx.margin + extraIndent,
|
|
1168
1305
|
y: ctx.y - ctx.fontSize,
|
|
1169
1306
|
size: ctx.fontSize,
|
|
1170
|
-
|
|
1171
|
-
color: rgb(ctx.colors.text.r, ctx.colors.text.g, ctx.colors.text.b)
|
|
1307
|
+
color: ctx.colors.text
|
|
1172
1308
|
});
|
|
1173
1309
|
ctx.y -= lineH + PARAGRAPH_SPACING;
|
|
1174
1310
|
}
|
|
@@ -67,10 +67,11 @@ import {
|
|
|
67
67
|
obfuscateDocxFont
|
|
68
68
|
} from "./chunk-LBXBRFBZ.js";
|
|
69
69
|
import {
|
|
70
|
+
authoredImageSize,
|
|
70
71
|
extToMime,
|
|
71
72
|
fitWithin,
|
|
72
73
|
readImageDimensions
|
|
73
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-JZR32FON.js";
|
|
74
75
|
|
|
75
76
|
// src/docx/export.ts
|
|
76
77
|
import { resolveFontFamily } from "@bendyline/squisq/schemas";
|
|
@@ -703,7 +704,8 @@ function convertImage(node, ctx) {
|
|
|
703
704
|
const ext = contentType.split("/")[1]?.replace("jpeg", "jpg") || "png";
|
|
704
705
|
const filename = `image${ctx.images.length + 1}.${ext}`;
|
|
705
706
|
const { relId, docPrId } = ctx.addImage(data, contentType, filename);
|
|
706
|
-
const
|
|
707
|
+
const natural = imageEntry.width && imageEntry.height ? { width: imageEntry.width, height: imageEntry.height } : readImageDimensions(data);
|
|
708
|
+
const dims = authoredImageSize(node, natural) ?? natural;
|
|
707
709
|
const EMU_PER_INCH3 = 914400;
|
|
708
710
|
const MAX_WIDTH_EMU2 = 6 * EMU_PER_INCH3;
|
|
709
711
|
const MAX_HEIGHT_EMU2 = 8 * EMU_PER_INCH3;
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
arrayBufferToBase64DataUrl,
|
|
3
3
|
extractFilename,
|
|
4
4
|
inferMimeType
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-WMIDXNGR.js";
|
|
6
6
|
import {
|
|
7
7
|
exportImageBytes
|
|
8
8
|
} from "./chunk-VCZUXQUL.js";
|
|
@@ -10,6 +10,9 @@ import {
|
|
|
10
10
|
FootnoteIndex,
|
|
11
11
|
footnoteIds
|
|
12
12
|
} from "./chunk-BXWNU4T5.js";
|
|
13
|
+
import {
|
|
14
|
+
imageSizeAttributes
|
|
15
|
+
} from "./chunk-JZR32FON.js";
|
|
13
16
|
|
|
14
17
|
// src/html/index.ts
|
|
15
18
|
import JSZip3 from "jszip";
|
|
@@ -504,7 +507,8 @@ function extractFirstImageFromBlock(block) {
|
|
|
504
507
|
);
|
|
505
508
|
const replacement = remainingKids.length === 0 ? null : { ...b, children: remainingKids };
|
|
506
509
|
return {
|
|
507
|
-
image
|
|
510
|
+
// A resized image parses with the size it was given in the editor.
|
|
511
|
+
image: { src: img.url, alt: img.alt ?? "", width: img.width, height: img.height },
|
|
508
512
|
replacement
|
|
509
513
|
};
|
|
510
514
|
}
|
|
@@ -780,7 +784,7 @@ function nodeToHtml(node, ctx) {
|
|
|
780
784
|
const resolved = ctx?.images?.get(original) ?? original;
|
|
781
785
|
const safeSrc = sanitizeUrl(resolved, "media") ?? svgDataImageToHtmlSrc(resolved);
|
|
782
786
|
if (!safeSrc) return escapeHtml2(node.alt ?? "");
|
|
783
|
-
return `<img src="${escapeAttr(safeSrc)}" alt="${escapeAttr(node.alt ?? "")}" />`;
|
|
787
|
+
return `<img src="${escapeAttr(safeSrc)}" alt="${escapeAttr(node.alt ?? "")}"${imageSizeAttributes(node)} />`;
|
|
784
788
|
}
|
|
785
789
|
case "thematicBreak":
|
|
786
790
|
return "<hr />";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
extractFilename,
|
|
3
3
|
inferMimeType
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-WMIDXNGR.js";
|
|
5
5
|
import {
|
|
6
6
|
exportImageBytes,
|
|
7
7
|
svgIslandsAsImages
|
|
@@ -21,6 +21,9 @@ import {
|
|
|
21
21
|
fontAwesomeFaces,
|
|
22
22
|
fontAwesomeGlyph
|
|
23
23
|
} from "./chunk-LBXBRFBZ.js";
|
|
24
|
+
import {
|
|
25
|
+
imageSizeAttributes
|
|
26
|
+
} from "./chunk-JZR32FON.js";
|
|
24
27
|
|
|
25
28
|
// src/epub/export.ts
|
|
26
29
|
import JSZip from "jszip";
|
|
@@ -432,7 +435,7 @@ function inlineToXhtml(node, ctx) {
|
|
|
432
435
|
const safeSrc = resolved ? `../images/${resolved.filename}` : sanitizeUrl(node.url, "media");
|
|
433
436
|
if (!safeSrc) return alt;
|
|
434
437
|
const src = escapeXml(safeSrc);
|
|
435
|
-
return `<img src="${src}" alt="${alt}"/>`;
|
|
438
|
+
return `<img src="${src}" alt="${alt}"${imageSizeAttributes(node)}/>`;
|
|
436
439
|
}
|
|
437
440
|
case "break":
|
|
438
441
|
return "<br/>";
|
|
@@ -65,9 +65,22 @@ function fitWithin(width, height, maxWidth, maxHeight) {
|
|
|
65
65
|
const scale = Math.min(1, maxWidth / width, maxHeight / height);
|
|
66
66
|
return { width: width * scale, height: height * scale };
|
|
67
67
|
}
|
|
68
|
+
function imageSizeAttributes(image) {
|
|
69
|
+
return (image.width !== void 0 ? ` width="${image.width}"` : "") + (image.height !== void 0 ? ` height="${image.height}"` : "");
|
|
70
|
+
}
|
|
71
|
+
function authoredImageSize(image, intrinsic) {
|
|
72
|
+
const { width, height } = image;
|
|
73
|
+
if (width !== void 0 && height !== void 0) return { width, height };
|
|
74
|
+
if (!intrinsic || intrinsic.width <= 0 || intrinsic.height <= 0) return void 0;
|
|
75
|
+
if (width !== void 0) return { width, height: width * intrinsic.height / intrinsic.width };
|
|
76
|
+
if (height !== void 0) return { width: height * intrinsic.width / intrinsic.height, height };
|
|
77
|
+
return void 0;
|
|
78
|
+
}
|
|
68
79
|
|
|
69
80
|
export {
|
|
70
81
|
extToMime,
|
|
71
82
|
readImageDimensions,
|
|
72
|
-
fitWithin
|
|
83
|
+
fitWithin,
|
|
84
|
+
imageSizeAttributes,
|
|
85
|
+
authoredImageSize
|
|
73
86
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
inferMimeType
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-WMIDXNGR.js";
|
|
4
4
|
import {
|
|
5
5
|
RelIdAllocator,
|
|
6
6
|
blipXml,
|
|
@@ -63,7 +63,7 @@ import {
|
|
|
63
63
|
} from "./chunk-LBXBRFBZ.js";
|
|
64
64
|
import {
|
|
65
65
|
extToMime
|
|
66
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-JZR32FON.js";
|
|
67
67
|
|
|
68
68
|
// src/pptx/export.ts
|
|
69
69
|
import { resolveFontFamily, VIEWPORT_PRESETS } from "@bendyline/squisq/schemas";
|
|
@@ -262,7 +262,7 @@ function dataReferenceWarnings(doc, formatLabel) {
|
|
|
262
262
|
}
|
|
263
263
|
async function collectContainerDocxImages(container, signal) {
|
|
264
264
|
const images = await collectContainerImages(container, signal);
|
|
265
|
-
const { extToMime } = await import("./images-
|
|
265
|
+
const { extToMime } = await import("./images-PQCYRJJ5.js");
|
|
266
266
|
return new Map(
|
|
267
267
|
[...images].map(([path, data]) => [
|
|
268
268
|
path,
|
package/dist/docx/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
docxToDoc,
|
|
5
5
|
docxToMarkdownDoc,
|
|
6
6
|
markdownDocToDocx
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-5YYF3Z6C.js";
|
|
8
8
|
import "../chunk-XVBQB2SL.js";
|
|
9
9
|
import "../chunk-VCZUXQUL.js";
|
|
10
10
|
import "../chunk-AVOZAKGP.js";
|
|
@@ -15,7 +15,7 @@ import "../chunk-7AWFHP5U.js";
|
|
|
15
15
|
import "../chunk-BXWNU4T5.js";
|
|
16
16
|
import "../chunk-IIQYS2YH.js";
|
|
17
17
|
import "../chunk-LBXBRFBZ.js";
|
|
18
|
-
import "../chunk-
|
|
18
|
+
import "../chunk-JZR32FON.js";
|
|
19
19
|
export {
|
|
20
20
|
docToDocx,
|
|
21
21
|
docxToContainer,
|