restructured project (shared-operations)

This commit is contained in:
Felix Kaspar
2023-11-07 01:40:00 +01:00
parent 7186c6c3e0
commit 47e0092378
36 changed files with 36 additions and 23 deletions

View File

@@ -0,0 +1,167 @@
//download.js v4.2, by dandavis; 2008-2016. [MIT] see http://danml.com/download.html for tests/usage
// v1 landed a FF+Chrome compat way of downloading strings to local un-named files, upgraded to use a hidden frame and optional mime
// v2 added named files via a[download], msSaveBlob, IE (10+) support, and window.URL support for larger+faster saves than dataURLs
// v3 added dataURL and Blob Input, bind-toggle arity, and legacy dataURL fallback was improved with force-download mime and base64 support. 3.1 improved safari handling.
// v4 adds AMD/UMD, commonJS, and plain browser support
// v4.1 adds url download capability via solo URL argument (same domain/CORS only)
// v4.2 adds semantic variable names, long (over 2MB) dataURL support, and hidden by default temp anchors
// https://github.com/rndme/download
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([], factory);
} else if (typeof exports === 'object') {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory();
} else {
// Browser globals (root is window)
root.download = factory();
}
}(this, function () {
return function download(data, strFileName, strMimeType) {
var self = window, // this script is only for browsers anyway...
defaultMime = "application/octet-stream", // this default mime also triggers iframe downloads
mimeType = strMimeType || defaultMime,
payload = data,
url = !strFileName && !strMimeType && payload,
anchor = document.createElement("a"),
toString = function(a){return String(a);},
myBlob = (self.Blob || self.MozBlob || self.WebKitBlob || toString),
fileName = strFileName || "download",
blob,
reader;
myBlob= myBlob.call ? myBlob.bind(self) : Blob ;
if(String(this)==="true"){ //reverse arguments, allowing download.bind(true, "text/xml", "export.xml") to act as a callback
payload=[payload, mimeType];
mimeType=payload[0];
payload=payload[1];
}
if(url && url.length< 2048){ // if no filename and no mime, assume a url was passed as the only argument
fileName = url.split("/").pop().split("?")[0];
anchor.href = url; // assign href prop to temp anchor
if(anchor.href.indexOf(url) !== -1){ // if the browser determines that it's a potentially valid url path:
var ajax=new XMLHttpRequest();
ajax.open( "GET", url, true);
ajax.responseType = 'blob';
ajax.onload= function(e){
download(e.target.response, fileName, defaultMime);
};
setTimeout(function(){ ajax.send();}, 0); // allows setting custom ajax headers using the return:
return ajax;
} // end if valid url?
} // end if url?
//go ahead and download dataURLs right away
if(/^data:([\w+-]+\/[\w+.-]+)?[,;]/.test(payload)){
if(payload.length > (1024*1024*1.999) && myBlob !== toString ){
payload=dataUrlToBlob(payload);
mimeType=payload.type || defaultMime;
}else{
return navigator.msSaveBlob ? // IE10 can't do a[download], only Blobs:
navigator.msSaveBlob(dataUrlToBlob(payload), fileName) :
saver(payload) ; // everyone else can save dataURLs un-processed
}
}else{//not data url, is it a string with special needs?
if(/([\x80-\xff])/.test(payload)){
var i=0, tempUiArr= new Uint8Array(payload.length), mx=tempUiArr.length;
for(i;i<mx;++i) tempUiArr[i]= payload.charCodeAt(i);
payload=new myBlob([tempUiArr], {type: mimeType});
}
}
blob = payload instanceof myBlob ?
payload :
new myBlob([payload], {type: mimeType}) ;
function dataUrlToBlob(strUrl) {
var parts= strUrl.split(/[:;,]/),
type= parts[1],
decoder= parts[2] == "base64" ? atob : decodeURIComponent,
binData= decoder( parts.pop() ),
mx= binData.length,
i= 0,
uiArr= new Uint8Array(mx);
for(i;i<mx;++i) uiArr[i]= binData.charCodeAt(i);
return new myBlob([uiArr], {type: type});
}
function saver(url, winMode){
if ('download' in anchor) { //html5 A[download]
anchor.href = url;
anchor.setAttribute("download", fileName);
anchor.className = "download-js-link";
anchor.innerHTML = "downloading...";
anchor.style.display = "none";
document.body.appendChild(anchor);
setTimeout(function() {
anchor.click();
document.body.removeChild(anchor);
if(winMode===true){setTimeout(function(){ self.URL.revokeObjectURL(anchor.href);}, 250 );}
}, 66);
return true;
}
// handle non-a[download] safari as best we can:
if(/(Version)\/(\d+)\.(\d+)(?:\.(\d+))?.*Safari\//.test(navigator.userAgent)) {
if(/^data:/.test(url)) url="data:"+url.replace(/^data:([\w\/\-\+]+)/, defaultMime);
if(!window.open(url)){ // popup blocked, offer direct download:
if(confirm("Displaying New Document\n\nUse Save As... to download, then click back to return to this page.")){ location.href=url; }
}
return true;
}
//do iframe dataURL download (old ch+FF):
var f = document.createElement("iframe");
document.body.appendChild(f);
if(!winMode && /^data:/.test(url)){ // force a mime that will download:
url="data:"+url.replace(/^data:([\w\/\-\+]+)/, defaultMime);
}
f.src=url;
setTimeout(function(){ document.body.removeChild(f); }, 333);
}//end saver
if (navigator.msSaveBlob) { // IE10+ : (has Blob, but not a[download] or URL)
return navigator.msSaveBlob(blob, fileName);
}
if(self.URL){ // simple fast and modern way using Blob and URL:
saver(self.URL.createObjectURL(blob), true);
}else{
// handle non-Blob()+non-URL browsers:
if(typeof blob === "string" || blob.constructor===toString ){
try{
return saver( "data:" + mimeType + ";base64," + self.btoa(blob) );
}catch(y){
return saver( "data:" + mimeType + "," + encodeURIComponent(blob) );
}
}
// Blob but not URL support:
reader=new FileReader();
reader.onload=function(e){
saver(this.result);
};
reader.readAsDataURL(blob);
}
return true;
}; /* end download() */
}));

10100
client-vanilla/dep/jsQR.js Normal file

File diff suppressed because it is too large Load Diff

16
client-vanilla/dep/pdf-lib.min.js vendored Normal file

File diff suppressed because one or more lines are too long

9995
client-vanilla/dep/pdf.min.js vendored Normal file

File diff suppressed because it is too large Load Diff

22
client-vanilla/dep/pdf.worker.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,165 @@
// JSON Representation of this Node Tree:
// https://discord.com/channels/1068636748814483718/1099390571493195898/1118192754103693483
// https://cdn.discordapp.com/attachments/1099390571493195898/1118192753759764520/image.png?ex=6537dba7&is=652566a7&hm=dc46820ef7c34bc37424794966c5f66f93ba0e15a740742c364d47d31ea119a9&
export const discordWorkflow = {
outputOptions: {
zip: false
},
operations: [
{
type: "extract",
values: { "index": "1" },
operations: [
{
type: "removeObjects",
values: { "objectNames": "photo, josh" },
operations: [
{
type: "wait",
values: { "id": 1 }
}
]
}
]
},
{
type: "extract",
values: { "index": "2-5" },
operations: [
{
type: "fillField",
values: { "objectName": "name", "inputValue": "Josh" },
operations: [
{
type: "wait",
values: { "id": 1 }
}
]
}
]
},
{
type: "done", // This gets called when the other merge-ops with the same id finish.
values: { "id": 1 },
operations: [
{
type: "merge",
values: {},
operations: []
}
]
},
{
type: "extractImages",
values: {},
operations: []
},
{
type: "merge",
values: {},
operations: [
{
type: "transform",
values: { "scale": "2x", "rotation": "90deg" },
operations: []
}
]
}
]
}
// This will merge all input files into one giant document
export const mergeOnly = {
outputOptions: {
zip: false
},
operations: [
{
type: "merge",
values: {},
operations: []
}
]
}
// Extract Pages and store them in a new document
export const extractOnly = {
outputOptions: {
zip: false
},
operations: [
{
type: "extract",
values: { "pagesToExtractArray": [0, 2] },
operations: []
}
]
}
// Split a document up into multiple documents
export const splitOnly = {
outputOptions: {
zip: false
},
operations: [
{
type: "split",
values: { "pagesToSplitAfterArray": [2, 10] },
operations: []
}
]
}
export const rotateOnly = {
outputOptions: {
zip: false
},
operations: [
{
type: "rotate",
values: { "rotation": -90 },
operations: []
}
]
}
export const imposeOnly = {
outputOptions: {
zip: false
},
operations: [
{
type: "impose",
values: { "nup": 2, "format": "A4L" },
operations: []
}
]
}
export const removeBlankPagesOnly = {
outputOptions: {
zip: false
},
operations: [
{
type: "removeBlankPages",
values: { "whiteThreashold": 10 },
operations: []
}
]
}
export const splitOnQR = {
outputOptions: {
zip: false
},
operations: [
{
type: "splitOn",
values: {
type: "QR_CODE"
},
operations: []
}
]
}

View File

@@ -0,0 +1,65 @@
// PDFLib gets imported via index.html script-tag
// PDFJS as pdfjsLib via index.html script-tag
// jsQR via index.html script-tag
import * as pdfcpuWraopper from "./wasm/pdfcpu/pdfcpu-wrapper-browser.js";
const OpenCV = { cv: cv } // OPENCV gets importet as cv via index.html script-tag
import { extractPages as dependantExtractPages } from "./functions/extractPages.js";
import { impose as dependantImpose } from './functions/impose.js';
import { mergePDFs as dependantMergePDFs } from './functions/mergePDFs.js';
import { rotatePages as dependantRotatePages } from './functions/rotatePages.js';
import { scaleContent as dependantScaleContent} from './functions/scaleContent.js';
import { scalePage as dependantScalePage } from './functions/scalePage.js';
import { splitPDF as dependantSplitPDF } from './functions/splitPDF.js';
import { editMetadata as dependantEditMetadata} from "./functions/editMetadata.js";
import { organizePages as dependantOrganizePages} from "./functions/organizePages.js";
import { removeBlankPages as dependantRemoveBlankPages} from "./functions/removeBlankPages.js";
import { splitOn as dependantSplitOn } from "./functions/splitOn.js";
// TODO: Dynamic loading & undloading of libraries.
export async function extractPages(snapshot, pagesToExtractArray) {
return dependantExtractPages(snapshot, pagesToExtractArray, PDFLib);
}
export async function impose(snapshot, nup, format) {
return dependantImpose(snapshot, nup, format, pdfcpuWraopper);
}
export async function mergePDFs(snapshots) {
return dependantMergePDFs(snapshots, PDFLib);
}
export async function rotatePages(snapshot, rotation) {
return dependantRotatePages(snapshot, rotation, PDFLib);
}
export async function scaleContent(snapshot, scaleFactor) {
return dependantScaleContent(snapshot, scaleFactor, PDFLib);
}
export async function scalePage(snapshot, pageSize) {
return dependantScalePage(snapshot, pageSize, PDFLib);
}
export async function splitPDF(snapshot, splitAfterPageArray) {
return dependantSplitPDF(snapshot, splitAfterPageArray, PDFLib);
}
export async function editMetadata(snapshot, metadata) {
return dependantEditMetadata(snapshot, metadata, PDFLib);
}
export async function organizePages(snapshot, operation, customOrderString) {
return dependantOrganizePages(snapshot, operation, customOrderString, PDFLib);
}
export async function removeBlankPages(snapshot, whiteThreashold) {
return dependantRemoveBlankPages(snapshot, whiteThreashold, pdfjsLib, OpenCV, PDFLib);
}
export async function splitOn(snapshot, type, whiteThreashold) {
return dependantSplitOn(snapshot, type, whiteThreashold, pdfjsLib, OpenCV, PDFLib, jsQR);
}

0
client-vanilla/index.css Normal file
View File

35
client-vanilla/index.html Normal file
View File

@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="/dep/pdf-lib.min.js"></script>
<script src="/dep/downloadjs_1.4.7.js"></script>
<script src="/dep/pdf.min.js"></script>
<script src="/dep/jsQR.js"></script>
<script src="/wasm/browserfs.min.js"></script>
<script src="/wasm/opencv/opencv_3_4_custom_O3.js"></script>
<script src="index.js" type="module"></script>
</head>
<body>
<input type="file" id="pdfFile" accept=".pdf" multiple>
<ul id="operations">
</ul>
<select id="pdfOptions">
<option value="scaleContent">Scale Content</option>
<option value="changePageSize">Change Page Size</option>
<option value="mergePDFs">Merge PDFs</option>
<option value="splitPDFs">Split PDFs</option>
</select>
<button id="addButton">Add</button>
<button id="doneButton">Done</button>
</body>
</html>

42
client-vanilla/index.js Normal file
View File

@@ -0,0 +1,42 @@
import { scaleContent } from "./functions/scaleContent.js";
import { scalePage, PageSize } from "./functions/scalePage.js";
import * as exampleWorkflows from "./exampleWorkflows.js";
import { traverseOperations } from "./traverseOperations.js";
import * as Functions from "./functions.js";
(async (workflow) => {
const pdfFileInput = document.getElementById('pdfFile');
const doneButton = document.getElementById("doneButton");
doneButton.addEventListener('click', async (e) => {
console.log("Starting...");
const files = Array.from(pdfFileInput.files);
const inputs = await Promise.all(files.map(async file => {
return {
originalFileName: file.name.replace(/\.[^/.]+$/, ""),
fileName: file.name.replace(/\.[^/.]+$/, ""),
buffer: new Uint8Array(await file.arrayBuffer())
}
}));
console.log(inputs);
const traverse = traverseOperations(workflow.operations, inputs, Functions);
let pdfResults;
let iteration;
while (true) {
iteration = await traverse.next();
if (iteration.done) {
pdfResults = iteration.value;
console.log(`data: processing done\n\n`);
break;
}
console.log(`data: ${iteration.value}\n\n`);
}
pdfResults.forEach(result => {
download(result.buffer, result.fileName, "application/pdf");
});
});
})(exampleWorkflows.splitOnQR);