Thread: Resizing bmp.

  1. #1
    Registered User
    Join Date
    Nov 2003
    Posts
    5

    Resizing bmp.

    Greetings,

    I am trying to resize a bitmap in memory using
    StretchDIBits and GetDIBits and, in turn, output
    the file to a BIP format.

    Without resizing the following code works fine
    when outputting a BIP.

    Code:
      
     
       out_byte = (BYTE *) calloc(NCOLS*JP2_CHANNELS,1);
       if (out_byte == NULL) return false;
       out_data = (BYTE *) calloc(NCOLS*NROWS*JP2_CHANNELS,1);
       if (out_data == NULL)
       {
    	   free(out_byte);
    	   return false;
       }
    
       // Open output bip and hdr files.
       success = true;
       success = success && (! ((out_bip = fopen(bip_path,"wb")) == NULL));
       success = success && (! ((out_hdr = fopen(hdr_path,"w")) == NULL));
    
      // Get source image
      // Contains Data and BITMAPINFO header.
       GetImage(Path,this->m_timage);
    
       BYTE *pData = (BYTE *)this->m_timage.Data;
    
    		// Have to flip bmp and change windows BGR to RGB.
    		for(int y = NROWS - 1; y >= 0; y--)
    		{
    			pData2 += (y * NCOLS * JP2_CHANNELS);
    
    			for(int x = 0; x < NCOLS*JP2_CHANNELS; x+=JP2_CHANNELS)
    			{
    				out_byte[x]   = pData2[2];  //R
    				out_byte[x+1] = pData2[1];  //G
    				out_byte[x+2] = pData2[0];  //B
    				pData2 += 3;
    			}
    			// Write out entire line.
    			fwrite(out_byte,1,NCOLS*JP2_CHANNELS,out_bip);
    			// Reset pData to bottom of image.
    			//pData = (BYTE *)this->m_timage.Data;
    			pData2 = out_data;
    		}
    
    
       free (out_byte);
       free (out_data);
    The above code is not compilable but should
    give a rough idea of what I am doing.

    When I attempt to add resizing in the picture
    I get an empty black image:

    Code:
       out_byte = (BYTE *) calloc(NCOLS*JP2_CHANNELS,1);
       if (out_byte == NULL) return false;
       out_data = (BYTE *) calloc(NCOLS*NROWS*JP2_CHANNELS,1);
       if (out_data == NULL)
       {
    	   free(out_byte);
    	   return false;
       }
    
       // Open output bip and hdr files.
       success = true;
       success = success && (! ((out_bip = fopen(bip_path,"wb")) == NULL));
       success = success && (! ((out_hdr = fopen(hdr_path,"w")) == NULL));
    
      // Get source image
      // Contains Data and BITMAPINFO header.
       GetImage(Path,this->m_timage);
    
     HDC MemDC = CreateCompatibleDC(NULL);
       //HBITMAP BmpHnd = CreateBitmap(NCOLS,NROWS,1,24,NULL);
       HBITMAP BmpHnd = CreateCompatibleBitmap(MemDC, NCOLS, NROWS); 
       HBITMAP OldBmp = (HBITMAP) SelectObject(MemDC,BmpHnd);
       StretchDIBits(MemDC,0,0,NCOLS,NROWS,0,0,this->Cols,this->Rows,this->m_timage.Data,&(this->m_timage.Info),DIB_RGB_COLORS,SRCCOPY);
       int numScanned = GetDIBits(MemDC,BmpHnd,0,NROWS-1,out_data,&Info,DIB_RGB_COLORS);
       char t[256];
       sprintf(t, "num scanned: %d\n", numScanned);
       OutputDebugString(t);
       //int err = GetLastError();
       //char t[256];
       //sprintf(t, "error message: %d\n", err);
       //OutputDebugString(t);
    
    	SelectObject(MemDC,OldBmp);
    	DeleteObject(BmpHnd);
    
       BYTE *pData = out_data;
    
    
    		// Have to flip bmp and change windows BGR to RGB.
    		for(int y = NROWS - 1; y >= 0; y--)
    		{
    			pData2 += (y * NCOLS * JP2_CHANNELS);
    
    			for(int x = 0; x < NCOLS*JP2_CHANNELS; x+=JP2_CHANNELS)
    			{
    				out_byte[x]   = pData2[2];  //R
    				out_byte[x+1] = pData2[1];  //G
    				out_byte[x+2] = pData2[0];  //B
    				pData2 += 3;
    			}
    			// Write out entire line.
    			fwrite(out_byte,1,NCOLS*JP2_CHANNELS,out_bip);
    			// Reset pData to bottom of image.
    			//pData = (BYTE *)this->m_timage.Data;
    			pData2 = out_data;
    		}
    
       free (out_byte);
       free (out_data);
    Is my use of StretchDIBits and GetDIbits correct?

    Am I missing something else?

    Any help would be greatly appreciated.

    Cheers.

  2. #2
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Try checking return values for errors and call GetLastError() if an error occurs. The error code may help out.

    gg

  3. #3
    Registered User
    Join Date
    Nov 2003
    Posts
    5
    I have tried GetLastError in various portions of
    my code, but I always get ERR_SUCCESS.

    Any other ideas?

  4. #4
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    What does the stretchdibits return?




    You could try.............

    GetObject() and fill a BITMAP struct.

    something like

    BITMAP BMP;
    GetObject(hBitmap,sizeof(BITMAP),&BMP);

    then check the colour depth. If it is not 24 bit then I don't think your loop to convert the bits will work.

    I would try using

    StretchBlt()

    And copying the image directly from one HDC to another.
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  5. #5
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    Code:
    HDC MemDC = CreateCompatibleDC(NULL);
    HBITMAP BmpHnd = CreateCompatibleBitmap(MemDC, NCOLS, NROWS);
    From documentation fro CreateCompatibleBitmap

    Note: When a memory device context is created, it initially has a 1-by-1 monochrome bitmap selected into it. If this memory device context is used in CreateCompatibleBitmap, the bitmap that is created is a monochrome bitmap. To create a color bitmap, use the hDC that was used to create the memory device context, as shown in the following code:

    HDC memDC = CreateCompatibleDC ( hDC );
    HBITMAP memBM = CreateCompatibleBitmap ( hDC );
    SelectObject ( memDC, memBM );
    I'm not sure what you pass as the first argument to CreateCompatibleBitmap when the original hdc is null(see below) but passing the memory dc will not work.

    EDIT - Try this:
    Code:
    HDC hdc = GetDC(NULL);
    HDC MemDC = CreateCompatibleDC(hdc);
    HBITMAP BmpHnd = CreateCompatibleBitmap(hdc, NCOLS, NROWS);
    
    ...
    
    ReleaseDC(hdc);
    Last edited by anonytmouse; 11-12-2003 at 12:29 AM.

  6. #6
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    MSDN
    CreateCompatibleDC(NULL);

    "If pDC is NULL, the function creates a memory device context that is compatible with the system display."

    But try the GetDC() as sometimes I find that works better, particularly in MFC.
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  7. #7
    Registered User
    Join Date
    Nov 2003
    Posts
    5
    Thanks.
    Not passing the memDC works much better.

    However, my output is still not perfect. I get
    a resized image that resembles the original,
    but sometimes it comes out grayscale and a
    little distorted.

    I checked the return value of StretchDIBits
    and for a 640x480 source image it always
    returns 480. The return value of GetDIBits
    is always the height of the resized image.

    Would this indicate that I am messing up the
    memory somewhere?

    [QUOTE
    EDIT - Try this:
    Code:
    HDC hdc = GetDC(NULL);
    HDC MemDC = CreateCompatibleDC(hdc);
    HBITMAP BmpHnd = CreateCompatibleBitmap(hdc, NCOLS, NROWS);
    
    ...
    
    ReleaseDC(hdc);
    [/QUOTE]

  8. #8
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    Could you define some times? With different images or the same image comes out differently?

    If the latter, my guess would be that the Info structure that you pass to GetDIBits is not correctly initialised and therefore you are asking for the bits in a random format.

  9. #9
    Registered User
    Join Date
    Nov 2003
    Posts
    5
    Originally posted by anonytmouse
    Could you define some times? With different images or the same image comes out differently?

    If the latter, my guess would be that the Info structure that you pass to GetDIBits is not correctly initialised and therefore you are asking for the bits in a random format.
    Actually sometimes is really all the time. For my testing I am
    always using the same source image.

    Here is how I initialize the header:

    Code:
    	   BITMAPINFO Info;
    
    	   Info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    	   Info.bmiHeader.biWidth = NCOLS;
    	   Info.bmiHeader.biHeight = NROWS;
    	   Info.bmiHeader.biPlanes = 1;
    	   Info.bmiHeader.biBitCount = 24;
    	   Info.bmiHeader.biCompression = BI_RGB;
    	   Info.bmiHeader.biSizeImage = NROWS*NCOLS*3;
    	   Info.bmiHeader.biXPelsPerMeter  = 0;
    	   Info.bmiHeader.biYPelsPerMeter  = 0;
    	   Info.bmiHeader.biClrUsed   = 0;
    	   Info.bmiHeader.biClrImportant   = 0;
    
    	   HDC hdc = GetDC(NULL);
    	   HDC MemDC = CreateCompatibleDC(hdc);
    	   HBITMAP BmpHnd = CreateCompatibleBitmap(hdc, NCOLS, NROWS);
    	   HBITMAP OldBmp = (HBITMAP) SelectObject(MemDC,BmpHnd);
    	   int sdibts = StretchDIBits(MemDC,0,0,NCOLS,NROWS,0,0,this->Cols,this->Rows,this->m_timage.Data,&(this->m_timage.Info),DIB_RGB_COLORS,SRCCOPY);
    	   int numScanned = GetDIBits(MemDC,BmpHnd,0,NROWS-1,out_data,&Info,DIB_RGB_COLORS);
    	   SelectObject(MemDC,OldBmp);
    	   DeleteObject(BmpHnd);
    	   DeleteDC(MemDC);
    	   DeleteDC(hdc);
    Last edited by NewCoder; 11-12-2003 at 11:27 AM.

  10. #10
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    I'm not sure but some ideas:
    What is the size of the resized image? You may be running into bit padding problems. Each line in a bitmap must end on a DWORD boundary. So choose a width that this will be the case.

    eg. 100,200,300,400 etc.

    Also try BitBlt-ing the memDC to the screen DC(I think this works) to see what it contains after the Stretch call.

    Finally, you need to call ReleaseDC on an hdc obtained with GetDC, not DeleteDC.

  11. #11
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    Uh, right in front of my face:
    The bitmap identified by the hbmp parameter must not be selected into a device context when the application calls this function.
    So swap the below lines.

    Code:
    int numScanned = GetDIBits(MemDC,BmpHnd,0,NROWS-1,out_data,&Info,DIB_RGB_COLORS);
    SelectObject(MemDC,OldBmp);

  12. #12
    Registered User
    Join Date
    Nov 2003
    Posts
    5
    Thanks.

    Working much better now.
    (The alignment was definitely an issue also.)

    Thanks again everyone.

    Cheers.

  13. #13
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    >>I get a resized image that resembles the original,but sometimes it comes outgrayscale and a little distorted.<<

    Expect poor results from an image resize unless you use an int multiple ie 0.5 (1/2) better than 0.45.

    >>Info.bmiHeader.biBitCount = 24;

    You create a bitmap compatible to the screen. Is the screen in 24bit or 16 or 32 bit?



    >>Info.bmiHeader.biSizeImage = NROWS*NCOLS*3


    For Windows NT, the width must be DWORD aligned unless the bitmap is RLE compressed.
    For Windows 95/98/Me, the width must be WORD aligned unless the bitmap is RLE compressed.
    try

    cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);

    //will need to ensure cClrBits is 1,4,8,16,24 or 32

    Info.bmiHeader.biSizeImage = ((Info.bmiHeader.biWidth * cClrBits +31) & ~31) /8 * Info.bmiHeader.biHeight;
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. using basic library to write curve to bmp
    By CIO in forum C Programming
    Replies: 3
    Last Post: 02-21-2009, 02:25 PM
  2. Problem reading BMP
    By Mortissus in forum C Programming
    Replies: 4
    Last Post: 02-02-2006, 06:32 AM
  3. Strange problem with bmp
    By Victor in forum Linux Programming
    Replies: 2
    Last Post: 04-04-2005, 02:48 PM
  4. [C++/WinAPI] Resizing image
    By jagi in forum Windows Programming
    Replies: 2
    Last Post: 04-04-2005, 07:44 AM
  5. adding encryption to bmp
    By GiraffeMan in forum C Programming
    Replies: 10
    Last Post: 04-16-2002, 01:42 PM