我尝试将 HTML 转换为 A4 页面大小的 PDF。但内容太长,PDF 分成了 2 页。我只想把它写进一页。所以我的想法是转换为A3尺寸的PDF,然后缩小到A4尺寸。 但另一个问题是从 A3 页面尺寸缩小到 A4 页面尺寸。
1) 将 html 转换为 A3 大小的文档
2)遍历页面并将每个页面复制为 formXObject
3)对于每个页面formXObject:
a) 用 0.5 系数缩放;
b) 添加到生成的文档中。
合适的Java代码如下(移植到C#应该没有问题,因为iText的API是一样的):
// 1
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(baos));
pdfDocument.setDefaultPageSize(PageSize.A3);
HtmlConverter.convertToPdf(new FileInputStream(sourcePath), pdfDocument);
PdfDocument resultantDocument = new PdfDocument(new PdfWriter(destPath));
pdfDocument = new PdfDocument(new PdfReader(new ByteArrayInputStream(baos.toByteArray())));
// 2
for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++) {
PdfPage page = pdfDocument.getPage(i);
PdfFormXObject formXObject = page.copyAsFormXObject(resultantDocument);
PdfCanvas pdfCanvas = new PdfCanvas(resultantDocument.addNewPage());
// 3a and 3b
pdfCanvas.addXObject(formXObject, 0.5f, 0, 0, 0.5f, 0, 0);
}
pdfDocument.close();
resultantDocument.close();
我的目标是将每一页都以纵向和 A4 格式放置。有时高度和宽度会翻转,所以也必须检查一下。最终,注释也没有缩放。想出了这个代码来完成这三个任务。
请参阅
ScalePageToA4
了解如何缩放每个页面。请记住,页面不是零索引。
//argument documents: byte[]?
MemoryStream readStream = new(documents);
MemoryStream writeStream = new();
try
{
var reader = new PdfReader(readStream);
var writer = new PdfWriter(writeStream);
PdfDocument pdf = new(reader, writer);
int numberOfPages = pdf.GetNumberOfPages();
for (int i = 1; i <= numberOfPages; i++)
{
PdfPage page = pdf.GetPage(i);
if (IsLandscape(page))
{
page.SetRotation((page.GetRotation() + 90) % 360);
}
ScalePageToA4(pdf, page);
}
pdf.Close();
return writeStream.ToArray();
}
finally
{
readStream?.Close();
readStream?.Dispose();
writeStream?.Close();
writeStream?.Dispose();
}
private static bool IsLandscape(PdfPage page)
{
Rectangle pageSize = page.GetPageSizeWithRotation();
float originalWidth = pageSize.GetWidth();
float originalHeight = pageSize.GetHeight();
return originalWidth > originalHeight;
}
private static void ScalePageToA4(PdfDocument pdf, PdfPage page)
{
const float A4_WIDTH = 842;
const float A4_HEIGHT = 595;
Rectangle media = page.GetCropBox() ?? page.GetMediaBox();
Rectangle crop = new(0, 0, A4_WIDTH, A4_HEIGHT);
double scaleX = A4_WIDTH / media.GetWidth();
double scaleY = A4_HEIGHT / media.GetHeight();
if (media.GetWidth() == page.GetPageSizeWithRotation().GetWidth())
{
crop = new(0, 0, A4_HEIGHT, A4_WIDTH);
scaleX = A4_HEIGHT / page.GetPageSizeWithRotation().GetWidth();
scaleY = A4_WIDTH / page.GetPageSizeWithRotation().GetHeight();
}
page.SetMediaBox(crop);
page.SetCropBox(crop);
if (scaleX != 1 || scaleY != 1)
{
double scale = Math.Min(scaleX, scaleY);
string scaleString = scale.ToString("G17", CultureInfo.InvariantCulture);
string s = $"\nq {scaleString} 0 0 {scaleString} 0 0 cm\nq\n";
new PdfCanvas(page.NewContentStreamBefore(), new PdfResources(), pdf).WriteLiteral(s);
new PdfCanvas(page.NewContentStreamAfter(), new PdfResources(), pdf).WriteLiteral("\nQ\nQ\n");
IList<PdfAnnotation> annotations = page.GetAnnotations();
ScaleAnnotations(scale, annotations);
}
}
private static void ScaleAnnotations(double scale, IEnumerable<PdfAnnotation> annotations)
{
foreach (var annotation in annotations)
{
Rectangle annotationRect = annotation.GetRectangle().ToRectangle();
float newX = (float)(annotationRect.GetX() * scale);
float newY = (float)(annotationRect.GetY() * scale);
float newWidth = (float)(annotationRect.GetWidth() * scale);
float newHeight = (float)(annotationRect.GetHeight() * scale);
PdfArray newRectArray = new()
{
new PdfNumber(newX),
new PdfNumber(newY),
new PdfNumber(newX + newWidth),
new PdfNumber(newY + newHeight)
};
annotation.SetRectangle(newRectArray);
}
}