【问题标题】:PixelFormat for PNG image in PDFPDF中PNG图像的PixelFormat
【发布时间】:2019-09-30 11:45:26
【问题描述】:

我正在尝试使用PDFsharp library 提取图像。如示例程序中所述,该库不支持提取非JPEG图像,因此,我正在尝试自己做。

出于同样的目的,我发现了一个不工作的sample program。我正在使用以下代码提取嵌入在 PDF 文件中的400 x 400 PNG 图像(该图像首先插入到 MS Word 文件中,然后保存为 PDF 文件)。

PDF 文件链接:

https://drive.google.com/open?id=1aB-SrMB3eu00BywliOBC8AW0JqRa0Hbd

提取码:

 static void ExportAsPngImage(PdfDictionary image, ref int count)
    {
        int width = image.Elements.GetInteger(PdfSharp.Pdf.Advanced.PdfImage.Keys.Width);
        int height = image.Elements.GetInteger(PdfSharp.Pdf.Advanced.PdfImage.Keys.Height);            
        System.Drawing.Imaging.PixelFormat pixelFormat = System.Drawing.Imaging.PixelFormat.Format8bppIndexed;           

        byte[] original_byte_boundary = image.Stream.UnfilteredValue;
        byte[] result_byte_boundary = null;           

        //Image data in BMP files always starts at a DWORD boundary, in PDF it starts at a BYTE boundary.            
        //You must copy the image data line by line and start each line at the DWORD boundary.

            byte[, ,] copy_dword_boundary = new byte[3, height, width];

        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                if (x <= width && (x + (y * width) != original_byte_boundary.Length))
                // while not at end of line, take orignale array
                {
                    copy_dword_boundary[0, y, x] = original_byte_boundary[3*x + (y * width)];
                    copy_dword_boundary[1, y, x] = original_byte_boundary[3*x + (y * width) + 1];
                    copy_dword_boundary[2, y, x] = original_byte_boundary[3*x + (y * width) + 2];
                }
                else //fill new array with ending 0
                {
                    copy_dword_boundary[0, y, x] = 0;
                    copy_dword_boundary[1, y, x] = 0;
                    copy_dword_boundary[2, y, x] = 0;
                }
            }
        }
        result_byte_boundary = new byte[3 * width * height];
        int counter = 0;
        int n_width = copy_dword_boundary.GetLength(2);
        int n_height = copy_dword_boundary.GetLength(1);

        for (int x = 0; x < width; x++)
        {
            for (int y = 0; y < height; y++)
            {   //put 3dim array back in 1dim array
                result_byte_boundary[counter] = copy_dword_boundary[0, x, y];
                result_byte_boundary[counter + 1] = copy_dword_boundary[1, x, y];
                result_byte_boundary[counter + 2] = copy_dword_boundary[2, x, y];

                //counter++;
                counter = counter + 3;
            }
        }


        Bitmap bmp = new Bitmap(width, height, pixelFormat);            
        System.Drawing.Imaging.BitmapData bmd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat);
        System.Runtime.InteropServices.Marshal.Copy(result_byte_boundary, 0, bmd.Scan0, result_byte_boundary.Length);
        bmp.UnlockBits(bmd);
        using (FileStream fs = new FileStream(@"D:\TestPdf\" + String.Format("Image{0}.png", count), FileMode.Create, FileAccess.Write))
        {
            bmp.Save(fs, ImageFormat.Png);
            count++;
        }
    }

问题:

无论我选择什么PixelFormat 格式,保存的PNG 图像看起来都不正确。

原始 PNG 图像(位深 32):

PixelFormat = Format24bppRgb 的结果

【问题讨论】:

  • 流位的格式化方式有多种选择,因此通用解决方案可能超出了堆栈溢出答案的范围。是否可以查看具有适当许可证且已实现图像导出功能的开源 PDF 库的代码以获取灵感?
  • @mkl:您能否推荐一个可以可靠地从 PDF 中提取图像的开源库。 Bit Miracle 的库对我来说工作可靠,但它不是开源的。
  • 您的问题与 iText 无关,我删除了标签。
  • 我不做大规模图像提取,所以我不能谈论可靠性。此外,可靠性可能是出现的图像类型的问题:PDF 允许图像有多种变化......此外请注意,根据您让自己受到启发的方式,可能会产生许可方面的后果:如果您只是复制非平凡代码,您很可能会受到您复制的源库的许可的约束。
  • @mkl:我知道我不能简单地复制粘贴非平凡的代码 :) 我只需要一些灵感代码来提取图像。我不需要付费图书馆提供的其他功能。

标签: c# pdf png pdfsharp


【解决方案1】:

您可以从 PDF 文件中获取像素格式。由于您没有在帖子中包含 PDF,因此我无法告诉您哪种格式是正确的。

PDF 文件不包含 PNG 图像,而是使用一种特殊的 PDF 图像格式,这种格式有点类似于 Windows 使用的 BMP 文件,但在二进制数据中没有任何标题。相反,可以使用 Image 对象的属性找到“标题”信息。有关详细信息,请参阅 PDF 参考。

【讨论】:

  • 我添加了指向 PDF 文件的链接。
  • 在 PDF 中可以找到 /ColorSpace/DeviceRGB/BitsPerComponent 8,所以我认为 Format24bppRgb 是正确的。也许你复制的代码只支持 8 bpp,但不支持 24 bpp。分配的缓冲区每个像素只有一个字节,而不是三个。
  • 我已经更新了代码,使其可以处理 24 bpp。我创建了一个 3D 数组而不是 1D。我已经更新了我的问题中的代码,但结果仍然不正确(也更新了帖子中的新结果)。
猜你喜欢
  • 2020-08-18
  • 2014-01-07
  • 2020-06-24
  • 1970-01-01
  • 1970-01-01
  • 2013-10-03
  • 2017-03-01
  • 1970-01-01
  • 2012-05-15
相关资源
最近更新 更多