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

Load multiple images setup #1

Merged
merged 3 commits into from
Sep 4, 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
2 changes: 1 addition & 1 deletion dist/api.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/app.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "directus-extension-pdf-builder",
"description": "This package is a node for Directus flows, utilizing the PDFMake library for generating PDF documents.",
"icon": "extension",
"version": "1.0.6",
"version": "1.1.0",
"keywords": [
"directus",
"directus-extension",
Expand Down
81 changes: 73 additions & 8 deletions src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import * as pdfFonts from './vfs_fonts.js';

export default {
id: 'operation-pdf-builder',
handler: async ({filename, folder, storage, template, fonts}, {services, database, accountability, getSchema}) => {
handler: async ({filename, folder, storage, template, fonts, images}, {
services,
database,
accountability,
getSchema
}) => {
const {FilesService, AssetsService} = services;
const schema = await getSchema({database});
const filesService = new FilesService({
Expand All @@ -23,8 +28,7 @@ export default {
pdfMake.vfs = await getBase64Fonts(fonts, assetsService);
pdfMake.fonts = getPdfMakeFonts(fonts);

console.log('VFS:', pdfMake.vfs);
console.log('Fonts:', pdfMake.fonts);
template['images'] = await addImages(images, assetsService, filesService);

const pdfDocGenerator = pdfMake.createPdf(template);

Expand Down Expand Up @@ -92,12 +96,40 @@ async function streamToBuffer(stream) {
}

async function fetchExternalFont(url) {
return await fetch(url, {headers: {responseType: 'arraybuffer'}}).then((response) => {
return Buffer.from(response.data, 'binary').toString('base64');
}).catch((error) => {
try {
const response = await fetch(url);

if (!response.ok) {
console.error(`HTTP error! status: ${response.status}`);
return false;
}

const arrayBuffer = await response.arrayBuffer();
return Buffer.from(arrayBuffer).toString('base64');
} catch (error) {
console.error('Error fetching external font:', error);
return false;
});
}
}

async function fetchExternalImage(url) {
try {
const response = await fetch(url);

if (!response.ok) {
console.error(`HTTP error! status: ${response.status}`);
return false;
}

const contentType = response.headers.get('content-type');
const arrayBuffer = await response.arrayBuffer();
const base64Image = Buffer.from(arrayBuffer).toString('base64');

return `data:${contentType};base64,${base64Image}`;
} catch (error) {
console.error('Error fetching external image:', error);
return false;
}
}

async function fetchInternalFont(uuid, assetsService) {
Expand All @@ -113,6 +145,22 @@ async function fetchInternalFont(uuid, assetsService) {
});
}

async function fetchInternalImage(uuid, assetsService, filesService) {
return assetsService.getAsset(uuid)
.then(async (fileStream) => {
const {stream} = fileStream;
const {type} = await filesService.readOne(uuid);
const buffer = await streamToBuffer(stream);
const base64Image = Buffer.from(buffer).toString('base64');

return `data:${type};base64,${base64Image}`;
})
.catch((error) => {
console.error('Error fetching internal image:', error);
return false;
});
}

async function getBase64Fonts(fonts, assetsService) {
const base64Fonts = [];
// Load the default pdfMake fonts
Expand Down Expand Up @@ -163,8 +211,25 @@ function getPdfMakeFonts(fonts) {
};
}
return fontList;
}catch (e) {
} catch (e) {
console.error(e);
return false;
}
}

async function addImages(images, assetsService, filesService) {
let imageList = {};

if (Array.isArray(images)) {
for (const image of images) {
const {image_name, url} = image;
if (uuidValidate(url)) {
imageList[image_name] = await fetchInternalImage(url, assetsService, filesService);
} else if (url) {
imageList[image_name] = await fetchExternalImage(url, assetsService);
}
}
}

return imageList;
}
74 changes: 69 additions & 5 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ export default {
name: 'PDF Builder Operation',
icon: 'picture_as_pdf',
description: 'Generate a pdf with flow data and the template.',
overview: ({filename}) => [
overview: ({filename, fonts}) => [
{
label: 'Filename',
text: filename,
},
{
label: 'Fonts',
text: getFontList(fonts),
}
],
options: [
Expand Down Expand Up @@ -41,7 +45,7 @@ export default {
},
{
field: 'filename',
name: 'Filename',
name: '$t:fields.directus_files.filename_download',
type: 'string',
meta: {
width: 'full',
Expand All @@ -50,7 +54,7 @@ export default {
},
{
field: 'folder',
name: 'Folder',
name: '$t:folder',
type: 'uuid',
meta: {
width: 'half',
Expand All @@ -59,7 +63,7 @@ export default {
},
{
field: 'storage',
name: 'Storage',
name: '$t:fields.directus_files.storage',
type: 'string',
meta: {
width: 'half',
Expand All @@ -72,7 +76,7 @@ export default {
},
{
field: 'template',
name: 'Template',
name: '$t:template',
type: 'json',
meta: {
width: 'full',
Expand Down Expand Up @@ -145,6 +149,66 @@ export default {
]
}
}
},
{
field: 'images',
name: 'Images',
type: 'json',
meta: {
width: 'full',
interface: 'list',
special: 'cast-json',
options: {
template: '{{ image_name }}',
fields: [
{
field: 'image_name',
name: 'Name',
type: 'string',
meta: {
width: 'full',
interface: 'input',
required: true,
options: {
placeholder: 'image',
iconRight: 'image',
}
}
},
{
field: 'url',
name: 'Url',
type: 'string',
meta: {
width: 'full',
interface: 'input',
required: true,
options: {
placeholder: 'https://example.com/image.jpg',
iconRight: 'link',
}
}
},
]
}
}
}
],
};

function getFontList(fonts) {
if (!Array.isArray(fonts)) {
return '$t:no_items';
} else {
const uniqueFonts = fonts.reduce((acc, current) => {
const font = acc.find(item => item.font_family === current.font_family);
if (!font) {
return acc.concat([current]);
} else {
return acc;
}
}, []);

return uniqueFonts.map(font => `${font.font_family} - ${font.font_type}`).join(uniqueFonts.length > 1 ? ', ' : '');
}
}