【发布时间】:2011-12-13 17:33:41
【问题描述】:
当通过 iTextSharp 将 PDF 中的图像解码为FlateDecode 时,图像失真,我似乎无法弄清楚原因。
识别的 bpp 是Format1bppIndexed。如果我将PixelFormat 修改为Format4bppIndexed,则图像在某种程度上是可识别的(缩小,着色已关闭但可读),并且以水平方式复制了 4 次。如果我将像素格式调整为Format8bppIndexed,它在某种程度上也是可识别的,并且以水平方式复制了 8 次。
下图采用Format1bppIndexed 像素格式方法。不幸的是,由于安全限制,我无法向其他人展示。
代码如下所示,它基本上是我在 SO 和网络上遇到的单一解决方案。
int xrefIdx = ((PRIndirectReference)obj).Number;
PdfObject pdfObj = doc.GetPdfObject(xrefIdx);
PdfStream str = (PdfStream)(pdfObj);
byte[] bytes = PdfReader.GetStreamBytesRaw((PRStream)str);
string filter = ((PdfArray)tg.Get(PdfName.FILTER))[0].ToString();
string width = tg.Get(PdfName.WIDTH).ToString();
string height = tg.Get(PdfName.HEIGHT).ToString();
string bpp = tg.Get(PdfName.BITSPERCOMPONENT).ToString();
if (filter == "/FlateDecode")
{
bytes = PdfReader.FlateDecode(bytes, true);
System.Drawing.Imaging.PixelFormat pixelFormat;
switch (int.Parse(bpp))
{
case 1:
pixelFormat = System.Drawing.Imaging.PixelFormat.Format1bppIndexed;
break;
case 8:
pixelFormat = System.Drawing.Imaging.PixelFormat.Format8bppIndexed;
break;
case 24:
pixelFormat = System.Drawing.Imaging.PixelFormat.Format24bppRgb;
break;
default:
throw new Exception("Unknown pixel format " + bpp);
}
var bmp = new System.Drawing.Bitmap(Int32.Parse(width), Int32.Parse(height), pixelFormat);
System.Drawing.Imaging.BitmapData bmd = bmp.LockBits(new System.Drawing.Rectangle(0, 0, Int32.Parse(width),
Int32.Parse(height)), System.Drawing.Imaging.ImageLockMode.WriteOnly, pixelFormat);
Marshal.Copy(bytes, 0, bmd.Scan0, bytes.Length);
bmp.UnlockBits(bmd);
bmp.Save(@"C:\temp\my_flate_picture-" + DateTime.Now.Ticks.ToString() + ".png", ImageFormat.Png);
}
在处理FlateDecode 时,我需要做什么才能使我的图像提取工作正常?
注意:我不想使用其他库来提取图像。我正在寻找一种利用ONLY iTextSharp 和.NET FW 的解决方案。如果通过 Java (iText) 存在解决方案,并且可以轻松移植到 .NET FW 位,那也足够了。
更新:ImageMask 属性设置为 true,这意味着没有色彩空间,因此隐含黑白。当 bpp 为 1 时,PixelFormat 应该是 Format1bppIndexed,如前所述,它会生成上面看到的嵌入图像。
更新:为了获得图像大小,我使用 Acrobat X Pro 将其提取出来,此特定示例的图像大小被列为 2403x3005。通过 iTextSharp 提取时,大小被列为 2544x3300。我在调试器中修改了图像大小以镜像 2403x3005 但是在调用 Marshal.Copy(bytes, 0, bmd.Scan0, bytes.Length); 时出现异常。
试图读取或写入受保护的内存。这通常是一个 指示其他内存已损坏。
我的假设是这是由于修改了大小,因此不再对应正在使用的字节数据。
更新:根据 Jimmy 的建议,我验证调用 PdfReader.GetStreamBytes 返回的 byte[] 长度等于 widthheight/8,因为 GetStreamBytes 应该调用 FlateDecode。手动调用FlateDecode和调用PdfReader.GetStreamBytes都产生了byte[]长度为1049401,而widthheight/8为2544*3300/8或1049400,所以相差1。不确定是否这将是根本原因与否,一个关闭;但是,如果确实如此,我不确定如何解决。
更新:在尝试 kuujinbo 提到的方法时,当我尝试在 RenderImage 侦听器中调用 renderInfo.GetImage(); 时,我遇到了 IndexOutOfRangeException。前面提到的 width*height/8 在调用FlateDecode 时与 byte[] 长度相比相差 1,这让我认为这些都是同一个;但是我仍然找不到解决方案。
at System.util.zlib.Adler32.adler32(Int64 adler, Byte[] buf, Int32 index, Int32 len)
at System.util.zlib.ZStream.read_buf(Byte[] buf, Int32 start, Int32 size)
at System.util.zlib.Deflate.fill_window()
at System.util.zlib.Deflate.deflate_slow(Int32 flush)
at System.util.zlib.Deflate.deflate(ZStream strm, Int32 flush)
at System.util.zlib.ZStream.deflate(Int32 flush)
at System.util.zlib.ZDeflaterOutputStream.Write(Byte[] b, Int32 off, Int32 len)
at iTextSharp.text.pdf.codec.PngWriter.WriteData(Byte[] data, Int32 stride)
at iTextSharp.text.pdf.parser.PdfImageObject.DecodeImageBytes()
at iTextSharp.text.pdf.parser.PdfImageObject..ctor(PdfDictionary dictionary, Byte[] samples)
at iTextSharp.text.pdf.parser.PdfImageObject..ctor(PRStream stream)
at iTextSharp.text.pdf.parser.ImageRenderInfo.PrepareImageObject()
at iTextSharp.text.pdf.parser.ImageRenderInfo.GetImage()
at cyos.infrastructure.Core.MyImageRenderListener.RenderImage(ImageRenderInfo renderInfo)
更新:尝试改变我的原始解决方案中列出的不同方法以及 kuujinbo 提出的解决方案,在 PDF 中使用不同的页面会产生图像;但是,当过滤器类型为 /FlateDecode 并且没有为该给定实例生成图像时,问题总是会浮出水面。
【问题讨论】:
-
图片是怎么变形的?可以发截图吗?听起来您在某处步幅错误,或者乘数不正确。
-
这与这个问题有关吗? stackoverflow.com/questions/757265/…如果没有,我会在有机会时尝试更深入地挖掘
-
看起来您的步幅确实有误。嗯,当我以前定期进行图像阅读时,这种事情会一直发生。您需要检查
width、height和bpp的值是否符合您的预期。尝试在调试器中更改它们,直到获得正确的结果,然后返回到您从文件中读取的内容。 -
@ChrisHaas 我不确定是不是这样。看起来它可能是但是到目前为止我所知道的一切都表明指定的
PixelFormat是准确的,但结果却不是。 -
我假设 GetStreamBytes 将代表您调用 FlateDecode。你检查过 bytes.length 是否等于(height*width/8)?我会相信图像字典中的宽度和高度(而不是 Adobe Acrobat 给出的值)。我最近做了类似的事情,但是因为我一直在使用 Java,所以我没有 C# 中的内存访问权限(我已经单独绘制了像素)。希望你能把它整理好。
标签: c# pdf itextsharp itext