【问题标题】:Convert image data (PDEImage) in PDF to DIB using C++?使用 C++ 将 PDF 中的图像数据 (PDEImage) 转换为 DIB?
【发布时间】:2012-02-23 07:16:13
【问题描述】:

我正在尝试提取 PDF 中的所有图像,然后将它们转换为 DIB 格式。第一部分很简单。我提取 PDF 中的所有内容,然后遍历它们,每当找到 PDEImage 时,我将它们放入一个数组中。

但我对如何进行第二部分一无所知。看起来所有 AVConversion 方法都允许您将 PDF 的整个页面,而不仅仅是图像,转换为其他格式。

有什么方法可以完成这项任务吗?提前致谢!

编辑:进一步阐述问题。

我正在使用带有 .NET Framework 4 的 Visual C++ 编写一个 Adob​​e Acrobat 插件。

插件的目的是(除其他外)从 PDF 文件中提取图像数据,然后将这些数据转换为 DIB。需要转换为 DIS 是因为我将这些 DIB 传递给另一个库,该库对它们进行一些图像校正工作。

现在我的问题是将 PDF 中的上述图像数据转换为 DIB。 PDF 上的图像数据以一种称为 PDEImage(参考链接)的格式找到,其中显然包含图像的所有颜色数据。现在我使用以下代码从图像中提取所述图像数据位,以与 CreateCompatibleBitmap() 和 SetBitmapBits() 一起使用以获得 HBITMAP 句柄。然后,我将它与其他必要参数一起传递给 GetDIBits() 以获取 MSDN 中所述的字节数组形式的 DIB。

void GetDIBImage(PDEElement element)
{
    //Obtaining a PDEImage
    PDEImage image;
    memset(&image, 0, sizeof(PDEImage));
    image = (PDEImage)element;

    //Obtaining attributes (such as width, height)
    //of the image for later use
    PDEImageAttrs attrs;
    memset(&attrs, 0, sizeof(attrs));
    PDEImageGetAttrs(image, &attrs, sizeof(attrs));

    //Obtainig image data from PDEImage to a byte array
    ASInt32 len = PDEImageGetDataLen(image);
    byte *data = (byte *)malloc(len);
    PDEImageGetData(image, 0, data);

    //Creating a DDB using said data
    HDC hdc = CreateCompatibleDC(NULL); 
    HBITMAP hBmp = CreateCompatibleBitmap(hdc, attrs.width, attrs.height);  
    LONG bitsSet = SetBitmapBits(hBmp, len, data);  //Here bitsSet gets a value of 59000 which is close to the image's actual size

    //Buffer which GetDIBits() will fill with DIB data
    unsigned char* buff = new unsigned char[len];

    //BITMAPINFO stucture to be passed to GetDIBits()
    BITMAPINFO bmpInfo;
    memset(&bmpInfo, 0, sizeof(bmpInfo));

    bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmpInfo.bmiHeader.biWidth = (LONG)attrs.width;
    bmpInfo.bmiHeader.biHeight = (LONG)attrs.height;
    bmpInfo.bmiHeader.biPlanes = 1;
    bmpInfo.bmiHeader.biBitCount = 8;
    bmpInfo.bmiHeader.biCompression = BI_RGB;
    bmpInfo.bmiHeader.biSizeImage = ((((bmpInfo.bmiHeader.biWidth * bmpInfo.bmiHeader.biBitCount) + 31) & ~31) >> 3) * bmpInfo.bmiHeader.biHeight;  
    bmpInfo.bmiHeader.biXPelsPerMeter = 0;
    bmpInfo.bmiHeader.biYPelsPerMeter = 0;
    bmpInfo.bmiHeader.biClrUsed = 0;
    bmpInfo.bmiHeader.biClrImportant = 0;

    //Callling GetDIBits()
    //Here scanLines get a value of 0, while buff receives no data.
    int scanLines = GetDIBits(hdc, hBmp, 0, attrs.height, &buff, &bmpInfo, DIB_RGB_COLORS);

    if(scanLines > 0)
    {
        MessageBox(NULL, L"SUCCESS", L"Message", MB_OK);
    }
    else
    {
        MessageBox(NULL, L"FAIL", L"Message", MB_OK);
    }
}

这是我的问题/疑虑。

  1. 我使用 CreateCompatibleDC()、CreateCompatibleBitmap() 和 SetBitmapBits() 函数的方式是否正确?我的想法是我使用 CreateCompatibleDC() 获取当前 DC,然后使用 CreateCompatibleBitmap() 创建一个 DDB,然后使用 SetBitmapBits() 将实际数据设置到 DDB。对吗?

  2. 我创建 BITMAPINFO 结构的方式是否存在问题。我假设它需要包含有关我最终将获得的 DIB 格式的所有详细信息。

  3. 为什么我在调用 GetDIBits() 时没有将位图数据作为 DIB 获取到缓冲区?

【问题讨论】:

    标签: pdf dib


    【解决方案1】:

    我不知道您用于访问 PDF 文件内部结构的库,但手头的问题将有树不同的子问题:

    1. 查找 PDF 文件中的所有图像
    2. 将图像解码为其组件
    3. 将解码后的图像转换为 DIB

    查找所有图片

    图像可以出现在内容流中或附加到字典的流中。要在内容流中查找所有图像,您需要在 Pages、XObjects 或 Patterns 中查找所有内容流。每一个都可以有一个 Resources -> XObject 字典,它引用所有的 XObject(并且一个 XObject 可以是一个图像)。

    如果您避免使用内联图像,您可以简单地扫描 PDF 文件,并且可以解码每个 XObject 子类型 Image 类型的说明。

    解码

    PDF 文件中单独对象中的所有流(内容流中的内联)都经过编码,可能需要使用 Decode 数组进行后处理。您需要能够执行多个过滤器才能进行解码。 Flate decode (ZLIB)、JPEG 和 CCITT (fax G3/G4) 可能最常用于图像。希望您使用的 PDF 库知道如何解码流..

    接下来是解码数组(有点少见),其中每个颜色分量都可以从输入值缩放到输出值。这是一个线性变换。

    到 DIB

    接下来是将解码图像转换为 DIB。这意味着您需要将颜色组件转换为 Windows 可以“获取”的内容(例如,调色板、RGB 的灰度(特殊调色板)。PDF 支持非常多的颜色空间,将它们转换为 RGB 并非难事。你最好希望在这里您需要处理的 PDF 只使用一个选择子集(如 RGB 和调色板)。现在可以通过创建位图标题 (BITMAPINFO) 来简单地创建一个 DIB,填写所有数据并调用 DIB 创建函数 CreateDIBSection 和他们按照您的应用程序需要的方式处理 DIB。

    结语

    总而言之:能够处理所有 PDF 文件并找到所有图像是一项艰巨的任务,如果您控制 PDF 的源并且您知道它们始终是 DeviceRGB 格式并且始终是 JPEG 等,并且从不内联到内容流是可行的。

    【讨论】:

    • 1.找到我想要转换 PDEImage 对象的所有图像,这些对象是 XObjects 对吗?我遍历每个 PDF 页面的内容并获取它们,我可以做得很好。 2.解码这是我认为我有问题的地方。我的印象是 PDEImageGetData(image, 0, data) 将用图像中的颜色数据填充数据缓冲区。我对 PDF 非常陌生,所以我不确定你所说的解码是什么意思。您是否碰巧有代码示例? 3. 对于 DIB,我认为我可以为此目的使用 CreateDIBSection。那么,如果我只是将上面获得的数据数组传递给它,它不会起作用吗?
    • @Sach:我不知道解码您的 PDF 库已经做了什么。但让我们假设它不解码流。现在,用于颜色/调色板图像的两种最常用的编码是 Flate (ZLib) 和 JPEG 解码。因此,如果您知道如何使用 ZLib 并拥有 JPEG 解码器,您的代码可能如下所示:打开 PDF 文件 -> 扫描文件中的所有对象。如果 object 是字典并且有一个流并且 type = XObject ans 子类型是 Image -> decode stream 如果需要的话。现在您有了可以提供给 DIB IF 的原始字节,并且只有当 Windows 支持使用的颜色空间时。如果是 Lab 或 Separed colorspace 怎么办...
    • 我不明白你所说的“如果需要,解码流”。我所做的是,我提取 PDEImage 对象,然后我想将它们转换为 DIB,以便我可以将这些 DIB(以 BYTE 数组形式)发送到一个单独的库,该库进行一些颜色编辑/校正工作。我不熟悉 ZLib 以及如何解码图像。我有幸知道色彩空间只能是 sRGB 或 Adob​​eRGB 之一。
    • Sach:PDF 支持大量的色彩空间。灰度和 RGB 是两个,但它们可以是设备特定的或校准的,或基于 ICC。您还有 CMYK(用于打印)、Lab、Separation、DeviceN、Indexed(基于调色板)。将所有这些转换为 sRGB 需要 1000 行代码,而且非常棘手。希望您不需要支持那么多色彩空间。 PDF 还支持每个颜色分量 1、2、4、8 和 16 位数据,而 Windows 仅支持 1、4 和 8。不幸的是,对于有多种编码的编码流也是如此。哦,我有没有提到可能的加密?
    • @Sach:这里的问题是:你想要的看起来很简单,对于大多数 PDF,你只需要 DeviceRGB 和 JPEGDecode / FlateDecode。如果是JPEGDecode,则找到的字节数组只是一个JPEG文件。对于 FlateDecode,只需使用 ZLib(应该是几乎所有编程语言的库)解码字节,从而产生图像的原始字节。也许您可以阅读 ISO32000 标准以获得更好的理解。专注于色彩空间、流和文档结构,你应该很好地理解你所面临的..
    猜你喜欢
    • 2015-12-14
    • 2016-04-24
    • 2011-03-30
    • 1970-01-01
    • 2012-06-28
    • 2020-06-28
    • 2016-02-11
    • 2012-08-23
    • 2020-06-27
    相关资源
    最近更新 更多