From 5be901cb776e15c9c73afeb22d0239067bc182d2 Mon Sep 17 00:00:00 2001 From: James Wassink Date: Thu, 10 Nov 2022 11:56:43 +1100 Subject: [PATCH] add ability to provide captions for images --- README.md | 1 + examples/example-node/index.js | 2 +- src/processTemplate.ts | 18 ++++++++++++++---- src/types.ts | 7 ++++++- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c4b0abc5..770c6909 100755 --- a/README.md +++ b/README.md @@ -374,6 +374,7 @@ The JS snippet must return an _image object_ or a Promise of an _image object_, * `thumbnail` _[optional]_: when injecting an SVG image, a fallback non-SVG (png/jpg/gif, etc.) image can be provided. This thumbnail is used when SVG images are not supported (e.g. older versions of Word) or when the document is previewed by e.g. Windows Explorer. See usage example below. * `alt` _[optional]_: optional alt text. * `rotation` _[optional]_: optional rotation in degrees, with positive angles moving clockwise. +* `caption` _[optional]_: optional caption displayed below the image In the .docx template: ``` diff --git a/examples/example-node/index.js b/examples/example-node/index.js index 2379e056..3dd19f21 100755 --- a/examples/example-node/index.js +++ b/examples/example-node/index.js @@ -31,7 +31,7 @@ createReport({ qr: contents => { const dataUrl = qrcode(contents, { size: 500 }); const data = dataUrl.slice('data:image/gif;base64,'.length); - return { width: 6, height: 6, data, extension: '.gif' }; + return { width: 6, height: 6, data, extension: '.gif', caption: 'QR Code caption' }; }, }, }).then( diff --git a/src/processTemplate.ts b/src/processTemplate.ts index 3bc80599..0237d4b5 100755 --- a/src/processTemplate.ts +++ b/src/processTemplate.ts @@ -274,12 +274,16 @@ export async function walkTemplate( !nodeOut._fTextNode && nodeOut._tag === 'w:t' ) { - const imgNode = ctx.pendingImageNode; + const imgNode = ctx.pendingImageNode.image; + const captionNodes = ctx.pendingImageNode.caption; const parent = nodeOut._parent; if (parent) { imgNode._parent = parent; parent._children.pop(); parent._children.push(imgNode); + if (captionNodes) { + parent._children.push(...captionNodes); + } // Prevent containing paragraph or table row from being removed ctx.buffers['w:p'].fInsertedText = true; ctx.buffers['w:tr'].fInsertedText = true; @@ -575,7 +579,7 @@ const processCmd: CommandProcessor = async ( ); if (img != null) { try { - await processImage(ctx, img); + processImage(ctx, img); } catch (e) { if (!(e instanceof Error)) throw e; throw new ImageError(e, cmd); @@ -813,7 +817,7 @@ function validateImagePars(pars: ImagePars) { if (pars.thumbnail) validateImage(pars.thumbnail); } -const processImage = async (ctx: Context, imagePars: ImagePars) => { +const processImage = (ctx: Context, imagePars: ImagePars) => { validateImagePars(imagePars); const cx = (imagePars.width * 360e3).toFixed(0); const cy = (imagePars.height * 360e3).toFixed(0); @@ -913,7 +917,13 @@ const processImage = async (ctx: Context, imagePars: ImagePars) => { ), ]), ]); - ctx.pendingImageNode = drawing; + ctx.pendingImageNode = { image: drawing }; + if (imagePars.caption) { + ctx.pendingImageNode.caption = [ + node('w:br'), + node('w:t', {}, [newTextNode(imagePars.caption)]), + ]; + } }; function getImageData(imagePars: ImagePars): Image { diff --git a/src/types.ts b/src/types.ts index c216544f..8acd74b5 100755 --- a/src/types.ts +++ b/src/types.ts @@ -137,7 +137,7 @@ export type Context = { 'w:p': BufferStatus; 'w:tr': BufferStatus; }; - pendingImageNode?: NonTextNode; + pendingImageNode?: { image: NonTextNode; caption?: NonTextNode[] }; imageId: number; images: Images; pendingLinkNode?: NonTextNode; @@ -223,6 +223,11 @@ export type ImagePars = { * Optional rotation in degrees, with positive angles moving clockwise. */ rotation?: number; + + /** + * Optional caption + */ + caption?: string; }; export type LinkPars = {