使用C ++将PDF格式的图像数据(PDEImage)转换为DIB?

时间:2012-02-23 07:16:14

标签: pdf dib

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

但我对如何处理第二部分毫无头绪。看起来所有AVConversion方法都允许您将PDF的整页(而不仅仅是图像)转换为其他格式。

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

编辑:进一步阐述问题。

我正在使用Visual C ++和.NET Framework 4编写Adobe Acrobat插件。

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

现在我的问题是将PDF中的所述图像数据转换为DIB。 PDF上的图像数据以称为PDEImage(Ref Link)的格式找到,显然它包含图像的所有颜色数据。现在我使用以下代码从要与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?

1 个答案:

答案 0 :(得分:0)

我不知道你用来访问PDF文件内部结构的库,但是手头的问题会有树不同的子问题:

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

    图像可以在内容流内或附加到词典的流中发生。要查找内容流中的所有图像,您需要在Pages,XObjects或Patterns中查找所有内容流。每个都可以有一个资源 - >引用所有XObject的XObject字典(和XObject可以是图像)。

    如果您避开内联图像,则可能只是扫描PDF文件,并且可以解码XObject子类型Image的每个dectionary。

    解码

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

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

    致DIB

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

    后记

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