Fix PDF generation not using DPI settings

This commit is contained in:
2026-06-29 09:41:02 +02:00
parent 8207e84fa2
commit cc9170de9d
+57 -63
View File
@@ -14,23 +14,14 @@ export function downloadBlob(blob: Blob, filename: string) {
URL.revokeObjectURL(url);
}
export async function prepareSVG(
handler: VectraceHandler,
imageRender: CanvasImageEx
): Promise<Blob> {
export async function prepareSVG(handler: VectraceHandler, imageRender: CanvasImageEx): Promise<Blob> {
if (imageRender.svg.scale !== imageRender.scale || imageRender.svg.dirty) {
handler.redrawSvg(imageRender.id);
}
return new Blob([imageRender.svg.data], { type: "image/svg+xml" });
}
function getGridCells(
paperWidth: number,
paperHeight: number,
grid: string
): GridCell[] {
function getGridCells(paperWidth: number, paperHeight: number, grid: string): GridCell[] {
const cols = grid === "3x3" ? 3 : grid === "2x2" ? 2 : 1;
const rows = grid === "3x3" ? 3 : grid === "2x2" ? 2 : 1;
const cellW = paperWidth / cols;
@@ -51,39 +42,51 @@ function getGridCells(
return cells;
}
function getGridCellsMm(paperWidth: number, paperHeight: number, grid: string): GridCell[] {
const cols = grid === "3x3" ? 3 : grid === "2x2" ? 2 : 1;
const rows = grid === "3x3" ? 3 : grid === "2x2" ? 2 : 1;
const cellW = paperWidth / cols;
const cellH = paperHeight / rows;
const cells: GridCell[] = [];
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
cells.push({
col,
row,
x: col * cellW,
y: row * cellH,
w: cellW,
h: cellH,
});
}
}
return cells;
}
function createCellPdf(
handler: VectraceHandler,
cell: GridCell
): jsPDF {
function createCellPdf(handler: VectraceHandler, cellMm: GridCell): jsPDF {
const { DPI } = handler.globalSettingsHandler.settings;
const pxToMm = (px: number): number => (px / DPI) * MM_TO_INCH;
const doc = new jsPDF({
orientation: cell.w > cell.h ? "landscape" : "portrait",
orientation: cellMm.w > cellMm.h ? "landscape" : "portrait",
unit: "mm",
format: [cell.w, cell.h],
format: [cellMm.w, cellMm.h],
});
for (const imageObject of handler.imagesRenders) {
if (!imageObject.visible) continue;
const imgX = imageObject.x - cell.x;
const imgY = imageObject.y - cell.y;
const imgW = imageObject.image.naturalWidth * imageObject.scale;
const imgH = imageObject.image.naturalHeight * imageObject.scale;
const imgXMm = pxToMm(imageObject.x) - cellMm.x;
const imgYMm = pxToMm(imageObject.y) - cellMm.y;
const imgWMm = pxToMm(imageObject.image.naturalWidth * imageObject.scale);
const imgHMm = pxToMm(imageObject.image.naturalHeight * imageObject.scale);
const overlapX = imgX + imgW > 0 && imgX < cell.w;
const overlapY = imgY + imgH > 0 && imgY < cell.h;
const overlapX = imgXMm + imgWMm > 0 && imgXMm < cellMm.w;
const overlapY = imgYMm + imgHMm > 0 && imgYMm < cellMm.h;
if (!overlapX || !overlapY) continue;
doc.addImage(
imageObject.image,
"PNG",
imgX,
imgY,
imgW,
imgH
);
doc.addImage(imageObject.image, "PNG", imgXMm, imgYMm, imgWMm, imgHMm);
}
return doc;
@@ -95,47 +98,44 @@ const gridConfigs: Record<string, number[]> = {
};
export function createPdf(handler: VectraceHandler, withGuides: boolean): jsPDF {
const { DPI, paperHeight, paperWidth } = handler.globalSettingsHandler.settings;
const width = (paperWidth / MM_TO_INCH) * DPI;
const height = (paperHeight / MM_TO_INCH) * DPI;
const pxToMm = (px: number): number => (px / DPI) * MM_TO_INCH;
const doc = new jsPDF({
orientation: paperWidth > paperHeight ? "landscape" : "portrait",
unit: "mm",
format: [width, height],
format: [paperWidth, paperHeight],
});
if (withGuides) {
const setLine = () => {
doc.setDrawColor(64, 64, 64);
doc.setLineWidth(1);
};
doc.setLineWidth(0.5);
const fractions = gridConfigs[handler.globalSettingsHandler.settings.grid];
if (fractions) {
setLine();
fractions.forEach(f => {
doc.line(width * f, 0, width * f, height);
doc.line(0, height * f, width, height * f);
fractions.forEach((f) => {
doc.line(paperWidth * f, 0, paperWidth * f, paperHeight);
doc.line(0, paperHeight * f, paperWidth, paperHeight * f);
});
}
}
for (const imageObject of handler.imagesRenders) {
if (imageObject.visible) {
if (!imageObject.visible) continue;
doc.addImage(
imageObject.image,
"PNG",
imageObject.x,
imageObject.y,
imageObject.image.naturalWidth * imageObject.scale,
imageObject.image.naturalHeight * imageObject.scale
pxToMm(imageObject.x),
pxToMm(imageObject.y),
pxToMm(imageObject.image.naturalWidth * imageObject.scale),
pxToMm(imageObject.image.naturalHeight * imageObject.scale),
);
}
}
return doc;
}
export function createSVGDoc(handler: VectraceHandler) {
const { paperWidth, paperHeight, DPI } = handler.globalSettingsHandler.settings;
const width = (paperWidth / MM_TO_INCH) * DPI;
@@ -172,7 +172,7 @@ export async function downloadZip(handler: VectraceHandler): Promise<void> {
canvas.height = render.image.naturalHeight * render.scale;
ctx.drawImage(render.image, 0, 0, canvas.width, canvas.height);
const blob = new Promise<Blob>((resolve, reject) => {
canvas.toBlob(data => {
canvas.toBlob((data) => {
if (data) {
resolve(data);
} else {
@@ -204,16 +204,17 @@ export async function downloadZip(handler: VectraceHandler): Promise<void> {
if (grid !== "none") {
const cells = getGridCells(width, height, grid);
const cellsMm = getGridCellsMm(paperWidth, paperHeight, grid);
const cellPdfs = mainFolder.folder("cells/pdfs")!;
const cellSvgs = mainFolder.folder("cells/svgs")!;
for (const cell of cells) {
const label = `cell-r${cell.row}-c${cell.col}`;
for (let i = 0; i < cells.length; i++) {
const label = `cell-r${cells[i].row}-c${cells[i].col}`;
const cellPdf = createCellPdf(handler, cell);
const cellPdf = createCellPdf(handler, cellsMm[i]);
cellPdfs.file(`${label}.pdf`, cellPdf.output("blob"));
const cellSvgBlob = await createCellSvg(handler, cell);
const cellSvgBlob = await createCellSvg(handler, cells[i]);
cellSvgs.file(`${label}.svg`, cellSvgBlob);
}
}
@@ -231,10 +232,7 @@ function collectPaths(node: INode): INode[] {
return results;
}
export async function createCellSvg(
handler: VectraceHandler,
cell: GridCell
) {
export async function createCellSvg(handler: VectraceHandler, cell: GridCell) {
const pathElements: string[] = [];
for (const imageObject of handler.imagesRenders) {
if (!imageObject.visible) continue;
@@ -249,11 +247,7 @@ export async function createCellSvg(
const imgH = imageObject.image.naturalHeight * imageObject.scale;
// Does this image even overlap the cell at all?
const overlaps =
imgX + imgW > cell.x &&
imgX < cell.x + cell.w &&
imgY + imgH > cell.y &&
imgY < cell.y + cell.h;
const overlaps = imgX + imgW > cell.x && imgX < cell.x + cell.w && imgY + imgH > cell.y && imgY < cell.y + cell.h;
if (!overlaps) continue;
@@ -271,7 +265,7 @@ export async function createCellSvg(
pathElements.push(
`<g transform="translate(${imgX - cell.x} ${imgY - cell.y})">` +
`<path d="${d}" fill="${fill}" stroke="${stroke}" stroke-width="${strokeWidth}"/>` +
`</g>`
`</g>`,
);
}
}