展平后遗漏注释(图章)
Annotation(stamp) missed after flattened
Annotation(PdfName.STAMP) 在被 itextsharp5.5.13.1 扁平化后丢失。
我有两个pdf。一个有效,另一个无效。
任何想法将不胜感激。
代码如下
string outFile = inputFile + "_f.pdf";
using (PdfReader pdfReader = new PdfReader(inputFileName))
{
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(outFile, FileMode.Create, FileAccess.Write, FileShare.None))
//pdfStamper.FormFlattening = true;
//pdfStamper.FreeTextFlattening = true;
pdfStamper.AnnotationFlattening = true;
//pdfStamper.AcroFields.GenerateAppearances = true;
}
原因是iTextSharp中的一个错误,如果其边界框不使用原点,则注释展平无法正确计算展平注释的位置左下角.
如果你看一下 PdfStamperImp.FlattenAnnotations(bool)
的代码,你会很快意识到 if (app != null)
块中的计算只有在边界框位于原点或没有缩放时才有意义将外观边界框装入注释矩形所必需的。
(由于边界框的左下角通常是原点,因此不会经常弹出。)
因此,要展平 此类注释,您必须使用不同的展平方法, 例如像这样:
using (PdfReader pdfReader = new PdfReader(inputFileName))
{
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(outFile, FileMode.Create, FileAccess.Write, FileShare.None));
ImprovedAnnotationFlattening(pdfStamper);
pdfStamper.Close();
}
使用这些辅助方法:
void ImprovedAnnotationFlattening(PdfStamper pdfStamper)
{
double[] DEFAULT_MATRIX = { 1, 0, 0, 1, 0, 0 };
PdfReader reader = pdfStamper.Reader;
for (int page = 1; page <= reader.NumberOfPages; ++page)
{
PdfDictionary pageDic = reader.GetPageN(page);
PdfArray annots = pageDic.GetAsArray(PdfName.ANNOTS);
if (annots == null)
continue;
for (int idx = 0; idx < annots.Size; ++idx)
{
PdfObject annoto = annots.GetDirectObject(idx);
if (!(annoto is PdfDictionary))
continue;
PdfDictionary annDic = (PdfDictionary)annoto;
PdfNumber ff = annDic.GetAsNumber(PdfName.F);
int flags = ff != null ? ff.IntValue : 0;
if ((flags & PdfFormField.FLAGS_PRINT) == 0 || (flags & PdfFormField.FLAGS_HIDDEN) != 0)
continue;
PdfObject obj1 = annDic.Get(PdfName.AP);
if (obj1 == null)
continue;
PdfDictionary appDic = obj1 is PdfIndirectReference
? (PdfDictionary)PdfReader.GetPdfObject(obj1)
: (PdfDictionary)obj1;
PdfObject obj = appDic.Get(PdfName.N);
PdfStream objDict = appDic.GetAsStream(PdfName.N);
if (objDict != null)
{
Rectangle rect = PdfReader.GetNormalizedRectangle(annDic.GetAsArray(PdfName.RECT));
Rectangle bbox = PdfReader.GetNormalizedRectangle(objDict.GetAsArray(PdfName.BBOX));
PdfContentByte cb = pdfStamper.GetOverContent(page);
cb.SetLiteral("Q ");
PdfArray matrixArray = objDict.GetAsArray(PdfName.MATRIX);
double[] matrix = matrixArray != null ? matrixArray.AsDoubleArray() : DEFAULT_MATRIX;
AffineTransform transform = new AffineTransform(matrix);
double[] bboxCorners = { bbox.Left, bbox.Bottom, bbox.Right, bbox.Bottom, bbox.Right, bbox.Top, bbox.Left, bbox.Top };
transform.Transform(bboxCorners, 0, bboxCorners, 0, 4);
double minX = Min(bboxCorners, 0, 2);
double maxX = Max(bboxCorners, 0, 2);
double minY = Min(bboxCorners, 1, 2);
double maxY = Max(bboxCorners, 1, 2);
transform.preConcatenate(AffineTransform.GetTranslateInstance(-minX, -minY));
transform.preConcatenate(AffineTransform.GetScaleInstance(rect.Width/(maxX-minX), rect.Height/(maxY-minY)));
transform.preConcatenate(AffineTransform.GetTranslateInstance(rect.Left, rect.Bottom));
transform.GetMatrix(matrix);
cb.AddFormXObj(objDict, GenerateName(), matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
cb.SetLiteral("q ");
annots.Remove(idx);
--idx;
}
}
}
}
double Min(double[] array, int start, int step)
{
double result = array[start];
for (int i = start + step; i < array.Length; i+=step)
{
result = Math.Min(result, array[i]);
}
return result;
}
double Max(double[] array, int start, int step)
{
double result = array[start];
for (int i = start + step; i < array.Length; i += step)
{
result = Math.Max(result, array[i]);
}
return result;
}
PdfName GenerateName()
{
PdfName name = new PdfName("XXX" + formXObjectsCounter);
++formXObjectsCounter;
return name;
}
int formXObjectsCounter = 4711;
注意: 我只是编写了这些方法(尽可能多地从原始扁平化代码中复制)并且仅使用您的示例文件进行了测试。对于一般用途,可能仍需考虑某些边界条件。特别是我没有做所有相关的 null
或 0
测试。我也没有尝试支持正确的标记。
Annotation(PdfName.STAMP) 在被 itextsharp5.5.13.1 扁平化后丢失。 我有两个pdf。一个有效,另一个无效。 任何想法将不胜感激。
代码如下
string outFile = inputFile + "_f.pdf";
using (PdfReader pdfReader = new PdfReader(inputFileName))
{
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(outFile, FileMode.Create, FileAccess.Write, FileShare.None))
//pdfStamper.FormFlattening = true;
//pdfStamper.FreeTextFlattening = true;
pdfStamper.AnnotationFlattening = true;
//pdfStamper.AcroFields.GenerateAppearances = true;
}
原因是iTextSharp中的一个错误,如果其边界框不使用原点,则注释展平无法正确计算展平注释的位置左下角.
如果你看一下 PdfStamperImp.FlattenAnnotations(bool)
的代码,你会很快意识到 if (app != null)
块中的计算只有在边界框位于原点或没有缩放时才有意义将外观边界框装入注释矩形所必需的。
(由于边界框的左下角通常是原点,因此不会经常弹出。)
因此,要展平 此类注释,您必须使用不同的展平方法, 例如像这样:
using (PdfReader pdfReader = new PdfReader(inputFileName))
{
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(outFile, FileMode.Create, FileAccess.Write, FileShare.None));
ImprovedAnnotationFlattening(pdfStamper);
pdfStamper.Close();
}
使用这些辅助方法:
void ImprovedAnnotationFlattening(PdfStamper pdfStamper)
{
double[] DEFAULT_MATRIX = { 1, 0, 0, 1, 0, 0 };
PdfReader reader = pdfStamper.Reader;
for (int page = 1; page <= reader.NumberOfPages; ++page)
{
PdfDictionary pageDic = reader.GetPageN(page);
PdfArray annots = pageDic.GetAsArray(PdfName.ANNOTS);
if (annots == null)
continue;
for (int idx = 0; idx < annots.Size; ++idx)
{
PdfObject annoto = annots.GetDirectObject(idx);
if (!(annoto is PdfDictionary))
continue;
PdfDictionary annDic = (PdfDictionary)annoto;
PdfNumber ff = annDic.GetAsNumber(PdfName.F);
int flags = ff != null ? ff.IntValue : 0;
if ((flags & PdfFormField.FLAGS_PRINT) == 0 || (flags & PdfFormField.FLAGS_HIDDEN) != 0)
continue;
PdfObject obj1 = annDic.Get(PdfName.AP);
if (obj1 == null)
continue;
PdfDictionary appDic = obj1 is PdfIndirectReference
? (PdfDictionary)PdfReader.GetPdfObject(obj1)
: (PdfDictionary)obj1;
PdfObject obj = appDic.Get(PdfName.N);
PdfStream objDict = appDic.GetAsStream(PdfName.N);
if (objDict != null)
{
Rectangle rect = PdfReader.GetNormalizedRectangle(annDic.GetAsArray(PdfName.RECT));
Rectangle bbox = PdfReader.GetNormalizedRectangle(objDict.GetAsArray(PdfName.BBOX));
PdfContentByte cb = pdfStamper.GetOverContent(page);
cb.SetLiteral("Q ");
PdfArray matrixArray = objDict.GetAsArray(PdfName.MATRIX);
double[] matrix = matrixArray != null ? matrixArray.AsDoubleArray() : DEFAULT_MATRIX;
AffineTransform transform = new AffineTransform(matrix);
double[] bboxCorners = { bbox.Left, bbox.Bottom, bbox.Right, bbox.Bottom, bbox.Right, bbox.Top, bbox.Left, bbox.Top };
transform.Transform(bboxCorners, 0, bboxCorners, 0, 4);
double minX = Min(bboxCorners, 0, 2);
double maxX = Max(bboxCorners, 0, 2);
double minY = Min(bboxCorners, 1, 2);
double maxY = Max(bboxCorners, 1, 2);
transform.preConcatenate(AffineTransform.GetTranslateInstance(-minX, -minY));
transform.preConcatenate(AffineTransform.GetScaleInstance(rect.Width/(maxX-minX), rect.Height/(maxY-minY)));
transform.preConcatenate(AffineTransform.GetTranslateInstance(rect.Left, rect.Bottom));
transform.GetMatrix(matrix);
cb.AddFormXObj(objDict, GenerateName(), matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
cb.SetLiteral("q ");
annots.Remove(idx);
--idx;
}
}
}
}
double Min(double[] array, int start, int step)
{
double result = array[start];
for (int i = start + step; i < array.Length; i+=step)
{
result = Math.Min(result, array[i]);
}
return result;
}
double Max(double[] array, int start, int step)
{
double result = array[start];
for (int i = start + step; i < array.Length; i += step)
{
result = Math.Max(result, array[i]);
}
return result;
}
PdfName GenerateName()
{
PdfName name = new PdfName("XXX" + formXObjectsCounter);
++formXObjectsCounter;
return name;
}
int formXObjectsCounter = 4711;
注意: 我只是编写了这些方法(尽可能多地从原始扁平化代码中复制)并且仅使用您的示例文件进行了测试。对于一般用途,可能仍需考虑某些边界条件。特别是我没有做所有相关的 null
或 0
测试。我也没有尝试支持正确的标记。