iTextSharp 5生成的PDF文档与AdobeReader兼容
我正在使用iText5生成一些报告 打开生成的.PDF文件,大多数PDF阅读器看起来和实际上都很好 但是,当我使用AdobeReader(DC)打开PDF时,它会询问我是否要在关闭时保存更改。虽然我没有改变什么 点击“取消”可以确保消息窗口消失,但点击“保存”会导致文件实际缩小 现在那里发生了什么?为什么?如何禁用它 应用程序的用户很可能也会使用AdobeReader 我不希望他们在任何时候打开报表时都看到“保存”对话框 这是我的基本报告课iTextSharp 5生成的PDF文档与AdobeReader兼容,itext,adobe-reader,Itext,Adobe Reader,我正在使用iText5生成一些报告 打开生成的.PDF文件,大多数PDF阅读器看起来和实际上都很好 但是,当我使用AdobeReader(DC)打开PDF时,它会询问我是否要在关闭时保存更改。虽然我没有改变什么 点击“取消”可以确保消息窗口消失,但点击“保存”会导致文件实际缩小 现在那里发生了什么?为什么?如何禁用它 应用程序的用户很可能也会使用AdobeReader 我不希望他们在任何时候打开报表时都看到“保存”对话框 这是我的基本报告课 public abstract class Base
public abstract class BaseReport : PdfPageEventHelper
{
protected const string SPACE = " ";
protected const string COLON = ":";
protected static string NEWLINE = Environment.NewLine;
protected Document document;
protected PdfTemplate footerTemplate;
protected PdfContentByte contentByte;
protected PdfWriter writer;
private PdfTemplate totalPageNoTemplate;
private int lastPageNumber;
// properties for header
private bool done;
// needs to be overriden in subclass order to use header feature
protected string kundeHeader { get; set; }
// font definitions
protected BaseFont baseFont;
protected Font fontFooter;
protected Font fontGeneralText;
protected Font fontLabelText;
protected Font fontBoldLabelText;
protected Font fontBoldText;
protected Font fontSpace;
protected Font fontLargeBoldText;
protected int language;
protected bool useLogo = false;
protected bool usePageNumbers = false;
protected bool usePrintDate = false;
protected const string PRINT_FULLDATE_FORMAT = "dd.MM.yyyy HH:mm";
protected const string PRINT_DATE_ONLY_FORMAT = "dd.MM.yyyy";
protected Rectangle pagesize = PageSize.A4;
protected float marginLeft = 80;
protected float marginRight = 35;
protected float marginTop = 40;
protected float marginBottom = 40;
private MemoryStream PDFStream { get; set; } = new MemoryStream();
private DateTime printDate;
public BaseReport(int language = Languages.DE, bool landscape = false)
{
this.language = language;
if (landscape)
{
pagesize = pagesize.Rotate();
}
}
public byte[] GenerateReport()
{
CultureInfo cultureBefore = Resources.Culture;
try
{
Resources.Culture = SelectCultureForLangauge();
PrepareReport();
document = new Document(pagesize, marginLeft, marginRight, marginTop, marginBottom);
BuildFonts();
OpenDocument();
PrepareDocument();
GenerateContent();
document.Close();
return PDFStream.GetBuffer();
} finally
{
Resources.Culture = cultureBefore;
}
}
public void GenerateReport(string filename)
{
byte[] report = GenerateReport();
using (FileStream f = new FileStream(filename, FileMode.Create))
{
f.Write(report, 0, report.Length);
}
}
protected CultureInfo SelectCultureForLangauge()
{
string languageCode = GetLanguageCode();
return CultureInfo.GetCultureInfo(languageCode);
}
protected string GetLanguageCode()
{
string languageCode = string.Empty;
switch (language)
{
case Languages.FR: languageCode = "FR"; break;
case Languages.IT: languageCode = "IT"; break;
case Languages.EN: languageCode = "EN"; break;
default: languageCode = "DE"; break;
}
return languageCode;
}
protected virtual void PrepareReport() { }
protected virtual void PrepareDocument() { }
protected abstract void GenerateContent();
private void BuildFonts()
{
baseFont = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED);
fontFooter = FontFactory.GetFont(FontFactory.HELVETICA, 11, Font.ITALIC, BaseColor.DARK_GRAY);
fontGeneralText = FontFactory.GetFont(FontFactory.HELVETICA, 11, Font.NORMAL, BaseColor.BLACK);
fontLabelText = FontFactory.GetFont(FontFactory.HELVETICA, 8.5f, Font.NORMAL, BaseColor.BLACK);
fontBoldLabelText = FontFactory.GetFont(FontFactory.HELVETICA, 8.5f, Font.BOLD, BaseColor.BLACK);
fontBoldText = FontFactory.GetFont(FontFactory.HELVETICA, 11, Font.BOLD, BaseColor.BLACK);
fontSpace = FontFactory.GetFont(FontFactory.HELVETICA, 3.5f, Font.NORMAL, BaseColor.BLACK);
fontLargeBoldText = FontFactory.GetFont(FontFactory.HELVETICA, 17, Font.BOLD, BaseColor.BLACK);
GetFontIfAvailable();
}
private void GetFontIfAvailable()
{
string fileName = "IF_Rg";
try
{
baseFont = LoadFontFromFile(fileName, true);
fontFooter = new Font(baseFont, 11, Font.ITALIC, BaseColor.DARK_GRAY);
fontGeneralText = new Font(baseFont, 11, Font.NORMAL, BaseColor.BLACK);
fontLabelText = new Font(baseFont, 8.5f, Font.NORMAL, BaseColor.BLACK);
fontBoldLabelText = new Font(baseFont, 8.5f, Font.BOLD, BaseColor.BLACK);
fontBoldText = new Font(baseFont, 11, Font.BOLD, BaseColor.BLACK);
fontSpace = new Font(baseFont, 3.5f, Font.NORMAL, BaseColor.BLACK);
fontLargeBoldText = new Font(baseFont, 17, Font.BOLD, BaseColor.BLACK);
} catch (FileNotFoundException)
{
LogWrapper.Warn("Font not found - using default.");
}
}
protected BaseFont LoadFontFromFile(string fileName, bool embedded)
{
string fontPath = Environment.GetEnvironmentVariable("SystemRoot") + "\\fonts\\" + fileName + ".ttf";
if (File.Exists(fontPath))
{
return BaseFont.CreateFont(fontPath, BaseFont.WINANSI, embedded);
}
else
{
throw new FileNotFoundException($"Fontfile {fileName} was not found!");
}
}
protected Image HeaderLogo()
{
Image logo = Image.GetInstance(Resources.logo, BaseColor.BLACK);
// TODO msc pick logo from debitor
logo.ScaleToFit(100f, 100f);
return logo;
}
protected void OpenDocument()
{
writer = PdfWriter.GetInstance(document, PDFStream);
writer.PageEvent = this;
writer.SetFullCompression();
document.Open();
contentByte = writer.DirectContent;
}
protected void AddLabelAt(string label, float posX, float posY)
{
PdfContentByte cb = writer.DirectContent;
ColumnText column = new ColumnText(cb);
column.SetText(new Paragraph(label + NEWLINE, fontLabelText));
column.SetSimpleColumn(posX, 20, posX + 200, posY);
column.Go();
}
protected void AddLabelOnMargin(string label)
{
AddLabelAt(label, document.LeftMargin - 40, writer.GetVerticalPosition(false));
}
protected Phrase ParaLine(string Text, Font textfont)
{
return new Phrase(Text, textfont);
}
public override void OnOpenDocument(PdfWriter writer, Document document)
{
if (usePageNumbers)
{
totalPageNoTemplate = writer.DirectContentUnder.CreateTemplate(50, 50);
}
if (usePrintDate)
{
printDate = DateTime.Now;
}
}
public override void OnStartPage(PdfWriter writer, Document document)
{
if (useLogo || (document.PageNumber > 1 && !string.IsNullOrEmpty(kundeHeader)))
{
PdfContentByte canvas = writer.DirectContentUnder;
canvas.SaveState();
if (document.PageNumber > 1 && !string.IsNullOrEmpty(kundeHeader))
{
//showtextaligned only shows a single line
//therefor the header needs to be split and its parts need to be added seperately
string[] headerParts = kundeHeader.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
Phrase header = new Phrase(kundeHeader, fontLabelText);
ColumnText.ShowTextAligned(canvas, Element.ALIGN_LEFT,
ParaLine(headerParts[0], fontLabelText),
document.LeftMargin,
document.Top + 30, 0);
ColumnText.ShowTextAligned(canvas, Element.ALIGN_LEFT,
ParaLine(headerParts[1], fontLabelText),
document.LeftMargin,
document.Top + 20, 0);
}
if (useLogo)
{
Image logo = HeaderLogo();
logo.SetAbsolutePosition(marginLeft - 17.5f, document.Top + document.TopMargin - 50);
document.Add(logo);
}
canvas.RestoreState();
}
}
public override void OnEndPage(PdfWriter writer, Document document)
{
if (usePageNumbers || usePrintDate)
{
PdfContentByte canvas = writer.DirectContentUnder;
canvas.SaveState();
if (usePageNumbers)
{
// adds current page number to the footer section of the document
int pageN = writer.PageNumber;
string text = Resources.LabelSeite + SPACE + pageN + "/";
float len = fontLabelText.BaseFont.GetWidthPoint(text, fontLabelText.Size);
ColumnText.ShowTextAligned(canvas, Element.ALIGN_LEFT,
ParaLine(text, fontLabelText),
document.LeftMargin,
document.Bottom - 10, 0);
// adds template to fill in total page number (see OnCloseDocument method)
canvas.AddTemplate(totalPageNoTemplate, document.LeftMargin + len, document.Bottom - 10);
lastPageNumber = pageN;
}
if (usePrintDate)
{
// adds the printdate to the footer secdtion of the document
string dateFormatted = printDate.ToString(PRINT_FULLDATE_FORMAT);
ColumnText.ShowTextAligned(canvas, Element.ALIGN_RIGHT,
ParaLine(dateFormatted, fontLabelText),
document.Right,
document.Bottom - 10, 0);
}
canvas.RestoreState();
}
}
public override void OnCloseDocument(PdfWriter writer, Document document)
{
if (usePageNumbers)
{
// fills in the total page number to the prepared template in the footer section of the document
string text = lastPageNumber + "";
float widthPoint = fontLabelText.BaseFont.GetWidthPoint(text, fontLabelText.Size);
totalPageNoTemplate.Width = widthPoint;
ColumnText.ShowTextAligned(totalPageNoTemplate, Element.ALIGN_LEFT, ParaLine(text, fontLabelText), 0, 0, 0);
}
}
我必须将PDFStream.GetBuffer()与PDFStream.ToArray()切换;问题已解决。大多数PDF查看器都能容忍较小的PDF语法问题。Adobe也很宽容,但希望解决这些问题。这就是为什么会出现一个对话框,询问您是否要保存文档。Adobe希望修复此问题,以便下次打开文档时不会发生此问题。如果您使用的是iText 5.2.x,则应升级,因为该版本存在已知问题。我们不知道其他版本存在问题,尽管如果代码错误,使用iText创建错误的PDF总是可能的。如果看不到您的代码或PDF,没有人可以回答您的问题。请注意,使用iText填写奇怪的表单时也会出现此问题。您可以通过修复表单或以不同的方式填写表单来避免问题(如果这适用于您,请向我们展示您的代码)。至于“收缩”:我打赌你创建PDF的方式与PDF 1.5之前创建PDF的方式相同。从PDF 1.5开始,可以压缩交叉引用表和特定对象(在iText中,我们称之为完全压缩)。当Adobe Reader保存PDF的固定版本时,它可能会压缩
xref
表和所选对象。感谢您的快速响应!我使用的是iTextSharp 5.5.10.0,所以应该可以。因此,如果我对我的报告实施完全压缩
,AdobeReader应该可以吗?如果您需要帮助,请共享您的PDF。我们可以检查它是否是一个表单(用于解决已知问题)。如果它不是一个表单,我们可以使用飞行前验证它,以查看Adobe Reader抱怨的语法错误。您还可以共享您的代码,以便我们查看您是否执行了与ISO 32000冲突的低级操作。一个显而易见的错误是,您正在OnStartPage()
方法中添加内容。这是禁止的(如文件所述)。此外,在该方法中使用的是document.Add()
。禁止在页面事件实现中使用文档
对象,因为文档
对象不是您认为的文档
对象。它实际上是一个内部PdfDocument
实例,只应用于只读目的。旧版本的iText中的所有这些设计缺陷都在iText 7.Ah中修复。因此,这实际上是一个重复的问题,应该标记为这样。。。