iTextSharp (C#):在位置添加文本(覆盖所有内容)
iTextSharp (C#): Add text (over everything) at position
我正在尝试在 WPF 项目中使用 iTextSharp 将文本添加到现有 PDF 中的所有其他内容并在给定点添加文本。基本上相当于在纸质文档上书写的数字效果
我尝试了多种方法,但似乎没有任何方法可以真正将文本写入新的 PDF。我的代码因测试各种事情而变得混乱(留下来所以我知道我尝试了什么 - 是的,我会在解决后清除它),所以我会尝试获取所有重要的行。
var stream = new FileStream(targetFilePath, FileMode.Create);
var doc = new iTextSharp.text.Document();
var target = new PdfCopy(doc, stream);
doc.Open();
var baseFont = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1252, false);
foreach (var vm in Pages) // Cycles through pages in WPF object...
{
var srcDoc = vm.DocTmpFName;
if (Path.GetExtension(srcDoc).ToUpperInvariant() == ".PDF")
{
var reader = new iTextSharp.text.pdf.PdfReader(srcDoc);
var page = reader.GetPageN(vm.Number);
var stamper = new PdfStamper(reader, stream);
target.AddPage(target.GetImportedPage(reader, vm.Number));
page.Put(PdfName.ROTATE, new PdfNumber(vm.Rotation % 360f));
// Inside this 'foreach' loop is what isn't working. The rest works fine.
foreach(var str in vm.Strings) // str is a container class (just a string and two 'double' vars for positioning)
{
// This isn't writing to new PDF even though it gets run (verified with breakpoints)
var contentByte = stamper.GetOverContent(vm.Number);
contentByte.BeginText();
contentByte.SetTextMatrix((float)str.X, (float)str.Y);
contentByte.SetFontAndSize(baseFont, 72f); //Making it stupid-big so I don't miss it
contentByte.ShowText(str.String);
contentByte.EndText();
}
target.FreeReader(reader);
reader.Close();
}
}
target.Close();
doc.Close();
stream.Close();
如果您觉得我遗漏了什么,请告诉我。我试图保持问题区域的上下文,所以希望它不是太可怕的黑客工作。
- 已编辑以更正代码 -
编辑
我重命名了一些变量,以便更容易辨别它们的用途。此外,我还包含了新的固定(尽管有错误)代码,该代码在某个位置添加文本 - 供以后遇到此问题的任何人使用。 =)
@mkl 回答后的工作代码:
var stream = new FileStream(targetFilePath, FileMode.Create);
var doc = new iTextSharp.text.Document();
var targetPdf = new PdfCopy(doc, stream);
doc.Open();
foreach (ViewModels.PageViewModel vm in document.Pages)
{
var srcDocPath = FileIO.ToTempFileName(vm.DocName);
// Copy pageDict from source...
if (Path.GetExtension(srcDocPath).ToUpperInvariant() == ".PDF")
{
var srcReader = new iTextSharp.text.pdf.PdfReader(srcDocPath);
var pageDict = srcReader.GetPageN(vm.Number);
var importedPage = targetPdf.GetImportedPage(srcReader, vm.Number);
var pageStamp = targetPdf.CreatePageStamp(importedPage);
foreach(var str in vm.Strings)
{
ColumnText.ShowTextAligned(pageStamp.GetOverContent(),
iTextSharp.text.Element.ALIGN_LEFT,
new iTextSharp.text.Phrase(str.String),
(float) str.X,
// pdf-origin is bottom-left, not top-left
(float)(importedPage.Height - str.Y),
0);
}
pageDict.Put(PdfName.ROTATE, new PdfNumber(vm.Rotation % 360f));
pageStamp.AlterContents();
targetPdf.AddPage(importedPage);
targetPdf.FreeReader(srcReader);
srcReader.Close();
}
}
targetPdf.Close();
doc.Close();
stream.Close();
您不能关闭 foreach
循环中的 reader。也不(我怀疑)你应该做 target.FreeReader
电话:
foreach(var str in vm.Strings) // str is a container class (just a string and two 'double' vars for positioning)
{
// This isn't writing to new PDF even though it gets run (verified with breakpoints)
var contentByte = stamper.GetOverContent(vm.Number);
contentByte.BeginText();
contentByte.SetTextMatrix((float)str.X, (float)str.Y);
contentByte.SetFontAndSize(baseFont, 72f); //Making it stupid-big so I don't miss it
contentByte.ShowText(str.String);
contentByte.EndText();
}
//moved the next two lines out of the foreach loop
target.FreeReader(reader);
reader.Close();
这三行同样适用:
target.Close();
doc.Close();
stream.Close();
它们也应该移出当前包含它们的 foreach (var vm in Pages)
循环。
您的代码有很多问题,@Übercoder 已经在他的回答中解决了其中的一些问题。
此外,您有 一个 PdfCopy
和多个 PdfStamper
实例写入同一个流 。这将导致流输出完全混乱。如果你想戳你复制的页面,你应该使用PdfCopy.PageStamp
,例如像这样:
using (PdfCopy copy = new PdfCopy(document, OUTPUT_STREAM)) {
document.Open();
PdfReader reader1 = new PdfReader(r1);
int n1 = reader1.NumberOfPages;
PdfImportedPage page;
PdfCopy.PageStamp stamp;
for (int i = 0; i < n1; ) {
page = copy.GetImportedPage(reader1, ++i);
stamp = copy.CreatePageStamp(page);
// CHANGE THE PAGE,
// e.g. by manipulating stamp.GetOverContent()
...
//
stamp.AlterContents();
copy.AddPage(page);
}
}
(摘自官方 iTextSharp 示例 ConcatenateStamp.cs)
我正在尝试在 WPF 项目中使用 iTextSharp 将文本添加到现有 PDF 中的所有其他内容并在给定点添加文本。基本上相当于在纸质文档上书写的数字效果
我尝试了多种方法,但似乎没有任何方法可以真正将文本写入新的 PDF。我的代码因测试各种事情而变得混乱(留下来所以我知道我尝试了什么 - 是的,我会在解决后清除它),所以我会尝试获取所有重要的行。
var stream = new FileStream(targetFilePath, FileMode.Create);
var doc = new iTextSharp.text.Document();
var target = new PdfCopy(doc, stream);
doc.Open();
var baseFont = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1252, false);
foreach (var vm in Pages) // Cycles through pages in WPF object...
{
var srcDoc = vm.DocTmpFName;
if (Path.GetExtension(srcDoc).ToUpperInvariant() == ".PDF")
{
var reader = new iTextSharp.text.pdf.PdfReader(srcDoc);
var page = reader.GetPageN(vm.Number);
var stamper = new PdfStamper(reader, stream);
target.AddPage(target.GetImportedPage(reader, vm.Number));
page.Put(PdfName.ROTATE, new PdfNumber(vm.Rotation % 360f));
// Inside this 'foreach' loop is what isn't working. The rest works fine.
foreach(var str in vm.Strings) // str is a container class (just a string and two 'double' vars for positioning)
{
// This isn't writing to new PDF even though it gets run (verified with breakpoints)
var contentByte = stamper.GetOverContent(vm.Number);
contentByte.BeginText();
contentByte.SetTextMatrix((float)str.X, (float)str.Y);
contentByte.SetFontAndSize(baseFont, 72f); //Making it stupid-big so I don't miss it
contentByte.ShowText(str.String);
contentByte.EndText();
}
target.FreeReader(reader);
reader.Close();
}
}
target.Close();
doc.Close();
stream.Close();
如果您觉得我遗漏了什么,请告诉我。我试图保持问题区域的上下文,所以希望它不是太可怕的黑客工作。
- 已编辑以更正代码 -
编辑
我重命名了一些变量,以便更容易辨别它们的用途。此外,我还包含了新的固定(尽管有错误)代码,该代码在某个位置添加文本 - 供以后遇到此问题的任何人使用。 =)
@mkl 回答后的工作代码:
var stream = new FileStream(targetFilePath, FileMode.Create);
var doc = new iTextSharp.text.Document();
var targetPdf = new PdfCopy(doc, stream);
doc.Open();
foreach (ViewModels.PageViewModel vm in document.Pages)
{
var srcDocPath = FileIO.ToTempFileName(vm.DocName);
// Copy pageDict from source...
if (Path.GetExtension(srcDocPath).ToUpperInvariant() == ".PDF")
{
var srcReader = new iTextSharp.text.pdf.PdfReader(srcDocPath);
var pageDict = srcReader.GetPageN(vm.Number);
var importedPage = targetPdf.GetImportedPage(srcReader, vm.Number);
var pageStamp = targetPdf.CreatePageStamp(importedPage);
foreach(var str in vm.Strings)
{
ColumnText.ShowTextAligned(pageStamp.GetOverContent(),
iTextSharp.text.Element.ALIGN_LEFT,
new iTextSharp.text.Phrase(str.String),
(float) str.X,
// pdf-origin is bottom-left, not top-left
(float)(importedPage.Height - str.Y),
0);
}
pageDict.Put(PdfName.ROTATE, new PdfNumber(vm.Rotation % 360f));
pageStamp.AlterContents();
targetPdf.AddPage(importedPage);
targetPdf.FreeReader(srcReader);
srcReader.Close();
}
}
targetPdf.Close();
doc.Close();
stream.Close();
您不能关闭 foreach
循环中的 reader。也不(我怀疑)你应该做 target.FreeReader
电话:
foreach(var str in vm.Strings) // str is a container class (just a string and two 'double' vars for positioning)
{
// This isn't writing to new PDF even though it gets run (verified with breakpoints)
var contentByte = stamper.GetOverContent(vm.Number);
contentByte.BeginText();
contentByte.SetTextMatrix((float)str.X, (float)str.Y);
contentByte.SetFontAndSize(baseFont, 72f); //Making it stupid-big so I don't miss it
contentByte.ShowText(str.String);
contentByte.EndText();
}
//moved the next two lines out of the foreach loop
target.FreeReader(reader);
reader.Close();
这三行同样适用:
target.Close();
doc.Close();
stream.Close();
它们也应该移出当前包含它们的 foreach (var vm in Pages)
循环。
您的代码有很多问题,@Übercoder 已经在他的回答中解决了其中的一些问题。
此外,您有 一个 PdfCopy
和多个 PdfStamper
实例写入同一个流 。这将导致流输出完全混乱。如果你想戳你复制的页面,你应该使用PdfCopy.PageStamp
,例如像这样:
using (PdfCopy copy = new PdfCopy(document, OUTPUT_STREAM)) {
document.Open();
PdfReader reader1 = new PdfReader(r1);
int n1 = reader1.NumberOfPages;
PdfImportedPage page;
PdfCopy.PageStamp stamp;
for (int i = 0; i < n1; ) {
page = copy.GetImportedPage(reader1, ++i);
stamp = copy.CreatePageStamp(page);
// CHANGE THE PAGE,
// e.g. by manipulating stamp.GetOverContent()
...
//
stamp.AlterContents();
copy.AddPage(page);
}
}
(摘自官方 iTextSharp 示例 ConcatenateStamp.cs)