add single-page pdf export
This commit is contained in:
parent
bf417a201f
commit
2867b9c340
6 changed files with 83 additions and 45 deletions
|
@ -155,13 +155,11 @@ export const handleExport = async ({
|
||||||
let pattern = themedPattern(Design, settings, { layout }, format, t)
|
let pattern = themedPattern(Design, settings, { layout }, format, t)
|
||||||
|
|
||||||
// a specified size should override the settings one
|
// a specified size should override the settings one
|
||||||
if (format !== 'pdf') {
|
pageSettings.size = format
|
||||||
pageSettings.size = format
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// add pages to pdf exports
|
// add pages to pdf exports
|
||||||
if (format !== 'svg') {
|
if (!exportTypes.exportForEditing.includes(format)) {
|
||||||
pattern.use(
|
pattern.use(
|
||||||
pagesPlugin({
|
pagesPlugin({
|
||||||
...pageSettings,
|
...pageSettings,
|
||||||
|
@ -184,11 +182,13 @@ export const handleExport = async ({
|
||||||
pattern.draft()
|
pattern.draft()
|
||||||
workerArgs.svg = pattern.render()
|
workerArgs.svg = pattern.render()
|
||||||
|
|
||||||
|
if (format === 'pdf') pageSettings.size = [pattern.width, pattern.height]
|
||||||
|
|
||||||
// add the svg and pages data to the worker args
|
// add the svg and pages data to the worker args
|
||||||
workerArgs.pages = pattern.setStores[pattern.activeSet].get('pages')
|
workerArgs.pages = pattern.setStores[pattern.activeSet].get('pages')
|
||||||
|
|
||||||
// add cutting layouts if requested
|
// add cutting layouts if requested
|
||||||
if (format !== 'svg' && pageSettings.cutlist) {
|
if (!exportTypes.exportForEditing.includes(format) && pageSettings.cutlist) {
|
||||||
workerArgs.cutLayouts = generateCutLayouts(pattern, Design, settings, format, t, ui)
|
workerArgs.cutLayouts = generateCutLayouts(pattern, Design, settings, format, t, ui)
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
import yaml from 'js-yaml'
|
import yaml from 'js-yaml'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { PdfMaker } from './pdf-maker'
|
import { PdfMaker } from './pdf-maker'
|
||||||
|
import { SinglePdfMaker } from './single-pdf-maker.mjs'
|
||||||
|
|
||||||
/** when the worker receives data from the page, do the appropriate export */
|
/** when the worker receives data from the page, do the appropriate export */
|
||||||
addEventListener('message', async (e) => {
|
addEventListener('message', async (e) => {
|
||||||
|
@ -49,7 +50,7 @@ const exportYaml = (settings) => exportBlob(yaml.dump(settings), 'application/x-
|
||||||
const exportSvg = (svg) => exportBlob(svg, 'image/svg+xml')
|
const exportSvg = (svg) => exportBlob(svg, 'image/svg+xml')
|
||||||
|
|
||||||
const exportPdf = async (data) => {
|
const exportPdf = async (data) => {
|
||||||
const maker = new PdfMaker(data)
|
const maker = data.format === 'pdf' ? new SinglePdfMaker(data) : new PdfMaker(data)
|
||||||
await maker.makePdf()
|
await maker.makePdf()
|
||||||
postSuccess(await maker.toBlob())
|
postSuccess(await maker.toBlob())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import PDFDocument from 'pdfkit/js/pdfkit.standalone'
|
import { Pdf, mmToPoints } from './pdf.mjs'
|
||||||
import SVGtoPDF from 'svg-to-pdfkit'
|
import SVGtoPDF from 'svg-to-pdfkit'
|
||||||
import { logoPath } from 'shared/components/logos/freesewing.mjs'
|
import { logoPath } from 'shared/components/logos/freesewing.mjs'
|
||||||
|
|
||||||
|
@ -8,11 +8,6 @@ const logoSvg = `<svg viewBox="0 0 25 25">
|
||||||
<path d="${logoPath}" />
|
<path d="${logoPath}" />
|
||||||
</svg>`
|
</svg>`
|
||||||
|
|
||||||
/**
|
|
||||||
* PdfKit, the library we're using for pdf generation, uses points as a unit, so when we tell it things like where to put the svg and how big the svg is, we need those numbers to be in points
|
|
||||||
* The svg uses mm internally, so when we do spatial reasoning inside the svg, we need to know values in mm
|
|
||||||
* */
|
|
||||||
const mmToPoints = 2.834645669291339
|
|
||||||
const lineStart = 50
|
const lineStart = 50
|
||||||
/**
|
/**
|
||||||
* Freesewing's first explicit class?
|
* Freesewing's first explicit class?
|
||||||
|
@ -58,7 +53,10 @@ export class PdfMaker {
|
||||||
this.strings = strings
|
this.strings = strings
|
||||||
this.cutLayouts = cutLayouts
|
this.cutLayouts = cutLayouts
|
||||||
|
|
||||||
this.initPdf()
|
this.pdf = Pdf({
|
||||||
|
size: this.pageSettings.size.toUpperCase(),
|
||||||
|
layout: this.pageSettings.orientation,
|
||||||
|
})
|
||||||
|
|
||||||
this.margin = this.pageSettings.margin * mmToPoints // margin is in mm because it comes from us, so we convert it to points
|
this.margin = this.pageSettings.margin * mmToPoints // margin is in mm because it comes from us, so we convert it to points
|
||||||
this.pageHeight = this.pdf.page.height - this.margin * 2 // this is in points because it comes from pdfKit
|
this.pageHeight = this.pdf.page.height - this.margin * 2 // this is in points because it comes from pdfKit
|
||||||
|
@ -73,22 +71,6 @@ export class PdfMaker {
|
||||||
this.svgHeight = this.rows * this.pageHeight
|
this.svgHeight = this.rows * this.pageHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
/** create the pdf document */
|
|
||||||
initPdf() {
|
|
||||||
// instantiate with the correct size and orientation
|
|
||||||
this.pdf = new PDFDocument({
|
|
||||||
size: this.pageSettings.size.toUpperCase(),
|
|
||||||
layout: this.pageSettings.orientation,
|
|
||||||
})
|
|
||||||
|
|
||||||
// PdfKit wants to flush the buffer on each new page.
|
|
||||||
// We can't save directly from inside a worker, so we have to manage the buffers ourselves so we can return a blob
|
|
||||||
this.buffers = []
|
|
||||||
|
|
||||||
// use a listener to add new data to our buffer storage
|
|
||||||
this.pdf.on('data', this.buffers.push.bind(this.buffers))
|
|
||||||
}
|
|
||||||
|
|
||||||
/** make the pdf */
|
/** make the pdf */
|
||||||
async makePdf() {
|
async makePdf() {
|
||||||
await this.generateCoverPage()
|
await this.generateCoverPage()
|
||||||
|
@ -97,21 +79,8 @@ export class PdfMaker {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** convert the pdf to a blob */
|
/** convert the pdf to a blob */
|
||||||
toBlob() {
|
async toBlob() {
|
||||||
return new Promise((resolve) => {
|
return this.pdf.toBlob()
|
||||||
// have to do it this way so that the document flushes everything to buffers
|
|
||||||
this.pdf.on('end', () => {
|
|
||||||
// convert buffers to a blob
|
|
||||||
resolve(
|
|
||||||
new Blob(this.buffers, {
|
|
||||||
type: 'application/pdf',
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
// end the stream
|
|
||||||
this.pdf.end()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** generate the cover page for the pdf */
|
/** generate the cover page for the pdf */
|
||||||
|
|
45
sites/shared/components/workbench/exporting/pdf.mjs
Normal file
45
sites/shared/components/workbench/exporting/pdf.mjs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import PDFDocument from 'pdfkit/js/pdfkit.standalone'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PdfKit, the library we're using for pdf generation, uses points as a unit, so when we tell it things like where to put the svg and how big the svg is, we need those numbers to be in points
|
||||||
|
* The svg uses mm internally, so when we do spatial reasoning inside the svg, we need to know values in mm
|
||||||
|
* */
|
||||||
|
export const mmToPoints = 2.834645669291339
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A PDFKit Pdf with a few of our utilities included
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const Pdf = ({ size, layout }) => {
|
||||||
|
const pdf = new PDFDocument({
|
||||||
|
size,
|
||||||
|
layout,
|
||||||
|
})
|
||||||
|
|
||||||
|
// PdfKit wants to flush the buffer on each new page.
|
||||||
|
// We can't save directly from inside a worker, so we have to manage the buffers ourselves so we can return a blob
|
||||||
|
const buffers = []
|
||||||
|
|
||||||
|
// use a listener to add new data to our buffer storage
|
||||||
|
pdf.on('data', buffers.push.bind(buffers))
|
||||||
|
|
||||||
|
/** convert the pdf to a blob */
|
||||||
|
pdf.toBlob = function () {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
// have to do it this way so that the document flushes everything to buffers
|
||||||
|
pdf.on('end', () => {
|
||||||
|
// convert buffers to a blob
|
||||||
|
resolve(
|
||||||
|
new Blob(buffers, {
|
||||||
|
type: 'application/pdf',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// end the stream
|
||||||
|
pdf.end()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return pdf
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { Pdf, mmToPoints } from './pdf.mjs'
|
||||||
|
import SVGtoPDF from 'svg-to-pdfkit'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic exporter for a single-page pdf containing the rendered pattern.
|
||||||
|
* This generates a PDF that is the size of the pattern and has no additional frills*/
|
||||||
|
export class SinglePdfMaker {
|
||||||
|
pdf
|
||||||
|
svg
|
||||||
|
|
||||||
|
constructor({ svg, pageSettings }) {
|
||||||
|
this.pdf = Pdf({ size: pageSettings.size.map((s) => s * mmToPoints) })
|
||||||
|
this.svg = svg
|
||||||
|
}
|
||||||
|
|
||||||
|
async makePdf() {
|
||||||
|
await SVGtoPDF(this.pdf, this.svg)
|
||||||
|
}
|
||||||
|
|
||||||
|
async toBlob() {
|
||||||
|
return this.pdf.toBlob()
|
||||||
|
}
|
||||||
|
}
|
|
@ -73,7 +73,7 @@ export const PrintView = ({
|
||||||
|
|
||||||
const exportIt = () => {
|
const exportIt = () => {
|
||||||
handleExport({
|
handleExport({
|
||||||
format: 'pdf',
|
format: pageSettings.size,
|
||||||
settings,
|
settings,
|
||||||
design,
|
design,
|
||||||
t,
|
t,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue