added 2 new root folders

This commit is contained in:
Saud Fatayerji 2023-10-23 18:08:28 +03:00
parent 31b746eb4b
commit 368d742d41
58 changed files with 10235 additions and 250 deletions

6
.gitignore vendored
View File

@ -1,5 +1 @@
/node_modules/
.env
/testFiles/
/ignore/
*.code-workspace
*/node_modules/

View File

@ -0,0 +1,10 @@
import { defineConfig } from "cypress";
export default defineConfig({
e2e: {
baseUrl: "http://localhost:5173",
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
});

View File

@ -0,0 +1,6 @@
describe('My First Test', () => {
it('Visits the app root url', () => {
cy.visit('/')
cy.contains('#container', 'Ready to create an app?')
})
})

View File

@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View File

@ -0,0 +1,37 @@
/// <reference types="cypress" />
// ***********************************************
// This example commands.ts shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
//
// declare global {
// namespace Cypress {
// interface Chainable {
// login(email: string, password: string): Chainable<void>
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
// }
// }
// }

View File

@ -0,0 +1,20 @@
// ***********************************************************
// This example support/e2e.ts is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')

30
client-ionic/index.html Normal file
View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Ionic App</title>
<base href="/" />
<meta name="color-scheme" content="light dark" />
<meta
name="viewport"
content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<meta name="format-detection" content="telephone=no" />
<meta name="msapplication-tap-highlight" content="no" />
<link rel="manifest" href="/manifest.json" />
<link rel="shortcut icon" type="image/png" href="/favicon.png" />
<!-- add to homescreen for ios -->
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-title" content="Ionic App" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

View File

@ -0,0 +1,5 @@
{
"name": "ionic-app-base",
"integrations": {},
"type": "react-vite"
}

View File

@ -0,0 +1,12 @@
{
"name": "Blank Starter",
"baseref": "main",
"tarignore": [
"node_modules",
"package-lock.json",
"www"
],
"scripts": {
"test": "npm run build && npm run test.unit -- --watch=false && npm i --no-save concurrently && ./node_modules/.bin/concurrently \"npm run dev\" \"npm run test.e2e\" --kill-others --success first"
}
}

8877
client-ionic/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

43
client-ionic/package.json Normal file
View File

@ -0,0 +1,43 @@
{
"name": "ionic-app-base",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"ionic": "ionic serve",
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"test.e2e": "cypress run",
"test.unit": "vitest",
"lint": "eslint"
},
"dependencies": {
"@ionic/react": "^7.0.0",
"@ionic/react-router": "^7.0.0",
"@types/react-router": "^5.1.20",
"@types/react-router-dom": "^5.3.3",
"ionicons": "^7.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router": "^5.3.4",
"react-router-dom": "^5.3.4",
"shared-operations": "file:../shared-operations"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10",
"@vitejs/plugin-legacy": "^4.0.2",
"@vitejs/plugin-react": "^4.0.1",
"cypress": "^13.3.2",
"eslint": "^8.35.0",
"eslint-plugin-react": "^7.32.2",
"jsdom": "^22.1.0",
"typescript": "^5.1.6",
"vite": "^4.3.9",
"vitest": "^0.32.2"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B

View File

@ -0,0 +1,21 @@
{
"short_name": "Ionic App",
"name": "My Ionic App",
"icons": [
{
"src": "assets/icon/favicon.png",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "assets/icon/icon.png",
"type": "image/png",
"sizes": "512x512",
"purpose": "maskable"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#ffffff",
"background_color": "#ffffff"
}

View File

@ -0,0 +1,8 @@
import React from 'react';
import { render } from '@testing-library/react';
import App from './App';
test('renders without crashing', () => {
const { baseElement } = render(<App />);
expect(baseElement).toBeDefined();
});

42
client-ionic/src/App.tsx Normal file
View File

@ -0,0 +1,42 @@
import { Redirect, Route } from 'react-router-dom';
import { IonApp, IonRouterOutlet, setupIonicReact } from '@ionic/react';
import { IonReactRouter } from '@ionic/react-router';
import Home from './pages/Home';
/* Core CSS required for Ionic components to work properly */
import '@ionic/react/css/core.css';
/* Basic CSS for apps built with Ionic */
import '@ionic/react/css/normalize.css';
import '@ionic/react/css/structure.css';
import '@ionic/react/css/typography.css';
/* Optional CSS utils that can be commented out */
import '@ionic/react/css/padding.css';
import '@ionic/react/css/float-elements.css';
import '@ionic/react/css/text-alignment.css';
import '@ionic/react/css/text-transformation.css';
import '@ionic/react/css/flex-utils.css';
import '@ionic/react/css/display.css';
/* Theme variables */
import './theme/variables.css';
setupIonicReact();
const App: React.FC = () => (
<IonApp>
<IonReactRouter>
<IonRouterOutlet>
<Route exact path="/home">
<Home />
</Route>
<Route exact path="/">
<Redirect to="/home" />
</Route>
</IonRouterOutlet>
</IonReactRouter>
</IonApp>
);
export default App;

View File

@ -0,0 +1,24 @@
#container {
text-align: center;
position: absolute;
left: 0;
right: 0;
top: 50%;
transform: translateY(-50%);
}
#container strong {
font-size: 20px;
line-height: 26px;
}
#container p {
font-size: 16px;
line-height: 22px;
color: #8c8c8c;
margin: 0;
}
#container a {
text-decoration: none;
}

View File

@ -0,0 +1,14 @@
import './ExploreContainer.css';
interface ContainerProps { }
const ExploreContainer: React.FC<ContainerProps> = () => {
return (
<div id="container">
<strong>Ready to create an app?</strong>
<p>Start with Ionic <a target="_blank" rel="noopener noreferrer" href="https://ionicframework.com/docs/components">UI Components</a></p>
</div>
);
};
export default ExploreContainer;

11
client-ionic/src/main.tsx Normal file
View File

@ -0,0 +1,11 @@
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
const container = document.getElementById('root');
const root = createRoot(container!);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);

View File

@ -0,0 +1,27 @@
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/react';
import ExploreContainer from '../components/ExploreContainer';
import './Home.css';
import { splitPDF } from '../utils/pdf-operations.js';
console.log(splitPDF);
const Home: React.FC = () => {
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Blank</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Blank</IonTitle>
</IonToolbar>
</IonHeader>
<ExploreContainer />
</IonContent>
</IonPage>
);
};
export default Home;

View File

@ -0,0 +1,14 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom/extend-expect';
// Mock matchmedia
window.matchMedia = window.matchMedia || function() {
return {
matches: false,
addListener: function() {},
removeListener: function() {}
};
};

View File

@ -0,0 +1,242 @@
/* Ionic Variables and Theming. For more info, please see:
http://ionicframework.com/docs/theming/ */
/** Ionic CSS Variables **/
:root {
/** primary **/
--ion-color-primary: #3880ff;
--ion-color-primary-rgb: 56, 128, 255;
--ion-color-primary-contrast: #ffffff;
--ion-color-primary-contrast-rgb: 255, 255, 255;
--ion-color-primary-shade: #3171e0;
--ion-color-primary-tint: #4c8dff;
/** secondary **/
--ion-color-secondary: #3dc2ff;
--ion-color-secondary-rgb: 61, 194, 255;
--ion-color-secondary-contrast: #ffffff;
--ion-color-secondary-contrast-rgb: 255, 255, 255;
--ion-color-secondary-shade: #36abe0;
--ion-color-secondary-tint: #50c8ff;
/** tertiary **/
--ion-color-tertiary: #5260ff;
--ion-color-tertiary-rgb: 82, 96, 255;
--ion-color-tertiary-contrast: #ffffff;
--ion-color-tertiary-contrast-rgb: 255, 255, 255;
--ion-color-tertiary-shade: #4854e0;
--ion-color-tertiary-tint: #6370ff;
/** success **/
--ion-color-success: #2dd36f;
--ion-color-success-rgb: 45, 211, 111;
--ion-color-success-contrast: #ffffff;
--ion-color-success-contrast-rgb: 255, 255, 255;
--ion-color-success-shade: #28ba62;
--ion-color-success-tint: #42d77d;
/** warning **/
--ion-color-warning: #ffc409;
--ion-color-warning-rgb: 255, 196, 9;
--ion-color-warning-contrast: #000000;
--ion-color-warning-contrast-rgb: 0, 0, 0;
--ion-color-warning-shade: #e0ac08;
--ion-color-warning-tint: #ffca22;
/** danger **/
--ion-color-danger: #eb445a;
--ion-color-danger-rgb: 235, 68, 90;
--ion-color-danger-contrast: #ffffff;
--ion-color-danger-contrast-rgb: 255, 255, 255;
--ion-color-danger-shade: #cf3c4f;
--ion-color-danger-tint: #ed576b;
/** dark **/
--ion-color-dark: #222428;
--ion-color-dark-rgb: 34, 36, 40;
--ion-color-dark-contrast: #ffffff;
--ion-color-dark-contrast-rgb: 255, 255, 255;
--ion-color-dark-shade: #1e2023;
--ion-color-dark-tint: #383a3e;
/** medium **/
--ion-color-medium: #92949c;
--ion-color-medium-rgb: 146, 148, 156;
--ion-color-medium-contrast: #ffffff;
--ion-color-medium-contrast-rgb: 255, 255, 255;
--ion-color-medium-shade: #808289;
--ion-color-medium-tint: #9d9fa6;
/** light **/
--ion-color-light: #f4f5f8;
--ion-color-light-rgb: 244, 245, 248;
--ion-color-light-contrast: #000000;
--ion-color-light-contrast-rgb: 0, 0, 0;
--ion-color-light-shade: #d7d8da;
--ion-color-light-tint: #f5f6f9;
}
@media (prefers-color-scheme: dark) {
/*
* Dark Colors
* -------------------------------------------
*/
body {
--ion-color-primary: #428cff;
--ion-color-primary-rgb: 66,140,255;
--ion-color-primary-contrast: #ffffff;
--ion-color-primary-contrast-rgb: 255,255,255;
--ion-color-primary-shade: #3a7be0;
--ion-color-primary-tint: #5598ff;
--ion-color-secondary: #50c8ff;
--ion-color-secondary-rgb: 80,200,255;
--ion-color-secondary-contrast: #ffffff;
--ion-color-secondary-contrast-rgb: 255,255,255;
--ion-color-secondary-shade: #46b0e0;
--ion-color-secondary-tint: #62ceff;
--ion-color-tertiary: #6a64ff;
--ion-color-tertiary-rgb: 106,100,255;
--ion-color-tertiary-contrast: #ffffff;
--ion-color-tertiary-contrast-rgb: 255,255,255;
--ion-color-tertiary-shade: #5d58e0;
--ion-color-tertiary-tint: #7974ff;
--ion-color-success: #2fdf75;
--ion-color-success-rgb: 47,223,117;
--ion-color-success-contrast: #000000;
--ion-color-success-contrast-rgb: 0,0,0;
--ion-color-success-shade: #29c467;
--ion-color-success-tint: #44e283;
--ion-color-warning: #ffd534;
--ion-color-warning-rgb: 255,213,52;
--ion-color-warning-contrast: #000000;
--ion-color-warning-contrast-rgb: 0,0,0;
--ion-color-warning-shade: #e0bb2e;
--ion-color-warning-tint: #ffd948;
--ion-color-danger: #ff4961;
--ion-color-danger-rgb: 255,73,97;
--ion-color-danger-contrast: #ffffff;
--ion-color-danger-contrast-rgb: 255,255,255;
--ion-color-danger-shade: #e04055;
--ion-color-danger-tint: #ff5b71;
--ion-color-dark: #f4f5f8;
--ion-color-dark-rgb: 244,245,248;
--ion-color-dark-contrast: #000000;
--ion-color-dark-contrast-rgb: 0,0,0;
--ion-color-dark-shade: #d7d8da;
--ion-color-dark-tint: #f5f6f9;
--ion-color-medium: #989aa2;
--ion-color-medium-rgb: 152,154,162;
--ion-color-medium-contrast: #000000;
--ion-color-medium-contrast-rgb: 0,0,0;
--ion-color-medium-shade: #86888f;
--ion-color-medium-tint: #a2a4ab;
--ion-color-light: #222428;
--ion-color-light-rgb: 34,36,40;
--ion-color-light-contrast: #ffffff;
--ion-color-light-contrast-rgb: 255,255,255;
--ion-color-light-shade: #1e2023;
--ion-color-light-tint: #383a3e;
}
/*
* iOS Dark Theme
* -------------------------------------------
*/
.ios body {
--ion-background-color: #000000;
--ion-background-color-rgb: 0,0,0;
--ion-text-color: #ffffff;
--ion-text-color-rgb: 255,255,255;
--ion-color-step-50: #0d0d0d;
--ion-color-step-100: #1a1a1a;
--ion-color-step-150: #262626;
--ion-color-step-200: #333333;
--ion-color-step-250: #404040;
--ion-color-step-300: #4d4d4d;
--ion-color-step-350: #595959;
--ion-color-step-400: #666666;
--ion-color-step-450: #737373;
--ion-color-step-500: #808080;
--ion-color-step-550: #8c8c8c;
--ion-color-step-600: #999999;
--ion-color-step-650: #a6a6a6;
--ion-color-step-700: #b3b3b3;
--ion-color-step-750: #bfbfbf;
--ion-color-step-800: #cccccc;
--ion-color-step-850: #d9d9d9;
--ion-color-step-900: #e6e6e6;
--ion-color-step-950: #f2f2f2;
--ion-item-background: #000000;
--ion-card-background: #1c1c1d;
}
.ios ion-modal {
--ion-background-color: var(--ion-color-step-100);
--ion-toolbar-background: var(--ion-color-step-150);
--ion-toolbar-border-color: var(--ion-color-step-250);
}
/*
* Material Design Dark Theme
* -------------------------------------------
*/
.md body {
--ion-background-color: #121212;
--ion-background-color-rgb: 18,18,18;
--ion-text-color: #ffffff;
--ion-text-color-rgb: 255,255,255;
--ion-border-color: #222222;
--ion-color-step-50: #1e1e1e;
--ion-color-step-100: #2a2a2a;
--ion-color-step-150: #363636;
--ion-color-step-200: #414141;
--ion-color-step-250: #4d4d4d;
--ion-color-step-300: #595959;
--ion-color-step-350: #656565;
--ion-color-step-400: #717171;
--ion-color-step-450: #7d7d7d;
--ion-color-step-500: #898989;
--ion-color-step-550: #949494;
--ion-color-step-600: #a0a0a0;
--ion-color-step-650: #acacac;
--ion-color-step-700: #b8b8b8;
--ion-color-step-750: #c4c4c4;
--ion-color-step-800: #d0d0d0;
--ion-color-step-850: #dbdbdb;
--ion-color-step-900: #e7e7e7;
--ion-color-step-950: #f3f3f3;
--ion-item-background: #1e1e1e;
--ion-toolbar-background: #1f1f1f;
--ion-tab-bar-background: #1f1f1f;
--ion-card-background: #1e1e1e;
}
}
html {
/* For more information on dynamic font scaling, visit the documentation:
https://ionicframework.com/docs/layout/dynamic-font-scaling */
--ion-dynamic-font: var(--ion-default-dynamic-font);
}

View File

@ -1,14 +1,14 @@
// PDFLib gets importet via index.html script-tag
import * as pdfcpuWraopper from "./wasm/pdfcpu-wrapper-browser.js";
import * as pdfcpuWraopper from "shared-operations/packages/wasm/pdfcpu-wrapper-browser";
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 { extractPages as dependantExtractPages } from "shared-operations/functions/extractPages.js";
import { impose as dependantImpose } from 'shared-operations/functions/impose.js';
import { mergePDFs as dependantMergePDFs } from 'shared-operations/functions/mergePDFs.js';
import { rotatePages as dependantRotatePages } from 'shared-operations/functions/rotatePages.js';
import { scaleContent as dependantScaleContent} from 'shared-operations/functions/scaleContent.js';
import { scalePage as dependantScalePage } from 'shared-operations/functions/scalePage.js';
import { splitPDF as dependantSplitPDF } from 'shared-operations/functions/splitPDF.js';
import { editMetadata as dependantEditMetadata} from "shared-operations/functions/editMetadata.js";
export async function extractPages(snapshot, pagesToExtractArray) {
return dependantExtractPages(snapshot, pagesToExtractArray, PDFLib);

1
client-ionic/src/vite-env.d.ts vendored Normal file
View File

@ -0,0 +1 @@
/// <reference types="vite/client" />

View File

@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["src", "../shared-operations/packages/wasm", "../server-node/public/utils/pdfcpu-wrapper-node.js"],
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@ -0,0 +1,9 @@
{
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

View File

@ -0,0 +1,16 @@
import legacy from '@vitejs/plugin-legacy'
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react(),
legacy()
],
test: {
globals: true,
environment: 'jsdom',
setupFiles: './src/setupTests.ts',
}
})

4
server-node/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.env
/testFiles/
/ignore/
*.code-workspace

142
server-node/README.md Normal file
View File

@ -0,0 +1,142 @@
# StirlingPDF rewrite
This is the development repository for the new StirlingPDF backend. With the power of JS, WASM & GO this will provide almost all functionality SPDF can do currently directly on the client. For automation purposes this will still provide an API to automate your workflows.
## Try the new API!
[![Run in Postman](https://run.pstmn.io/button.svg)](https://documenter.getpostman.com/view/30633786/2s9YRB1Wto)
## Understanding Workflows
Workflows define how to apply operations to a PDF, including their order and relations with eachother.
Workflows can be created via the web-ui and then exported or, if you want to brag a bit, you can create the JSON object yourself.
### Basics
To create your own, you have to understand a few key features first. You can also look at more examples our github repository.
```json
{
"outputOptions": {
"zip": false
},
"operations": [
{
"type": "extract",
"values": {
"pagesToExtractArray": [0, 2]
},
"operations": []
}
]
}
```
The workflow above will extract the first (p\[0\]) and third (p\[2\]) page of the document.
You can also nest workflows like this:
```json
{
"outputOptions": {
"zip": false
},
"operations": [
{
"type": "extract",
"values": {
"pagesToExtractArray": [0, 2]
},
"operations": [
{
"type": "impose",
"values": {
"nup": 2, // 2 pages of the input document will be put on one page of the output document.
"format": "A4L" // A4L -> The page size of the Ouput will be an A4 in Landscape. You can also use other paper formats and "P" for portrait output.
},
"operations": []
}
]
}
]
}
```
If you look at it closely, you will see that the extract operation has another nested operation of the type impose. This workflow will produce a PDF with the 1st and 2nd page of the input on one single page.
### Advanced
If that is not enought for you usecase, there is also the possibility to connect operations with eachother.
You can also do different operations to produce two different output PDFs from one input.
If you are interested in learning about this, take a look at the Example workflows provided in the repository, ask on the discord, or wait for me to finish this documentation.
## Features
### Rewrite Roadmap
* [x] Client side PDF-Manipulation
* [x] Workflows
* [ ] Feature equivalent with S-PDF v1
* [ ] Stateful UI
* [ ] Node based editing of Workflows
* [ ] Propper auth using passportjs
### Functions
Current functions of spdf and their progress in this repo.
| Status | Feature | Description |
| ------ | ---------------------- | ----------- |
| ✔️ | Merge | |
| ✔️ | Split | |
| ✔️ | Rotate | |
| ✔️ | Multi-Page-Layout | |
| ✔️ | Adjust page size/scale | |
| ✔️ | Organize | |
| ✔️ | Change Metadata | |
| ❌ | Add Watermark | |
| Status | Feature | Description |
| ------ | --------------------------- | ----------- |
| ❌ | Remove Pages | |
| ❌ | Remove Blank Pages | |
| ❌ | Detect/Split Scanned photos | |
| Status | Feature | Description |
| ------ | ------------ | ----------- |
| ❌ | Repair | |
| ❌ | Compress | |
| ❌ | Flatten | |
| ❌ | Compare/Diff | |
| Status | Feature | Description |
| ------ | --------------------- | ----------- |
| ❌ | Sign | |
| ❌ | Sign with Certificate | |
| ❌ | Add Password | |
| ❌ | Remove Password | |
| ❌ | Change Permissions | |
| Status | Feature | Description |
| ------ | -------------- | ----------- |
| ❌ | Image to PDF | |
| ❌ | Add image | |
| ❌ | Extract Images | |
| ❌ | PDF to Image | |
| ❌ | OCR | |
| Status | Feature | Description |
| ------ | ------------------- | ----------- |
| ❌ | Convert file to PDF | |
| ❌ | PDF to Text/RTF | |
| ❌ | PDF to HTML | |
| ❌ | PDF to XML | |
✔️: Done, 🚧: Started Developement, ❌: Planned Feature
## Contribute
For initial instructions look at [CONTRIBUTE.md](./CONTRIBUTE.md)

View File

@ -9,6 +9,7 @@ import { scaleContent as dependantScaleContent} from './public/functions/scaleCo
import { scalePage as dependantScalePage } from './public/functions/scalePage.js';
import { splitPDF as dependantSplitPDF } from './public/functions/splitPDF.js';
import { editMetadata as dependantEditMetadata } from './public/functions/editMetadata.js';
import { organizePages as dependantOrganizePages } from './public/functions/organizePages.js';
export async function extractPages(snapshot, pagesToExtractArray) {
return dependantExtractPages(snapshot, pagesToExtractArray, PDFLib);
@ -40,4 +41,8 @@ export async function splitPDF(snapshot, splitAfterPageArray) {
export async function editMetadata(snapshot, metadata) {
return dependantEditMetadata(snapshot, metadata, PDFLib);
}
export async function organizePages(snapshot, operation, customOrderString) {
return dependantOrganizePages(snapshot, operation, customOrderString, PDFLib);
}

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,8 @@
"archiver": "^6.0.1",
"express": "^4.18.2",
"express-fileupload": "^1.4.1",
"pdf-lib": "^1.17.1"
"pdf-lib": "^1.17.1",
"shared-operations": "file:../shared-operations"
},
"type": "module"
}

View File

View File

@ -0,0 +1,48 @@
// PDFLib gets importet via index.html script-tag
import * as pdfcpuWraopper from "./wasm/pdfcpu-wrapper-browser.js";
import { extractPages as dependantExtractPages } from "shared-operations/functions/extractPages.js";
import { impose as dependantImpose } from 'shared-operations/functions/impose.js';
import { mergePDFs as dependantMergePDFs } from 'shared-operations/functions/mergePDFs.js';
import { rotatePages as dependantRotatePages } from 'shared-operations/functions/rotatePages.js';
import { scaleContent as dependantScaleContent} from 'shared-operations/functions/scaleContent.js';
import { scalePage as dependantScalePage } from 'shared-operations/functions/scalePage.js';
import { splitPDF as dependantSplitPDF } from 'shared-operations/functions/splitPDF.js';
import { editMetadata as dependantEditMetadata} from "shared-operations/functions/editMetadata.js";
import { organizePages as dependantOrganizePages} from "shared-operations/functions/organizePages.js";
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);
}

View File

@ -103,6 +103,12 @@ export async function * traverseOperations(operations, input, Functions) {
input.buffer = await Functions.editMetadata(input.buffer, operation.values["metadata"]);
});
break;
case "organizePages":
yield* nToN(input, operation, async (input) => {
input.fileName += "_pagesOrganized";
input.buffer = await Functions.organizePages(input.buffer, operation.values["operation"], operation.values["customOrderString"]);
});
break;
default:
throw new Error(`${operation.type} not implemented yet.`);
break;

View File

@ -1,5 +1,5 @@
export async function impose(snapshot, nup, format, pdfcpuWraopper) {
return await pdfcpuWraopper.oneToOne([
export async function impose(snapshot, nup, format, pdfcpuWrapper) {
return await pdfcpuWrapper.oneToOne([
"pdfcpu.wasm",
"nup",
"-c",

View File

@ -0,0 +1,2 @@
export {};

View File

@ -0,0 +1,12 @@
{
"name": "shared-operations",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}