I am trying to extract all the images in a PDF and then convert them into DIB format using an Acrobat plugin. First part is easy. I extract all the contents in the PDF, then iterate through them and whenever I find a PDEImage, I put them in an array.

But I am clueless about how to go about the second part. Looks like all the AVConversion methods allow you to convert a whole page of a PDF, not just images, into other formats.

Is there any way I can accomplish this task? Thanks in advance!

Recommended Answers

All 7 Replies

I am trying to extract all the images in a PDF and then convert them into DIB format using an Acrobat plugin. First part is easy. I extract all the contents in the PDF, then iterate through them and whenever I find a PDEImage, I put them in an array.

But I am clueless about how to go about the second part. Looks like all the AVConversion methods allow you to convert a whole page of a PDF, not just images, into other formats.

Is there any way I can accomplish this task? Thanks in advance!

You may have to use the Win32 API to convert your PDEImage to DIB. Specifically, a starting point would be CreateDIBSection as found in the following link

http://msdn.microsoft.com/en-us/library/dd183494%28v=vs.85%29.aspx

Thanks for the reply Bob. I will take a look. Meantime it would be great if you could direct me in the right direction, especially with a code sample.

Thanks for the reply Bob. I will take a look. Meantime it would be great if you could direct me in the right direction, especially with a code sample.

First of all my caveat. This is nothing but pure theory sample code since I am totally unfamiliar with the PDE format.

You'll have to replace the LoadImage function in line 152 with a function that can return a HBITMAP handle from your PDE data.

Finally, the sample code must be thoroughly tested to verify it's accuracy and completeness.

#pragma comment(lib, "user32.lib") 
#pragma comment(lib, "gdi32.lib") 
#include <windows.h>
#include <stdio.h>

int SaveBitmap(char *szFilename, HBITMAP hBitmap)
{
    HDC        hdc=NULL;
    FILE*      fp=NULL;
    LPVOID     pBuf=NULL;
    BITMAPINFO bmpInfo;
    BITMAPFILEHEADER  bmpFileHeader;
    do
    {
        hdc=GetDC(NULL);
        ZeroMemory(&bmpInfo,sizeof(BITMAPINFO));
        bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
        GetDIBits(hdc,hBitmap,0,0,NULL,&bmpInfo,DIB_RGB_COLORS);
        if(bmpInfo.bmiHeader.biSizeImage<=0)
            bmpInfo.bmiHeader.biSizeImage=bmpInfo.bmiHeader.biWidth*abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8;
        if((pBuf = malloc(bmpInfo.bmiHeader.biSizeImage))==NULL)
        {
            printf("Unable to Allocate Bitmap Memory", "Error\n");
            return -1;
        }
        bmpInfo.bmiHeader.biCompression=BI_RGB;
        GetDIBits(hdc,hBitmap,0,bmpInfo.bmiHeader.biHeight,pBuf, &bmpInfo, DIB_RGB_COLORS);
        if((fp = fopen(szFilename,"wb"))==NULL)
        {
            printf("Unable to Create Bitmap File\n");
            return -1;
        }
        bmpFileHeader.bfReserved1=0;
        bmpFileHeader.bfReserved2=0;
        bmpFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+bmpInfo.bmiHeader.biSizeImage;
        bmpFileHeader.bfType='MB';
        bmpFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
        fwrite(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp);
        fwrite(&bmpInfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);
        fwrite(pBuf,bmpInfo.bmiHeader.biSizeImage,1,fp);
    } while(false);
    if(hdc)     ::ReleaseDC(NULL,hdc);
    if(pBuf)    free(pBuf);
    if(fp)      fclose(fp);
	return 0;
}

// This function converts the given bitmap to a DIB.
bool ConvertToDIB(HBITMAP& hBitmap)
{
    bool bConverted = false;
    BITMAP stBitmap;
    if (GetObject(hBitmap, sizeof(stBitmap),
                  &stBitmap) && !stBitmap.bmBits)
    {
        // that is a DFB. Now we attempt to create
        // a DIB with the same sizes and pixel format.
        HDC hScreen = GetDC(NULL);
        if (hScreen)
        {
            union {
                BITMAPINFO stBitmapInfo;
                BYTE pReserveSpace[sizeof(BITMAPINFO)
                                   + 0xFF * sizeof(RGBQUAD)];
            };
            ZeroMemory(pReserveSpace, sizeof(pReserveSpace));
            stBitmapInfo.bmiHeader.biSize = sizeof(stBitmapInfo.bmiHeader);
            stBitmapInfo.bmiHeader.biWidth = stBitmap.bmWidth;
            stBitmapInfo.bmiHeader.biHeight = stBitmap.bmHeight;
            stBitmapInfo.bmiHeader.biPlanes = 1;
            stBitmapInfo.bmiHeader.biBitCount = stBitmap.bmBitsPixel;
            stBitmapInfo.bmiHeader.biCompression = BI_RGB;

            if (stBitmap.bmBitsPixel <= 8)
            {
                stBitmapInfo.bmiHeader.biClrUsed = 1 << stBitmap.bmBitsPixel;
                // This image is paletted-managed.
                // We have to synthesize its palette.
            }
            stBitmapInfo.bmiHeader.biClrImportant =
                stBitmapInfo.bmiHeader.biClrUsed;

            PVOID pBits;
            HBITMAP hDib = CreateDIBSection(hScreen,
                                            &stBitmapInfo, DIB_RGB_COLORS, &pBits, NULL, 0);

            if (hDib)
            {
                // Now we have to transfer the image to the DFB.
                HDC hMemSrc = CreateCompatibleDC(NULL);
                if (hMemSrc)
                {
                    HGDIOBJ hOldSrc = SelectObject(hMemSrc, hBitmap);
                    if (hOldSrc)
                    {
                        HDC hMemDst = CreateCompatibleDC(NULL);
                        if (hMemDst)
                        {
                            HGDIOBJ hOldDst = SelectObject(hMemDst, hDib);
                            if (hOldDst)
                            {
                                if (stBitmap.bmBitsPixel <= 8)
                                {
                                    // take the DFB's palette and set it to our DIB
                                    HPALETTE hPalette =
                                        (HPALETTE) GetCurrentObject(hMemSrc, OBJ_PAL);
                                    if (hPalette)
                                    {
                                        PALETTEENTRY pPaletteEntries[0x100];
                                        UINT nEntries = GetPaletteEntries(hPalette,
                                                                          0, stBitmapInfo.bmiHeader.biClrUsed,
                                                                          pPaletteEntries);
                                        if (nEntries)
                                        {
                                            for (UINT nIndex = 0; nIndex < nEntries; nIndex++)
                                                pPaletteEntries[nEntries].peFlags = 0;
                                            SetDIBColorTable(hMemDst, 0, nEntries, (RGBQUAD*) pPaletteEntries);
                                        }
                                    }
                                }
                                // transfer the image using BitBlt function.
                                if (BitBlt(hMemDst, 0, 0, stBitmap.bmWidth,
                                           stBitmap.bmHeight, hMemSrc, 0, 0, SRCCOPY))
                                    bConverted = true; // success
                                SelectObject(hMemDst, hOldDst);
                            }
                            DeleteDC(hMemDst);
                        }
                        SelectObject(hMemSrc, hOldSrc);
                    }
                    DeleteDC(hMemSrc);
                }
                if (bConverted)
                {
                    DeleteObject(hBitmap); // it's no longer needed
                    hBitmap = hDib;
                }
                else
                    DeleteObject(hDib);
            }
            ReleaseDC(NULL, hScreen);
        }
    }
    return bConverted;
}

int main(void)
{
    HBITMAP hbitmap;
	// You'll have to replace the LoadImage function with whatever you use
	// to load your PDE.  It must return a HBITMAP handle.  
    hbitmap= (HBITMAP)LoadImage(NULL, "test.bmp",IMAGE_BITMAP, 0,0, LR_LOADFROMFILE );
    if(hbitmap == NULL)
    {
        printf("bitmap not loaded\n");
        return -1;
    }
    ConvertToDIB(hbitmap);
    SaveBitmap("testout.bmp", hbitmap);
    return 0;
}

Thanks a lot mate! I will try this and let you know.

First of all my caveat. This is nothing but pure theory sample code since I am totally unfamiliar with the PDE format.

You'll have to replace the LoadImage function in line 152 with a function that can return a HBITMAP handle from your PDE data.

Finally, the sample code must be thoroughly tested to verify it's accuracy and completeness.

#pragma comment(lib, "user32.lib") 
#pragma comment(lib, "gdi32.lib") 
#include <windows.h>
#include <stdio.h>

int SaveBitmap(char *szFilename, HBITMAP hBitmap)
{
    HDC        hdc=NULL;
    FILE*      fp=NULL;
    LPVOID     pBuf=NULL;
    BITMAPINFO bmpInfo;
    BITMAPFILEHEADER  bmpFileHeader;
    do
    {
        hdc=GetDC(NULL);
        ZeroMemory(&bmpInfo,sizeof(BITMAPINFO));
        bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
        GetDIBits(hdc,hBitmap,0,0,NULL,&bmpInfo,DIB_RGB_COLORS);
        if(bmpInfo.bmiHeader.biSizeImage<=0)
            bmpInfo.bmiHeader.biSizeImage=bmpInfo.bmiHeader.biWidth*abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8;
        if((pBuf = malloc(bmpInfo.bmiHeader.biSizeImage))==NULL)
        {
            printf("Unable to Allocate Bitmap Memory", "Error\n");
            return -1;
        }
        bmpInfo.bmiHeader.biCompression=BI_RGB;
        GetDIBits(hdc,hBitmap,0,bmpInfo.bmiHeader.biHeight,pBuf, &bmpInfo, DIB_RGB_COLORS);
        if((fp = fopen(szFilename,"wb"))==NULL)
        {
            printf("Unable to Create Bitmap File\n");
            return -1;
        }
        bmpFileHeader.bfReserved1=0;
        bmpFileHeader.bfReserved2=0;
        bmpFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+bmpInfo.bmiHeader.biSizeImage;
        bmpFileHeader.bfType='MB';
        bmpFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
        fwrite(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp);
        fwrite(&bmpInfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);
        fwrite(pBuf,bmpInfo.bmiHeader.biSizeImage,1,fp);
    } while(false);
    if(hdc)     ::ReleaseDC(NULL,hdc);
    if(pBuf)    free(pBuf);
    if(fp)      fclose(fp);
	return 0;
}

// This function converts the given bitmap to a DIB.
bool ConvertToDIB(HBITMAP& hBitmap)
{
    bool bConverted = false;
    BITMAP stBitmap;
    if (GetObject(hBitmap, sizeof(stBitmap),
                  &stBitmap) && !stBitmap.bmBits)
    {
        // that is a DFB. Now we attempt to create
        // a DIB with the same sizes and pixel format.
        HDC hScreen = GetDC(NULL);
        if (hScreen)
        {
            union {
                BITMAPINFO stBitmapInfo;
                BYTE pReserveSpace[sizeof(BITMAPINFO)
                                   + 0xFF * sizeof(RGBQUAD)];
            };
            ZeroMemory(pReserveSpace, sizeof(pReserveSpace));
            stBitmapInfo.bmiHeader.biSize = sizeof(stBitmapInfo.bmiHeader);
            stBitmapInfo.bmiHeader.biWidth = stBitmap.bmWidth;
            stBitmapInfo.bmiHeader.biHeight = stBitmap.bmHeight;
            stBitmapInfo.bmiHeader.biPlanes = 1;
            stBitmapInfo.bmiHeader.biBitCount = stBitmap.bmBitsPixel;
            stBitmapInfo.bmiHeader.biCompression = BI_RGB;

            if (stBitmap.bmBitsPixel <= 8)
            {
                stBitmapInfo.bmiHeader.biClrUsed = 1 << stBitmap.bmBitsPixel;
                // This image is paletted-managed.
                // We have to synthesize its palette.
            }
            stBitmapInfo.bmiHeader.biClrImportant =
                stBitmapInfo.bmiHeader.biClrUsed;

            PVOID pBits;
            HBITMAP hDib = CreateDIBSection(hScreen,
                                            &stBitmapInfo, DIB_RGB_COLORS, &pBits, NULL, 0);

            if (hDib)
            {
                // Now we have to transfer the image to the DFB.
                HDC hMemSrc = CreateCompatibleDC(NULL);
                if (hMemSrc)
                {
                    HGDIOBJ hOldSrc = SelectObject(hMemSrc, hBitmap);
                    if (hOldSrc)
                    {
                        HDC hMemDst = CreateCompatibleDC(NULL);
                        if (hMemDst)
                        {
                            HGDIOBJ hOldDst = SelectObject(hMemDst, hDib);
                            if (hOldDst)
                            {
                                if (stBitmap.bmBitsPixel <= 8)
                                {
                                    // take the DFB's palette and set it to our DIB
                                    HPALETTE hPalette =
                                        (HPALETTE) GetCurrentObject(hMemSrc, OBJ_PAL);
                                    if (hPalette)
                                    {
                                        PALETTEENTRY pPaletteEntries[0x100];
                                        UINT nEntries = GetPaletteEntries(hPalette,
                                                                          0, stBitmapInfo.bmiHeader.biClrUsed,
                                                                          pPaletteEntries);
                                        if (nEntries)
                                        {
                                            for (UINT nIndex = 0; nIndex < nEntries; nIndex++)
                                                pPaletteEntries[nEntries].peFlags = 0;
                                            SetDIBColorTable(hMemDst, 0, nEntries, (RGBQUAD*) pPaletteEntries);
                                        }
                                    }
                                }
                                // transfer the image using BitBlt function.
                                if (BitBlt(hMemDst, 0, 0, stBitmap.bmWidth,
                                           stBitmap.bmHeight, hMemSrc, 0, 0, SRCCOPY))
                                    bConverted = true; // success
                                SelectObject(hMemDst, hOldDst);
                            }
                            DeleteDC(hMemDst);
                        }
                        SelectObject(hMemSrc, hOldSrc);
                    }
                    DeleteDC(hMemSrc);
                }
                if (bConverted)
                {
                    DeleteObject(hBitmap); // it's no longer needed
                    hBitmap = hDib;
                }
                else
                    DeleteObject(hDib);
            }
            ReleaseDC(NULL, hScreen);
        }
    }
    return bConverted;
}

int main(void)
{
    HBITMAP hbitmap;
	// You'll have to replace the LoadImage function with whatever you use
	// to load your PDE.  It must return a HBITMAP handle.  
    hbitmap= (HBITMAP)LoadImage(NULL, "test.bmp",IMAGE_BITMAP, 0,0, LR_LOADFROMFILE );
    if(hbitmap == NULL)
    {
        printf("bitmap not loaded\n");
        return -1;
    }
    ConvertToDIB(hbitmap);
    SaveBitmap("testout.bmp", hbitmap);
    return 0;
}

I tried the code but at a bit of a loss as to how to replace the LoadImage() function.
From my PDEImage object, by using an Acrobat API I can extract image data to an ASStm stream (Ref. ASStm). So I'm wondering if there is a Windows API which let me create a HBITMAP handle using that data? Because from what I understand the hbitmap must contain the actual image data, right?

I looked up and found CreateBitmap(), CreateCompatibleBitmap() and CreateDIBitmap() but they all seem to give you a handle to a device dependent bitmap, not a DIB.

I tried the code but at a bit of a loss as to how to replace the LoadImage() function.
From my PDEImage object, by using an Acrobat API I can extract image data to an ASStm stream (Ref. ASStm). So I'm wondering if there is a Windows API which let me create a HBITMAP handle using that data? Because from what I understand the hbitmap must contain the actual image data, right?

I looked up and found CreateBitmap(), CreateCompatibleBitmap() and CreateDIBitmap() but they all seem to give you a handle to a device dependent bitmap, not a DIB.

First of all, my caveat again. I am totally unfamiliar with the Adobe PDE format. With that said, I assumed this "PDE" was probably a Device Dependent Bitmap (DDB). A DDB is suitable for only display (screen or printer) purposes. Also, your post indicated a need to convert a PDE to DIB. The DDB format is not suitable for storing to disk. Thus, the need for a DDB to DIB conversion.

The sample "theory" code would load the PDE in DDB format and then convert the DDB to DIB format using the conversion function. After it is converted to DIB format, it is saved to disk.

The CreateBitmap would create a HBITMAP handle to the DDB. You'll have to use the array of color data from your PDE in the call to CreateBitmap. So, you'll need a detailed understanding of PDE format.

First of all, my caveat again. I am totally unfamiliar with the Adobe PDE format. With that said, I assumed this "PDE" was probably a Device Dependent Bitmap (DDB). A DDB is suitable for only display (screen or printer) purposes. Also, your post indicated a need to convert a PDE to DIB. The DDB format is not suitable for storing to disk. Thus, the need for a DDB to DIB conversion.

The sample "theory" code would load the PDE in DDB format and then convert the DDB to DIB format using the conversion function. After it is converted to DIB format, it is saved to disk.

The CreateBitmap would create a HBITMAP handle to the DDB. You'll have to use the array of color data from your PDE in the call to CreateBitmap. So, you'll need a detailed understanding of PDE format.

I tried a little different approach to the problem. I tried to create a DDB by using color data in the image along with CreateCompatibleBitmap(), and then convert that DDB into a DIB using GetDIBits().
Following is what I did, and the problems I ran into. Do you reckon you can help me with any of the questions there?

I am writing an Adobe Acrobat Plug-in using Visual C++ with .NET Framework 4.

The purpose of the plug-in is to (among other things) extract image data from a PDF file, then convert those data to DIBs. The need to convert to DISs is because I then pass those DIBs to another library which do some image correction work on them.

Now my problem is with converting the said image data in PDFs to DIBs. The image data on PDFs are found in a format called PDEImage (Ref Link) where apparently it contains all the color data of the image. Now I'm using the following code to extract the said image data bits from the image to be used with CreateCompatibleBitmap() and SetBitmapBits() to obtain a HBITMAP handle. Then, I pass that along with other necessary parameters to the GetDIBits() to obtain a DIB in the form of a byte array as stated in the MSDN.

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);
	}
}

Here are my questions / concerns.

  1. Is it correct the way I'm using CreateCompatibleDC(), CreateCompatibleBitmap() and SetBitmapBits() functions? My thinking is that I use CreateCompatibleDC() to obtain current DC, then create a DDB using CreateCompatibleBitmap() and then set the actual data to the DDB using SetBitmapBits(). Is that correct?

[LIST=2]
[*]Is there a problem with the way I've created the BITMAPINFO structure. I am under the assumption that it need to contain all the details regarding the format of the DIB I will eventually obtain.
[/LIST]
[LIST=3]
[*]Why am I not getting the bitmap data as a DIB to the buff when I call GetDIBits()?
[/LIST]
Thanks and any help would be much appreciated!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.