mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-06-22 23:45:02 +00:00
scaleContent, rotatePage allow negative rotations, validateOperations casts action.values now
This commit is contained in:
parent
6f4bb8242b
commit
a484a804ad
3
package-lock.json
generated
3
package-lock.json
generated
@ -10651,6 +10651,9 @@
|
|||||||
"next-i18next": "^15.1.1",
|
"next-i18next": "^15.1.1",
|
||||||
"pdf-lib": "^1.17.1",
|
"pdf-lib": "^1.17.1",
|
||||||
"pdfjs-dist": "^4.2.67"
|
"pdfjs-dist": "^4.2.67"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/multer": "^1.4.11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shared-operations/node_modules/buffer": {
|
"shared-operations/node_modules/buffer": {
|
||||||
|
@ -17,5 +17,8 @@
|
|||||||
"next-i18next": "^15.1.1",
|
"next-i18next": "^15.1.1",
|
||||||
"pdf-lib": "^1.17.1",
|
"pdf-lib": "^1.17.1",
|
||||||
"pdfjs-dist": "^4.2.67"
|
"pdfjs-dist": "^4.2.67"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/multer": "^1.4.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,8 @@ export class RotatePages extends Operator {
|
|||||||
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({
|
||||||
rotation: Joi.alternatives().try(
|
rotation: Joi.alternatives().try(
|
||||||
Joi.number().min(0).max(360).allow(null),
|
Joi.number().integer().min(-360).max(360),
|
||||||
CommaArrayJoiExt.comma_array().items(Joi.number().integer().min(0).max(360))
|
CommaArrayJoiExt.comma_array().items(Joi.number().integer().min(-360).max(360))
|
||||||
).label(i18next.t("values.rotation.friendlyName", { ns: "rotatePages" })).description(i18next.t("values.rotation.description", { ns: "rotatePages" }))
|
).label(i18next.t("values.rotation.friendlyName", { ns: "rotatePages" })).description(i18next.t("values.rotation.description", { ns: "rotatePages" }))
|
||||||
.example("90").example("-180").example("[90, 0, 270]"),
|
.example("90").example("-180").example("[90, 0, 270]"),
|
||||||
});
|
});
|
||||||
|
@ -1,42 +1,83 @@
|
|||||||
|
import { Operator, Progress, oneToOne } from ".";
|
||||||
|
|
||||||
|
import Joi from "@stirling-tools/joi";
|
||||||
|
import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi";
|
||||||
|
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
import CommaArrayJoiExt from "../wrappers/CommaArrayJoiExt";
|
||||||
|
|
||||||
import { PDFPage } from "pdf-lib";
|
import { PDFPage } from "pdf-lib";
|
||||||
import { PdfFile, RepresentationType } from "../wrappers/PdfFile";
|
import { PdfFile, RepresentationType } from "../wrappers/PdfFile";
|
||||||
|
|
||||||
export interface ScaleContentParamsType {
|
export class ScaleContent extends Operator {
|
||||||
file: PdfFile;
|
static type = "scaleContent";
|
||||||
scaleFactor: number|number[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function scaleContent(params: ScaleContentParamsType): Promise<PdfFile> {
|
/**
|
||||||
const { file, scaleFactor } = params;
|
* Validation & Localisation
|
||||||
|
*/
|
||||||
|
|
||||||
const pdfDoc = await file.pdfLibDocument;
|
protected static inputSchema = JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description"));
|
||||||
const pages = pdfDoc.getPages();
|
protected static valueSchema = Joi.object({
|
||||||
|
scaleFactor: Joi.alternatives().try(
|
||||||
|
Joi.number(),
|
||||||
|
CommaArrayJoiExt.comma_array().items(Joi.number())
|
||||||
|
).label(i18next.t("values.scaleFactor.friendlyName", { ns: "scaleContent" })).description(i18next.t("values.scaleFactor.description", { ns: "scaleContent" }))
|
||||||
|
.example("2").example("1.5").example("[1, 1.5, 0.9]"),
|
||||||
|
});
|
||||||
|
protected static outputSchema = JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description"));
|
||||||
|
|
||||||
if (Array.isArray(scaleFactor)) {
|
static schema = Joi.object({
|
||||||
if (scaleFactor.length != pages.length) {
|
input: ScaleContent.inputSchema,
|
||||||
throw new Error(`Number of given scale factors '${scaleFactor.length}' is not the same as the number of pages '${pages.length}'`);
|
values: ScaleContent.valueSchema.required(),
|
||||||
}
|
output: ScaleContent.outputSchema
|
||||||
for (let i=0; i<scaleFactor.length; i++) {
|
}).label(i18next.t("friendlyName", { ns: "scaleContent" })).description(i18next.t("description", { ns: "scaleContent" }));
|
||||||
scalePage(pages[i], scaleFactor[i]);
|
|
||||||
}
|
|
||||||
} else {
|
/**
|
||||||
pages.forEach(page => { scalePage(page, scaleFactor) });
|
* Logic
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Detect and remove white pages */
|
||||||
|
async run(input: PdfFile[], progressCallback: (state: Progress) => void): Promise<PdfFile[]> {
|
||||||
|
return oneToOne<PdfFile, PdfFile>(input, async (input, index, max) => {
|
||||||
|
|
||||||
|
const pdfDoc = await input.pdfLibDocument;
|
||||||
|
const pages = pdfDoc.getPages();
|
||||||
|
|
||||||
|
// Different rotations applied to each page
|
||||||
|
if (Array.isArray(this.actionValues.scaleFactor)) {
|
||||||
|
if (this.actionValues.scaleFactor.length != pages.length) {
|
||||||
|
throw new Error(`Number of given rotations '${this.actionValues.scaleFactor.length}' is not the same as the number of pages '${pages.length}'`);
|
||||||
|
}
|
||||||
|
for (let pageIdx = 0; pageIdx < this.actionValues.scaleFactor.length; pageIdx++) {
|
||||||
|
ScaleContent.scalePageContent(pages[pageIdx], this.actionValues.scaleFactor[pageIdx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Only one rotation applied to each page
|
||||||
|
else {
|
||||||
|
console.log(typeof this.actionValues.scaleFactor);
|
||||||
|
pages.forEach(page => { ScaleContent.scalePageContent(page, this.actionValues.scaleFactor) });
|
||||||
|
}
|
||||||
|
|
||||||
|
progressCallback({ curFileProgress: 1, operationProgress: index/max });
|
||||||
|
|
||||||
|
return new PdfFile(input.originalFilename, pdfDoc, RepresentationType.PDFLibDocument, input.filename + "_rotated");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PdfFile(file.originalFilename, pdfDoc, RepresentationType.PDFLibDocument, file.filename+"_scaledContent");
|
private static scalePageContent(page: PDFPage, scaleFactor: number) {
|
||||||
}
|
const width = page.getWidth();
|
||||||
|
const height = page.getHeight();
|
||||||
function scalePage(page: PDFPage, scaleFactor: number) {
|
|
||||||
const width = page.getWidth();
|
// Scale content
|
||||||
const height = page.getHeight();
|
page.scaleContent(scaleFactor, scaleFactor);
|
||||||
|
const scaled_diff = {
|
||||||
// Scale content
|
width: Math.round(width - scaleFactor * width),
|
||||||
page.scaleContent(scaleFactor, scaleFactor);
|
height: Math.round(height - scaleFactor * height)
|
||||||
const scaled_diff = {
|
};
|
||||||
width: Math.round(width - scaleFactor * width),
|
|
||||||
height: Math.round(height - scaleFactor * height),
|
// Center content in new page format
|
||||||
};
|
page.translateContent(Math.round(scaled_diff.width / 2), Math.round(scaled_diff.height / 2));
|
||||||
|
}
|
||||||
// Center content in new page format
|
|
||||||
page.translateContent(Math.round(scaled_diff.width / 2), Math.round(scaled_diff.height / 2));
|
|
||||||
}
|
}
|
@ -24,6 +24,7 @@ export async function validateOperations(actions: Action[]): Promise<{ valid: bo
|
|||||||
if(validationResult.error) {
|
if(validationResult.error) {
|
||||||
return { valid: false, reason: validationResult.error.message};
|
return { valid: false, reason: validationResult.error.message};
|
||||||
}
|
}
|
||||||
|
action.values = validationResult.value.values;
|
||||||
|
|
||||||
if (action.actions) {
|
if (action.actions) {
|
||||||
// Check io compatibility of the operators
|
// Check io compatibility of the operators
|
||||||
|
@ -12,14 +12,16 @@ export default Joi.extend((joi) => {
|
|||||||
from: 'string',
|
from: 'string',
|
||||||
method(value, helpers) {
|
method(value, helpers) {
|
||||||
|
|
||||||
if (typeof value !== 'string' || !/(\d+)(,\s*\d+)*/.test(value)) { // is string and in format "[number], [number]"
|
if (typeof value !== 'string') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return { value: value.split(",").map(v => v.trim()) };
|
return { value: value.split(",").map(v => v.trim()) };
|
||||||
}
|
}
|
||||||
catch (ignoreErr) { }
|
catch (err) {
|
||||||
|
helpers.error(err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
"#pdfcpu": ["../../shared-operations/src/wasm/pdfcpu/pdfcpu-wrapper.server"],
|
"#pdfcpu": ["../../shared-operations/src/wasm/pdfcpu/pdfcpu-wrapper.server"],
|
||||||
},
|
},
|
||||||
"types": [
|
"types": [
|
||||||
"vite/client"
|
"vite/client",
|
||||||
|
"multer"
|
||||||
],
|
],
|
||||||
} /* Specify a set of entries that re-map imports to additional lookup locations. */
|
} /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user