给定一个包含纵向页面的现有 PDF 文件,我该如何以编程方式(使用 .NET)处理该文件,以便在横向页面上生成具有相同内容的新文件。
新页面应该充分利用可用的横向宽度。页面数量可能会增加,因为现有的纵向页面可能不适合一个横向页面。
背景故事:我们使用Google Sheets REST API来生成pdf文档。如果有很多列,文档可能会很宽。不幸的是,Google Drive REST API总是以纵向模式导出,并且不提供更改为横向模式的选项。
下面是我们需要处理的一个示例PDF文件:https://drive . Google . com/file/d/1 dvf 1 GD 7 zmdx 9 wjhsegebfpcvytjbn-uG/view?usp =共享
使用iTextSharp(iText for. Net v5.5.13)和PdfVeryDenseMergeTool
和PageVerticalAnalyzer
类从这个问题(在"UPDATE 2"和"UPDATE 3"中,OP从接受的C#答案发布了他的Java解决方案的端口)如下所示:
List<PdfReader> Files = new List<PdfReader>();
Files.Add(new PdfReader(@"Example.pdf"));
PdfVeryDenseMergeTool tool = new PdfVeryDenseMergeTool(new RectangleReadOnly(595, 420), 18, 18, 10);
using (MemoryStream ms = new MemoryStream())
{
tool.Merge(ms, Files);
byte[] bytes = ms.ToArray();
// bytes contains the result
}
我得到一个五页的横向结果PDF,看起来像这样:
您可以使用文档目录.pdf库来执行此操作。最简单的解决方案是将每个源页面转换为 XObject,然后将其缩放为横向并在多个目标页面上绘制。
以下是示例:
using System.Linq;
using BitMiracle.Docotic.Pdf;
namespace SplitToMultiplePages
{
public static class SplitToMultiplePages
{
public static void Main()
{
// NOTE:
// When used in trial mode, the library imposes some restrictions.
// Please visit http://bitmiracle.com/pdf-library/trial-restrictions.aspx
// for more information.
BitMiracle.Docotic.LicenseManager.AddLicenseData("temporary or permanent license key here");
using (var src = new PdfDocument(@"Example.pdf"))
{
// Calculate common parameters based on the first page.
// That makes sense when all pages have the same size, portrait orientation, and margins.
PdfPage srcPage = src.Pages[0];
PdfCollection<PdfTextData> words = srcPage.GetWords();
double topMargin = words[0].Position.Y;
double bottomMargin = srcPage.Height - words[words.Count - 1].Bounds.Bottom;
double scale = srcPage.Height / srcPage.Width;
const int BorderHeight = 1;
// This sample shows how to convert existing PDF content in portrait orientation to landscape
Debug.Assert(scale > 1);
using (var dest = new PdfDocument())
{
bool addDestPage = false;
double destPageY = topMargin;
for (int s = 0; s < src.PageCount; ++s)
{
if (s > 0)
{
srcPage = src.Pages[s];
words = srcPage.GetWords();
}
// skip empty pages
if (words.Count == 0)
continue;
// Get content of the source page, scale to landscape and draw on multiple pages
double textStartY = words[0].Bounds.Top;
double[] lineBottomPositions = words
.Select(w => (w.Bounds.Bottom - textStartY + BorderHeight) * scale)
.Distinct()
.ToArray();
double contentHeight = lineBottomPositions[lineBottomPositions.Length - 1];
PdfXObject xobj = dest.CreateXObject(srcPage);
double remainingHeight = contentHeight;
while (true)
{
PdfPage destPage = addDestPage ? dest.AddPage() : dest.Pages[dest.PageCount - 1];
destPage.Width = srcPage.Height;
destPage.Height = srcPage.Width;
double availableHeight = destPage.Height - destPageY - bottomMargin;
if (remainingHeight > availableHeight)
availableHeight = adjustToNearestLine(availableHeight, lineBottomPositions);
PdfCanvas destCanvas = destPage.Canvas;
destCanvas.SaveState();
destCanvas.TranslateTransform(0, destPageY);
destCanvas.AppendRectangle(new PdfRectangle(0, 0, destPage.Width, availableHeight), 0);
destCanvas.SetClip(PdfFillMode.Winding);
double y = -topMargin * scale - (contentHeight - remainingHeight);
destCanvas.DrawXObject(xobj, 0, y, xobj.Width * scale, xobj.Height * scale, 0);
destCanvas.RestoreState();
if (remainingHeight <= availableHeight)
{
// Move to next source page
addDestPage = false;
destPageY = remainingHeight + bottomMargin;
break;
}
// Need more pages in the resulting document
remainingHeight -= availableHeight;
addDestPage = true;
destPageY = topMargin;
}
}
// Optionally you can use Single Column layout by default
//dest.PageLayout = PdfPageLayout.OneColumn;
dest.Save("SplitToMultiplePages.pdf");
}
}
}
private static double adjustToNearestLine(double height, double[] lineHeights)
{
// TODO: Use binary search for better performance
for (int i = lineHeights.Length - 1; i >= 0; --i)
{
double lh = lineHeights[i];
if (height > lh)
return lh;
}
return lineHeights[0];
}
}
}
该样本产生以下结果:https://drive.google.com/file/d/1ITtV3Uw84wKd9mouV4kBpPoeWtsHlB9A/view?usp=sharing
根据您的要求,您也可以跳过除第一页以外的所有页面的标题。以下是这种情况的示例:
using System.Linq;
using BitMiracle.Docotic.Pdf;
namespace SplitToMultiplePages
{
public static class SplitToMultiplePages
{
public static void Main()
{
// NOTE:
// When used in trial mode, the library imposes some restrictions.
// Please visit http://bitmiracle.com/pdf-library/trial-restrictions.aspx
// for more information.
BitMiracle.Docotic.LicenseManager.AddLicenseData("temporary or permanent license key here");
using (var src = new PdfDocument(@"Example.pdf"))
{
// Calculate common parameters based on the first page.
// That makes sense when all pages have the same size, portrait orientation, and margins.
PdfPage srcPage = src.Pages[0];
PdfCollection<PdfTextData> words = srcPage.GetWords();
double topMargin = words[0].Position.Y;
double bottomMargin = srcPage.Height - words[words.Count - 1].Bounds.Bottom;
double scale = srcPage.Height / srcPage.Width;
const int BorderHeight = 1;
// This sample shows how to convert existing PDF content in portrait orientation to landscape
Debug.Assert(scale > 1);
using (var dest = new PdfDocument())
{
bool addDestPage = false;
double destPageY = topMargin;
for (int s = 0; s < src.PageCount; ++s)
{
if (s > 0)
{
srcPage = src.Pages[s];
words = srcPage.GetWords();
}
// skip empty pages
if (words.Count == 0)
continue;
// Get content of the source page, scale to landscape and draw on multiple pages
double textStartY = words[0].Bounds.Top;
// Skip the header line of all pages except first
if (s > 0)
{
double? firstDataRowY = words.Select(w => w.Bounds.Top).FirstOrDefault(y => y > textStartY);
if (!firstDataRowY.HasValue)
continue;
textStartY = firstDataRowY.Value;
}
double[] lineBottomPositions = words
.Select(w => (w.Bounds.Bottom - textStartY + BorderHeight) * scale)
.Distinct()
.ToArray();
double contentHeight = lineBottomPositions[lineBottomPositions.Length - 1];
PdfXObject xobj = dest.CreateXObject(srcPage);
double remainingHeight = contentHeight;
while (true)
{
PdfPage destPage = addDestPage ? dest.AddPage() : dest.Pages[dest.PageCount - 1];
destPage.Width = srcPage.Height;
destPage.Height = srcPage.Width;
double availableHeight = destPage.Height - destPageY - bottomMargin;
if (remainingHeight > availableHeight)
availableHeight = adjustToNearestLine(availableHeight, lineBottomPositions);
PdfCanvas destCanvas = destPage.Canvas;
destCanvas.SaveState();
destCanvas.TranslateTransform(0, destPageY);
destCanvas.AppendRectangle(new PdfRectangle(0, 0, destPage.Width, availableHeight), 0);
destCanvas.SetClip(PdfFillMode.Winding);
double y = -textStartY * scale - (contentHeight - remainingHeight);
destCanvas.DrawXObject(xobj, 0, y, xobj.Width * scale, xobj.Height * scale, 0);
destCanvas.RestoreState();
if (remainingHeight <= availableHeight)
{
// Move to the next source page
addDestPage = false;
destPageY = remainingHeight + bottomMargin;
break;
}
// Need more pages in the resulting document
remainingHeight -= availableHeight;
addDestPage = true;
destPageY = topMargin;
}
}
// Optionally you can use Single Column layout by default
//dest.PageLayout = PdfPageLayout.OneColumn;
dest.Save("SplitToMultiplePages.pdf");
}
}
}
private static double adjustToNearestLine(double height, double[] lineHeights)
{
// TODO: Use binary search for better performance
for (int i = lineHeights.Length - 1; i >= 0; --i)
{
double lh = lineHeights[i];
if (height > lh)
return lh;
}
return lineHeights[0];
}
}
}
“skip headers”示例的结果文件:https://drive . Google . com/file/d/1v 9 lpyiposknngheuzz 8 KD 3 xswmxgbjiz/view?usp =共享
我有一个从LibreOffice Writer导出的PDF文件。这里有一个例子。一些页面具有纵向,其他页面具有横向。我正在使用Linux,当我在evice或Foxit Reader中查看文件时,它会正确显示,即所有文本行都是水平的。它也可以在我的打印机上用A4纸正确打印:横向页面逆时针旋转90度,使文本行垂直。 问题是:文档将在另一台设备(出版商中)上打印,我被告知所有页面都必须具有纵向方向。我不
问题内容: 我有一个PDFReader,其中包含横向模式的某些页面和纵向模式的其他页面。 我需要区分它们以进行一些处理…但是,如果我调用getOrientation或getPageSize,则该值始终是相同的(pagesize为595,方向为0)。 为什么横向页面的值没有不同? 我试图找到其他方法来检索页面宽度/方向,但没有任何效果。 这是我的代码: 谢谢 ! 问题答案: 解决: 用 代替
问题内容: 我有一个PDFReader,其中包含横向模式的某些页面和纵向模式的其他页面。 我需要区分它们以进行一些处理…但是,如果我调用getOrientation或getPageSize,则该值始终是相同的(pagesize为595,方向为0)。 为什么横向页面的值没有不同? 我试图找到其他方法来检索页面宽度/方向,但没有任何效果。 这是我的代码: 谢谢 ! 问题答案: 解决: 用 代替
问题内容: 我有一个移动Web应用程序,其无序列表包含多个列表项,每个li内都有一个超链接: …我的问题是如何格式化超链接,以使它们在iPhone上查看时不会改变大小,并且加速计从纵向切换为横向?现在,我将超链接的字体大小指定为14px,但是切换到横向时,它会炸裂到20px。我希望字体大小保持不变。这是代码: 问题答案: 您可以通过CSS属性禁用此行为:
是否有工具来确定PDF是横向的还是纵向的? 旋转:270 “旋转”到底是什么意思?
我正在关注w3c学校关于制作幻灯片网页的教程。 对我来说,唯一不同的要求是,我有相同垂直分辨率的横向和纵向图像(1280x720和420x720)。 当我加载肖像图像时,它们的比例会大得多,因为图像仅受最大宽度的限制。实际上,我希望边界是垂直最大高度,所以当我循环通过它们时,高度是恒定的。 问题是,当我在上指定“最大高度”并删除“最大宽度”时。幻灯片容器,然后将图像左对齐放置在页面上。所以看起来我