import {AnnotationFactory} from '@digital-blueprint/annotpdf/_bundles/pdfAnnotate.js'; import {html} from "lit-element"; import {humanFileSize} from "@dbp-toolkit/common/i18next"; /** * Finds an object in a JSON result by identifier * * @param identifier * @param results * @param identifierAttribute */ export const findObjectInApiResults = (identifier, results, identifierAttribute = "@id") => { const members = results["hydra:member"]; if (members === undefined) { return; } for (const object of members) { if (object[identifierAttribute] === identifier) { return object; } } }; export const getPDFFileBase64Content = (file) => { return file.contentUrl.replace(/data:\s*application\/pdf;\s*base64,/, ""); }; export const convertDataURIToBinary = (dataURI) => { const BASE64_MARKER = ';base64,'; const base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length; const base64 = dataURI.substring(base64Index); const raw = window.atob(base64); const rawLength = raw.length; let array = new Uint8Array(rawLength); for(let i = 0; i < rawLength; i++) { array[i] = raw.charCodeAt(i); } return array; }; export const getDataURIContentType = (dataURI) => { const BASE64_MARKER = ';base64,'; const base64Index = dataURI.indexOf(BASE64_MARKER); return dataURI.substring(5, base64Index); }; export const baseName = (str) => { let base = String(str).substring(str.lastIndexOf('/') + 1); if (base.lastIndexOf(".") !== -1) { base = base.substring(0, base.lastIndexOf(".")); } return base; }; export const fabricjs2pdfasPosition = (data) => { let angle = -(data.angle - 360) % 360; let bottom = data.bottom; let left = data.left; if (data.angle === 90) { bottom += data.height; left -= data.height; } else if (data.angle === 180) { bottom += data.height * 2; } else if (data.angle === 270) { bottom += data.height; left += data.height; } return { y: Math.round(bottom), x: Math.round(left), r: angle, w: Math.round(data.width), // only width, no "height" allowed in PDF-AS p: data.currentPage }; }; /** * Returns the content of the file * * @param {File} file The file to read * @returns {string} The content */ export const readBinaryFileContent = async (file) => { return new Promise((resolve, reject) => { let reader = new FileReader(); reader.onload = () => { resolve(reader.result); }; reader.onerror = () => { reject(reader.error); }; reader.readAsBinaryString(file); }); }; /** * Returns the content of the file as array buffer * * @param {File} file The file to read * @returns {string} The content */ export const readArrayBufferFileContent = async (file) => { return new Promise((resolve, reject) => { let reader = new FileReader(); reader.onload = () => { resolve(reader.result); }; reader.onerror = () => { reject(reader.error); }; reader.readAsArrayBuffer(file); }); }; /** * Given a PDF file returns the amount of signatures found in it. * * Note that this uses an heuristic, so the result can be wrong * (improvements welcome). * * @param {File} file The PDF file object * @returns {number} The amount of signatures found */ export const getPDFSignatureCount = async (file) => { const sigRegex = new RegExp( "/Type\\s*/Sig(.|\\s)*?/SubFilter\\s*(/ETSI\\.CAdES\\.detached|/adbe\\.pkcs7\\.detached)", "g"); const content = await readBinaryFileContent(file); let matches = 0; while (sigRegex.exec(content) !== null) { matches++; } return matches; }; /** * Adds an annotation to a PDF file * * @param file * @param appNameDE * @param appNameEN * @param personName * @param key * @param value * @returns {File} */ export const addKeyValuePdfAnnotation = async (file, appNameDE, appNameEN, personName, key, value) => { key = key.trim(); value = value.trim(); // don't annotate if key or value are empty if (key === '' || value === '') { return file; } let annotationFactory = await getAnnotationFactoryFromFile(file); annotationFactory = addKeyValuePdfAnnotationsToAnnotationFactory(annotationFactory, appNameDE, appNameEN, personName, key, 'Name DE', 'Name EN', 'key2', value); return writeAnnotationFactoryToFile(annotationFactory, file); }; /** * Returns a File from an AnnotationFactory * * @param annotationFactory * @param file * @returns {File} */ export const writeAnnotationFactoryToFile = (annotationFactory, file) => { const blob = annotationFactory.write(); return new File([blob], file.name, { type: file.type }); } /** * Creates an AnnotationFactory from a File * * @param file * @returns AnnotationFactory */ export const getAnnotationFactoryFromFile = async (file) => { const data = await readArrayBufferFileContent(file); return new AnnotationFactory(data); }; /** * Adds a key/value annotation to a AnnotationFactory and returns the AnnotationFactory * * @param annotationFactory * @param appNameDE * @param appNameEN * @param personName * @param key1 * @param key1NameDE * @param key1NameEN * @param key2 * @param value * @returns PdfFactory */ export const addKeyValuePdfAnnotationsToAnnotationFactory = (annotationFactory, appNameDE, appNameEN, personName, key1, key1NameDE, key1NameEN, key2, value) => { key1 = key1.trim(); key1NameDE = key1NameDE.trim(); key1NameEN = key1NameEN.trim(); key2 = key2.trim(); value = value.trim(); // don't annotate if key or value are empty if (key1 === '' || key2 === '' || value === '') { return annotationFactory; } // add human readable annotation let author = personName + ' via "' + appNameDE + ' / ' + appNameEN + '"'; let content = key1NameDE + ': ' + value +"\n" + key1NameEN + ': ' + value; annotationFactory = addPdfAnnotationToAnnotationFactory(annotationFactory, author, content); // add machine readable annotation author = 'Maschinell aufgebracht, bitte nicht entfernen / Applied automatically, please do not remove'; content = 'dbp-annotation-' + key1 + '-' + key2 + '=' + value; annotationFactory = addPdfAnnotationToAnnotationFactory(annotationFactory, author, content); return annotationFactory; }; export const addPdfAnnotationToAnnotationFactory = (annotationFactory, author, content) => { author = author.trim(); content = content.trim(); // don't annotate if author of content are empty if (author === '' || content === '') { return annotationFactory; } const page = 0; const rect = [0, 0, 0, 0]; // annotationFactory.checkRect(4, rect); // Create single free text annotation with print flag and 0 font size let annotation = Object.assign(annotationFactory.createBaseAnnotation(page, rect, content, author), { annotation_flag: 4, // enable print to be PDF/A conform color: {r: 1, g: 1, b: 1}, // white to (maybe) hide it better opacity: 0.001, // we can't set to 0 because of "if (opacity) {" defaultAppearance: "/Invalid_font 0 Tf" // font size 0 to (maybe) hide it better }); annotation.type = "/FreeText"; annotationFactory.annotations.push(annotation); return annotationFactory; }; /** * Returns an object with all annotations types or only the values for one type * * @param key * @returns {} */ export const getAnnotationTypes = (key = null) => { const types = { 'bbe3a371': { 'de': 'Geschäftszahl', 'en': 'Businessnumber', }, '85a4eb4c': { 'de': 'Andere Zahl', 'en': 'Other number', } } return key === null ? types : types[key] || {}; }; /** * Returns the html for the annotation type select * * @returns {*[]} Array of html templates */ export const getAnnotationTypeSelectOptionsHtml = (selectedKey, lang) => { const annotationTypes = getAnnotationTypes(); const keys = Object.keys(annotationTypes); let results = []; keys.forEach((key) => { const name = annotationTypes[key][lang]; results.push(html` <option value="${key}" .selected=${selectedKey === key}>${name}</option> `); }); return results; };