Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scale page content #991

Merged
merged 16 commits into from
Oct 16, 2021
81 changes: 81 additions & 0 deletions src/api/PDFPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
pushGraphicsState,
translate,
LineCapStyle,
scale,
} from 'src/api/operators';
import PDFDocument from 'src/api/PDFDocument';
import PDFEmbeddedPage from 'src/api/PDFEmbeddedPage';
Expand All @@ -39,6 +40,10 @@ import {
PDFOperator,
PDFPageLeaf,
PDFRef,
PDFNumber,
PDFDict,
PDFArray,
PDFObject,
} from 'src/core';
import {
addRandomSuffix,
Expand Down Expand Up @@ -566,6 +571,73 @@ export default class PDFPage {
this.node.wrapContentStreams(startRef, endRef);
}

/**
* Scale the content of a page. This is useful after resizing an exisiting page.
* This scales only the content not the annots. See also: [[scaleAnnots]]
* ```js
* // bisect the size of the page
* p.setSize(p.getWidth() / 2, p.getHeight() / 2);
*
* // scale the content of the page down by 50% in x and y
* page.scaleContent(0.5, 0.5);
* ```
* @param x The factor by wich the x-axis for the content should be scaled (e.g. 0.5 is 50%)
* @param y The factor by wich the y-axis for the content should be scaled (e.g. 0.5 is 50%)
*/
scaleContent(x: number, y: number): void {
JNK90 marked this conversation as resolved.
Show resolved Hide resolved
assertIs(x, 'x', ['number']);
Hopding marked this conversation as resolved.
Show resolved Hide resolved
assertIs(y, 'y', ['number']);

this.node.normalize();
this.getContentStream();

const start = this.createContentStream(pushGraphicsState(), scale(x, y));
const startRef = this.doc.context.register(start);

const end = this.createContentStream(popGraphicsState());
const endRef = this.doc.context.register(end);

this.node.wrapContentStreams(startRef, endRef);
}

/**
* Scale the annots of a page. This is useful if you want to scale a page with comments or other annots.
* ```JS
Hopding marked this conversation as resolved.
Show resolved Hide resolved
* // scale the content of the page down by 50% in x and y
* page.scaleContent(0.5, 0.5);
*
* // scale the content of the page down by 50% in x and y
* page.scaleAnnots(0.5, 0.5);
* ```
* See alos: [[scaleContent]]
Hopding marked this conversation as resolved.
Show resolved Hide resolved
* @param x The factor by wich the x-axis for the annots should be scaled (e.g. 0.5 is 50%)
* @param y The factor by wich the y-axis for the annots should be scaled (e.g. 0.5 is 50%)
*/
scaleAnnots(x: number, y: number) {
JNK90 marked this conversation as resolved.
Show resolved Hide resolved
const annots = this.node.Annots();

// loop annotations
annots?.asArray().forEach((ref: PDFObject) => {
const i = annots.indexOf(ref);

if (i === undefined) return;

const annot = annots.lookup(i, PDFDict);

if (!annot) return;

['RD', 'CL', 'Vertices', 'QuadPoints', 'L', 'Rect'].forEach((el) => {
const list = annot.get(PDFName.of(el)) as PDFArray;
if (list) this.scalePDFNumbers(list, x, y);
});

const pdfNameInkList = annot.get(PDFName.of('InkList')) as PDFArray;
pdfNameInkList
?.asArray()
.forEach((arr) => this.scalePDFNumbers(arr as PDFArray, x, y));
Hopding marked this conversation as resolved.
Show resolved Hide resolved
});
}

/**
* Reset the x and y coordinates of this page to `(0, 0)`. This operation is
* often useful after calling [[translateContent]]. For example:
Expand Down Expand Up @@ -1500,4 +1572,13 @@ export default class PDFPage {

return key;
}

private scalePDFNumbers(arr: PDFArray, x: number, y: number): void {
JNK90 marked this conversation as resolved.
Show resolved Hide resolved
arr?.asArray().forEach((el, i) => {
JNK90 marked this conversation as resolved.
Show resolved Hide resolved
if (el instanceof PDFNumber) {
const factor = i % 2 === 0 ? x : y;
arr.set(i, PDFNumber.of(el.asNumber() * factor));
}
});
}
}