Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change drawSvg to be synchronous #53

Merged
merged 2 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions apps/web/test19.html
Original file line number Diff line number Diff line change
Expand Up @@ -248,21 +248,21 @@
y: 0,
size: 20,
});
await firstPage.drawSvg(svg, {
firstPage.drawSvg(svg, {
x: 100,
y: 841 /*
width: 427 / 3,
height: 769 / 3 */,
});
await firstPage.drawSvg(svgPowerTwo, {
firstPage.drawSvg(svgPowerTwo, {
x: 550,
y: 841,
});
await secondPage.drawSvg(svgDemo, {
secondPage.drawSvg(svgDemo, {
x: 100,
y: 841,
});
await secondPage.drawSvg(scienceSvgs, {
secondPage.drawSvg(scienceSvgs, {
x: 100,
y: 500,
});
Expand Down
4 changes: 2 additions & 2 deletions apps/web/test20.html
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,11 @@
x: 100,
y: 1000
}); */
await firstPage.drawSvg(svg3, {
firstPage.drawSvg(svg3, {
x: 100,
y: 950,
});
await firstPage.drawSvg(svg2, {
firstPage.drawSvg(svg2, {
x: 100,
y: 800,
});
Expand Down
2 changes: 1 addition & 1 deletion apps/web/test21.html
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
drawLines(firstPage);
drawLines(secondPage);

await firstPage.drawSvg(svg, {
firstPage.drawSvg(svg, {
x: 100,
y: 800,
});
Expand Down
2 changes: 1 addition & 1 deletion apps/web/test22.html
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@
// drawGrid(firstPage)
drawLines(firstPage);

await firstPage.drawSvg(svg, {
firstPage.drawSvg(svg, {
height: 173.0060640625,
width: 167.68455000000003,
x: 100,
Expand Down
2 changes: 1 addition & 1 deletion apps/web/test23.html
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@
// drawGrid(firstPage)
drawLines(firstPage);

await firstPage.drawSvg(svg, {
firstPage.drawSvg(svg, {
height: 595.28,
width: 841.89,
// height: 100,
Expand Down
2 changes: 1 addition & 1 deletion apps/web/test24.html
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@
// drawGrid(firstPage)
drawLines(firstPage);

await firstPage.drawSvg(svg, {
firstPage.drawSvg(svg, {
height: 719,
width: 611,
// height: 100,
Expand Down
8 changes: 4 additions & 4 deletions apps/web/test25.html
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@
// drawGrid(firstPage)
drawLines(firstPage);

await firstPage.drawSvg(svg, {
firstPage.drawSvg(svg, {
height: 602,
width: 409,
// height: 32,
Expand All @@ -149,21 +149,21 @@
y: 700,
});

// await firstPage.drawSvg(svg3, {
// firstPage.drawSvg(svg3, {
// height: 100,
// width: 100,
// x: 100,
// y: 700
// })

// await firstPage.drawSvg(svg2, {
// firstPage.drawSvg(svg2, {
// height: 100,
// width: 100,
// x: 100,
// y: 500
// })

// await firstPage.drawSvg(svg4, {
// firstPage.drawSvg(svg4, {
// height: 100,
// width: 100,
// x: 100,
Expand Down
2 changes: 1 addition & 1 deletion apps/web/test26.html
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@
// drawGrid(firstPage)
drawLines(firstPage);

await firstPage.drawSvg(svg, {
firstPage.drawSvg(svg, {
height: 240.75,
width: 249.75,
x: 100,
Expand Down
6 changes: 3 additions & 3 deletions apps/web/test27.html
Original file line number Diff line number Diff line change
Expand Up @@ -321,21 +321,21 @@
// drawGrid(firstPage)
drawLines(firstPage);

await firstPage.drawSvg(svg, {
firstPage.drawSvg(svg, {
height: 246.75,
width: 231,
x: 100,
y: 700,
});

await firstPage.drawSvg(cutArrowSvg, {
firstPage.drawSvg(cutArrowSvg, {
height: 246.75,
width: 231,
x: 500,
y: 700,
});

await firstPage.drawSvg(simpleCutArrowSvg, {
firstPage.drawSvg(simpleCutArrowSvg, {
height: 246.75,
width: 231,
x: 500,
Expand Down
2 changes: 1 addition & 1 deletion apps/web/test28.html
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@
// drawGrid(firstPage)
drawLines(firstPage);

await firstPage.drawSvg(svg, {
firstPage.drawSvg(svg, {
height: 300,
width: 400,
x: 100,
Expand Down
15 changes: 13 additions & 2 deletions apps/web/test29.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<iframe id="iframe"></iframe>
</body>

<script type="text/javascript">
<script type="text/javascript" >
// startFpsTracker('animation-target');

const renderInIframe = (pdfBytes) => {
Expand Down Expand Up @@ -105,12 +105,23 @@
// drawGrid(firstPage)
drawLines(firstPage);

await firstPage.drawSvg(svg, {
firstPage.drawSvg(svg, {
height: 100,
width: 100,
x: 100,
y: 700,
});

const svg2 = `<svg height="200" width="300">
<image width="300" height="200" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII" />
</svg>`
const pdfSvg = await pdfDoc.embedSvg(svg2)
firstPage.drawSvg(pdfSvg, {
height: 200,
width: 300,
x: 500,
y: 700,
});
firstPage.moveUp(600);
firstPage.moveRight(100);
firstPage.drawSvgPath(
Expand Down
28 changes: 28 additions & 0 deletions src/api/PDFDocument.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import {
parse as parseHtml,
HTMLElement,
NodeType,
} from 'node-html-better-parser';
import Embeddable from './Embeddable';
import {
EncryptedPDFError,
Expand Down Expand Up @@ -68,6 +73,7 @@ import PDFEmbeddedFile from './PDFEmbeddedFile';
import PDFJavaScript from './PDFJavaScript';
import JavaScriptEmbedder from '../core/embedders/JavaScriptEmbedder';
import { CipherTransformFactory } from '../core/crypto';
import PDFSvg from './PDFSvg';

/**
* Represents a PDF document.
Expand Down Expand Up @@ -1110,6 +1116,28 @@ export default class PDFDocument {
return pdfImage;
}

async embedSvg(svg: string): Promise<PDFSvg> {
if (!svg) return new PDFSvg(svg)
const parsedSvg = parseHtml(svg)
const findImages = (element: HTMLElement): HTMLElement[] => {
if (element.tagName === 'image') return [element]
else return element.childNodes.map(child => child.nodeType === NodeType.ELEMENT_NODE ? findImages(child): []).flat()
}
const images = findImages(parsedSvg)
const imagesDict = {} as Record<string, PDFImage>

await Promise.all(
images.map(async image => {
const href = image.attributes.href
if (!href || imagesDict[href]) return
const isPng = href.match(/\.png(\?|$)|^data:image\/png;base64/gim)
const pdfImage = isPng ? await this.embedPng(href) : await this.embedJpg(href)
imagesDict[href] = pdfImage
})
)

return new PDFSvg(svg, imagesDict)
}
/**
* Embed one or more PDF pages into this document.
*
Expand Down
11 changes: 6 additions & 5 deletions src/api/PDFPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import PDFDocument from './PDFDocument';
import PDFEmbeddedPage from './PDFEmbeddedPage';
import PDFFont from './PDFFont';
import PDFImage from './PDFImage';
import PDFSvg from './PDFSvg';
import {
PDFPageDrawCircleOptions,
PDFPageDrawEllipseOptions,
Expand Down Expand Up @@ -1585,17 +1586,17 @@ export default class PDFPage {
* @param svg The SVG to be drawn.
* @param options The options to be used when drawing the SVG.
*/
async drawSvg(
svg: string,
drawSvg(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to avoid breaking changes, this method can't be made sync, because it is exposed to the public. But we could decide to make a breaking change. In this case, we should change the signature of this method to drawSvg(svg: PDFSvg, options: PDFPageDrawSVGElementOptions)

In case you want to go with the no breaking change option, you'd need to create the method:

drawSvgSync(svg: PDFSvg, options: PDFPageDrawSVGElementOptions): void {
  drawSvg(this, svg, options)
}

async drawSvg(svg: string, options: PDFPageDrawSVGElementOptions): void {
  const svgPdf = await embedSvg(svg)
  this.drawSvgSync(svgPdf, options)
}

The other option would lead to only:

drawSvg(svg: PDFSvg, options: PDFPageDrawSVGElementOptions): void {
  drawSvg(this, svg, options)
}

Of course, you can keep the asserts and detail the options like in the current code

svg: PDFSvg | string,
options: PDFPageDrawSVGElementOptions = {},
): Promise<void> {
assertIs(svg, 'svg', ['string']);
): void {
assertIs(svg, 'svg', ['string', [PDFSvg, 'PDFSvg']]);
assertOrUndefined(options.x, 'options.x', ['number']);
assertOrUndefined(options.y, 'options.y', ['number']);
assertOrUndefined(options.width, 'options.width', ['number']);
assertOrUndefined(options.height, 'options.height', ['number']);

await drawSvg(this, svg, {
drawSvg(this, svg, {
x: options.x ?? this.x,
y: options.y ?? this.y,
fonts: options.fonts,
Expand Down
10 changes: 10 additions & 0 deletions src/api/PDFSvg.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import PDFImage from "./PDFImage";

export default class PDFSvg {
svg: string
images: Record<string, PDFImage>
constructor(svg: string, images: Record<string, PDFImage> = {}) {
this.svg = svg
this.images = images
}
}
1 change: 1 addition & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export { default as PDFPage } from './PDFPage';
export { default as PDFEmbeddedPage } from './PDFEmbeddedPage';
export { default as PDFJavaScript } from './PDFJavaScript';
export { default as Embeddable } from './Embeddable';
export { default as PDFSvg } from './PDFSvg'
Loading
Loading