使用iTextSharp解码为FlateDecode时,为什么我的图像会失真?

Aar*_*ver 4 c# pdf itext itextsharp

FlateDecode通过iTextSharp 解码PDF中的图像时,图像会失真,我似乎无法弄清楚原因.

公认的bpp是Format1bppIndexed.如果我修改PixelFormatFormat4bppIndexed的图像是可识别的在一定程度上(缩水,着色是关闭的,但可读),并以水平的方式被复制的4倍.如果我调整像素格式,Format8bppIndexed它在某种程度上也是可识别的,并且以水平方式重复8次.

下图是采用Format1bppIndexed像素格式的方法.不幸的是,由于安全限制,我无法展示其他人.

扭曲的形象

代码如下所示,这实际上是我遇到的SO和Web的单一解决方案.

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);
}
Run Code Online (Sandbox Code Playgroud)

我需要做什么才能使我的图像提取在处理时按预期工作FlateDecode

注意:我不想使用其他库来提取图像.我正在寻找一个利用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 []长度等于width height/8,因为GetStreamBytes应该调用FlateDecode.手动调用FlateDecode和调用PdfReader.GetStreamBytes 两者产生的字节[]长度为1049401,而宽度高度/ 8为2544*3300/8或1049400,因此存在差异1.不确定这是否是根本原因,一个人; 但是,如果情况确实如此,我不知道如何解决.

更新:在尝试kuujinbo提到的方法时,我遇到了一个IndexOutOfRangeException当我试图renderInfo.GetImage();RenderImage听众中打电话时.与调用时字节[]长度相比,前面所述宽度*高度/ 8减去1的事实FlateDecode使我认为这些都是同一个; 然而,解决方案仍然无法解决.

   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)
Run Code Online (Sandbox Code Playgroud)

更新:尝试改变我原始解决方案中列出的变化方法,以及由kuujinbo在PDF中使用不同页面提出的解决方案,生成图像; 但是,当过滤器类型是/FlateDecode并且没有为该给定实例生成图像时,问题总是浮出水面.

big*_*san 10

尝试逐行复制数据,也许它会解决问题.

int w = imgObj.GetAsNumber(PdfName.WIDTH).IntValue;
int h = imgObj.GetAsNumber(PdfName.HEIGHT).IntValue;
int bpp = imgObj.GetAsNumber(PdfName.BITSPERCOMPONENT).IntValue;
var pixelFormat = PixelFormat.Format1bppIndexed;

byte[] rawBytes = PdfReader.GetStreamBytesRaw((PRStream)imgObj);
byte[] decodedBytes = PdfReader.FlateDecode(rawBytes);
byte[] streamBytes = PdfReader.DecodePredictor(decodedBytes, imgObj.GetAsDict(PdfName.DECODEPARMS));
// byte[] streamBytes = PdfReader.GetStreamBytes((PRStream)imgObj); // same result as above 3 lines of code.

using (Bitmap bmp = new Bitmap(w, h, pixelFormat))
{
    var bmpData = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.WriteOnly, pixelFormat);
    int length = (int)Math.Ceiling(w * bpp / 8.0);
    for (int i = 0; i < h; i++)
    {
        int offset = i * length;
        int scanOffset = i * bmpData.Stride;
        Marshal.Copy(streamBytes, offset, new IntPtr(bmpData.Scan0.ToInt32() + scanOffset), length);
    }
    bmp.UnlockBits(bmpData);

    bmp.Save(fileName);
}
Run Code Online (Sandbox Code Playgroud)