英文:
Java iText scale document to A4
问题
我有以下方法,可以将文档的所有页面调整为A4页面尺寸:
for (PdfDocument doc : pdfDocuments) {
int n = doc.getNumberOfPages();
for (int i = 1; i <= n; i++) {
PdfPage page = doc.getPage(i);
Rectangle media = page.getCropBox();
if (media == null) {
media = page.getMediaBox();
}
Rectangle crop = new Rectangle(0, 0, 210, 297);
page.setMediaBox(crop);
page.setCropBox(crop);
// 在之前放置在内容流上的内容将在其他内容之前呈现,
// 因此可以理解为背景(底部“图层”)
new PdfCanvas(page.newContentStreamBefore(),
page.getResources(), doc).writeLiteral("\nq 0.5 0 0 0.5 0 0 cm\nq\n");
// 在之后放置在内容流上的内容将在其他内容之后呈现,
// 因此可以理解为前景(顶部“图层”)
new PdfCanvas(page.newContentStreamAfter(),
page.getResources(), doc).writeLiteral("\nQ\nQ\n");
}
}
然而,目前这不按预期工作,页面虽然被调整为A4(297x210),但内容没有被适当地缩放以适应其中,内容似乎被裁剪,因为原始页面大于297x210。您应该如何修复这个问题?
英文:
I have the following method that "resizes" all the pages of a document to A4 page dimensions:
for (PdfDocument doc : pdfDocuments) {
int n = doc.getNumberOfPages();
for (int i = 1; i <= n; i++) {
PdfPage page = doc.getPage(i);
Rectangle media = page.getCropBox();
if (media == null) {
media = page.getMediaBox();
}
Rectangle crop = new Rectangle(0, 0, 210, 297);
page.setMediaBox(crop);
page.setCropBox(crop);
// The content, placed on a content stream before, will be rendered before the other content
// and, therefore, could be understood as a background (bottom "layer")
new PdfCanvas(page.newContentStreamBefore(),
page.getResources(), doc).writeLiteral("\nq 0.5 0 0 0.5 0 0 cm\nq\n");
// The content, placed on a content stream after, will be rendered after the other content
// and, therefore, could be understood as a foreground (top "layer")
new PdfCanvas(page.newContentStreamAfter(),
page.getResources(), doc).writeLiteral("\nQ\nQ\n");
}
}
However , this is not working as expected , the pages are being transformed to A4 (297x210) BUT the content is not being fitted inside (scaled) , the content appears cutted because the original pages are larger than 297X210 . How can I fix this ?
答案1
得分: 1
你在评论中进行了澄清:
> 我想要前一内容的边界框被缩放,并在目标中添加边距
因此,我们首先必须确定原始页面内容的边界框。这可以通过使用来自此答案的MarginFinder
类来完成。注意:该类确定所有内容的边界框,即使它只是一个白色矩形,在视觉上与没有内容或先前在裁剪框外的内容在外观上没有区别... 如果您的用例需要,您可能还需要扩展该类以考虑这些情况。
有了内容边界框的确定,剩下要做的就是一些计算。
以下方法使用上述类来确定边界框,相应地转换内容,并更改结果的裁剪框。
void scale(PdfDocument pdfDocument, Rectangle pageSize, Rectangle pageBodySize) {
int n = pdfDocument.getNumberOfPages();
for (int i = 1; i <= n; i++) {
PdfPage page = pdfDocument.getPage(i);
MarginFinder marginFinder = new MarginFinder();
PdfCanvasProcessor pdfCanvasProcessor = new PdfCanvasProcessor(marginFinder);
pdfCanvasProcessor.processPageContent(page);
Rectangle boundingBox = marginFinder.getBoundingBox();
if (boundingBox == null || boundingBox.getWidth() == 0 || boundingBox.getHeight() == 0) {
System.err.printf("无法缩放第 %d 页的内容,边界框为 %s\n", i , boundingBox);
continue;
} else {
// 缩放并将内容移入带边距的 A4 页面
double scale = 0, xDiff= 0, yDiff = 0;
double xScale = pageBodySize.getWidth()/boundingBox.getWidth();
double yScale = pageBodySize.getHeight()/boundingBox.getHeight();
if (xScale < yScale) {
yDiff = boundingBox.getHeight() * (yScale / xScale - 1) / 2;
scale = xScale;
} else {
xDiff = boundingBox.getWidth() * (xScale / yScale - 1) / 2;
scale = yScale;
}
AffineTransform transform = AffineTransform.getTranslateInstance(pageBodySize.getLeft() + xDiff, pageBodySize.getBottom() + yDiff);
transform.scale(scale, scale);
transform.translate(-boundingBox.getLeft(), -boundingBox.getBottom());
new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDocument)
.concatMatrix(transform);
}
page.setMediaBox(pageSize);
page.setCropBox(pageSize);
}
}
(来自 ScaleToA4 方法 scale
)
对于带有每边一英寸边距的 A4 结果页面大小,您可以为 PdfDocument pdfDocument
这样调用它:
Rectangle pageSize = PageSize.A4;
Rectangle pageBodySize = pageSize.clone().applyMargins(72, 72, 72, 72, false);
scale(pdfDocument, pageSize, pageBodySize);
(摘自 ScaleToA4 测试 testFdaRequiresUseOfEctdFormatAndStandardizedStudyDataInFutureRegulatorySubmissionsSept
)
英文:
In a comment you clarified
> I want the bounding box of the former content be scaled and a margin be added in the target
So, we first have to determine the bounding box of the original page content. This can be done using the MarginFinder
class from this answer. Beware: That class determines the bounding box of all content, even if it is merely a white rectangle visually not distinct from no content or something formerly outside the crop box... If your use case requires it, you may have to extend that class to take such circumstances into consideration, too.
With the content bounding box determined all that remains to do is a bit of calculation.
The following method determines the bounding box using the class above, transforms the content accordingly, and changes the result crop box.
void scale(PdfDocument pdfDocument, Rectangle pageSize, Rectangle pageBodySize) {
int n = pdfDocument.getNumberOfPages();
for (int i = 1; i <= n; i++) {
PdfPage page = pdfDocument.getPage(i);
MarginFinder marginFinder = new MarginFinder();
PdfCanvasProcessor pdfCanvasProcessor = new PdfCanvasProcessor(marginFinder);
pdfCanvasProcessor.processPageContent(page);
Rectangle boundingBox = marginFinder.getBoundingBox();
if (boundingBox == null || boundingBox.getWidth() == 0 || boundingBox.getHeight() == 0) {
System.err.printf("Cannot scale page %d contents with bounding box %s\n", i , boundingBox);
continue;
} else {
// Scale and move content into A4 with margin
double scale = 0, xDiff= 0, yDiff = 0;
double xScale = pageBodySize.getWidth()/boundingBox.getWidth();
double yScale = pageBodySize.getHeight()/boundingBox.getHeight();
if (xScale < yScale) {
yDiff = boundingBox.getHeight() * (yScale / xScale - 1) / 2;
scale = xScale;
} else {
xDiff = boundingBox.getWidth() * (xScale / yScale - 1) / 2;
scale = yScale;
}
AffineTransform transform = AffineTransform.getTranslateInstance(pageBodySize.getLeft() + xDiff, pageBodySize.getBottom() + yDiff);
transform.scale(scale, scale);
transform.translate(-boundingBox.getLeft(), -boundingBox.getBottom());
new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDocument)
.concatMatrix(transform);
}
page.setMediaBox(pageSize);
page.setCropBox(pageSize);
}
}
(ScaleToA4 method scale
)
For an A4 result page size with an inch of margin on each side you can call it like this for a PdfDocument pdfDocument
:
Rectangle pageSize = PageSize.A4;
Rectangle pageBodySize = pageSize.clone().applyMargins(72, 72, 72, 72, false);
scale(pdfDocument, pageSize, pageBodySize);
(excerpt from ScaleToA4 test testFdaRequiresUseOfEctdFormatAndStandardizedStudyDataInFutureRegulatorySubmissionsSept
)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论