@nzz/q-server
Version:
**Maintainer**: [Franco Gervasi](https://github.com/fgervasi)
18 lines • 8.72 kB
JSON
{
"sourceFile": "plugins/print/rendering-info.js",
"activeCommit": 0,
"commits": [
{
"activePatchIndex": 0,
"patches": [
{
"date": 1698924615452,
"content": "Index: \n===================================================================\n--- \n+++ \n"
}
],
"date": 1698924615452,
"name": "Commit-0",
"content": "const Joi = require(\"../../helper/custom-joi.js\");\nconst Boom = require(\"@hapi/boom\");\nconst querystring = require(\"querystring\");\nconst fs = require(\"fs\").promises;\nconst util = require(\"util\");\nconst exec = util.promisify(require(\"child_process\").exec);\nconst crypto = require(\"crypto\");\nconst getInnerWidth = require(\"../screenshot/helpers.js\").getInnerWidth;\n\nconst {\n getCmykTiffBufferFromPng,\n promoteTiffBufferToBlack,\n} = require(\"./conversions.js\");\nconst { getPDF } = require(\"../screenshot/helpers.js\");\n\n// this seems to be the standard chrome points per pixel unit\nconst chromePPI = 96;\n\nfunction mmToInch(mm) {\n return mm / 25.4;\n}\n\nmodule.exports = {\n method: \"POST\",\n path: \"/print/rendering-info.{format}\",\n options: {\n validate: {\n options: {\n allowUnknown: true,\n },\n params: {\n format: Joi.string().valid(\"png\", \"pdf\", \"tiff\", \"tif\"),\n },\n payload: {\n item: Joi.object().required(),\n toolRuntimeConfig: Joi.object()\n .required()\n .keys({\n displayOptions: Joi.object().required().keys({\n columns: Joi.number().required(),\n }),\n }),\n },\n query: {\n _id: Joi.string().required(),\n },\n },\n cache: {\n expiresIn: 1000 * 60, // 60 seconds\n },\n tags: [\"api\"],\n },\n handler: async function (request, h) {\n try {\n const displayOptions = request.payload.toolRuntimeConfig.displayOptions;\n const screenshotRequestQuery = {};\n\n if (displayOptions && displayOptions.printTitle) {\n request.payload.item.title = displayOptions.printTitle;\n }\n\n if (displayOptions && displayOptions.printSubtitle) {\n request.payload.item.subtitle = displayOptions.printSubtitle;\n }\n\n if (displayOptions && displayOptions.printNotes) {\n request.payload.item.notes = displayOptions.printNotes;\n }\n\n screenshotRequestToolRuntimeConfig = JSON.parse(\n JSON.stringify(request.payload.toolRuntimeConfig)\n );\n\n // pass all the displayOptions to the tool\n // set hideTitle to true if the titleStyle is 'hide'\n screenshotRequestToolRuntimeConfig.displayOptions = Object.assign(\n displayOptions,\n {\n hideTitle: displayOptions.titleStyle === \"hide\",\n }\n );\n\n const screenshotRequestPayload = {\n toolRuntimeConfig: screenshotRequestToolRuntimeConfig,\n item: request.payload.item,\n };\n\n const dpi = request.payload.toolRuntimeConfig.dpi || 300;\n screenshotRequestQuery.dpr = dpi / chromePPI;\n\n // the screenshot width is the width in inch * target dpi\n const mm = await request.server.methods.plugins.q.print.colsToMm(\n displayOptions.columnsProfile,\n displayOptions.columns\n );\n\n screenshotRequestQuery.width = Math.round(\n (mmToInch(mm) * dpi) / screenshotRequestQuery.dpr\n );\n screenshotRequestQuery.background =\n screenshotRequestQuery.background || \"white\";\n screenshotRequestQuery.wait =\n request.payload.toolRuntimeConfig.wait || 2000;\n screenshotRequestQuery.target = await request.server.settings.app.print\n .target;\n\n const screenshotImageResponse = await request.server.inject({\n method: \"POST\",\n url: `/screenshot.png?${querystring.stringify(screenshotRequestQuery)}`,\n payload: screenshotRequestPayload,\n });\n\n // fail early if there is an error to generate the screenshot\n if (screenshotImageResponse.statusCode !== 200) {\n request.server.log([\"error\"], screenshotImageResponse.payload);\n return screenshotImageResponse;\n }\n\n if (request.params.format === \"png\") {\n return h.response(screenshotImageResponse.rawPayload).type(\"image/png\");\n }\n\n return await new Promise(async (resolve, reject) => {\n // TODO:\n const server =request.server;\n const target = server.settings.app.targets.get(`/${screenshotRequestQuery.target}`);\n\n\n const width = getInnerWidth(screenshotRequestQuery.width, screenshotRequestQuery.padding);\n if (width) {\n request.payload.toolRuntimeConfig.size = {\n width: [\n {\n value: width,\n unit: \"px\",\n comparison: \"=\",\n },\n ],\n };\n }\n\n\n const response = await server.inject({\n method: \"POST\",\n url: `/rendering-info/${screenshotRequestQuery.target}`,\n payload: {\n toolRuntimeConfig: request.payload.toolRuntimeConfig,\n item: request.payload.item,\n ignoreInactive: true,\n },\n });\n\n const renderingInfo = JSON.parse(response.payload);\n\n let scripts = await server.methods.plugins.q.screenshot.getScripts(\n renderingInfo\n );\n let stylesheets = await server.methods.plugins.q.screenshot.getStylesheets(\n renderingInfo\n );\n\n if (Array.isArray(target.context.scripts)) {\n scripts = target.scripts.context.concat(scripts);\n }\n if (Array.isArray(target.context.stylesheets)) {\n stylesheets = target.context.stylesheets.concat(stylesheets);\n }\n\n const config = {\n width: screenshotRequestQuery.width,\n dpr: screenshotRequestQuery.dpr || 1,\n padding: screenshotRequestQuery.padding || \"0\",\n background: screenshotRequestQuery.background,\n };\n\n const pdf = await getPDF(\n `${server.info.protocol}://localhost:${server.info.port}/screenshot/empty-page.html`,\n renderingInfo.markup,\n scripts,\n stylesheets,\n config\n )\n\n // const pngBuffer = screenshotImageResponse.rawPayload;\n // const profiles = await request.server.settings.app.print.profiles;\n // const tiffBuffer = await getCmykTiffBufferFromPng(\n // pngBuffer,\n // dpi,\n // profiles\n // );\n // const finalTiffBuffer = await promoteTiffBufferToBlack(tiffBuffer);\n\n // if a TIFF is requested we return it here\n if (\n request.params.format === \"tiff\" ||\n request.params.format === \"tif\"\n ) {\n return resolve(finalTiffBuffer);\n }\n\n // if the format is not pdf here, we have a problem and return this\n if (request.params.format !== \"pdf\") {\n throw Boom.badRequest();\n }\n\n // const requestId = crypto\n // .createHash(\"sha1\")\n // .update(request.info.id)\n // .digest(\"hex\");\n\n // the following could all be optimised maybe by implementing it using streams and buffers\n // instead of writing and reading files\n // but we do it easy for now...\n // const fileNameBase = `${__dirname}/${requestId}`;\n\n // write the tiff buffer to disk\n // await fs.writeFile(`${fileNameBase}orig.tiff`, tiffBuffer);\n // remove the alpha channel for tiff2pdf to work\n // const { stdoutA, stderrA } = await exec(\n // `convert ${fileNameBase}orig.tiff -alpha off -compress lzw ${fileNameBase}-no-alpha.tiff`\n // );\n\n // we need to use tiff2pdf instead of imagemagick since this produces pdf v1.3 compatible PDFs where imagemagick does not\n // const { stdoutP, stderrP } = await exec(\n // `tiff2pdf -z -o ${fileNameBase}.pdf ${fileNameBase}-no-alpha.tiff`\n // );\n\n // const pdfBuffer = await fs.readFile(`${fileNameBase}.pdf`);\n\n resolve(h.response(pdf).type(\"application/pdf\"));\n\n // remove all the intermediate files\n // fs.unlink(`${fileNameBase}orig.tiff`);\n // fs.unlink(`${fileNameBase}-no-alpha.tiff`);\n // fs.unlink(`${fileNameBase}.pdf`);\n });\n } catch (e) {\n request.server.log([\"error\"], e);\n throw e;\n }\n },\n};\n"
}
]
}