固定 PDF 的方向以缩放它
Fix the orientation of a PDF in order to scale it
我在使用 Xerox 扫描仪创建的包含旋转 属性 的 PDF 时遇到了一些问题。
下面的函数最初是为了按变量 scaleHeight 给定的量来缩放输入 PDF 的高度而创建的。
这适用于没有旋转的输入文档。
在测试文档旋转 270 度时,我发现忽略了会使文档以纵向显示的旋转 属性。相反,该文档在输出 PDF 中显示为横向。
所以我更新了下面的函数以仅在没有旋转时应用缩放,并使用我在网上找到的另一个示例来尝试修复旋转。
此 无效,并且 生成纵向格式的原始文档的镜像。
所以现在我有两个问题:
1.如何正确旋转文档内容。
2.如何缩放旋转后的内容
如果我能解决第 1 项,我可以简单地再次调用该函数(删除旋转 属性)来修复第 2 项。
感谢您的帮助,功能如下。
引用 rotationEvent 的注释掉的行在这里也没有帮助。
public String resizePDF (String pdfIn, float x, float y, float scaleHeight) throws Exception {
String pdfOut = pdfIn.substring(0, pdfIn.length() - 4) + "_resize.pdf";
PdfReader reader = new PdfReader(pdfIn);
int rotation = reader.getPageRotation(1);
com.itextpdf.text.Document doc = new com.itextpdf.text.Document(reader.getPageSizeWithRotation(1), 0, 0, 0, 0);
PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(pdfOut));
doc.open();
PdfContentByte cb = writer.getDirectContent();
Rotate rotationEvent = new Rotate();
writer.setPageEvent(rotationEvent);
for(int i=1; i<=reader.getNumberOfPages(); i++){
float pageWidth = reader.getPageSizeWithRotation(i).getWidth();
float pageHeight = reader.getPageSizeWithRotation(i).getHeight();
doc.newPage();
PdfImportedPage page = writer.getImportedPage(reader, i);
if (rotation == 0) {
cb.addTemplate(page, 1f, 0, 0, scaleHeight, x, y);
//rotationEvent.setRotation(PdfPage.PORTRAIT);
} else if (rotation == 90) {
cb.addTemplate(page, 0, -1f, 1f, 0, 0, pageHeight);
//rotationEvent.setRotation(PdfPage.LANDSCAPE);
} else if (rotation == 180) {
cb.addTemplate(page, 1f, 0, 0, -1f, pageWidth, pageHeight);
//rotationEvent.setRotation(PdfPage.INVERTEDPORTRAIT);
} else if (rotation == 270) {
cb.addTemplate(page, 0, -1f, 1f, 0, 0, pageHeight);
//cb.addTemplate(page, 0, 1f, -1f, 0, pageWidth, 0);
//rotationEvent.setRotation(PdfPage.SEASCAPE);
}
}
doc.close();
return pdfOut;
}
我不明白你的代码,但是当我告诉别人时"please throw away your code and start anew",很多人觉得被冒犯了(虽然我肯定不是有意冒犯他们)。
我了解到您想缩放现有 PDF 的内容并保持旋转或将其删除(该部分并不完全清楚)。
因此我给你写了一个名为 ScaleDown
的例子,它可以用来缩小,保持方向。删除单行即可删除方向。
这个例子使用了一个页面事件(我把它命名为ScaleEvent
):
public class ScaleEvent extends PdfPageEventHelper {
protected float scale = 1;
protected PdfDictionary pageDict;
public ScaleEvent(float scale) {
this.scale = scale;
}
public void setPageDict(PdfDictionary pageDict) {
this.pageDict = pageDict;
}
@Override
public void onStartPage(PdfWriter writer, Document document) {
writer.addPageDictEntry(PdfName.ROTATE, pageDict.getAsNumber(PdfName.ROTATE));
writer.addPageDictEntry(PdfName.MEDIABOX, scaleDown(pageDict.getAsArray(PdfName.MEDIABOX), scale));
writer.addPageDictEntry(PdfName.CROPBOX, scaleDown(pageDict.getAsArray(PdfName.CROPBOX), scale));
}
}
创建事件时,您传递一个值 scale
来定义比例因子。我将缩放比例应用于宽度和高度,如果您只想缩放高度,请随意调整它。
有关页面大小和旋转的信息存储在页面字典中。显然 ScaleEvent
需要原始文档的值,这就是为什么我们要为我们复制的每一页传递一个 pageDict
。
每次创建新页面时,我们都会copy/replace:
/Rotate
值。如果要去掉旋转,去掉这一行,
/MediaBox
值。这定义了页面的完整大小。
/CropBox
值。这定义了页面的可见大小。
由于我们要缩放页面,我们使用下面的scaleDown()
方法:
public PdfArray scaleDown(PdfArray original, float scale) {
if (original == null)
return null;
float width = original.getAsNumber(2).floatValue()
- original.getAsNumber(0).floatValue();
float height = original.getAsNumber(3).floatValue()
- original.getAsNumber(1).floatValue();
return new PdfRectangle(width * scale, height * scale);
}
假设我想将页面的宽度和高度缩小到原来宽度和高度的50%,那么我创建的事件是这样的:
PdfReader reader = new PdfReader(src);
float scale = 0.5f;
ScaleEvent event = new ScaleEvent(scale);
event.setPageDict(reader.getPageN(1));
我可以用我想要的任何页面大小定义一个 Document
,因为无论如何 ScaleEvent
中的大小都会改变。显然,为了让它工作,我需要向 PdfWriter
实例声明事件:
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
writer.setPageEvent(event);
document.open();
现在只需要遍历页面即可:
int n = reader.getNumberOfPages();
Image page;
for (int p = 1; p <= n; p++) {
page = Image.getInstance(writer.getImportedPage(reader, p));
page.setAbsolutePosition(0, 0);
page.scalePercent(scale * 100);
document.add(page);
if (p < n) {
event.setPageDict(reader.getPageN(p + 1));
}
document.newPage();
}
document.close();
我将导入的页面包装在 Image
中,因为我个人认为 Image
class 可用的方法比定义 [=] 的参数更容易使用30=] 方法。如果您想使用 addTemplate()
而不是 Image
,请随意使用;结果将是相同的(与您在评论中所写的相反,将页面包裹在图像中不会导致任何损失 "resolution" 因为所有文本仍然可以作为矢量数据使用)。
请注意,我会为每个新页面更新 pageDict
。
此代码将文件 orientations.pdf measuring 8.26 by 11.69 in and transforms it into the file scaled_down.pdf 尺寸为 4.13 x 5.85 英寸。
如果您希望所有页面都是纵向的,只需删除以下行:
writer.addPageDictEntry(PdfName.ROTATE, pageDict.getAsNumber(PdfName.ROTATE));
我在使用 Xerox 扫描仪创建的包含旋转 属性 的 PDF 时遇到了一些问题。 下面的函数最初是为了按变量 scaleHeight 给定的量来缩放输入 PDF 的高度而创建的。 这适用于没有旋转的输入文档。
在测试文档旋转 270 度时,我发现忽略了会使文档以纵向显示的旋转 属性。相反,该文档在输出 PDF 中显示为横向。
所以我更新了下面的函数以仅在没有旋转时应用缩放,并使用我在网上找到的另一个示例来尝试修复旋转。
此 无效,并且 生成纵向格式的原始文档的镜像。
所以现在我有两个问题: 1.如何正确旋转文档内容。 2.如何缩放旋转后的内容
如果我能解决第 1 项,我可以简单地再次调用该函数(删除旋转 属性)来修复第 2 项。
感谢您的帮助,功能如下。 引用 rotationEvent 的注释掉的行在这里也没有帮助。
public String resizePDF (String pdfIn, float x, float y, float scaleHeight) throws Exception {
String pdfOut = pdfIn.substring(0, pdfIn.length() - 4) + "_resize.pdf";
PdfReader reader = new PdfReader(pdfIn);
int rotation = reader.getPageRotation(1);
com.itextpdf.text.Document doc = new com.itextpdf.text.Document(reader.getPageSizeWithRotation(1), 0, 0, 0, 0);
PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(pdfOut));
doc.open();
PdfContentByte cb = writer.getDirectContent();
Rotate rotationEvent = new Rotate();
writer.setPageEvent(rotationEvent);
for(int i=1; i<=reader.getNumberOfPages(); i++){
float pageWidth = reader.getPageSizeWithRotation(i).getWidth();
float pageHeight = reader.getPageSizeWithRotation(i).getHeight();
doc.newPage();
PdfImportedPage page = writer.getImportedPage(reader, i);
if (rotation == 0) {
cb.addTemplate(page, 1f, 0, 0, scaleHeight, x, y);
//rotationEvent.setRotation(PdfPage.PORTRAIT);
} else if (rotation == 90) {
cb.addTemplate(page, 0, -1f, 1f, 0, 0, pageHeight);
//rotationEvent.setRotation(PdfPage.LANDSCAPE);
} else if (rotation == 180) {
cb.addTemplate(page, 1f, 0, 0, -1f, pageWidth, pageHeight);
//rotationEvent.setRotation(PdfPage.INVERTEDPORTRAIT);
} else if (rotation == 270) {
cb.addTemplate(page, 0, -1f, 1f, 0, 0, pageHeight);
//cb.addTemplate(page, 0, 1f, -1f, 0, pageWidth, 0);
//rotationEvent.setRotation(PdfPage.SEASCAPE);
}
}
doc.close();
return pdfOut;
}
我不明白你的代码,但是当我告诉别人时"please throw away your code and start anew",很多人觉得被冒犯了(虽然我肯定不是有意冒犯他们)。
我了解到您想缩放现有 PDF 的内容并保持旋转或将其删除(该部分并不完全清楚)。
因此我给你写了一个名为 ScaleDown
的例子,它可以用来缩小,保持方向。删除单行即可删除方向。
这个例子使用了一个页面事件(我把它命名为ScaleEvent
):
public class ScaleEvent extends PdfPageEventHelper {
protected float scale = 1;
protected PdfDictionary pageDict;
public ScaleEvent(float scale) {
this.scale = scale;
}
public void setPageDict(PdfDictionary pageDict) {
this.pageDict = pageDict;
}
@Override
public void onStartPage(PdfWriter writer, Document document) {
writer.addPageDictEntry(PdfName.ROTATE, pageDict.getAsNumber(PdfName.ROTATE));
writer.addPageDictEntry(PdfName.MEDIABOX, scaleDown(pageDict.getAsArray(PdfName.MEDIABOX), scale));
writer.addPageDictEntry(PdfName.CROPBOX, scaleDown(pageDict.getAsArray(PdfName.CROPBOX), scale));
}
}
创建事件时,您传递一个值 scale
来定义比例因子。我将缩放比例应用于宽度和高度,如果您只想缩放高度,请随意调整它。
有关页面大小和旋转的信息存储在页面字典中。显然 ScaleEvent
需要原始文档的值,这就是为什么我们要为我们复制的每一页传递一个 pageDict
。
每次创建新页面时,我们都会copy/replace:
/Rotate
值。如果要去掉旋转,去掉这一行,/MediaBox
值。这定义了页面的完整大小。/CropBox
值。这定义了页面的可见大小。
由于我们要缩放页面,我们使用下面的scaleDown()
方法:
public PdfArray scaleDown(PdfArray original, float scale) {
if (original == null)
return null;
float width = original.getAsNumber(2).floatValue()
- original.getAsNumber(0).floatValue();
float height = original.getAsNumber(3).floatValue()
- original.getAsNumber(1).floatValue();
return new PdfRectangle(width * scale, height * scale);
}
假设我想将页面的宽度和高度缩小到原来宽度和高度的50%,那么我创建的事件是这样的:
PdfReader reader = new PdfReader(src);
float scale = 0.5f;
ScaleEvent event = new ScaleEvent(scale);
event.setPageDict(reader.getPageN(1));
我可以用我想要的任何页面大小定义一个 Document
,因为无论如何 ScaleEvent
中的大小都会改变。显然,为了让它工作,我需要向 PdfWriter
实例声明事件:
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
writer.setPageEvent(event);
document.open();
现在只需要遍历页面即可:
int n = reader.getNumberOfPages();
Image page;
for (int p = 1; p <= n; p++) {
page = Image.getInstance(writer.getImportedPage(reader, p));
page.setAbsolutePosition(0, 0);
page.scalePercent(scale * 100);
document.add(page);
if (p < n) {
event.setPageDict(reader.getPageN(p + 1));
}
document.newPage();
}
document.close();
我将导入的页面包装在 Image
中,因为我个人认为 Image
class 可用的方法比定义 [=] 的参数更容易使用30=] 方法。如果您想使用 addTemplate()
而不是 Image
,请随意使用;结果将是相同的(与您在评论中所写的相反,将页面包裹在图像中不会导致任何损失 "resolution" 因为所有文本仍然可以作为矢量数据使用)。
请注意,我会为每个新页面更新 pageDict
。
此代码将文件 orientations.pdf measuring 8.26 by 11.69 in and transforms it into the file scaled_down.pdf 尺寸为 4.13 x 5.85 英寸。
如果您希望所有页面都是纵向的,只需删除以下行:
writer.addPageDictEntry(PdfName.ROTATE, pageDict.getAsNumber(PdfName.ROTATE));