mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-06-23 07:55:07 +00:00
refactor: apply eslint
This commit is contained in:
parent
5fd505d4f4
commit
9c1588d150
17
.eslintrc.js
17
.eslintrc.js
@ -4,7 +4,9 @@ module.exports = {
|
|||||||
"es2021": true
|
"es2021": true
|
||||||
},
|
},
|
||||||
"extends": [
|
"extends": [
|
||||||
"plugin:@typescript-eslint/strict"
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/strict-type-checked",
|
||||||
|
"plugin:@typescript-eslint/stylistic-type-checked"
|
||||||
],
|
],
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
@ -22,7 +24,12 @@ module.exports = {
|
|||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": "latest",
|
"ecmaVersion": "latest",
|
||||||
"sourceType": "module"
|
"sourceType": "module",
|
||||||
|
"project": [
|
||||||
|
"./client-tauri/tsconfig.json",
|
||||||
|
"./server-node/tsconfig.json",
|
||||||
|
"./shared-operations/tsconfig.json"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"@typescript-eslint"
|
"@typescript-eslint"
|
||||||
@ -47,7 +54,11 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
"semi": [
|
"semi": [
|
||||||
"error",
|
"error",
|
||||||
"always"
|
"always",
|
||||||
|
{
|
||||||
|
"omitLastInOneLineBlock": true,
|
||||||
|
"omitLastInOneLineClassBody": true
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,80 +1,80 @@
|
|||||||
import { Suspense } from 'react';
|
import { Suspense } from "react";
|
||||||
|
|
||||||
import { Routes, Route, Outlet } from "react-router-dom";
|
import { Routes, Route, Outlet } from "react-router-dom";
|
||||||
import Home from "./pages/Home";
|
import Home from "./pages/Home";
|
||||||
import About from "./pages/About";
|
import About from "./pages/About";
|
||||||
import Dashboard from "./pages/Dashboard";
|
import Dashboard from "./pages/Dashboard";
|
||||||
import ToPdf from "./pages/convert/ToPdf"
|
import ToPdf from "./pages/convert/ToPdf";
|
||||||
import Impose from "./pages/page-operations/Impose"
|
import Impose from "./pages/page-operations/Impose";
|
||||||
import NoMatch from "./pages/NoMatch";
|
import NoMatch from "./pages/NoMatch";
|
||||||
import NavBar from "./components/NavBar";
|
import NavBar from "./components/NavBar";
|
||||||
|
|
||||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
import "bootstrap/dist/css/bootstrap.min.css";
|
||||||
import { Container } from "react-bootstrap";
|
import { Container } from "react-bootstrap";
|
||||||
|
|
||||||
import i18n from "i18next";
|
import i18n from "i18next";
|
||||||
import { useTranslation, initReactI18next } from "react-i18next";
|
import { useTranslation, initReactI18next } from "react-i18next";
|
||||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
import LanguageDetector from "i18next-browser-languagedetector";
|
||||||
import ar from './locales/ar.json';
|
import ar from "./locales/ar.json";
|
||||||
import en from './locales/en.json';
|
import en from "./locales/en.json";
|
||||||
|
|
||||||
import './general.css'
|
import "./general.css";
|
||||||
|
|
||||||
i18n
|
i18n
|
||||||
.use(LanguageDetector)
|
.use(LanguageDetector)
|
||||||
.use(initReactI18next) // passes i18n down to react-i18next
|
.use(initReactI18next) // passes i18n down to react-i18next
|
||||||
.init({
|
.init({
|
||||||
fallbackLng: "en",
|
fallbackLng: "en",
|
||||||
resources: { ar,en },
|
resources: { ar,en },
|
||||||
});
|
});
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Suspense fallback="loading">
|
<Suspense fallback="loading">
|
||||||
{/* Routes nest inside one another. Nested route paths build upon
|
{/* Routes nest inside one another. Nested route paths build upon
|
||||||
parent route paths, and nested route elements render inside
|
parent route paths, and nested route elements render inside
|
||||||
parent route elements. See the note about <Outlet> below. */}
|
parent route elements. See the note about <Outlet> below. */}
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Layout />}>
|
<Route path="/" element={<Layout />}>
|
||||||
<Route index element={<Home />} />
|
<Route index element={<Home />} />
|
||||||
<Route path="about" element={<About />} />
|
<Route path="about" element={<About />} />
|
||||||
<Route path="dashboard" element={<Dashboard />} />
|
<Route path="dashboard" element={<Dashboard />} />
|
||||||
|
|
||||||
{/* Using path="*"" means "match anything", so this route
|
{/* Using path="*"" means "match anything", so this route
|
||||||
acts like a catch-all for URLs that we don't have explicit
|
acts like a catch-all for URLs that we don't have explicit
|
||||||
routes for. */}
|
routes for. */}
|
||||||
<Route path="*" element={<NoMatch />} />
|
<Route path="*" element={<NoMatch />} />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="/convert" element={<Layout />}>
|
<Route path="/convert" element={<Layout />}>
|
||||||
<Route path="file-to-pdf" element={<ToPdf />} />
|
<Route path="file-to-pdf" element={<ToPdf />} />
|
||||||
<Route path="*" element={<NoMatch />} />
|
<Route path="*" element={<NoMatch />} />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="/page-operations" element={<Layout />}>
|
<Route path="/page-operations" element={<Layout />}>
|
||||||
<Route path="impose" element={<Impose />} />
|
<Route path="impose" element={<Impose />} />
|
||||||
<Route path="*" element={<NoMatch />} />
|
<Route path="*" element={<NoMatch />} />
|
||||||
</Route>
|
</Route>
|
||||||
</Routes>
|
</Routes>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Layout() {
|
function Layout() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<div lang-direction={t('language.direction')}>
|
<div lang-direction={t("language.direction")}>
|
||||||
<NavBar/>
|
<NavBar/>
|
||||||
|
|
||||||
{/* An <Outlet> renders whatever child route is currently active,
|
{/* An <Outlet> renders whatever child route is currently active,
|
||||||
so you can think about this <Outlet> as a placeholder for
|
so you can think about this <Outlet> as a placeholder for
|
||||||
the child routes we defined above. */}
|
the child routes we defined above. */}
|
||||||
<Container fluid="sm" className="">
|
<Container fluid="sm" className="">
|
||||||
<div className="row justify-content-center">
|
<div className="row justify-content-center">
|
||||||
<div className="col-md-6">
|
<div className="col-md-6">
|
||||||
<Outlet/>
|
<Outlet/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</Container>
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
);
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
import Form from 'react-bootstrap/Form';
|
import Form from "react-bootstrap/Form";
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from "react-i18next";
|
||||||
import { FieldConstraint, RecordConstraint } from '@stirling-pdf/shared-operations/src/dynamic-ui/OperatorConstraints'
|
import { FieldConstraint, RecordConstraint } from "@stirling-pdf/shared-operations/src/dynamic-ui/OperatorConstraints";
|
||||||
|
|
||||||
interface DynamicParameterFieldsProps {
|
interface DynamicParameterFieldsProps {
|
||||||
constraints: RecordConstraint;
|
constraints: RecordConstraint;
|
||||||
@ -13,15 +13,15 @@ const DynamicParameterFields: React.FC<DynamicParameterFieldsProps> = ({constrai
|
|||||||
|
|
||||||
return (<>
|
return (<>
|
||||||
{Object.entries(constraints.record).map(([fieldName, value]) => {
|
{Object.entries(constraints.record).map(([fieldName, value]) => {
|
||||||
console.log(fieldName, value)
|
console.log(fieldName, value);
|
||||||
const globallyUniqueId = joinKeyPath([...parentKeyPath, fieldName]);
|
const globallyUniqueId = joinKeyPath([...parentKeyPath, fieldName]);
|
||||||
return <div className='mb-3' key={fieldName} >
|
return <div className='mb-3' key={fieldName} >
|
||||||
<label htmlFor={globallyUniqueId}>{t(value.displayNameKey)}</label>
|
<label htmlFor={globallyUniqueId}>{t(value.displayNameKey)}</label>
|
||||||
{fieldConstraintToElement(fieldName, parentKeyPath, globallyUniqueId, value)}
|
{fieldConstraintToElement(fieldName, parentKeyPath, globallyUniqueId, value)}
|
||||||
</div>
|
</div>;
|
||||||
})}
|
})}
|
||||||
</>);
|
</>);
|
||||||
}
|
};
|
||||||
|
|
||||||
function joinKeyPath(keyPath: string[]) {
|
function joinKeyPath(keyPath: string[]) {
|
||||||
return keyPath.join(".");
|
return keyPath.join(".");
|
||||||
@ -29,7 +29,7 @@ function joinKeyPath(keyPath: string[]) {
|
|||||||
|
|
||||||
function fieldConstraintToElement(fieldName: string, parentKeyPath: string[], globallyUniqueId: string, fieldConstraint: FieldConstraint) {
|
function fieldConstraintToElement(fieldName: string, parentKeyPath: string[], globallyUniqueId: string, fieldConstraint: FieldConstraint) {
|
||||||
if (Array.isArray(fieldConstraint.type)) {
|
if (Array.isArray(fieldConstraint.type)) {
|
||||||
if (fieldConstraint.type.every(e => typeof e == 'string' || typeof e == 'number')) {
|
if (fieldConstraint.type.every(e => typeof e == "string" || typeof e == "number")) {
|
||||||
return (
|
return (
|
||||||
<Form.Select id={globallyUniqueId} name={fieldName}>
|
<Form.Select id={globallyUniqueId} name={fieldName}>
|
||||||
<option value="" disabled>Select an option</option>
|
<option value="" disabled>Select an option</option>
|
||||||
@ -37,27 +37,27 @@ function fieldConstraintToElement(fieldName: string, parentKeyPath: string[], gl
|
|||||||
</Form.Select>
|
</Form.Select>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return <div key={fieldName}>Error: Field type '{fieldConstraint.type}' not supported</div>
|
return <div key={fieldName}>Error: Field type '{fieldConstraint.type}' not supported</div>;
|
||||||
}
|
}
|
||||||
} else if (typeof fieldConstraint.type == 'string') {
|
} else if (typeof fieldConstraint.type == "string") {
|
||||||
switch (fieldConstraint.type) {
|
switch (fieldConstraint.type) {
|
||||||
case "file.pdf":
|
case "file.pdf":
|
||||||
return <input id={globallyUniqueId} type="file" name={fieldName} required={fieldConstraint.required} className="form-control required" accept="application/pdf" multiple={false}/>;
|
return <input id={globallyUniqueId} type="file" name={fieldName} required={fieldConstraint.required} className="form-control required" accept="application/pdf" multiple={false}/>;
|
||||||
case "files.pdf":
|
case "files.pdf":
|
||||||
return <input id={globallyUniqueId} type="file" name={fieldName} required={fieldConstraint.required} className="form-control required" accept="application/pdf" multiple={true}/>;
|
return <input id={globallyUniqueId} type="file" name={fieldName} required={fieldConstraint.required} className="form-control required" accept="application/pdf" multiple={true}/>;
|
||||||
case "string":
|
case "string":
|
||||||
return <input id={globallyUniqueId} type="text" name={fieldName} required={fieldConstraint.required} />;
|
return <input id={globallyUniqueId} type="text" name={fieldName} required={fieldConstraint.required} />;
|
||||||
case "number":
|
case "number":
|
||||||
return <input id={globallyUniqueId} type="number" name={fieldName} required={fieldConstraint.required} />;
|
return <input id={globallyUniqueId} type="number" name={fieldName} required={fieldConstraint.required} />;
|
||||||
default:
|
default:
|
||||||
return <div key={fieldName}>Error: Field type '{fieldConstraint.type}' not supported</div>
|
return <div key={fieldName}>Error: Field type '{fieldConstraint.type}' not supported</div>;
|
||||||
}
|
}
|
||||||
} else if (fieldConstraint.type instanceof RecordConstraint) {
|
} else if (fieldConstraint.type instanceof RecordConstraint) {
|
||||||
//return <DynamicParameterFields constraints={fieldConstraint.type} parentKeyPath={[...parentKeyPath, fieldName]}/>
|
//return <DynamicParameterFields constraints={fieldConstraint.type} parentKeyPath={[...parentKeyPath, fieldName]}/>
|
||||||
return <div key={fieldName}>Error: Field type 'RecordConstraint' not supported yet!</div>
|
return <div key={fieldName}>Error: Field type 'RecordConstraint' not supported yet!</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div key={fieldName}>Error: Field type '{fieldConstraint.type}' not supported</div>
|
return <div key={fieldName}>Error: Field type '{fieldConstraint.type}' not supported</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DynamicParameterFields;
|
export default DynamicParameterFields;
|
@ -2,25 +2,25 @@
|
|||||||
import { AiOutlineMergeCells, AiOutlineSplitCells } from "react-icons/ai";
|
import { AiOutlineMergeCells, AiOutlineSplitCells } from "react-icons/ai";
|
||||||
import { BiCrop, BiSprayCan } from "react-icons/bi";
|
import { BiCrop, BiSprayCan } from "react-icons/bi";
|
||||||
import {
|
import {
|
||||||
BsTools, BsSortNumericDown, BsArrowClockwise, BsFileEarmarkX, BsLayoutSplit, BsPalette, BsArrowUpSquare, Bs1Square, BsFileEarmarkPdf,
|
BsTools, BsSortNumericDown, BsArrowClockwise, BsFileEarmarkX, BsLayoutSplit, BsPalette, BsArrowUpSquare, Bs1Square, BsFileEarmarkPdf,
|
||||||
BsArrowLeftRight, BsFileEarmarkImage, BsFileEarmark, BsFiletypeHtml, BsLink, BsFiletypeMd, BsFileEarmarkWord, BsFiletypePpt, BsFiletypeTxt,
|
BsArrowLeftRight, BsFileEarmarkImage, BsFileEarmark, BsFiletypeHtml, BsLink, BsFiletypeMd, BsFileEarmarkWord, BsFiletypePpt, BsFiletypeTxt,
|
||||||
BsFiletypeXml, BsLock, BsUnlock, BsShieldLock, BsDroplet, BsAward, BsEraserFill, BsCardList, BsClipboardData, BsFile, BsFileEarmarkRichtext,
|
BsFiletypeXml, BsLock, BsUnlock, BsShieldLock, BsDroplet, BsAward, BsEraserFill, BsCardList, BsClipboardData, BsFile, BsFileEarmarkRichtext,
|
||||||
BsFileZip, BsFiletypeJs, BsFonts, BsImages, BsInfoCircle, BsSearch, BsShieldCheck, BsVectorPen, BsWrench, BsArrowsCollapse, BsGrid, Bs123,
|
BsFileZip, BsFiletypeJs, BsFonts, BsImages, BsInfoCircle, BsSearch, BsShieldCheck, BsVectorPen, BsWrench, BsArrowsCollapse, BsGrid, Bs123,
|
||||||
BsArrowsFullscreen
|
BsArrowsFullscreen
|
||||||
} from "react-icons/bs";
|
} from "react-icons/bs";
|
||||||
import { MdOutlineScanner, MdOutlineBalance } from "react-icons/md";
|
import { MdOutlineScanner, MdOutlineBalance } from "react-icons/md";
|
||||||
import { IconType } from "react-icons";
|
import { IconType } from "react-icons";
|
||||||
|
|
||||||
import Container from 'react-bootstrap/Container';
|
import Container from "react-bootstrap/Container";
|
||||||
import Nav from 'react-bootstrap/Nav';
|
import Nav from "react-bootstrap/Nav";
|
||||||
import Navbar from 'react-bootstrap/Navbar';
|
import Navbar from "react-bootstrap/Navbar";
|
||||||
import NavDropdown from 'react-bootstrap/NavDropdown';
|
import NavDropdown from "react-bootstrap/NavDropdown";
|
||||||
import { LinkContainer } from 'react-router-bootstrap';
|
import { LinkContainer } from "react-router-bootstrap";
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import LanguagePicker from "./toolbar/LanguagePicker";
|
import LanguagePicker from "./toolbar/LanguagePicker";
|
||||||
import Logo from '../../public/stirling-pdf-logo.svg'
|
import Logo from "../../public/stirling-pdf-logo.svg";
|
||||||
import './NavBar.css';
|
import "./NavBar.css";
|
||||||
|
|
||||||
interface NavInfoItem {
|
interface NavInfoItem {
|
||||||
displayText: string;
|
displayText: string;
|
||||||
@ -31,143 +31,143 @@ interface NavInfoItem {
|
|||||||
interface NavInfoSublist {
|
interface NavInfoSublist {
|
||||||
displayText: string;
|
displayText: string;
|
||||||
icon: IconType;
|
icon: IconType;
|
||||||
sublist: Array<NavInfoItem>;
|
sublist: NavInfoItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertToNavLink(item: NavInfoItem, index: number) {
|
function convertToNavLink(item: NavInfoItem, index: number) {
|
||||||
return <LinkContainer key={"nav-link-"+index} to={item.dest}><Nav.Link className="nav-icon" title={item.tooltip}><item.icon/><span>{item.displayText}</span></Nav.Link></LinkContainer>;
|
return <LinkContainer key={"nav-link-"+index} to={item.dest}><Nav.Link className="nav-icon" title={item.tooltip}><item.icon/><span>{item.displayText}</span></Nav.Link></LinkContainer>;
|
||||||
}
|
}
|
||||||
function convertToNavDropdownItem(item: NavInfoItem | null, index: number) {
|
function convertToNavDropdownItem(item: NavInfoItem | null, index: number) {
|
||||||
if (item == null)
|
if (item == null)
|
||||||
return <NavDropdown.Divider key={"nav-dropdown-divider-"+index}/>;
|
return <NavDropdown.Divider key={"nav-dropdown-divider-"+index}/>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LinkContainer to={item.dest} key={"nav-dropdown-item-"+index}>
|
<LinkContainer to={item.dest} key={"nav-dropdown-item-"+index}>
|
||||||
<NavDropdown.Item className="nav-icon" title={item.tooltip}>
|
<NavDropdown.Item className="nav-icon" title={item.tooltip}>
|
||||||
<item.icon/>
|
<item.icon/>
|
||||||
<span>{item.displayText}</span>
|
<span>{item.displayText}</span>
|
||||||
</NavDropdown.Item>
|
</NavDropdown.Item>
|
||||||
</LinkContainer>
|
</LinkContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
function convertToNavDropdown(sublist: NavInfoSublist, index: number) {
|
function convertToNavDropdown(sublist: NavInfoSublist, index: number) {
|
||||||
var myTitle = <>
|
const myTitle = <>
|
||||||
<span className="nav-icon">
|
<span className="nav-icon">
|
||||||
<sublist.icon/>
|
<sublist.icon/>
|
||||||
<span>{sublist.displayText}</span>
|
<span>{sublist.displayText}</span>
|
||||||
</span>
|
</span>
|
||||||
</>;
|
</>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavDropdown title={myTitle} id="basic-nav-dropdown" key={"nav-dropdown-"+index}>
|
<NavDropdown title={myTitle} id="basic-nav-dropdown" key={"nav-dropdown-"+index}>
|
||||||
{sublist.sublist.map((item, i) => convertToNavDropdownItem(item, i))}
|
{sublist.sublist.map((item, i) => convertToNavDropdownItem(item, i))}
|
||||||
</NavDropdown>
|
</NavDropdown>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function NavBar() {
|
function NavBar() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const navInfo = [
|
const navInfo = [
|
||||||
{displayText: t('multiTool.title'), icon: BsTools, dest: "/home", tooltip: t('home.multiTool.desc')},
|
{displayText: t("multiTool.title"), icon: BsTools, dest: "/home", tooltip: t("home.multiTool.desc")},
|
||||||
{displayText: t('navbar.pageOps'), icon: BsFileEarmarkPdf, sublist: [
|
{displayText: t("navbar.pageOps"), icon: BsFileEarmarkPdf, sublist: [
|
||||||
{ displayText: t('home.merge.title'), icon: AiOutlineMergeCells, dest: "/dashboard", tooltip: t('home.merge.desc') },
|
{ displayText: t("home.merge.title"), icon: AiOutlineMergeCells, dest: "/dashboard", tooltip: t("home.merge.desc") },
|
||||||
{ displayText: t('home.split.title'), icon: AiOutlineSplitCells, dest: "/about", tooltip: t('home.split.desc') },
|
{ displayText: t("home.split.title"), icon: AiOutlineSplitCells, dest: "/about", tooltip: t("home.split.desc") },
|
||||||
{ displayText: t('home.pdfOrganiser.title'), icon: BsSortNumericDown, dest: "/nothing-here", tooltip: t('home.pdfOrganiser.desc') },
|
{ displayText: t("home.pdfOrganiser.title"), icon: BsSortNumericDown, dest: "/nothing-here", tooltip: t("home.pdfOrganiser.desc") },
|
||||||
{ displayText: t('home.rotate.title'), icon: BsArrowClockwise, dest: "/nothing-here", tooltip: t('home.rotate.desc') },
|
{ displayText: t("home.rotate.title"), icon: BsArrowClockwise, dest: "/nothing-here", tooltip: t("home.rotate.desc") },
|
||||||
{ displayText: t('home.removePages.title'), icon: BsFileEarmarkX, dest: "/nothing-here", tooltip: t('home.removePages.desc') },
|
{ displayText: t("home.removePages.title"), icon: BsFileEarmarkX, dest: "/nothing-here", tooltip: t("home.removePages.desc") },
|
||||||
{ displayText: t('home.pageLayout.title'), icon: BsGrid, dest: "/page-operations/impose", tooltip: t('home.pageLayout.desc') },
|
{ displayText: t("home.pageLayout.title"), icon: BsGrid, dest: "/page-operations/impose", tooltip: t("home.pageLayout.desc") },
|
||||||
{ displayText: t('home.scalePages.title'), icon: BsArrowsFullscreen, dest: "/nothing-here", tooltip: t('home.scalePages.desc') },
|
{ displayText: t("home.scalePages.title"), icon: BsArrowsFullscreen, dest: "/nothing-here", tooltip: t("home.scalePages.desc") },
|
||||||
{ displayText: t('home.autoSplitPDF.title'), icon: BsLayoutSplit, dest: "/nothing-here", tooltip: t('home.autoSplitPDF.desc') },
|
{ displayText: t("home.autoSplitPDF.title"), icon: BsLayoutSplit, dest: "/nothing-here", tooltip: t("home.autoSplitPDF.desc") },
|
||||||
{ displayText: t('home.adjust-contrast.title'), icon: BsPalette, dest: "/nothing-here", tooltip: t('home.adjust-contrast.desc') },
|
{ displayText: t("home.adjust-contrast.title"), icon: BsPalette, dest: "/nothing-here", tooltip: t("home.adjust-contrast.desc") },
|
||||||
{ displayText: t('home.crop.title'), icon: BiCrop, dest: "/nothing-here", tooltip: t('home.crop.desc') },
|
{ displayText: t("home.crop.title"), icon: BiCrop, dest: "/nothing-here", tooltip: t("home.crop.desc") },
|
||||||
{ displayText: t('home.extractPage.title'), icon: BsArrowUpSquare, dest: "/nothing-here", tooltip: t('home.extractPage.desc') },
|
{ displayText: t("home.extractPage.title"), icon: BsArrowUpSquare, dest: "/nothing-here", tooltip: t("home.extractPage.desc") },
|
||||||
{ displayText: t('home.PdfToSinglePage.title'), icon: Bs1Square, dest: "/nothing-here", tooltip: t('home.PdfToSinglePage.desc') },
|
{ displayText: t("home.PdfToSinglePage.title"), icon: Bs1Square, dest: "/nothing-here", tooltip: t("home.PdfToSinglePage.desc") },
|
||||||
]},
|
]},
|
||||||
{displayText: t('navbar.convert'), icon: BsArrowLeftRight, sublist: [
|
{displayText: t("navbar.convert"), icon: BsArrowLeftRight, sublist: [
|
||||||
{ displayText: t('home.imageToPdf.title'), icon: BsFileEarmarkImage, dest: "/dashboard", tooltip: t('home.imageToPdf.desc') },
|
{ displayText: t("home.imageToPdf.title"), icon: BsFileEarmarkImage, dest: "/dashboard", tooltip: t("home.imageToPdf.desc") },
|
||||||
{ displayText: t('home.fileToPDF.title'), icon: BsFileEarmark, dest: "/convert/file-to-pdf", tooltip: t('home.fileToPDF.desc') },
|
{ displayText: t("home.fileToPDF.title"), icon: BsFileEarmark, dest: "/convert/file-to-pdf", tooltip: t("home.fileToPDF.desc") },
|
||||||
{ displayText: t('home.HTMLToPDF.title'), icon: BsFiletypeHtml, dest: "/nothing-here", tooltip: t('home.HTMLToPDF.desc') },
|
{ displayText: t("home.HTMLToPDF.title"), icon: BsFiletypeHtml, dest: "/nothing-here", tooltip: t("home.HTMLToPDF.desc") },
|
||||||
{ displayText: t('home.URLToPDF.title'), icon: BsLink, dest: "/nothing-here", tooltip: t('home.URLToPDF.desc') },
|
{ displayText: t("home.URLToPDF.title"), icon: BsLink, dest: "/nothing-here", tooltip: t("home.URLToPDF.desc") },
|
||||||
{ displayText: t('home.MarkdownToPDF.title'), icon: BsFiletypeMd, dest: "/nothing-here", tooltip: t('home.MarkdownToPDF.desc') },
|
{ displayText: t("home.MarkdownToPDF.title"), icon: BsFiletypeMd, dest: "/nothing-here", tooltip: t("home.MarkdownToPDF.desc") },
|
||||||
null,
|
null,
|
||||||
{ displayText: t('home.pdfToImage.title'), icon: BsFileEarmarkImage, dest: "/nothing-here", tooltip: t('home.pdfToImage.desc') },
|
{ displayText: t("home.pdfToImage.title"), icon: BsFileEarmarkImage, dest: "/nothing-here", tooltip: t("home.pdfToImage.desc") },
|
||||||
{ displayText: t('home.PDFToWord.title'), icon: BsFileEarmarkWord, dest: "/nothing-here", tooltip: t('home.PDFToWord.desc') },
|
{ displayText: t("home.PDFToWord.title"), icon: BsFileEarmarkWord, dest: "/nothing-here", tooltip: t("home.PDFToWord.desc") },
|
||||||
{ displayText: t('home.PDFToPresentation.title'), icon: BsFiletypePpt, dest: "/nothing-here", tooltip: t('home.PDFToPresentation.desc') },
|
{ displayText: t("home.PDFToPresentation.title"), icon: BsFiletypePpt, dest: "/nothing-here", tooltip: t("home.PDFToPresentation.desc") },
|
||||||
{ displayText: t('home.PDFToText.title'), icon: BsFiletypeTxt, dest: "/nothing-here", tooltip: t('home.PDFToText.desc') },
|
{ displayText: t("home.PDFToText.title"), icon: BsFiletypeTxt, dest: "/nothing-here", tooltip: t("home.PDFToText.desc") },
|
||||||
{ displayText: t('home.PDFToHTML.title'), icon: BsFiletypeHtml, dest: "/nothing-here", tooltip: t('home.PDFToHTML.desc') },
|
{ displayText: t("home.PDFToHTML.title"), icon: BsFiletypeHtml, dest: "/nothing-here", tooltip: t("home.PDFToHTML.desc") },
|
||||||
{ displayText: t('home.PDFToXML.title'), icon: BsFiletypeXml, dest: "/nothing-here", tooltip: t('home.PDFToXML.desc') },
|
{ displayText: t("home.PDFToXML.title"), icon: BsFiletypeXml, dest: "/nothing-here", tooltip: t("home.PDFToXML.desc") },
|
||||||
{ displayText: t('home.pdfToPDFA.title'), icon: BsFileEarmarkPdf, dest: "/nothing-here", tooltip: t('home.pdfToPDFA.desc') },
|
{ displayText: t("home.pdfToPDFA.title"), icon: BsFileEarmarkPdf, dest: "/nothing-here", tooltip: t("home.pdfToPDFA.desc") },
|
||||||
]},
|
]},
|
||||||
{displayText: t('navbar.security'), icon: BsShieldCheck, sublist: [
|
{displayText: t("navbar.security"), icon: BsShieldCheck, sublist: [
|
||||||
{ displayText: t('home.addPassword.title'), icon: BsLock, dest: "/dashboard", tooltip: t('home.addPassword.desc') },
|
{ displayText: t("home.addPassword.title"), icon: BsLock, dest: "/dashboard", tooltip: t("home.addPassword.desc") },
|
||||||
{ displayText: t('home.removePassword.title'), icon: BsUnlock, dest: "/nothing-here", tooltip: t('home.removePassword.desc') },
|
{ displayText: t("home.removePassword.title"), icon: BsUnlock, dest: "/nothing-here", tooltip: t("home.removePassword.desc") },
|
||||||
{ displayText: t('home.permissions.title'), icon: BsShieldLock, dest: "/nothing-here", tooltip: t('home.permissions.desc') },
|
{ displayText: t("home.permissions.title"), icon: BsShieldLock, dest: "/nothing-here", tooltip: t("home.permissions.desc") },
|
||||||
{ displayText: t('home.watermark.title'), icon: BsDroplet, dest: "/nothing-here", tooltip: t('home.watermark.desc') },
|
{ displayText: t("home.watermark.title"), icon: BsDroplet, dest: "/nothing-here", tooltip: t("home.watermark.desc") },
|
||||||
{ displayText: t('home.certSign.title'), icon: BsAward, dest: "/nothing-here", tooltip: t('home.certSign.desc') },
|
{ displayText: t("home.certSign.title"), icon: BsAward, dest: "/nothing-here", tooltip: t("home.certSign.desc") },
|
||||||
{ displayText: t('home.sanitizePdf.title'), icon: BiSprayCan, dest: "/nothing-here", tooltip: t('home.sanitizePdf.desc') },
|
{ displayText: t("home.sanitizePdf.title"), icon: BiSprayCan, dest: "/nothing-here", tooltip: t("home.sanitizePdf.desc") },
|
||||||
{ displayText: t('home.autoRedact.title'), icon: BsEraserFill, dest: "/nothing-here", tooltip: t('home.autoRedact.desc') },
|
{ displayText: t("home.autoRedact.title"), icon: BsEraserFill, dest: "/nothing-here", tooltip: t("home.autoRedact.desc") },
|
||||||
]},
|
]},
|
||||||
{displayText: t('navbar.other'), icon: BsCardList, sublist: [
|
{displayText: t("navbar.other"), icon: BsCardList, sublist: [
|
||||||
{ displayText: t('home.ocr.title'), icon: BsSearch, dest: "/dashboard", tooltip: t('home.ocr.desc') },
|
{ displayText: t("home.ocr.title"), icon: BsSearch, dest: "/dashboard", tooltip: t("home.ocr.desc") },
|
||||||
{ displayText: t('home.addImage.title'), icon: BsFileEarmarkRichtext, dest: "/nothing-here", tooltip: t('home.addImage.desc') },
|
{ displayText: t("home.addImage.title"), icon: BsFileEarmarkRichtext, dest: "/nothing-here", tooltip: t("home.addImage.desc") },
|
||||||
{ displayText: t('home.compressPdfs.title'), icon: BsFileZip, dest: "/nothing-here", tooltip: t('home.compressPdfs.desc') },
|
{ displayText: t("home.compressPdfs.title"), icon: BsFileZip, dest: "/nothing-here", tooltip: t("home.compressPdfs.desc") },
|
||||||
{ displayText: t('home.extractImages.title'), icon: BsImages, dest: "/nothing-here", tooltip: t('home.extractImages.desc') },
|
{ displayText: t("home.extractImages.title"), icon: BsImages, dest: "/nothing-here", tooltip: t("home.extractImages.desc") },
|
||||||
{ displayText: t('home.changeMetadata.title'), icon: BsClipboardData, dest: "/nothing-here", tooltip: t('home.changeMetadata.desc') },
|
{ displayText: t("home.changeMetadata.title"), icon: BsClipboardData, dest: "/nothing-here", tooltip: t("home.changeMetadata.desc") },
|
||||||
{ displayText: t('home.ScannerImageSplit.title'), icon: MdOutlineScanner, dest: "/nothing-here", tooltip: t('home.ScannerImageSplit.desc') },
|
{ displayText: t("home.ScannerImageSplit.title"), icon: MdOutlineScanner, dest: "/nothing-here", tooltip: t("home.ScannerImageSplit.desc") },
|
||||||
{ displayText: t('home.sign.title'), icon: BsVectorPen, dest: "/nothing-here", tooltip: t('home.sign.desc') },
|
{ displayText: t("home.sign.title"), icon: BsVectorPen, dest: "/nothing-here", tooltip: t("home.sign.desc") },
|
||||||
{ displayText: t('home.flatten.title'), icon: BsArrowsCollapse, dest: "/nothing-here", tooltip: t('home.flatten.desc') },
|
{ displayText: t("home.flatten.title"), icon: BsArrowsCollapse, dest: "/nothing-here", tooltip: t("home.flatten.desc") },
|
||||||
{ displayText: t('home.repair.title'), icon: BsWrench, dest: "/nothing-here", tooltip: t('home.repair.desc') },
|
{ displayText: t("home.repair.title"), icon: BsWrench, dest: "/nothing-here", tooltip: t("home.repair.desc") },
|
||||||
{ displayText: t('home.removeBlanks.title'), icon: BsFile, dest: "/nothing-here", tooltip: t('home.removeBlanks.desc') },
|
{ displayText: t("home.removeBlanks.title"), icon: BsFile, dest: "/nothing-here", tooltip: t("home.removeBlanks.desc") },
|
||||||
{ displayText: t('home.compare.title'), icon: MdOutlineBalance, dest: "/nothing-here", tooltip: t('home.compare.desc') },
|
{ displayText: t("home.compare.title"), icon: MdOutlineBalance, dest: "/nothing-here", tooltip: t("home.compare.desc") },
|
||||||
{ displayText: t('home.add-page-numbers.title'), icon: Bs123, dest: "/nothing-here", tooltip: t('home.add-page-numbers.desc') },
|
{ displayText: t("home.add-page-numbers.title"), icon: Bs123, dest: "/nothing-here", tooltip: t("home.add-page-numbers.desc") },
|
||||||
{ displayText: t('home.auto-rename.title'), icon: BsFonts, dest: "/nothing-here", tooltip: t('home.auto-rename.desc') },
|
{ displayText: t("home.auto-rename.title"), icon: BsFonts, dest: "/nothing-here", tooltip: t("home.auto-rename.desc") },
|
||||||
{ displayText: t('home.getPdfInfo.title'), icon: BsInfoCircle, dest: "/nothing-here", tooltip: t('home.getPdfInfo.desc') },
|
{ displayText: t("home.getPdfInfo.title"), icon: BsInfoCircle, dest: "/nothing-here", tooltip: t("home.getPdfInfo.desc") },
|
||||||
{ displayText: t('home.showJS.title'), icon: BsFiletypeJs, dest: "/nothing-here", tooltip: t('home.showJS.desc') },
|
{ displayText: t("home.showJS.title"), icon: BsFiletypeJs, dest: "/nothing-here", tooltip: t("home.showJS.desc") },
|
||||||
]},
|
]},
|
||||||
] as Array<NavInfoItem | NavInfoSublist>;
|
] as (NavInfoItem | NavInfoSublist)[];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Navbar expand="lg" className="bg-light">
|
<Navbar expand="lg" className="bg-light">
|
||||||
<Container>
|
<Container>
|
||||||
<LinkContainer to="/home">
|
<LinkContainer to="/home">
|
||||||
<Navbar.Brand className="nav-icon">
|
<Navbar.Brand className="nav-icon">
|
||||||
<img src={Logo} alt="Image" className="main-icon" />
|
<img src={Logo} alt="Image" className="main-icon" />
|
||||||
<span className="icon-text">Stirling PDF</span>
|
<span className="icon-text">Stirling PDF</span>
|
||||||
</Navbar.Brand>
|
</Navbar.Brand>
|
||||||
</LinkContainer>
|
</LinkContainer>
|
||||||
<Navbar.Toggle aria-controls="basic-navbar-nav"/>
|
<Navbar.Toggle aria-controls="basic-navbar-nav"/>
|
||||||
<Navbar.Collapse id="basic-navbar-nav">
|
<Navbar.Collapse id="basic-navbar-nav">
|
||||||
|
|
||||||
<Nav>
|
<Nav>
|
||||||
{navInfo.map((ni, idx) => {
|
{navInfo.map((ni, idx) => {
|
||||||
var element;
|
let element;
|
||||||
if ('dest' in ni) {
|
if ("dest" in ni) {
|
||||||
element = convertToNavLink(ni, idx);
|
element = convertToNavLink(ni, idx);
|
||||||
} else {
|
} else {
|
||||||
element = convertToNavDropdown(ni, idx);
|
element = convertToNavDropdown(ni, idx);
|
||||||
}
|
}
|
||||||
const out: JSX.Element[] = [];
|
const out: JSX.Element[] = [];
|
||||||
if (idx >= 1 ) {
|
if (idx >= 1 ) {
|
||||||
out.push( <div className="nav-item nav-item-separator" key={"nav-item-separator-"+idx}></div> );
|
out.push( <div className="nav-item nav-item-separator" key={"nav-item-separator-"+idx}></div> );
|
||||||
}
|
}
|
||||||
out.push(element);
|
out.push(element);
|
||||||
return out;
|
return out;
|
||||||
})}
|
})}
|
||||||
</Nav>
|
</Nav>
|
||||||
|
|
||||||
<div className="flex-fill-remaining-space"></div>
|
<div className="flex-fill-remaining-space"></div>
|
||||||
|
|
||||||
<Nav>
|
<Nav>
|
||||||
<LanguagePicker />
|
<LanguagePicker />
|
||||||
</Nav>
|
</Nav>
|
||||||
|
|
||||||
</Navbar.Collapse>
|
</Navbar.Collapse>
|
||||||
</Container>
|
</Container>
|
||||||
</Navbar>
|
</Navbar>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NavBar;
|
export default NavBar;
|
@ -1,29 +1,29 @@
|
|||||||
|
|
||||||
import NavDropdown from 'react-bootstrap/NavDropdown';
|
import NavDropdown from "react-bootstrap/NavDropdown";
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from "react-i18next";
|
||||||
import { BsGlobe2 } from 'react-icons/bs';
|
import { BsGlobe2 } from "react-icons/bs";
|
||||||
|
|
||||||
function generateSublist() {
|
function generateSublist() {
|
||||||
const { i18n } = useTranslation();
|
const { i18n } = useTranslation();
|
||||||
const out: JSX.Element[] = [];
|
const out: JSX.Element[] = [];
|
||||||
const languages = i18n.options.resources;
|
const languages = i18n.options.resources;
|
||||||
for (var key in languages) {
|
for (const key in languages) {
|
||||||
const lang: any = languages[key].translation;
|
const lang: any = languages[key].translation;
|
||||||
const staticKey = key;
|
const staticKey = key;
|
||||||
out.push((
|
out.push((
|
||||||
<NavDropdown.Item key={"language-"+key} className="nav-icon" onClick={()=>i18n.changeLanguage(staticKey)}>
|
<NavDropdown.Item key={"language-"+key} className="nav-icon" onClick={()=>i18n.changeLanguage(staticKey)}>
|
||||||
<span>{lang.language?.flag}</span>
|
<span>{lang.language?.flag}</span>
|
||||||
<span>{lang.language?.name}</span>
|
<span>{lang.language?.name}</span>
|
||||||
</NavDropdown.Item>
|
</NavDropdown.Item>
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
return <>{out}</>;
|
return <>{out}</>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function LanguagePicker() {
|
export default function LanguagePicker() {
|
||||||
return (
|
return (
|
||||||
<NavDropdown id="languages-dropdown" title={<><span className="nav-icon"><BsGlobe2/></span></>}>
|
<NavDropdown id="languages-dropdown" title={<><span className="nav-icon"><BsGlobe2/></span></>}>
|
||||||
{generateSublist()}
|
{generateSublist()}
|
||||||
</NavDropdown>
|
</NavDropdown>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
declare module '@stirling-pdf/shared-operations/wasm/pdfcpu/pdfcpu-wrapper-browser.js' {
|
declare module "@stirling-pdf/shared-operations/wasm/pdfcpu/pdfcpu-wrapper-browser.js" {
|
||||||
export async function oneToOne(wasmArray: any, snapshot: any): Promise<Uint8Array>;
|
export async function oneToOne(wasmArray: any, snapshot: any): Promise<Uint8Array>;
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,9 @@ import App from "./App";
|
|||||||
import "./index.css";
|
import "./index.css";
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById("root")!).render(
|
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<App />
|
<App />
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
);
|
);
|
@ -1,10 +1,10 @@
|
|||||||
|
|
||||||
function About() {
|
function About() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2>About</h2>
|
<h2>About</h2>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default About;
|
export default About;
|
@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
function Dashboard() {
|
function Dashboard() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2>Dashboard</h2>
|
<h2>Dashboard</h2>
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis aliquet felis in ornare molestie. Quisque et dolor gravida, vulputate libero ultricies, suscipit diam. Pellentesque semper eget purus et rutrum. Duis fringilla elementum tellus, ut egestas nisi ultrices sed. Fusce id elit ipsum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nulla facilisi. Duis varius, orci vel tempor cursus, elit tellus interdum sem, at vulputate lorem ex et dolor. Vestibulum purus mauris, consequat viverra gravida eget, fermentum a lacus. Phasellus eu varius dolor. Etiam a vulputate sapien. Etiam pulvinar, neque eu elementum imperdiet, nibh ex lobortis magna, ut varius lectus ante tristique massa.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis aliquet felis in ornare molestie. Quisque et dolor gravida, vulputate libero ultricies, suscipit diam. Pellentesque semper eget purus et rutrum. Duis fringilla elementum tellus, ut egestas nisi ultrices sed. Fusce id elit ipsum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nulla facilisi. Duis varius, orci vel tempor cursus, elit tellus interdum sem, at vulputate lorem ex et dolor. Vestibulum purus mauris, consequat viverra gravida eget, fermentum a lacus. Phasellus eu varius dolor. Etiam a vulputate sapien. Etiam pulvinar, neque eu elementum imperdiet, nibh ex lobortis magna, ut varius lectus ante tristique massa.
|
||||||
|
|
||||||
Nullam quis porttitor sapien. Suspendisse dictum enim vitae tristique aliquet. Nunc imperdiet pellentesque quam, sit amet luctus dui dignissim non. Vivamus eleifend sagittis mauris, at imperdiet nisl. Morbi rutrum magna ut tortor euismod efficitur. Pellentesque quis tortor consectetur, lobortis turpis eget, tincidunt turpis. Nulla consectetur massa ex. Donec lectus purus, interdum sit amet sapien eu, maximus dapibus diam. Suspendisse potenti. In lacinia augue massa, et vulputate eros convallis id. Suspendisse bibendum sagittis posuere. Integer ullamcorper odio eget risus venenatis, non mollis arcu lacinia. Vestibulum feugiat arcu elit, eu varius enim fermentum vitae.
|
Nullam quis porttitor sapien. Suspendisse dictum enim vitae tristique aliquet. Nunc imperdiet pellentesque quam, sit amet luctus dui dignissim non. Vivamus eleifend sagittis mauris, at imperdiet nisl. Morbi rutrum magna ut tortor euismod efficitur. Pellentesque quis tortor consectetur, lobortis turpis eget, tincidunt turpis. Nulla consectetur massa ex. Donec lectus purus, interdum sit amet sapien eu, maximus dapibus diam. Suspendisse potenti. In lacinia augue massa, et vulputate eros convallis id. Suspendisse bibendum sagittis posuere. Integer ullamcorper odio eget risus venenatis, non mollis arcu lacinia. Vestibulum feugiat arcu elit, eu varius enim fermentum vitae.
|
||||||
@ -42,8 +42,8 @@ Proin faucibus efficitur sollicitudin. Curabitur pharetra lectus ut metus molest
|
|||||||
Aenean tincidunt scelerisque ante non vestibulum. Curabitur eleifend ipsum sem, elementum ornare enim ornare eu. In molestie sodales mattis. Morbi ac posuere lorem. Aliquam in nisi ac ipsum euismod bibendum eget id urna. Quisque suscipit lectus non magna varius venenatis sed sit amet lectus. Nam leo nisl, imperdiet at lorem fringilla, lacinia bibendum lacus. Nunc auctor mauris at orci condimentum venenatis at non augue. Donec iaculis aliquam risus. Suspendisse vel massa leo.
|
Aenean tincidunt scelerisque ante non vestibulum. Curabitur eleifend ipsum sem, elementum ornare enim ornare eu. In molestie sodales mattis. Morbi ac posuere lorem. Aliquam in nisi ac ipsum euismod bibendum eget id urna. Quisque suscipit lectus non magna varius venenatis sed sit amet lectus. Nam leo nisl, imperdiet at lorem fringilla, lacinia bibendum lacus. Nunc auctor mauris at orci condimentum venenatis at non augue. Donec iaculis aliquam risus. Suspendisse vel massa leo.
|
||||||
|
|
||||||
Mauris sed est turpis. Nullam ut magna eu elit vehicula tempus. Sed mollis ultrices eleifend. Curabitur metus felis, sodales a turpis accumsan, ultricies feugiat arcu. Donec sit amet dui commodo, lacinia sem facilisis, lobortis urna. Donec cursus arcu ex, ac imperdiet lorem rutrum at. Curabitur faucibus erat in dolor placerat, vel blandit ligula eleifend. Morbi blandit nisl ut arcu semper consequat. Nulla malesuada convallis lectus a egestas. Sed volutpat metus vitae libero pulvinar, ut pretium magna malesuada.
|
Mauris sed est turpis. Nullam ut magna eu elit vehicula tempus. Sed mollis ultrices eleifend. Curabitur metus felis, sodales a turpis accumsan, ultricies feugiat arcu. Donec sit amet dui commodo, lacinia sem facilisis, lobortis urna. Donec cursus arcu ex, ac imperdiet lorem rutrum at. Curabitur faucibus erat in dolor placerat, vel blandit ligula eleifend. Morbi blandit nisl ut arcu semper consequat. Nulla malesuada convallis lectus a egestas. Sed volutpat metus vitae libero pulvinar, ut pretium magna malesuada.
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Dashboard;
|
export default Dashboard;
|
@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
function Home() {
|
function Home() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2>Home</h2>
|
<h2>Home</h2>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
function NoMatch() {
|
function NoMatch() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2>Nothing to see here!</h2>
|
<h2>Nothing to see here!</h2>
|
||||||
<p>
|
<p>
|
||||||
<Link to="/">Go to the home page 3</Link>
|
<Link to="/">Go to the home page 3</Link>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NoMatch;
|
export default NoMatch;
|
@ -2,7 +2,7 @@
|
|||||||
import { isLibreOfficeInstalled } from "../../utils/libre-office-utils";
|
import { isLibreOfficeInstalled } from "../../utils/libre-office-utils";
|
||||||
|
|
||||||
const hasLibreOffice = await isLibreOfficeInstalled();
|
const hasLibreOffice = await isLibreOfficeInstalled();
|
||||||
console.log(hasLibreOffice)
|
console.log(hasLibreOffice);
|
||||||
|
|
||||||
function About() {
|
function About() {
|
||||||
return (
|
return (
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
import DynamicParameterFields from "../../components/DynamicParameterFields";
|
import DynamicParameterFields from "../../components/DynamicParameterFields";
|
||||||
import { ImposeParamConstraints } from "@stirling-pdf/shared-operations/src/functions/impose";
|
import { ImposeParamConstraints } from "@stirling-pdf/shared-operations/src/functions/impose";
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
function Impose() {
|
function Impose() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
export function appendToFilename(inputPath: string, toAppend: string) {
|
export function appendToFilename(inputPath: string, toAppend: string) {
|
||||||
const parts = inputPath.split('.');
|
const parts = inputPath.split(".");
|
||||||
if (parts.length > 1) {
|
if (parts.length > 1) {
|
||||||
parts[parts.length-2] = parts[parts.length-2] + toAppend;
|
parts[parts.length-2] = parts[parts.length-2] + toAppend;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
import { readBinaryFile, writeBinaryFile, removeDir, BaseDirectory } from '@tauri-apps/api/fs';
|
import { readBinaryFile, writeBinaryFile, removeDir, BaseDirectory } from "@tauri-apps/api/fs";
|
||||||
import { PdfFile,RepresentationType } from '@stirling-pdf/shared-operations/src/wrappers/PdfFile'
|
import { PdfFile,RepresentationType } from "@stirling-pdf/shared-operations/src/wrappers/PdfFile";
|
||||||
import { runShell, isTauriAvailable } from './tauri-wrapper';
|
import { runShell, isTauriAvailable } from "./tauri-wrapper";
|
||||||
|
|
||||||
export async function fileToPdf(byteArray: Uint8Array, filename: string): Promise<PdfFile> {
|
export async function fileToPdf(byteArray: Uint8Array, filename: string): Promise<PdfFile> {
|
||||||
const randUuid = crypto.randomUUID();
|
const randUuid = crypto.randomUUID();
|
||||||
@ -18,9 +18,9 @@ export async function fileToPdf(byteArray: Uint8Array, filename: string): Promis
|
|||||||
}
|
}
|
||||||
console.debug(`${stream}, ${randUuid}: ${message}`);
|
console.debug(`${stream}, ${randUuid}: ${message}`);
|
||||||
});
|
});
|
||||||
const lastMessage = messageList[messageList.length-1]
|
const lastMessage = messageList[messageList.length-1];
|
||||||
const outputFilePath = lastMessage.split(" -> ")[1].split(".pdf")[0]+".pdf";
|
const outputFilePath = lastMessage.split(" -> ")[1].split(".pdf")[0]+".pdf";
|
||||||
const outputFilePathSplit = outputFilePath.toString().split("[\\/]")
|
const outputFilePathSplit = outputFilePath.toString().split("[\\/]");
|
||||||
const outputFileName = outputFilePathSplit[outputFilePathSplit.length-1];
|
const outputFileName = outputFilePathSplit[outputFilePathSplit.length-1];
|
||||||
const outputBytes = await readBinaryFile(outputFilePath);
|
const outputBytes = await readBinaryFile(outputFilePath);
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ export async function isLibreOfficeInstalled() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
console.log("messageList", messageList)
|
console.log("messageList", messageList);
|
||||||
const result = messageList[0].match("LibreOffice ([0-9]+\.){4}.*");
|
const result = messageList[0].match("LibreOffice ([0-9]+\.){4}.*");
|
||||||
return result ? true : false;
|
return result ? true : false;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
import SharedOperations, { OperationsType } from '@stirling-pdf/shared-operations/src'
|
import SharedOperations, { OperationsType } from "@stirling-pdf/shared-operations/src";
|
||||||
import { ImposeParamsType } from '@stirling-pdf/shared-operations/src/functions/impose'
|
import { ImposeParamsType } from "@stirling-pdf/shared-operations/src/functions/impose";
|
||||||
import { PdfFile } from "@stirling-pdf/shared-operations/src/wrappers/PdfFile"
|
import { PdfFile } from "@stirling-pdf/shared-operations/src/wrappers/PdfFile";
|
||||||
|
|
||||||
// Import injected libraries here!
|
// Import injected libraries here!
|
||||||
import * as pdfcpuWrapper from "@stirling-pdf/shared-operations/wasm/pdfcpu/pdfcpu-wrapper-browser.js";
|
import * as pdfcpuWrapper from "@stirling-pdf/shared-operations/wasm/pdfcpu/pdfcpu-wrapper-browser.js";
|
||||||
@ -13,5 +13,5 @@ async function impose(params: ImposeParamsType): Promise<PdfFile> {
|
|||||||
const toExport: OperationsType = {
|
const toExport: OperationsType = {
|
||||||
...SharedOperations,
|
...SharedOperations,
|
||||||
impose,
|
impose,
|
||||||
}
|
};
|
||||||
export default toExport;
|
export default toExport;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
import { open, save } from '@tauri-apps/api/dialog';
|
import { open, save } from "@tauri-apps/api/dialog";
|
||||||
import { readBinaryFile, writeBinaryFile } from '@tauri-apps/api/fs';
|
import { readBinaryFile, writeBinaryFile } from "@tauri-apps/api/fs";
|
||||||
import { Command } from '@tauri-apps/api/shell'
|
import { Command } from "@tauri-apps/api/shell";
|
||||||
|
|
||||||
export type TauriBrowserFile = {
|
export interface TauriBrowserFile {
|
||||||
name: string,
|
name: string,
|
||||||
relativePath?: string,
|
relativePath?: string,
|
||||||
data: Uint8Array,
|
data: Uint8Array,
|
||||||
@ -29,13 +29,13 @@ export function isTauriAvailable() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// [*] = Not available in browser
|
// [*] = Not available in browser
|
||||||
type SelectFilesDialogOptions = {
|
interface SelectFilesDialogOptions {
|
||||||
defaultPath?: string, // [*] the default path to open the dialog on
|
defaultPath?: string, // [*] the default path to open the dialog on
|
||||||
directory?: boolean, // should the dialog be a directory dialog
|
directory?: boolean, // should the dialog be a directory dialog
|
||||||
filters?: Array<{ // list of file type filters
|
filters?: { // list of file type filters
|
||||||
name: string, // category name eg. 'Images'
|
name: string, // category name eg. 'Images'
|
||||||
extensions: string[] // list of extensions eg ['png', 'jpeg', 'jpg']
|
extensions: string[] // list of extensions eg ['png', 'jpeg', 'jpg']
|
||||||
}>,
|
}[],
|
||||||
multiple?: boolean, // allow multiple selections
|
multiple?: boolean, // allow multiple selections
|
||||||
recursive?: boolean, // [*] If directory is true, indicates that it will be read recursively later. Defines whether subdirectories will be allowed on the scope or not.
|
recursive?: boolean, // [*] If directory is true, indicates that it will be read recursively later. Defines whether subdirectories will be allowed on the scope or not.
|
||||||
title?: string // [*] the title of the dialog
|
title?: string // [*] the title of the dialog
|
||||||
@ -43,7 +43,7 @@ type SelectFilesDialogOptions = {
|
|||||||
export function openFiles(options: SelectFilesDialogOptions): Promise<TauriBrowserFile[] | null> {
|
export function openFiles(options: SelectFilesDialogOptions): Promise<TauriBrowserFile[] | null> {
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
if (isTauriAvailable()) {
|
if (isTauriAvailable()) {
|
||||||
var selected = await open(options);
|
let selected = await open(options);
|
||||||
if (!selected) {
|
if (!selected) {
|
||||||
resolve(null);
|
resolve(null);
|
||||||
return;
|
return;
|
||||||
@ -65,15 +65,15 @@ export function openFiles(options: SelectFilesDialogOptions): Promise<TauriBrows
|
|||||||
resolve(files);
|
resolve(files);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
var input = document.createElement('input');
|
const input = document.createElement("input");
|
||||||
input.type = 'file';
|
input.type = "file";
|
||||||
if (options.directory) input.setAttribute("webkitdirectory", "");
|
if (options.directory) input.setAttribute("webkitdirectory", "");
|
||||||
if (options.filters) input.setAttribute("accept", options.filters.flatMap(f => f.extensions).map(ext => "."+ext).join(", "));
|
if (options.filters) input.setAttribute("accept", options.filters.flatMap(f => f.extensions).map(ext => "."+ext).join(", "));
|
||||||
if (options.multiple) input.setAttribute("multiple", "");
|
if (options.multiple) input.setAttribute("multiple", "");
|
||||||
|
|
||||||
input.onchange = async () => {
|
input.onchange = async () => {
|
||||||
if (input.files && input.files.length) {
|
if (input.files && input.files.length) {
|
||||||
console.log("input.files", input.files)
|
console.log("input.files", input.files);
|
||||||
const files: TauriBrowserFile[] = [];
|
const files: TauriBrowserFile[] = [];
|
||||||
for (const f of input.files) {
|
for (const f of input.files) {
|
||||||
const contents = new Uint8Array(await f.arrayBuffer());
|
const contents = new Uint8Array(await f.arrayBuffer());
|
||||||
@ -91,8 +91,8 @@ export function openFiles(options: SelectFilesDialogOptions): Promise<TauriBrows
|
|||||||
|
|
||||||
// detect the user clicking cancel
|
// detect the user clicking cancel
|
||||||
document.body.onfocus = () => {
|
document.body.onfocus = () => {
|
||||||
setTimeout(()=>resolve(null), 200); // the timeout is needed because 'document.body.onfocus' is called before 'input.onchange'
|
setTimeout(()=>{ resolve(null) }, 200); // the timeout is needed because 'document.body.onfocus' is called before 'input.onchange'
|
||||||
}
|
};
|
||||||
|
|
||||||
input.click();
|
input.click();
|
||||||
}
|
}
|
||||||
@ -100,40 +100,40 @@ export function openFiles(options: SelectFilesDialogOptions): Promise<TauriBrows
|
|||||||
}
|
}
|
||||||
|
|
||||||
// [*] = Not available in browser
|
// [*] = Not available in browser
|
||||||
type DownloadFilesDialogOptions = {
|
interface DownloadFilesDialogOptions {
|
||||||
defaultPath?: string, // the default path to open the dialog on
|
defaultPath?: string, // the default path to open the dialog on
|
||||||
filters?: Array<{ // [*] list of file type filters
|
filters?: { // [*] list of file type filters
|
||||||
name: string, // category name eg. 'Images'
|
name: string, // category name eg. 'Images'
|
||||||
extensions: string[] // list of extensions eg ['png', 'jpeg', 'jpg']
|
extensions: string[] // list of extensions eg ['png', 'jpeg', 'jpg']
|
||||||
}>,
|
}[],
|
||||||
title?: string // [*] the title of the dialog
|
title?: string // [*] the title of the dialog
|
||||||
}
|
}
|
||||||
export async function downloadFile(fileData: Uint8Array, options: DownloadFilesDialogOptions): Promise<undefined> {
|
export async function downloadFile(fileData: Uint8Array, options: DownloadFilesDialogOptions): Promise<undefined> {
|
||||||
if (isTauriAvailable()) {
|
if (isTauriAvailable()) {
|
||||||
const pathToSave = await save(options);
|
const pathToSave = await save(options);
|
||||||
console.log("pathToSave", pathToSave)
|
console.log("pathToSave", pathToSave);
|
||||||
if (pathToSave) {
|
if (pathToSave) {
|
||||||
await writeBinaryFile(pathToSave, fileData);
|
await writeBinaryFile(pathToSave, fileData);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const pdfBlob = new Blob([fileData], { type: 'application/pdf' });
|
const pdfBlob = new Blob([fileData], { type: "application/pdf" });
|
||||||
const url = URL.createObjectURL(pdfBlob);
|
const url = URL.createObjectURL(pdfBlob);
|
||||||
const downloadOption = localStorage.getItem('downloadOption');
|
const downloadOption = localStorage.getItem("downloadOption");
|
||||||
|
|
||||||
// ensure filename is not a path
|
// ensure filename is not a path
|
||||||
const separator = options.defaultPath?.includes("\\") ? "\\" : "/";
|
const separator = options.defaultPath?.includes("\\") ? "\\" : "/";
|
||||||
const filename = options.defaultPath?.split(separator).pop();
|
const filename = options.defaultPath?.split(separator).pop();
|
||||||
const filenameToUse = filename ? filename : 'edited.pdf';
|
const filenameToUse = filename ? filename : "edited.pdf";
|
||||||
|
|
||||||
if (downloadOption === 'sameWindow') {
|
if (downloadOption === "sameWindow") {
|
||||||
// Open the file in the same window
|
// Open the file in the same window
|
||||||
window.location.href = url;
|
window.location.href = url;
|
||||||
} else if (downloadOption === 'newWindow') {
|
} else if (downloadOption === "newWindow") {
|
||||||
// Open the file in a new window
|
// Open the file in a new window
|
||||||
window.open(url, '_blank');
|
window.open(url, "_blank");
|
||||||
} else {
|
} else {
|
||||||
// Download the file
|
// Download the file
|
||||||
const downloadLink = document.createElement('a');
|
const downloadLink = document.createElement("a");
|
||||||
downloadLink.href = url;
|
downloadLink.href = url;
|
||||||
downloadLink.download = filenameToUse;
|
downloadLink.download = filenameToUse;
|
||||||
downloadLink.click();
|
downloadLink.click();
|
||||||
@ -152,18 +152,18 @@ export function runShell(commandName: string, args: string[], callback: (message
|
|||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
|
|
||||||
const comm = new Command(commandName, args);
|
const comm = new Command(commandName, args);
|
||||||
comm.on('close', data => {
|
comm.on("close", data => {
|
||||||
if (data.code === 0) {
|
if (data.code === 0) {
|
||||||
resolve();
|
resolve();
|
||||||
} else {
|
} else {
|
||||||
reject(new Error(`Command failed with exit code ${data.code} and signal ${data.signal}`));
|
reject(new Error(`Command failed with exit code ${data.code} and signal ${data.signal}`));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
comm.on('error', error => callback(error, "error"));
|
comm.on("error", error => { callback(error, "error") });
|
||||||
comm.stdout.on('data', line => callback(line, "stdout"));
|
comm.stdout.on("data", line => { callback(line, "stdout") });
|
||||||
comm.stderr.on('data', line => callback(line, "stderr"));
|
comm.stderr.on("data", line => { callback(line, "stderr") });
|
||||||
|
|
||||||
const child = await comm.spawn();
|
const child = await comm.spawn();
|
||||||
console.debug(`Started child process with pid: ${child.pid}`)
|
console.debug(`Started child process with pid: ${child.pid}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -4,26 +4,26 @@ import topLevelAwait from "vite-plugin-top-level-await";
|
|||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig(async () => ({
|
export default defineConfig(async () => ({
|
||||||
plugins: [
|
plugins: [
|
||||||
react(),
|
react(),
|
||||||
topLevelAwait({
|
topLevelAwait({
|
||||||
// The export name of top-level await promise for each chunk module
|
// The export name of top-level await promise for each chunk module
|
||||||
promiseExportName: "__tla",
|
promiseExportName: "__tla",
|
||||||
// The function to generate import names of top-level await promise in each chunk module
|
// The function to generate import names of top-level await promise in each chunk module
|
||||||
promiseImportName: i => `__tla_${i}`
|
promiseImportName: i => `__tla_${i}`
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|
||||||
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
||||||
//
|
//
|
||||||
// 1. prevent vite from obscuring rust errors
|
// 1. prevent vite from obscuring rust errors
|
||||||
clearScreen: false,
|
clearScreen: false,
|
||||||
// 2. tauri expects a fixed port, fail if that port is not available
|
// 2. tauri expects a fixed port, fail if that port is not available
|
||||||
server: {
|
server: {
|
||||||
port: 1420,
|
port: 1420,
|
||||||
strictPort: true,
|
strictPort: true,
|
||||||
},
|
},
|
||||||
// 3. to make use of `TAURI_DEBUG` and other env variables
|
// 3. to make use of `TAURI_DEBUG` and other env variables
|
||||||
// https://tauri.app/v1/api/config#buildconfig.beforedevcommand
|
// https://tauri.app/v1/api/config#buildconfig.beforedevcommand
|
||||||
envPrefix: ["VITE_"],
|
envPrefix: ["VITE_"],
|
||||||
}));
|
}));
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
import "@stirling-pdf/shared-operations/src/locales/i18next.config";
|
import "@stirling-pdf/shared-operations/src/locales/i18next.config";
|
||||||
|
|
||||||
import express from 'express';
|
import express from "express";
|
||||||
const app = express();
|
const app = express();
|
||||||
const PORT = 8000;
|
const PORT = 8000;
|
||||||
|
|
||||||
// server-node: backend api
|
// server-node: backend api
|
||||||
import api from './routes/api/api-controller';
|
import api from "./routes/api/api-controller";
|
||||||
app.use("/api", api);
|
app.use("/api", api);
|
||||||
|
|
||||||
// serve
|
// serve
|
||||||
app.listen(PORT, () => {
|
app.listen(PORT, () => {
|
||||||
console.log(`http://localhost:${PORT}`);
|
console.log(`http://localhost:${PORT}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
process.on('unhandledRejection', (reason, promise) => {
|
||||||
|
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
||||||
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import express, { Request, Response } from 'express';
|
import express, { Request, Response } from "express";
|
||||||
|
|
||||||
import workflow from './workflow-controller';
|
import workflow from "./workflow-controller";
|
||||||
import dynamicOperations from './dynamic-operations-controller';
|
import dynamicOperations from "./dynamic-operations-controller";
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
import express, { Request, Response } from 'express';
|
import express, { Request, Response } from "express";
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
import multer from 'multer';
|
import multer from "multer";
|
||||||
const upload = multer();
|
const upload = multer();
|
||||||
import { getOperatorByName } from '@stirling-pdf/shared-operations/src/workflow/getOperatorByName';
|
import { getOperatorByName } from "@stirling-pdf/shared-operations/src/workflow/getOperatorByName";
|
||||||
import { Operator } from '@stirling-pdf/shared-operations/src/functions';
|
import { Operator } from "@stirling-pdf/shared-operations/src/functions";
|
||||||
|
|
||||||
import { PdfFile } from '@stirling-pdf/shared-operations/src/wrappers/PdfFile';
|
import { PdfFile } from "@stirling-pdf/shared-operations/src/wrappers/PdfFile";
|
||||||
import { respondWithPdfFiles } from '../../utils/endpoint-utils';
|
import { respondWithPdfFiles } from "../../utils/endpoint-utils";
|
||||||
import { Action } from '@stirling-pdf/shared-operations/declarations/Action';
|
import { Action } from "@stirling-pdf/shared-operations/declarations/Action";
|
||||||
import { JoiPDFFileSchema } from '@stirling-pdf/shared-operations/src/wrappers/PdfFileJoi';
|
import { JoiPDFFileSchema } from "@stirling-pdf/shared-operations/src/wrappers/PdfFileJoi";
|
||||||
|
|
||||||
router.post('/:func', upload.array("file"), async function(req: Request, res: Response) {
|
router.post("/:func", upload.array("file"), async function(req: Request, res: Response) {
|
||||||
handleEndpoint(req, res);
|
handleEndpoint(req, res);
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/:dir/:func', upload.array("file"), async function(req: Request, res: Response) {
|
router.post("/:dir/:func", upload.array("file"), async function(req: Request, res: Response) {
|
||||||
handleEndpoint(req, res);
|
handleEndpoint(req, res);
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleEndpoint(req: Request, res: Response) {
|
function handleEndpoint(req: Request, res: Response) {
|
||||||
if(!req.files || req.files.length == 0) {
|
if(!req.files || req.files.length == 0) {
|
||||||
res.status(400).json({error: "no input file(s) were provided"})
|
res.status(400).json({error: "no input file(s) were provided"});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,11 +46,11 @@ function handleEndpoint(req: Request, res: Response) {
|
|||||||
|
|
||||||
operation.run(validationResults.value.input, (progress) => {}).then(pdfFiles => {
|
operation.run(validationResults.value.input, (progress) => {}).then(pdfFiles => {
|
||||||
respondWithPdfFiles(res, pdfFiles, req.params.func + "_result");
|
respondWithPdfFiles(res, pdfFiles, req.params.func + "_result");
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res.status(400).json({error: `the operator of type ${req.params.func} does not exist`})
|
res.status(400).json({error: `the operator of type ${req.params.func} does not exist`});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import express, { Request, Response } from 'express';
|
import express, { Request, Response } from "express";
|
||||||
import crypto from 'crypto';
|
import crypto from "crypto";
|
||||||
import multer from 'multer'
|
import multer from "multer";
|
||||||
const upload = multer();
|
const upload = multer();
|
||||||
|
|
||||||
import { traverseOperations } from "@stirling-pdf/shared-operations/src/workflow/traverseOperations";
|
import { traverseOperations } from "@stirling-pdf/shared-operations/src/workflow/traverseOperations";
|
||||||
import { PdfFile, RepresentationType } from '@stirling-pdf/shared-operations/src/wrappers/PdfFile';
|
import { PdfFile, RepresentationType } from "@stirling-pdf/shared-operations/src/wrappers/PdfFile";
|
||||||
import { respondWithPdfFiles } from '../../utils/endpoint-utils';
|
import { respondWithPdfFiles } from "../../utils/endpoint-utils";
|
||||||
import { JoiPDFFileSchema } from '@stirling-pdf/shared-operations/src/wrappers/PdfFileJoi';
|
import { JoiPDFFileSchema } from "@stirling-pdf/shared-operations/src/wrappers/PdfFileJoi";
|
||||||
|
|
||||||
interface Workflow {
|
interface Workflow {
|
||||||
eventStream?: express.Response<any, Record<string, any>>,
|
eventStream?: express.Response,
|
||||||
result?: PdfFile[],
|
result?: PdfFile[],
|
||||||
finished: boolean,
|
finished: boolean,
|
||||||
createdAt: EpochTimeStamp,
|
createdAt: EpochTimeStamp,
|
||||||
@ -73,19 +73,19 @@ router.post("/:workflowUuid?", [
|
|||||||
} else {
|
} else {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
console.log("Start Aync Workflow");
|
console.log("Start Aync Workflow");
|
||||||
// TODO: UUID collision checks
|
// TODO: UUID collision checks
|
||||||
let workflowID = req.params.workflowUuid
|
let workflowID = req.params.workflowUuid;
|
||||||
if(!workflowID)
|
if(!workflowID)
|
||||||
workflowID = generateWorkflowID();
|
workflowID = generateWorkflowID();
|
||||||
|
|
||||||
activeWorkflows[workflowID] = {
|
activeWorkflows[workflowID] = {
|
||||||
createdAt: Date.now(),
|
createdAt: Date.now(),
|
||||||
finished: false
|
finished: false
|
||||||
}
|
};
|
||||||
const activeWorkflow = activeWorkflows[workflowID];
|
const activeWorkflow = activeWorkflows[workflowID];
|
||||||
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
@ -104,7 +104,7 @@ router.post("/:workflowUuid?", [
|
|||||||
activeWorkflow.eventStream.write(`data: ${state}\n\n`);
|
activeWorkflow.eventStream.write(`data: ${state}\n\n`);
|
||||||
}).then(async (pdfResults) => {
|
}).then(async (pdfResults) => {
|
||||||
if(activeWorkflow.eventStream) {
|
if(activeWorkflow.eventStream) {
|
||||||
activeWorkflow.eventStream.write(`data: processing done\n\n`);
|
activeWorkflow.eventStream.write("data: processing done\n\n");
|
||||||
activeWorkflow.eventStream.end();
|
activeWorkflow.eventStream.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,16 +170,16 @@ router.get("/progress-stream/:workflowUuid", (req: Request, res: Response) => {
|
|||||||
// TODO: Check if already done
|
// TODO: Check if already done
|
||||||
|
|
||||||
// Send realtime updates
|
// Send realtime updates
|
||||||
res.setHeader('Cache-Control', 'no-cache');
|
res.setHeader("Cache-Control", "no-cache");
|
||||||
res.setHeader('Content-Type', 'text/event-stream');
|
res.setHeader("Content-Type", "text/event-stream");
|
||||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||||
res.setHeader('Connection', 'keep-alive');
|
res.setHeader("Connection", "keep-alive");
|
||||||
res.flushHeaders(); // flush the headers to establish SSE with client
|
res.flushHeaders(); // flush the headers to establish SSE with client
|
||||||
|
|
||||||
const workflow = activeWorkflows[req.params.workflowUuid];
|
const workflow = activeWorkflows[req.params.workflowUuid];
|
||||||
workflow.eventStream = res;
|
workflow.eventStream = res;
|
||||||
|
|
||||||
res.on('close', () => {
|
res.on("close", () => {
|
||||||
res.end();
|
res.end();
|
||||||
// TODO: Abort if not already done?
|
// TODO: Abort if not already done?
|
||||||
});
|
});
|
||||||
@ -203,7 +203,7 @@ router.get("/result/:workflowUuid", async (req: Request, res: Response) => {
|
|||||||
const workflow = activeWorkflows[req.params.workflowUuid];
|
const workflow = activeWorkflows[req.params.workflowUuid];
|
||||||
if(!workflow.finished) {
|
if(!workflow.finished) {
|
||||||
res.status(202).json({ message: "Workflow hasn't finished yet. Check progress or connect to progress-steam to get notified when its done." });
|
res.status(202).json({ message: "Workflow hasn't finished yet. Check progress or connect to progress-steam to get notified when its done." });
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await respondWithPdfFiles(res, workflow.result, "workflow-results");
|
await respondWithPdfFiles(res, workflow.result, "workflow-results");
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
|
|
||||||
import { Response } from 'express';
|
import { Response } from "express";
|
||||||
import { PdfFile } from '@stirling-pdf/shared-operations/src/wrappers/PdfFile'
|
import { PdfFile } from "@stirling-pdf/shared-operations/src/wrappers/PdfFile";
|
||||||
import Archiver from 'archiver';
|
import Archiver from "archiver";
|
||||||
|
|
||||||
export async function respondWithFile(res: Response, uint8Array: Uint8Array, filename: string, mimeType: string): Promise<void> {
|
export async function respondWithFile(res: Response, uint8Array: Uint8Array, filename: string, mimeType: string): Promise<void> {
|
||||||
res.writeHead(200, {
|
res.writeHead(200, {
|
||||||
'Content-Type': mimeType,
|
"Content-Type": mimeType,
|
||||||
'Content-disposition': `attachment; filename="${filename}"`,
|
"Content-disposition": `attachment; filename="${filename}"`,
|
||||||
'Content-Length': uint8Array.length
|
"Content-Length": uint8Array.length
|
||||||
});
|
});
|
||||||
res.end(uint8Array);
|
res.end(uint8Array);
|
||||||
}
|
}
|
||||||
@ -23,14 +23,14 @@ export async function respondWithZip(res: Response, filename: string, files: {ui
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(filename)
|
console.log(filename);
|
||||||
res.writeHead(200, {
|
res.writeHead(200, {
|
||||||
'Content-Type': 'application/zip',
|
"Content-Type": "application/zip",
|
||||||
'Content-disposition': `attachment; filename="${filename}.zip"`,
|
"Content-disposition": `attachment; filename="${filename}.zip"`,
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Also allow changing the compression level
|
// TODO: Also allow changing the compression level
|
||||||
var zip = Archiver('zip');
|
const zip = Archiver("zip");
|
||||||
|
|
||||||
// Stream the file to the user.
|
// Stream the file to the user.
|
||||||
zip.pipe(res);
|
zip.pipe(res);
|
||||||
@ -50,10 +50,10 @@ export async function respondWithPdfFiles(res: Response, pdfFiles: PdfFile[] | u
|
|||||||
res.status(500).json({"warning": "The workflow had no outputs."});
|
res.status(500).json({"warning": "The workflow had no outputs."});
|
||||||
}
|
}
|
||||||
else if (pdfFiles.length == 1) {
|
else if (pdfFiles.length == 1) {
|
||||||
respondWithPdfFile(res, pdfFiles[0])
|
respondWithPdfFile(res, pdfFiles[0]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const promises = pdfFiles.map(async (pdf) => {return{uint8Array: await pdf.uint8Array, filename: pdf.filename + ".pdf"}})
|
const promises = pdfFiles.map(async (pdf) => {return{uint8Array: await pdf.uint8Array, filename: pdf.filename + ".pdf"}});
|
||||||
const files = await Promise.all(promises);
|
const files = await Promise.all(promises);
|
||||||
respondWithZip(res, filename, files);
|
respondWithZip(res, filename, files);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
import fs from 'fs';
|
import fs from "fs";
|
||||||
import os from 'os';
|
import os from "os";
|
||||||
import path from 'path';
|
import path from "path";
|
||||||
import { exec, spawn } from 'child_process'
|
import { exec, spawn } from "child_process";
|
||||||
import { PdfFile, RepresentationType } from '@stirling-pdf/shared-operations/src/wrappers/PdfFile'
|
import { PdfFile, RepresentationType } from "@stirling-pdf/shared-operations/src/wrappers/PdfFile";
|
||||||
|
|
||||||
export async function fileToPdf(byteArray: Uint8Array, filename: string): Promise<PdfFile> {
|
export async function fileToPdf(byteArray: Uint8Array, filename: string): Promise<PdfFile> {
|
||||||
const parentDir = path.join(os.tmpdir(), "StirlingPDF");
|
const parentDir = path.join(os.tmpdir(), "StirlingPDF");
|
||||||
@ -46,14 +46,14 @@ export function isLibreOfficeInstalled() {
|
|||||||
const result = stdout.match("LibreOffice ([0-9]+\.){4}.*");
|
const result = stdout.match("LibreOffice ([0-9]+\.){4}.*");
|
||||||
resolve(result ? true : false);
|
resolve(result ? true : false);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeBytesToFile(filePath: string, bytes: Uint8Array): Promise<void> {
|
function writeBytesToFile(filePath: string, bytes: Uint8Array): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
fs.writeFile(filePath, bytes, function(err) {
|
fs.writeFile(filePath, bytes, function(err) {
|
||||||
if(err) {
|
if(err) {
|
||||||
reject(err)
|
reject(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
resolve();
|
resolve();
|
||||||
@ -80,17 +80,17 @@ function runLibreOfficeCommand(idKey: string, args: string[]): Promise<string[]>
|
|||||||
|
|
||||||
const process = spawn("libreoffice", args);
|
const process = spawn("libreoffice", args);
|
||||||
|
|
||||||
process.stdout.on('data', (data) => {
|
process.stdout.on("data", (data) => {
|
||||||
const dataStr = data.toString();
|
const dataStr = data.toString();
|
||||||
console.log(`Progress ${idKey}:`, dataStr);
|
console.log(`Progress ${idKey}:`, dataStr);
|
||||||
messageList.push(dataStr);
|
messageList.push(dataStr);
|
||||||
});
|
});
|
||||||
|
|
||||||
process.stderr.on('data', (data) => {
|
process.stderr.on("data", (data) => {
|
||||||
console.error(`stderr ${idKey}:`, data.toString());
|
console.error(`stderr ${idKey}:`, data.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on('exit', (code) => {
|
process.on("exit", (code) => {
|
||||||
if (code === 0) {
|
if (code === 0) {
|
||||||
resolve(messageList);
|
resolve(messageList);
|
||||||
} else {
|
} else {
|
||||||
@ -98,7 +98,7 @@ function runLibreOfficeCommand(idKey: string, args: string[]): Promise<string[]>
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on('error', (err) => {
|
process.on("error", (err) => {
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
2
shared-operations/declarations/pdfcpu.d.ts
vendored
2
shared-operations/declarations/pdfcpu.d.ts
vendored
@ -1,3 +1,3 @@
|
|||||||
declare module '#pdfcpu' {
|
declare module "#pdfcpu" {
|
||||||
export function oneToOne(wasmArray: string[], snapshot: Uint8Array): Promise<Uint8Array>;
|
export function oneToOne(wasmArray: string[], snapshot: Uint8Array): Promise<Uint8Array>;
|
||||||
}
|
}
|
@ -1,10 +1,10 @@
|
|||||||
|
|
||||||
import { PdfFile } from '../wrappers/PdfFile.js';
|
import { PdfFile } from "../wrappers/PdfFile.js";
|
||||||
import { Sorts } from './common/pageIndexesSorting.js';
|
import { Sorts } from "./common/pageIndexesSorting.js";
|
||||||
import { getPages } from './common/getPagesByIndex.js';
|
import { getPages } from "./common/getPagesByIndex.js";
|
||||||
import { parsePageIndexSpecification } from './common/pageIndexesUtils.js';
|
import { parsePageIndexSpecification } from "./common/pageIndexesUtils.js";
|
||||||
|
|
||||||
export type ArrangePagesParamsType = {
|
export interface ArrangePagesParamsType {
|
||||||
file: PdfFile;
|
file: PdfFile;
|
||||||
arrangementConfig: string; // a member of Sorts, or a page index specification
|
arrangementConfig: string; // a member of Sorts, or a page index specification
|
||||||
}
|
}
|
||||||
@ -22,6 +22,6 @@ export async function arrangePages(params: ArrangePagesParamsType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const newFile = await getPages(file, sortIndexes);
|
const newFile = await getPages(file, sortIndexes);
|
||||||
newFile.filename += "arrangedPages"
|
newFile.filename += "arrangedPages";
|
||||||
return newFile;
|
return newFile;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
import { PdfFile } from '../../wrappers/PdfFile';
|
import { PdfFile } from "../../wrappers/PdfFile";
|
||||||
import { PDFPageProxy } from "pdfjs-dist/types/src/display/api.js";
|
import { PDFPageProxy } from "pdfjs-dist/types/src/display/api.js";
|
||||||
import { Image, ImageKind } from 'image-js';
|
import { Image, ImageKind } from "image-js";
|
||||||
|
|
||||||
import { getImagesOnPage, PDFJSImage } from "./getImagesOnPage.js";
|
import { getImagesOnPage, PDFJSImage } from "./getImagesOnPage.js";
|
||||||
|
|
||||||
@ -45,8 +45,8 @@ async function areImagesBlank(page: PDFPageProxy, threshold: number): Promise<bo
|
|||||||
|
|
||||||
// TODO: Fix this function
|
// TODO: Fix this function
|
||||||
async function isImageBlank(image: PDFJSImage, threshold: number): Promise<boolean> {
|
async function isImageBlank(image: PDFJSImage, threshold: number): Promise<boolean> {
|
||||||
var img = new Image(image.width, image.height, image.data, { kind: "RGB" as ImageKind }); // TODO: Maybe respect image.kind and convert accordingly, needs to be tested with a pdf with alpha-image
|
const img = new Image(image.width, image.height, image.data, { kind: "RGB" as ImageKind }); // TODO: Maybe respect image.kind and convert accordingly, needs to be tested with a pdf with alpha-image
|
||||||
var grey = img.grey();
|
const grey = img.grey();
|
||||||
var mean = grey.getMean();
|
const mean = grey.getMean();
|
||||||
return mean[0] <= threshold;
|
return mean[0] <= threshold;
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
import jsQR from "jsqr";
|
import jsQR from "jsqr";
|
||||||
|
|
||||||
import { PdfFile } from '../../wrappers/PdfFile.js';
|
import { PdfFile } from "../../wrappers/PdfFile.js";
|
||||||
import { getImagesOnPage, PDFJSImage } from "./getImagesOnPage.js";
|
import { getImagesOnPage, PDFJSImage } from "./getImagesOnPage.js";
|
||||||
|
|
||||||
export async function detectQRCodePages(file: PdfFile) {
|
export async function detectQRCodePages(file: PdfFile) {
|
||||||
@ -24,7 +24,7 @@ export async function detectQRCodePages(file: PdfFile) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(pagesWithQR.length == 0) {
|
if(pagesWithQR.length == 0) {
|
||||||
console.warn("Could not find any QR Codes in the provided PDF.")
|
console.warn("Could not find any QR Codes in the provided PDF.");
|
||||||
}
|
}
|
||||||
return pagesWithQR;
|
return pagesWithQR;
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
|
|
||||||
import { PDFPageProxy } from "pdfjs-dist/types/src/display/api.js";
|
import { PDFPageProxy } from "pdfjs-dist/types/src/display/api.js";
|
||||||
|
|
||||||
import * as PDFJS from 'pdfjs-dist';
|
import * as PDFJS from "pdfjs-dist";
|
||||||
|
|
||||||
export type PDFJSImage = {
|
export interface PDFJSImage {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
interpolate?: any;
|
interpolate?: any;
|
||||||
kind: number; // TODO: Document what this is, maybe hasAlpha?
|
kind: number; // TODO: Document what this is, maybe hasAlpha?
|
||||||
data: Uint8ClampedArray;
|
data: Uint8ClampedArray;
|
||||||
};
|
}
|
||||||
|
|
||||||
export async function getImagesOnPage(page: PDFPageProxy): Promise<PDFJSImage[]> {
|
export async function getImagesOnPage(page: PDFPageProxy): Promise<PDFJSImage[]> {
|
||||||
const ops = await page.getOperatorList();
|
const ops = await page.getOperatorList();
|
||||||
const images: PDFJSImage[] = [];
|
const images: PDFJSImage[] = [];
|
||||||
for (var j=0; j < ops.fnArray.length; j++) {
|
for (let j=0; j < ops.fnArray.length; j++) {
|
||||||
if (ops.fnArray[j] == PDFJS.OPS.paintImageXObject) {
|
if (ops.fnArray[j] == PDFJS.OPS.paintImageXObject) {
|
||||||
const image = page.objs.get(ops.argsArray[j][0]) as PDFJSImage;
|
const image = page.objs.get(ops.argsArray[j][0]) as PDFJSImage;
|
||||||
images.push(image);
|
images.push(image);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
import { PdfFile, RepresentationType } from '../../wrappers/PdfFile.js';
|
import { PdfFile, RepresentationType } from "../../wrappers/PdfFile.js";
|
||||||
import { PDFDocument } from 'pdf-lib';
|
import { PDFDocument } from "pdf-lib";
|
||||||
|
|
||||||
export async function getPages(file: PdfFile, pageIndexes: number[]): Promise<PdfFile> {
|
export async function getPages(file: PdfFile, pageIndexes: number[]): Promise<PdfFile> {
|
||||||
const pdfLibDocument = await file.pdfLibDocument;
|
const pdfLibDocument = await file.pdfLibDocument;
|
||||||
|
@ -55,11 +55,11 @@ function bookletSort(totalPages: number): number[] {
|
|||||||
function sideStitchBooklet(totalPages: number): number[] {
|
function sideStitchBooklet(totalPages: number): number[] {
|
||||||
const newPageOrder: number[] = [];
|
const newPageOrder: number[] = [];
|
||||||
for (let i = 0; i < (totalPages + 3) / 4; i++) {
|
for (let i = 0; i < (totalPages + 3) / 4; i++) {
|
||||||
const begin = i * 4;
|
const begin = i * 4;
|
||||||
newPageOrder.push(Math.min(begin + 3, totalPages - 1));
|
newPageOrder.push(Math.min(begin + 3, totalPages - 1));
|
||||||
newPageOrder.push(Math.min(begin, totalPages - 1));
|
newPageOrder.push(Math.min(begin, totalPages - 1));
|
||||||
newPageOrder.push(Math.min(begin + 1, totalPages - 1));
|
newPageOrder.push(Math.min(begin + 1, totalPages - 1));
|
||||||
newPageOrder.push(Math.min(begin + 2, totalPages - 1));
|
newPageOrder.push(Math.min(begin + 2, totalPages - 1));
|
||||||
}
|
}
|
||||||
return newPageOrder;
|
return newPageOrder;
|
||||||
}
|
}
|
||||||
@ -72,10 +72,10 @@ function sideStitchBooklet(totalPages: number): number[] {
|
|||||||
function oddEvenSplit(totalPages: number): number[] {
|
function oddEvenSplit(totalPages: number): number[] {
|
||||||
const newPageOrder: number[] = [];
|
const newPageOrder: number[] = [];
|
||||||
for (let i = 1; i <= totalPages; i += 2) {
|
for (let i = 1; i <= totalPages; i += 2) {
|
||||||
newPageOrder.push(i - 1);
|
newPageOrder.push(i - 1);
|
||||||
}
|
}
|
||||||
for (let i = 2; i <= totalPages; i += 2) {
|
for (let i = 2; i <= totalPages; i += 2) {
|
||||||
newPageOrder.push(i - 1);
|
newPageOrder.push(i - 1);
|
||||||
}
|
}
|
||||||
return newPageOrder;
|
return newPageOrder;
|
||||||
}
|
}
|
||||||
@ -108,9 +108,7 @@ function removeFirstAndLast(totalPages: number): number[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type SortFunction = (totalPages: number) => number[];
|
export type SortFunction = (totalPages: number) => number[];
|
||||||
type Sorts = {
|
type Sorts = Record<string, SortFunction>;
|
||||||
[key: string]: SortFunction;
|
|
||||||
};
|
|
||||||
export const Sorts: Sorts = Object.freeze({
|
export const Sorts: Sorts = Object.freeze({
|
||||||
"REVERSE_ORDER": reverseSort,
|
"REVERSE_ORDER": reverseSort,
|
||||||
"DUPLEX_SORT": duplexSort,
|
"DUPLEX_SORT": duplexSort,
|
||||||
|
@ -18,7 +18,7 @@ export function invertSelection(selection: number[], pages: number|number[]): nu
|
|||||||
*/
|
*/
|
||||||
export function parsePageIndexSpecification(specification: string, totalPages: number): number[] {
|
export function parsePageIndexSpecification(specification: string, totalPages: number): number[] {
|
||||||
// Translated to JS from the original Java function
|
// Translated to JS from the original Java function
|
||||||
const pageOrderArr = specification.split(",")
|
const pageOrderArr = specification.split(",");
|
||||||
const newPageOrder: number[] = [];
|
const newPageOrder: number[] = [];
|
||||||
|
|
||||||
// loop through the page order array
|
// loop through the page order array
|
||||||
@ -32,13 +32,13 @@ export function parsePageIndexSpecification(specification: string, totalPages: n
|
|||||||
}
|
}
|
||||||
else if (element.match("\\d*n\\+?-?\\d*|\\d*\\+?n")) {
|
else if (element.match("\\d*n\\+?-?\\d*|\\d*\\+?n")) {
|
||||||
// Handle page order as a function
|
// Handle page order as a function
|
||||||
var coefficient = 0;
|
let coefficient = 0;
|
||||||
var constant = 0;
|
let constant = 0;
|
||||||
var coefficientExists = false;
|
let coefficientExists = false;
|
||||||
var constantExists = false;
|
let constantExists = false;
|
||||||
|
|
||||||
if (element.includes("n")) {
|
if (element.includes("n")) {
|
||||||
var parts = element.split("n");
|
const parts = element.split("n");
|
||||||
if (!parts[0]) {
|
if (!parts[0]) {
|
||||||
coefficient = parseInt(parts[0]);
|
coefficient = parseInt(parts[0]);
|
||||||
coefficientExists = true;
|
coefficientExists = true;
|
||||||
@ -53,7 +53,7 @@ export function parsePageIndexSpecification(specification: string, totalPages: n
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 1; i <= totalPages; i++) {
|
for (var i = 1; i <= totalPages; i++) {
|
||||||
var pageNum = coefficientExists ? coefficient * i : i;
|
let pageNum = coefficientExists ? coefficient * i : i;
|
||||||
pageNum += constantExists ? constant : 0;
|
pageNum += constantExists ? constant : 0;
|
||||||
|
|
||||||
if (pageNum <= totalPages && pageNum > 0) {
|
if (pageNum <= totalPages && pageNum > 0) {
|
||||||
@ -64,13 +64,13 @@ export function parsePageIndexSpecification(specification: string, totalPages: n
|
|||||||
// split the range into start and end page
|
// split the range into start and end page
|
||||||
const range = element.split("-");
|
const range = element.split("-");
|
||||||
const start = parseInt(range[0]);
|
const start = parseInt(range[0]);
|
||||||
var end = parseInt(range[1]);
|
let end = parseInt(range[1]);
|
||||||
// check if the end page is greater than total pages
|
// check if the end page is greater than total pages
|
||||||
if (end > totalPages) {
|
if (end > totalPages) {
|
||||||
end = totalPages;
|
end = totalPages;
|
||||||
}
|
}
|
||||||
// loop through the range of pages
|
// loop through the range of pages
|
||||||
for (var j = start; j <= end; j++) {
|
for (let j = start; j <= end; j++) {
|
||||||
// print the current index
|
// print the current index
|
||||||
newPageOrder.push(j - 1);
|
newPageOrder.push(j - 1);
|
||||||
}
|
}
|
||||||
|
@ -1,46 +1,46 @@
|
|||||||
|
|
||||||
import { PdfFile } from '../../wrappers/PdfFile';
|
import { PdfFile } from "../../wrappers/PdfFile";
|
||||||
|
|
||||||
export async function sortPdfArray(
|
export async function sortPdfArray(
|
||||||
files: PdfFile[],
|
files: PdfFile[],
|
||||||
sortType: "orderProvided"|"byFileName"|"byDateModified"|"byDateCreated"|"byPDFTitle" = "orderProvided"
|
sortType: "orderProvided"|"byFileName"|"byDateModified"|"byDateCreated"|"byPDFTitle" = "orderProvided"
|
||||||
): Promise<PdfFile[]> {
|
): Promise<PdfFile[]> {
|
||||||
|
|
||||||
const docCache = await PdfFile.cacheAsPdfLibDocuments(files);
|
const docCache = await PdfFile.cacheAsPdfLibDocuments(files);
|
||||||
|
|
||||||
switch(sortType) {
|
switch(sortType) {
|
||||||
case "byFileName":
|
case "byFileName":
|
||||||
files.sort((a, b) => {
|
files.sort((a, b) => {
|
||||||
if (!a || !b) return 0;
|
if (!a || !b) return 0;
|
||||||
const ad = a.filename, bd = b.filename;
|
const ad = a.filename, bd = b.filename;
|
||||||
if (!ad || !bd) return 0;
|
if (!ad || !bd) return 0;
|
||||||
return ad.localeCompare(bd);
|
return ad.localeCompare(bd);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "byDateModified":
|
case "byDateModified":
|
||||||
files.sort((a, b) => {
|
files.sort((a, b) => {
|
||||||
const ad = docCache.get(a)?.getModificationDate()?.getTime();
|
const ad = docCache.get(a).getModificationDate().getTime();
|
||||||
const bd = docCache.get(b)?.getModificationDate()?.getTime();
|
const bd = docCache.get(b).getModificationDate().getTime();
|
||||||
if (!ad || !bd) return 0;
|
if (!ad || !bd) return 0;
|
||||||
return ad > bd ? 1 : -1
|
return ad > bd ? 1 : -1;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "byDateCreated":
|
case "byDateCreated":
|
||||||
files.sort((a, b) => {
|
files.sort((a, b) => {
|
||||||
const ad = docCache.get(a)?.getCreationDate()?.getTime();
|
const ad = docCache.get(a).getCreationDate().getTime();
|
||||||
const bd = docCache.get(b)?.getCreationDate()?.getTime();
|
const bd = docCache.get(b).getCreationDate().getTime();
|
||||||
if (!ad || !bd) return 0;
|
if (!ad || !bd) return 0;
|
||||||
return ad > bd ? 1 : -1
|
return ad > bd ? 1 : -1;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "byPDFTitle":
|
case "byPDFTitle":
|
||||||
files.sort((a, b) => {
|
files.sort((a, b) => {
|
||||||
const ad = docCache.get(a)?.getTitle();
|
const ad = docCache.get(a).getTitle();
|
||||||
const bd = docCache.get(b)?.getTitle();
|
const bd = docCache.get(b).getTitle();
|
||||||
if (!ad || !bd) return 0;
|
if (!ad || !bd) return 0;
|
||||||
return ad.localeCompare(bd);
|
return ad.localeCompare(bd);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return files;
|
return files;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
import { PdfFile } from '../../wrappers/PdfFile.js';
|
import { PdfFile } from "../../wrappers/PdfFile.js";
|
||||||
import { getPages } from "./getPagesByIndex";
|
import { getPages } from "./getPagesByIndex";
|
||||||
|
|
||||||
export async function splitPagesByIndex(file: PdfFile, splitAfterPageIndexes: number[]): Promise<PdfFile[]> {
|
export async function splitPagesByIndex(file: PdfFile, splitAfterPageIndexes: number[]): Promise<PdfFile[]> {
|
||||||
@ -22,4 +22,4 @@ export async function splitPagesByIndex(file: PdfFile, splitAfterPageIndexes: nu
|
|||||||
pagesArray = [];
|
pagesArray = [];
|
||||||
|
|
||||||
return subDocuments;
|
return subDocuments;
|
||||||
};
|
}
|
@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
import { PdfFile } from '../wrappers/PdfFile.js';
|
import { PdfFile } from "../wrappers/PdfFile.js";
|
||||||
import { getPages } from './common/getPagesByIndex.js';
|
import { getPages } from "./common/getPagesByIndex.js";
|
||||||
import { parsePageIndexSpecification } from './common/pageIndexesUtils'
|
import { parsePageIndexSpecification } from "./common/pageIndexesUtils";
|
||||||
|
|
||||||
export type ExtractPagesParamsType = {
|
export interface ExtractPagesParamsType {
|
||||||
file: PdfFile;
|
file: PdfFile;
|
||||||
pageIndexes: string | number[];
|
pageIndexes: string | number[];
|
||||||
}
|
}
|
||||||
@ -11,13 +11,13 @@ export async function extractPages(params: ExtractPagesParamsType): Promise<PdfF
|
|||||||
const { file, pageIndexes } = params;
|
const { file, pageIndexes } = params;
|
||||||
const pdfLibDocument = await file.pdfLibDocument;
|
const pdfLibDocument = await file.pdfLibDocument;
|
||||||
|
|
||||||
var indexes = pageIndexes;
|
let indexes = pageIndexes;
|
||||||
|
|
||||||
if (!Array.isArray(indexes)) {
|
if (!Array.isArray(indexes)) {
|
||||||
indexes = parsePageIndexSpecification(indexes, pdfLibDocument.getPageCount());
|
indexes = parsePageIndexSpecification(indexes, pdfLibDocument.getPageCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
const newFile = await getPages(file, indexes);
|
const newFile = await getPages(file, indexes);
|
||||||
newFile.filename += "_extractedPages"
|
newFile.filename += "_extractedPages";
|
||||||
return newFile;
|
return newFile;
|
||||||
}
|
}
|
||||||
|
@ -7,20 +7,20 @@ import * as pdfcpuWrapper from "#pdfcpu"; // This is updated by tsconfig.json/pa
|
|||||||
import Joi from "joi";
|
import Joi from "joi";
|
||||||
import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi";
|
import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi";
|
||||||
|
|
||||||
import i18next from 'i18next';
|
import i18next from "i18next";
|
||||||
i18next.loadNamespaces('impose', (err, t) => { if (err) throw err; });
|
i18next.loadNamespaces("impose", (err, t) => { if (err) throw err; });
|
||||||
|
|
||||||
export class Impose extends Operator {
|
export class Impose extends Operator {
|
||||||
static type: string = "impose";
|
static type = "impose";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validation & Localisation
|
* Validation & Localisation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected static inputSchema = JoiPDFFileSchema.label(i18next.t('inputs.pdffile.name')).description(i18next.t('inputs.pdffile.description'));
|
protected static inputSchema = JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description"));
|
||||||
protected static valueSchema = Joi.object({
|
protected static valueSchema = Joi.object({
|
||||||
nup: Joi.number().integer().valid(2, 3, 4, 8, 9, 12, 16).required()
|
nup: Joi.number().integer().valid(2, 3, 4, 8, 9, 12, 16).required()
|
||||||
.label(i18next.t('values.nup.friendlyName', { ns: 'impose' })).description(i18next.t('values.nup.description', { ns: 'impose' }))
|
.label(i18next.t("values.nup.friendlyName", { ns: "impose" })).description(i18next.t("values.nup.description", { ns: "impose" }))
|
||||||
.example("3").example("4"),
|
.example("3").example("4"),
|
||||||
format: Joi.string().valid(...[
|
format: Joi.string().valid(...[
|
||||||
// ISO 216:1975 A
|
// ISO 216:1975 A
|
||||||
@ -62,16 +62,16 @@ export class Impose extends Operator {
|
|||||||
"JIS-B7", "JIS-B8", "JIS-B9", "JIS-B10", "JIS-B11", "JIS-B12",
|
"JIS-B7", "JIS-B8", "JIS-B9", "JIS-B10", "JIS-B11", "JIS-B12",
|
||||||
"Shirokuban4", "Shirokuban5", "Shirokuban6", "Kiku4", "Kiku5", "AB", "B40", "Shikisen"
|
"Shirokuban4", "Shirokuban5", "Shirokuban6", "Kiku4", "Kiku5", "AB", "B40", "Shikisen"
|
||||||
].flatMap(size => [size, size + "P", size + "L"])).required()
|
].flatMap(size => [size, size + "P", size + "L"])).required()
|
||||||
.label(i18next.t('values.format.friendlyName', { ns: 'impose' })).description(i18next.t('values.format.description', { ns: 'impose' }))
|
.label(i18next.t("values.format.friendlyName", { ns: "impose" })).description(i18next.t("values.format.description", { ns: "impose" }))
|
||||||
.example("A4").example("A3L")
|
.example("A4").example("A3L")
|
||||||
});
|
});
|
||||||
protected static outputSchema = JoiPDFFileSchema.label(i18next.t('outputs.pdffile.name')).description(i18next.t('outputs.pdffile.description'));
|
protected static outputSchema = JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description"));
|
||||||
|
|
||||||
static schema = Joi.object({
|
static schema = Joi.object({
|
||||||
input: Impose.inputSchema,
|
input: Impose.inputSchema,
|
||||||
values: Impose.valueSchema.required(),
|
values: Impose.valueSchema.required(),
|
||||||
output: Impose.outputSchema
|
output: Impose.outputSchema
|
||||||
}).label(i18next.t('friendlyName', { ns: 'impose' })).description(i18next.t('description', { ns: 'impose' }));
|
}).label(i18next.t("friendlyName", { ns: "impose" })).description(i18next.t("description", { ns: "impose" }));
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,7 +89,7 @@ export class Impose extends Operator {
|
|||||||
"nup",
|
"nup",
|
||||||
"-c",
|
"-c",
|
||||||
"disable",
|
"disable",
|
||||||
'f:' + this.actionValues.format,
|
"f:" + this.actionValues.format,
|
||||||
"/output.pdf",
|
"/output.pdf",
|
||||||
String(this.actionValues.nup),
|
String(this.actionValues.nup),
|
||||||
"input.pdf",
|
"input.pdf",
|
||||||
@ -104,10 +104,10 @@ export class Impose extends Operator {
|
|||||||
input.filename + "_imposed"
|
input.filename + "_imposed"
|
||||||
);
|
);
|
||||||
|
|
||||||
progressCallback({ curFileProgress: 1, operationProgress: index/max })
|
progressCallback({ curFileProgress: 1, operationProgress: index/max });
|
||||||
|
|
||||||
console.log("ImposeResult: ", result);
|
console.log("ImposeResult: ", result);
|
||||||
return result;
|
return result;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ export async function nToOne <I, O>(inputs: I[], callback: (input: I[]) => Promi
|
|||||||
|
|
||||||
/** This function should be used if the Operation takes one file as input and may output multiple files */
|
/** This function should be used if the Operation takes one file as input and may output multiple files */
|
||||||
export async function oneToN <I, O>(inputs: I[], callback: (input: I, index: number, max: number) => Promise<O[]>): Promise<O[]> {
|
export async function oneToN <I, O>(inputs: I[], callback: (input: I, index: number, max: number) => Promise<O[]>): Promise<O[]> {
|
||||||
let output: O[] = []
|
let output: O[] = [];
|
||||||
for (let i = 0; i < inputs.length; i++) {
|
for (let i = 0; i < inputs.length; i++) {
|
||||||
output = output.concat(await callback(inputs[i], i, inputs.length));
|
output = output.concat(await callback(inputs[i], i, inputs.length));
|
||||||
}
|
}
|
||||||
@ -55,6 +55,6 @@ export async function oneToN <I, O>(inputs: I[], callback: (input: I, index: num
|
|||||||
/** This function should be used if the Operation takes one file as input and outputs only one file */
|
/** This function should be used if the Operation takes one file as input and outputs only one file */
|
||||||
export async function oneToOne <I, O>(inputs: I[], callback: (input: I, index: number, max: number) => Promise<O>): Promise<O[]> {
|
export async function oneToOne <I, O>(inputs: I[], callback: (input: I, index: number, max: number) => Promise<O>): Promise<O[]> {
|
||||||
return oneToN(inputs, async (input, index, max) => {
|
return oneToN(inputs, async (input, index, max) => {
|
||||||
return [await callback(input, index, max)]
|
return [await callback(input, index, max)];
|
||||||
});
|
});
|
||||||
}
|
}
|
@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
import { PDFDocument } from 'pdf-lib';
|
import { PDFDocument } from "pdf-lib";
|
||||||
import { PdfFile, RepresentationType } from '../wrappers/PdfFile';
|
import { PdfFile, RepresentationType } from "../wrappers/PdfFile";
|
||||||
|
|
||||||
export type MergeParamsType = {
|
export interface MergeParamsType {
|
||||||
files: PdfFile[];
|
files: PdfFile[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15,6 +15,6 @@ export async function mergePDFs(params: MergeParamsType): Promise<PdfFile> {
|
|||||||
copiedPages.forEach((page) => mergedPdf.addPage(page));
|
copiedPages.forEach((page) => mergedPdf.addPage(page));
|
||||||
}
|
}
|
||||||
|
|
||||||
const newName = "("+params.files.map(input => input.filename).join("_and_") + ")_merged"
|
const newName = "("+params.files.map(input => input.filename).join("_and_") + ")_merged";
|
||||||
return new PdfFile("mergedPDF", mergedPdf, RepresentationType.PDFLibDocument, newName);
|
return new PdfFile("mergedPDF", mergedPdf, RepresentationType.PDFLibDocument, newName);
|
||||||
};
|
}
|
@ -1,10 +1,10 @@
|
|||||||
|
|
||||||
import { PdfFile } from '../wrappers/PdfFile.js';
|
import { PdfFile } from "../wrappers/PdfFile.js";
|
||||||
import { detectEmptyPages } from './common/detectEmptyPages.js';
|
import { detectEmptyPages } from "./common/detectEmptyPages.js";
|
||||||
import { getPages } from './common/getPagesByIndex.js';
|
import { getPages } from "./common/getPagesByIndex.js";
|
||||||
import { invertSelection } from './common/pageIndexesUtils.js';
|
import { invertSelection } from "./common/pageIndexesUtils.js";
|
||||||
|
|
||||||
export type RemoveBlankPagesParamsType = {
|
export interface RemoveBlankPagesParamsType {
|
||||||
file: PdfFile;
|
file: PdfFile;
|
||||||
whiteThreashold: number;
|
whiteThreashold: number;
|
||||||
}
|
}
|
||||||
@ -15,9 +15,9 @@ export async function removeBlankPages(params: RemoveBlankPagesParamsType) {
|
|||||||
|
|
||||||
const emptyPages = await detectEmptyPages(file, whiteThreashold);
|
const emptyPages = await detectEmptyPages(file, whiteThreashold);
|
||||||
console.debug("Empty Pages: ", emptyPages);
|
console.debug("Empty Pages: ", emptyPages);
|
||||||
const pagesToKeep = invertSelection(emptyPages, pageCount)
|
const pagesToKeep = invertSelection(emptyPages, pageCount);
|
||||||
|
|
||||||
const newFile = await getPages(file, pagesToKeep);
|
const newFile = await getPages(file, pagesToKeep);
|
||||||
newFile.filename += "_removedBlanks"
|
newFile.filename += "_removedBlanks";
|
||||||
return newFile;
|
return newFile;
|
||||||
}
|
}
|
@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
import { PdfFile } from '../wrappers/PdfFile.js';
|
import { PdfFile } from "../wrappers/PdfFile.js";
|
||||||
import { getPages } from './common/getPagesByIndex.js';
|
import { getPages } from "./common/getPagesByIndex.js";
|
||||||
import { invertSelection, parsePageIndexSpecification } from './common/pageIndexesUtils.js';
|
import { invertSelection, parsePageIndexSpecification } from "./common/pageIndexesUtils.js";
|
||||||
|
|
||||||
export type RemovePagesParamsType = {
|
export interface RemovePagesParamsType {
|
||||||
file: PdfFile;
|
file: PdfFile;
|
||||||
pageSelector: string;
|
pageSelector: string;
|
||||||
}
|
}
|
||||||
@ -16,6 +16,6 @@ export async function removePages(params: RemovePagesParamsType) {
|
|||||||
const pagesToKeep = invertSelection(pageSelection, pageCount);
|
const pagesToKeep = invertSelection(pageSelection, pageCount);
|
||||||
|
|
||||||
const newFile = await getPages(file, pagesToKeep);
|
const newFile = await getPages(file, pagesToKeep);
|
||||||
newFile.filename += "_removedPages"
|
newFile.filename += "_removedPages";
|
||||||
return newFile;
|
return newFile;
|
||||||
}
|
}
|
@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
import { degrees } from 'pdf-lib';
|
import { degrees } from "pdf-lib";
|
||||||
import { PdfFile, RepresentationType } from '../wrappers/PdfFile';
|
import { PdfFile, RepresentationType } from "../wrappers/PdfFile";
|
||||||
|
|
||||||
export type RotateParamsType = {
|
export interface RotateParamsType {
|
||||||
file: PdfFile;
|
file: PdfFile;
|
||||||
rotation: number|number[];
|
rotation: number|number[];
|
||||||
}
|
}
|
||||||
@ -15,19 +15,19 @@ export async function rotatePages(params: RotateParamsType): Promise<PdfFile> {
|
|||||||
|
|
||||||
if (Array.isArray(rotation)) {
|
if (Array.isArray(rotation)) {
|
||||||
if (rotation.length != pages.length) {
|
if (rotation.length != pages.length) {
|
||||||
throw new Error(`Number of given rotations '${rotation.length}' is not the same as the number of pages '${pages.length}'`)
|
throw new Error(`Number of given rotations '${rotation.length}' is not the same as the number of pages '${pages.length}'`);
|
||||||
}
|
}
|
||||||
for (let i=0; i<rotation.length; i++) {
|
for (let i=0; i<rotation.length; i++) {
|
||||||
const oldRotation = pages[i].getRotation().angle
|
const oldRotation = pages[i].getRotation().angle;
|
||||||
pages[i].setRotation(degrees(oldRotation + rotation[i]))
|
pages[i].setRotation(degrees(oldRotation + rotation[i]));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pages.forEach(page => {
|
pages.forEach(page => {
|
||||||
// Change page size
|
// Change page size
|
||||||
const oldRotation = page.getRotation().angle
|
const oldRotation = page.getRotation().angle;
|
||||||
page.setRotation(degrees(oldRotation + rotation))
|
page.setRotation(degrees(oldRotation + rotation));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PdfFile(file.originalFilename, pdfDoc, RepresentationType.PDFLibDocument, file.filename+"_rotated");
|
return new PdfFile(file.originalFilename, pdfDoc, RepresentationType.PDFLibDocument, file.filename+"_rotated");
|
||||||
};
|
}
|
@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
import { PDFPage } from 'pdf-lib';
|
import { PDFPage } from "pdf-lib";
|
||||||
import { PdfFile, RepresentationType } from '../wrappers/PdfFile';
|
import { PdfFile, RepresentationType } from "../wrappers/PdfFile";
|
||||||
|
|
||||||
export type ScaleContentParamsType = {
|
export interface ScaleContentParamsType {
|
||||||
file: PdfFile;
|
file: PdfFile;
|
||||||
scaleFactor: number|number[];
|
scaleFactor: number|number[];
|
||||||
}
|
}
|
||||||
@ -15,17 +15,17 @@ export async function scaleContent(params: ScaleContentParamsType): Promise<PdfF
|
|||||||
|
|
||||||
if (Array.isArray(scaleFactor)) {
|
if (Array.isArray(scaleFactor)) {
|
||||||
if (scaleFactor.length != pages.length) {
|
if (scaleFactor.length != pages.length) {
|
||||||
throw new Error(`Number of given scale factors '${scaleFactor.length}' is not the same as the number of pages '${pages.length}'`)
|
throw new Error(`Number of given scale factors '${scaleFactor.length}' is not the same as the number of pages '${pages.length}'`);
|
||||||
}
|
}
|
||||||
for (let i=0; i<scaleFactor.length; i++) {
|
for (let i=0; i<scaleFactor.length; i++) {
|
||||||
scalePage(pages[i], scaleFactor[i]);
|
scalePage(pages[i], scaleFactor[i]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pages.forEach(page => scalePage(page, scaleFactor));
|
pages.forEach(page => { scalePage(page, scaleFactor) });
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PdfFile(file.originalFilename, pdfDoc, RepresentationType.PDFLibDocument, file.filename+"_scaledContent");
|
return new PdfFile(file.originalFilename, pdfDoc, RepresentationType.PDFLibDocument, file.filename+"_scaledContent");
|
||||||
};
|
}
|
||||||
|
|
||||||
function scalePage(page: PDFPage, scaleFactor: number) {
|
function scalePage(page: PDFPage, scaleFactor: number) {
|
||||||
const width = page.getWidth();
|
const width = page.getWidth();
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
|
|
||||||
import Joi from 'joi';
|
import Joi from "joi";
|
||||||
import { PDFPage } from 'pdf-lib';
|
import { PDFPage } from "pdf-lib";
|
||||||
import { PdfFile, RepresentationType, JoiPDFFileSchema } from '../wrappers/PdfFileJoi';
|
import { PdfFile, RepresentationType, JoiPDFFileSchema } from "../wrappers/PdfFileJoi";
|
||||||
|
|
||||||
const whSchema = Joi.string().custom((value, helpers) => {
|
const whSchema = Joi.string().custom((value, helpers) => {
|
||||||
console.log("value.pageSize", typeof value)
|
console.log("value.pageSize", typeof value);
|
||||||
try {
|
try {
|
||||||
const obj = JSON.parse(value);
|
const obj = JSON.parse(value);
|
||||||
if (!obj.width && !obj.height) {
|
if (!obj.width && !obj.height) {
|
||||||
return helpers.error('any.required', { message: 'At least one of width/height must be present' });
|
return helpers.error("any.required", { message: "At least one of width/height must be present" });
|
||||||
}
|
}
|
||||||
if (typeof obj.width != 'number' && typeof obj.width != 'undefined') {
|
if (typeof obj.width != "number" && typeof obj.width != "undefined") {
|
||||||
return helpers.error('any.invalid', { message: 'Width must be a number if present' });
|
return helpers.error("any.invalid", { message: "Width must be a number if present" });
|
||||||
}
|
}
|
||||||
if (typeof obj.height != 'number' && typeof obj.height != 'undefined') {
|
if (typeof obj.height != "number" && typeof obj.height != "undefined") {
|
||||||
return helpers.error('any.invalid', { message: 'Height must be a number if present' });
|
return helpers.error("any.invalid", { message: "Height must be a number if present" });
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return helpers.error('any.invalid', { message: 'Value must be a valid JSON' });
|
return helpers.error("any.invalid", { message: "Value must be a valid JSON" });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ export const ScalePageSchema = Joi.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
export type ScalePageParamsType = {
|
export interface ScalePageParamsType {
|
||||||
file: PdfFile;
|
file: PdfFile;
|
||||||
pageSize: { width?:number,height?:number }|{ width?:number,height?:number }[];
|
pageSize: { width?:number,height?:number }|{ width?:number,height?:number }[];
|
||||||
}
|
}
|
||||||
@ -41,17 +41,17 @@ export async function scalePage(params: ScalePageParamsType): Promise<PdfFile> {
|
|||||||
|
|
||||||
if (Array.isArray(pageSize)) {
|
if (Array.isArray(pageSize)) {
|
||||||
if (pageSize.length != pages.length) {
|
if (pageSize.length != pages.length) {
|
||||||
throw new Error(`Number of given sizes '${pageSize.length}' is not the same as the number of pages '${pages.length}'`)
|
throw new Error(`Number of given sizes '${pageSize.length}' is not the same as the number of pages '${pages.length}'`);
|
||||||
}
|
}
|
||||||
for (let i=0; i<pageSize.length; i++) {
|
for (let i=0; i<pageSize.length; i++) {
|
||||||
resize(pages[i], pageSize[i]);
|
resize(pages[i], pageSize[i]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pages.forEach(page => resize(page, pageSize));
|
pages.forEach(page => { resize(page, pageSize) });
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PdfFile(file.originalFilename, pdfDoc, RepresentationType.PDFLibDocument, file.filename+"_scaledPages");
|
return new PdfFile(file.originalFilename, pdfDoc, RepresentationType.PDFLibDocument, file.filename+"_scaledPages");
|
||||||
};
|
}
|
||||||
|
|
||||||
function resize(page: PDFPage, newSize: {width?:number,height?:number}) {
|
function resize(page: PDFPage, newSize: {width?:number,height?:number}) {
|
||||||
const calculatedSize = calculateSize(page, newSize);
|
const calculatedSize = calculateSize(page, newSize);
|
||||||
@ -74,7 +74,7 @@ function calculateSize(page: PDFPage, newSize: {width?:number,height?:number}):
|
|||||||
const ratio = oldSize.height / oldSize.width;
|
const ratio = oldSize.height / oldSize.width;
|
||||||
return { width: newSize.width, height: newSize.width * ratio };
|
return { width: newSize.width, height: newSize.width * ratio };
|
||||||
}
|
}
|
||||||
return { width: newSize.width!, height: newSize.height! };
|
return { width: newSize.width, height: newSize.height };
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PageSize = Object.freeze({
|
export const PageSize = Object.freeze({
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
|
|
||||||
import { PdfFile } from '../wrappers/PdfFile.js';
|
import { PdfFile } from "../wrappers/PdfFile.js";
|
||||||
import { splitPagesByIndex } from "./common/splitPagesByIndex.js";
|
import { splitPagesByIndex } from "./common/splitPagesByIndex.js";
|
||||||
import { detectEmptyPages } from "./common/detectEmptyPages.js";
|
import { detectEmptyPages } from "./common/detectEmptyPages.js";
|
||||||
import { detectQRCodePages } from "./common/detectQRCodePages.js";
|
import { detectQRCodePages } from "./common/detectQRCodePages.js";
|
||||||
|
|
||||||
export type SplitPageByPresetParamsType = {
|
export interface SplitPageByPresetParamsType {
|
||||||
file: PdfFile;
|
file: PdfFile;
|
||||||
type: "BAR_CODE"|"QR_CODE"|"BLANK_PAGE";
|
type: "BAR_CODE"|"QR_CODE"|"BLANK_PAGE";
|
||||||
whiteThreashold?: number;
|
whiteThreashold?: number;
|
||||||
@ -16,22 +16,22 @@ export async function splitPagesByPreset(params: SplitPageByPresetParamsType): P
|
|||||||
|
|
||||||
let splitAtPages: number[];
|
let splitAtPages: number[];
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "BAR_CODE":
|
case "BAR_CODE":
|
||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
throw new Error("This split-type has not been implemented yet");
|
throw new Error("This split-type has not been implemented yet");
|
||||||
|
|
||||||
case "QR_CODE":
|
case "QR_CODE":
|
||||||
splitAtPages = await detectQRCodePages(file);
|
splitAtPages = await detectQRCodePages(file);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "BLANK_PAGE":
|
case "BLANK_PAGE":
|
||||||
if (!whiteThreashold)
|
if (!whiteThreashold)
|
||||||
throw new Error("White threshold not provided");
|
throw new Error("White threshold not provided");
|
||||||
splitAtPages = await detectEmptyPages(file, whiteThreashold);
|
splitAtPages = await detectEmptyPages(file, whiteThreashold);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error("An invalid split-type was provided.");
|
throw new Error("An invalid split-type was provided.");
|
||||||
}
|
}
|
||||||
|
|
||||||
console.debug("Split At Pages: ", splitAtPages);
|
console.debug("Split At Pages: ", splitAtPages);
|
||||||
@ -41,4 +41,4 @@ export async function splitPagesByPreset(params: SplitPageByPresetParamsType): P
|
|||||||
newFiles[i].filename += "_split-"+i;
|
newFiles[i].filename += "_split-"+i;
|
||||||
}
|
}
|
||||||
return newFiles;
|
return newFiles;
|
||||||
};
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
import { PdfFile } from '../wrappers/PdfFile.js';
|
import { PdfFile } from "../wrappers/PdfFile.js";
|
||||||
import { parsePageIndexSpecification } from './common/pageIndexesUtils'
|
import { parsePageIndexSpecification } from "./common/pageIndexesUtils";
|
||||||
import { splitPagesByIndex } from './common/splitPagesByIndex.js';
|
import { splitPagesByIndex } from "./common/splitPagesByIndex.js";
|
||||||
|
|
||||||
export type SplitPdfByIndexParamsType = {
|
export interface SplitPdfByIndexParamsType {
|
||||||
file: PdfFile;
|
file: PdfFile;
|
||||||
pageIndexes: string | number[];
|
pageIndexes: string | number[];
|
||||||
}
|
}
|
||||||
@ -11,7 +11,7 @@ export async function splitPdfByIndex(params: SplitPdfByIndexParamsType): Promis
|
|||||||
const { file, pageIndexes } = params;
|
const { file, pageIndexes } = params;
|
||||||
const pdfLibDocument = await file.pdfLibDocument;
|
const pdfLibDocument = await file.pdfLibDocument;
|
||||||
|
|
||||||
var indexes = pageIndexes;
|
let indexes = pageIndexes;
|
||||||
|
|
||||||
if (!Array.isArray(indexes)) {
|
if (!Array.isArray(indexes)) {
|
||||||
indexes = parsePageIndexSpecification(indexes, pdfLibDocument.getPageCount());
|
indexes = parsePageIndexSpecification(indexes, pdfLibDocument.getPageCount());
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
import { PdfFile } from '../wrappers/PdfFile';
|
import { PdfFile } from "../wrappers/PdfFile";
|
||||||
|
|
||||||
export type UpdateMetadataParams = {
|
export interface UpdateMetadataParams {
|
||||||
file: PdfFile,
|
file: PdfFile,
|
||||||
deleteAll?: boolean, // Delete all metadata if set to true
|
deleteAll?: boolean, // Delete all metadata if set to true
|
||||||
author?: string, // The author of the document
|
author?: string, // The author of the document
|
||||||
@ -21,34 +21,34 @@ export async function updateMetadata(params: UpdateMetadataParams): Promise<PdfF
|
|||||||
|
|
||||||
if (params.deleteAll) {
|
if (params.deleteAll) {
|
||||||
pdfDoc.setAuthor("");
|
pdfDoc.setAuthor("");
|
||||||
pdfDoc.setCreationDate(new Date(0))
|
pdfDoc.setCreationDate(new Date(0));
|
||||||
pdfDoc.setCreator("")
|
pdfDoc.setCreator("");
|
||||||
pdfDoc.setKeywords([])
|
pdfDoc.setKeywords([]);
|
||||||
pdfDoc.setModificationDate(new Date(0))
|
pdfDoc.setModificationDate(new Date(0));
|
||||||
pdfDoc.setProducer("")
|
pdfDoc.setProducer("");
|
||||||
pdfDoc.setSubject("")
|
pdfDoc.setSubject("");
|
||||||
pdfDoc.setTitle("")
|
pdfDoc.setTitle("");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(params.author)
|
if(params.author)
|
||||||
pdfDoc.setAuthor(params.author);
|
pdfDoc.setAuthor(params.author);
|
||||||
if(params.creationDate)
|
if(params.creationDate)
|
||||||
pdfDoc.setCreationDate(params.creationDate)
|
pdfDoc.setCreationDate(params.creationDate);
|
||||||
if(params.creator)
|
if(params.creator)
|
||||||
pdfDoc.setCreator(params.creator)
|
pdfDoc.setCreator(params.creator);
|
||||||
if(params.keywords)
|
if(params.keywords)
|
||||||
pdfDoc.setKeywords(params.keywords.split(","))
|
pdfDoc.setKeywords(params.keywords.split(","));
|
||||||
if(params.modificationDate)
|
if(params.modificationDate)
|
||||||
pdfDoc.setModificationDate(params.modificationDate)
|
pdfDoc.setModificationDate(params.modificationDate);
|
||||||
if(params.producer)
|
if(params.producer)
|
||||||
pdfDoc.setProducer(params.producer)
|
pdfDoc.setProducer(params.producer);
|
||||||
if(params.subject)
|
if(params.subject)
|
||||||
pdfDoc.setSubject(params.subject)
|
pdfDoc.setSubject(params.subject);
|
||||||
if(params.title)
|
if(params.title)
|
||||||
pdfDoc.setTitle(params.title)
|
pdfDoc.setTitle(params.title);
|
||||||
|
|
||||||
// TODO add trapped and custom metadata. May need another library
|
// TODO add trapped and custom metadata. May need another library
|
||||||
|
|
||||||
params.file.filename += "_updatedMetadata";
|
params.file.filename += "_updatedMetadata";
|
||||||
return params.file;
|
return params.file;
|
||||||
};
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import i18next from "i18next"
|
import i18next from "i18next";
|
||||||
import resourcesToBackend from 'i18next-resources-to-backend';
|
import resourcesToBackend from "i18next-resources-to-backend";
|
||||||
|
|
||||||
i18next
|
i18next
|
||||||
.use(resourcesToBackend((language, namespace) => import(`./${namespace}/${language}.json`)))
|
.use(resourcesToBackend((language, namespace) => import(`./${namespace}/${language}.json`)))
|
||||||
.init({
|
.init({
|
||||||
// debug: true,
|
// debug: true,
|
||||||
ns: ['common'], // Preload this namespace, no need to add the others
|
ns: ["common"], // Preload this namespace, no need to add the others
|
||||||
defaultNS: 'common',
|
defaultNS: "common",
|
||||||
fallbackLng: 'en',
|
fallbackLng: "en",
|
||||||
interpolation: {
|
interpolation: {
|
||||||
escapeValue: false,
|
escapeValue: false,
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import { Operator } from "../functions";
|
|||||||
import { Impose } from "../functions/impose";
|
import { Impose } from "../functions/impose";
|
||||||
export const Operators = {
|
export const Operators = {
|
||||||
Impose: Impose
|
Impose: Impose
|
||||||
}
|
};
|
||||||
|
|
||||||
// TODO: Convert this to a map or similar
|
// TODO: Convert this to a map or similar
|
||||||
export function getOperatorByName(name: string): typeof Operator | undefined {
|
export function getOperatorByName(name: string): typeof Operator | undefined {
|
||||||
@ -13,7 +13,7 @@ export function getOperatorByName(name: string): typeof Operator | undefined {
|
|||||||
// Loop over each default export
|
// Loop over each default export
|
||||||
Object.entries(Operators).some(([className, exportedClass]) => {
|
Object.entries(Operators).some(([className, exportedClass]) => {
|
||||||
// Check if the exported item is a class
|
// Check if the exported item is a class
|
||||||
if (typeof exportedClass === 'function' && exportedClass.prototype) {
|
if (typeof exportedClass === "function" && exportedClass.prototype) {
|
||||||
if (exportedClass.type === name) {
|
if (exportedClass.type === name) {
|
||||||
foundClass = exportedClass;
|
foundClass = exportedClass;
|
||||||
return true; // Stop the iteration
|
return true; // Stop the iteration
|
||||||
|
@ -4,8 +4,8 @@ import { PdfFile } from "../wrappers/PdfFile";
|
|||||||
export function organizeWaitOperations(actions: Action[]) {
|
export function organizeWaitOperations(actions: Action[]) {
|
||||||
|
|
||||||
// Initialize an object to store the counts and associated "done" operations
|
// Initialize an object to store the counts and associated "done" operations
|
||||||
const waitCounts: {[key: string]: number} = {};
|
const waitCounts: Record<string, number> = {};
|
||||||
const doneOperations: {[key: string]: Action} = {};
|
const doneOperations: Record<string, Action> = {};
|
||||||
|
|
||||||
// Function to count "type: wait" operations and associate "done" operations per id
|
// Function to count "type: wait" operations and associate "done" operations per id
|
||||||
function countWaitOperationsAndDone(actions: Action[]) {
|
function countWaitOperationsAndDone(actions: Action[]) {
|
||||||
@ -43,10 +43,8 @@ export function organizeWaitOperations(actions: Action[]) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ResultType = {
|
export type ResultType = Record<string, {
|
||||||
[key: string]: {
|
|
||||||
waitCount: number,
|
waitCount: number,
|
||||||
doneOperation: Action,
|
doneOperation: Action,
|
||||||
input: PdfFile[]
|
input: PdfFile[]
|
||||||
}
|
}>;
|
||||||
}
|
|
@ -34,27 +34,27 @@ export async function traverseOperations(operations: Action[], input: PdfFile[],
|
|||||||
async function computeOperation(action: Action, input: PdfFile[], progressCallback: (state: Progress) => void): Promise<void> {
|
async function computeOperation(action: Action, input: PdfFile[], progressCallback: (state: Progress) => void): Promise<void> {
|
||||||
console.log("Input: ", input);
|
console.log("Input: ", input);
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case "done": // Skip this, because it is a valid node.
|
case "done": // Skip this, because it is a valid node.
|
||||||
break;
|
break;
|
||||||
case "wait":
|
case "wait":
|
||||||
const waitOperation = waitOperations[(action as WaitAction).values.id];
|
const waitOperation = waitOperations[(action as WaitAction).values.id];
|
||||||
|
|
||||||
waitOperation.input.concat(input); // TODO: May have unexpected concequences. Needs further testing!
|
waitOperation.input.concat(input); // TODO: May have unexpected concequences. Needs further testing!
|
||||||
|
|
||||||
waitOperation.waitCount--;
|
waitOperation.waitCount--;
|
||||||
if(waitOperation.waitCount == 0 && waitOperation.doneOperation.actions) {
|
if(waitOperation.waitCount == 0 && waitOperation.doneOperation.actions) {
|
||||||
await nextOperation(waitOperation.doneOperation.actions, waitOperation.input, progressCallback);
|
await nextOperation(waitOperation.doneOperation.actions, waitOperation.input, progressCallback);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
const operator = getOperatorByName(action.type);
|
const operator = getOperatorByName(action.type);
|
||||||
if(operator) {
|
if(operator) {
|
||||||
let operation = new operator(action);
|
const operation = new operator(action);
|
||||||
input = await operation.run(input, progressCallback);
|
input = await operation.run(input, progressCallback);
|
||||||
await nextOperation(action.actions, input, progressCallback);
|
await nextOperation(action.actions, input, progressCallback);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw new Error(`${action.type} not implemented yet.`);
|
throw new Error(`${action.type} not implemented yet.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -17,7 +17,7 @@ export function validateOperations(actions: Action[]): { valid: boolean, reason?
|
|||||||
|
|
||||||
const operator = getOperatorByName(action.type);
|
const operator = getOperatorByName(action.type);
|
||||||
if(!operator) {
|
if(!operator) {
|
||||||
return { valid: false, reason: `action.type ${action.type} does not exist` }
|
return { valid: false, reason: `action.type ${action.type} does not exist` };
|
||||||
}
|
}
|
||||||
const validationResult = operator.schema.validate({values: action.values});
|
const validationResult = operator.schema.validate({values: action.values});
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ export function validateOperations(actions: Action[]): { valid: boolean, reason?
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (action.type === "done") {
|
else if (action.type === "done") {
|
||||||
return { valid: false, reason: `There shouldn't be a done action here.` };
|
return { valid: false, reason: "There shouldn't be a done action here." };
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const receivingOperator = getOperatorByName(childAction.type);
|
const receivingOperator = getOperatorByName(childAction.type);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import * as PDFJS from 'pdfjs-dist';
|
import * as PDFJS from "pdfjs-dist";
|
||||||
import type { PDFDocumentProxy as PDFJSDocument } from 'pdfjs-dist/types/src/display/api';
|
import type { PDFDocumentProxy as PDFJSDocument } from "pdfjs-dist/types/src/display/api";
|
||||||
import { PDFDocument as PDFLibDocument } from 'pdf-lib';
|
import { PDFDocument as PDFLibDocument } from "pdf-lib";
|
||||||
import Joi from 'joi';
|
import Joi from "joi";
|
||||||
|
|
||||||
export enum RepresentationType {
|
export enum RepresentationType {
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
@ -17,25 +17,25 @@ export class PdfFile {
|
|||||||
|
|
||||||
get uint8Array() : Promise<Uint8Array> {
|
get uint8Array() : Promise<Uint8Array> {
|
||||||
switch (this.representationType) {
|
switch (this.representationType) {
|
||||||
case RepresentationType.Uint8Array:
|
case RepresentationType.Uint8Array:
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
resolve(this.representation as Uint8Array);
|
resolve(this.representation as Uint8Array);
|
||||||
});
|
});
|
||||||
case RepresentationType.PDFLibDocument:
|
case RepresentationType.PDFLibDocument:
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
var uint8Array = await (this.representation as PDFLibDocument).save();
|
const uint8Array = await (this.representation as PDFLibDocument).save();
|
||||||
this.uint8Array = uint8Array;
|
this.uint8Array = uint8Array;
|
||||||
resolve(uint8Array);
|
resolve(uint8Array);
|
||||||
});
|
});
|
||||||
case RepresentationType.PDFJSDocument:
|
case RepresentationType.PDFJSDocument:
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
var uint8Array = await (this.representation as PDFJSDocument).getData();
|
const uint8Array = await (this.representation as PDFJSDocument).getData();
|
||||||
this.uint8Array = uint8Array;
|
this.uint8Array = uint8Array;
|
||||||
resolve(uint8Array);
|
resolve(uint8Array);
|
||||||
});
|
});
|
||||||
default:
|
default:
|
||||||
console.error("unhandeled PDF type: " + typeof this.representation as string);
|
console.error("unhandeled PDF type: " + typeof this.representation );
|
||||||
throw Error("unhandeled PDF type");
|
throw Error("unhandeled PDF type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set uint8Array(value: Uint8Array) {
|
set uint8Array(value: Uint8Array) {
|
||||||
@ -45,19 +45,19 @@ export class PdfFile {
|
|||||||
|
|
||||||
get pdfLibDocument() : Promise<PDFLibDocument> {
|
get pdfLibDocument() : Promise<PDFLibDocument> {
|
||||||
switch (this.representationType) {
|
switch (this.representationType) {
|
||||||
case RepresentationType.PDFLibDocument:
|
case RepresentationType.PDFLibDocument:
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
resolve(this.representation as PDFLibDocument);
|
resolve(this.representation as PDFLibDocument);
|
||||||
});
|
});
|
||||||
default:
|
default:
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
var uint8Array = await this.uint8Array;
|
const uint8Array = await this.uint8Array;
|
||||||
var pdfLibDoc = await PDFLibDocument.load(uint8Array, {
|
const pdfLibDoc = await PDFLibDocument.load(uint8Array, {
|
||||||
updateMetadata: false,
|
updateMetadata: false,
|
||||||
});
|
|
||||||
this.pdfLibDocument = pdfLibDoc;
|
|
||||||
resolve(pdfLibDoc);
|
|
||||||
});
|
});
|
||||||
|
this.pdfLibDocument = pdfLibDoc;
|
||||||
|
resolve(pdfLibDoc);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set pdfLibDocument(value: PDFLibDocument) {
|
set pdfLibDocument(value: PDFLibDocument) {
|
||||||
@ -67,16 +67,16 @@ export class PdfFile {
|
|||||||
|
|
||||||
get pdfJsDocument() : Promise<PDFJSDocument> {
|
get pdfJsDocument() : Promise<PDFJSDocument> {
|
||||||
switch (this.representationType) {
|
switch (this.representationType) {
|
||||||
case RepresentationType.PDFJSDocument:
|
case RepresentationType.PDFJSDocument:
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
resolve(this.representation as PDFJSDocument);
|
resolve(this.representation as PDFJSDocument);
|
||||||
});
|
});
|
||||||
default:
|
default:
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
const pdfjsDoc = await PDFJS.getDocument(await this.uint8Array).promise;
|
const pdfjsDoc = await PDFJS.getDocument(await this.uint8Array).promise;
|
||||||
this.pdfJsDocument = pdfjsDoc;
|
this.pdfJsDocument = pdfjsDoc;
|
||||||
resolve(pdfjsDoc);
|
resolve(pdfjsDoc);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set pdfJsDocument(value: PDFJSDocument) {
|
set pdfJsDocument(value: PDFJSDocument) {
|
||||||
|
@ -23,5 +23,5 @@ export const JoiPDFFileSchema = Joi.custom((value: Express.Multer.File[] /* <- a
|
|||||||
}, "pdffile validation");
|
}, "pdffile validation");
|
||||||
|
|
||||||
function isPdfFileArray(value: any[]): value is PdfFile[] { // "is" is a ts-typeguard - https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates
|
function isPdfFileArray(value: any[]): value is PdfFile[] { // "is" is a ts-typeguard - https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates
|
||||||
return value.every((e) => e instanceof PdfFile)
|
return value.every((e) => e instanceof PdfFile);
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user