0

我正在尝试提取 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 获取到 buff?

4

1 回答 1

0

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

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

查找所有图片

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

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

解码

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 等,并且从不内联到内容流中这是可行的。

于 2012-03-04T20:10:55.880 回答