using CIMAGE.LIB to make JPEGs

It's been asked 100 times already:  
How to write a bitmap to a JPEG file?
But I can't make it work either.
I can generate .BMPs without difficulty, but not .JPEGs.
An example of the contrast between my BMP and JPEG result
can be seen by following this link:

http://www.pointcover.com/snapshot.htm   

It seems like  most advice on this subject directs developers to CIMAGE.LIB.
CIMAGE.LIB is available from many sources around the web.
(e.g. http://www.anthemion.co.uk/code.htm )

Following the brief (too brief!) tutorial, I compiled the libraries
and added some simple code to my application to export a snapshot
of my CWnd subclass to a jpeg file.

Oddly, there is no problem when exporting to .BMP format,
but hideous artifacts are present in the JPEG format.
How could such a popular library have such hideous bugs?
There must be a problem with my very simple code.

Do I need to convert DDB to DIB or something?
What the hell is going wrong here?

      // device context for painting
      CPaintDC dc(this);
      CDC     memDC;
      CBitmap *pOldBitmap;
      CRect rect; GetClientRect(rect);
      CSize dcSize = rect.Size();
      // Need a memory DC
      memDC.CreateCompatibleDC(&dc);
      // Select in the bitmap
      CBitmap mBitmap;
      mBitmap.CreateCompatibleBitmap(&dc,
            dcSize.cx, dcSize.cy);
      pOldBitmap =  memDC.SelectObject(&mBitmap);
      :
      :
      :
      // Jpeg stuff
      CImage myJpegImage(&mBitmap);
      CString filename = "C:\\WINDOWS\\Desktop\\snapshot.jpg";
      int imageType = CIMAGE_FORMAT_JPEG;
      myJpegImage.SaveFile(filename, imageType);

      // Bmp stuff
      CImage myBmpImage(&mBitmap);
      filename = "C:\\WINDOWS\\Desktop\\snapshot.bmp";
      imageType = CIMAGE_FORMAT_BMP;
      myBmpImage.SaveFile(filename, imageType);

// This did not work wither
//      CImage myBmpImage(&mBitmap);
//      int imageType = CIMAGE_FORMAT_BMP;
//      filename = "C:\\WINDOWS\\Desktop\\snapshot.bmp";
//      myBmpImage.SaveFile(filename, imageType);
//      CImage myJpegImage;
//      myJpegImage.ReadFile(filename, CIMAGE_FORMAT_BMP);
//      imageType = CIMAGE_FORMAT_JPEG;
//      filename = "C:\\WINDOWS\\Desktop\\snapshot.jpg";
//      myJpegImage.SaveFile(filename, imageType);
   
      // Clean up
      memDC.SelectObject(pOldBitmap);
cternoeyAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

nil_dibCommented:
seems to be color problem ... if this is a screenshot try play with the display color setting (set to 256 color depth..)

nil_dib
0
zoferCommented:
Maybe you are using the wrong libarary...

I recommend Intel's Jpeg Libarary.
Although its API is in C, It is easy
to figure out what is going on.

Can be found at:
http://developer.intel.com/vtune/perflibst/
0
cternoeyAuthor Commented:
to: nil_dib
Thanks for the suggestion. Changing the settings of my monitor to 256 did improve the situation. This is a great clue. However, it degrades the image significantly. And I can not expect users to accomdate this requirement. Any more tips along this line?
0
Introducing Cloud Class® training courses

Tech changes fast. You can learn faster. That’s why we’re bringing professional training courses to Experts Exchange. With a subscription, you can access all the Cloud Class® courses to expand your education, prep for certifications, and get top-notch instructions.

cternoeyAuthor Commented:
to: zofer
I was not aware of the intel library. Thanks for pointing it out. It looks very powerful. Hwever, my drawing code uses CDC methods to manipulate a CBitmap object. And I can not see any way to initialize their data structures with a CBitmap object or access their data structures thru a CDC interface. If you know a way, please tell me. Thanks again for just pointing out this interesting library.
0
cternoeyAuthor Commented:
Edited text of question.
0
nil_dibCommented:
look for the evaluation of the colors.
I use the following code to capture a window:


unsigned short CScreenCapture::DIBNumColors(char * lpDIB)
{
      unsigned short wBitCount;  // DIB bit count
      unsigned long dwClrUsed;
      
      dwClrUsed = ((LPBITMAPINFOHEADER)lpDIB)->biClrUsed;
      if (dwClrUsed)
            return (WORD)dwClrUsed;
      
      //      Calculate the number of colors in the color table based on
      //      the number of bits per pixel for the DIB.
      
      wBitCount = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount;
      
      // return number of colors based on bits per pixel
      switch (wBitCount)
      {
      case 1:
            return 2;
      case 4:
            return 16;
      case 8:
            return 256;
      default:
            return 0;
      }
}


int CScreenCapture::WriteDIB( )
{
      BITMAPFILEHEADER hdr;
      LPBITMAPINFOHEADER lpbi;
             
      if (!m_pvDIB)
            return 0;
             
      CFile file;
      if( !file.Open( m_pszFilename, CFile::modeWrite|CFile::modeCreate) )
            return 0;
             
      lpbi = (LPBITMAPINFOHEADER)m_pvDIB;
      int nColors = DIBNumColors((char*)m_pvDIB);
             
      // Fill in the fields of the file header
      hdr.bfType                    = ((WORD) ('M' << 8) | 'B');        // is always "BM"
      hdr.bfSize                    = GlobalSize (m_pvDIB) + sizeof( hdr );
      hdr.bfReserved1         = 0;
      hdr.bfReserved2         = 0;
      hdr.bfOffBits              = (DWORD) (sizeof( hdr ) + lpbi->biSize +
            nColors * sizeof(RGBQUAD));
             
      // Write the file header
      file.Write( &hdr, sizeof(hdr) );
             
      // Write the DIB header and the bits
      file.Write( lpbi, GlobalSize(m_pvDIB) );
      file.Close();       
             
      return 1;
}




void * CScreenCapture::DDBToDIB( CBitmap& bitmap, DWORD dwCompression, CPalette* pPal )
{
      BITMAP                              bm;
      BITMAPINFOHEADER            bi;
      LPBITMAPINFOHEADER            lpbi;
      DWORD                              dwLen;
      void*                              hDIB;
      void*                              handle;
      HDC                               hDC;
      HPALETTE                        hPal;
      
      ASSERT( bitmap.GetSafeHandle() );
      
      // The function has no arg for bitfields
      if( dwCompression == BI_BITFIELDS )
            return 0;
      
      // If a palette has not been supplied use defaul palette
      hPal = (HPALETTE) pPal->GetSafeHandle();
      if (hPal==0)
            hPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);
      
      // Get bitmap information
      bitmap.GetObject(sizeof(bm),(char*)&bm);
      
      // calculate bits per pixel
      bi.biBitCount = bm.bmPlanes * bm.bmBitsPixel;
      
      // make sure bits per pixel is valid
      if (bi.biBitCount <= 1)
            bi.biBitCount = 1;
      else if (bi.biBitCount <= 4)
            bi.biBitCount = 4;
      else if (bi.biBitCount <= 8)
            bi.biBitCount = 8;
      else // if greater than 8-bit, force to 24-bit
            bi.biBitCount = 24;
      // Initialize the bitmapinfoheader
      bi.biSize                        = sizeof(BITMAPINFOHEADER);
      bi.biWidth                        = bm.bmWidth;
      bi.biHeight                   = bm.bmHeight;
      bi.biPlanes                   = 1;
      //      bi.biBitCount                  = bm.bmPlanes * bm.bmBitsPixel;
      bi.biCompression            = dwCompression;
      bi.biSizeImage                  = 0;
      bi.biXPelsPerMeter            = 0;
      bi.biYPelsPerMeter            = 0;
      bi.biClrUsed                  = 0;
      bi.biClrImportant            = 0;
      
      // Compute the size of the      infoheader and the color table
      dwLen  = bi.biSize + DIBNumColors((char*)&bi) * sizeof(RGBQUAD);
      
      // We need a device context to get the DIB from
      hDC = GetDC(0);
      hPal = SelectPalette(hDC,hPal,0);
      RealizePalette(hDC);
      
      // Allocate enough memory to hold bitmapinfoheader and color table
      hDIB = GlobalAlloc(GMEM_FIXED,dwLen);
      
      if (!hDIB)
      {
            SelectPalette(hDC,hPal,0);
            ReleaseDC(0,hDC);
            return 0;
      }
      
      lpbi = (LPBITMAPINFOHEADER)hDIB;
      
      *lpbi = bi;
      
      // Call GetDIBits with a 0 lpBits param, so the device driver
      // will calculate the biSizeImage field
      GetDIBits(hDC, (HBITMAP)bitmap.GetSafeHandle(), 0L, (DWORD)bi.biHeight,
            (LPBYTE)0, (LPBITMAPINFO)lpbi, (DWORD)DIB_RGB_COLORS);
      
      bi = *lpbi;
      
      // If the driver did not fill in the biSizeImage field, then compute it
      // Each scan line of the image is aligned on a DWORD (32bit) boundary
      if (bi.biSizeImage == 0)
      {
            bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8)
                  * bi.biHeight;
            
            // If a compression scheme is used the result may infact be larger
            // Increase the size to account for this.
            if (dwCompression != BI_RGB)
                  bi.biSizeImage = (bi.biSizeImage * 3) / 2;
      }
      
      // Realloc the buffer so that it can hold all the bits
      dwLen += bi.biSizeImage;
      if (handle = GlobalReAlloc(hDIB, dwLen, GMEM_MOVEABLE))
            hDIB = handle;
      else
      {
            GlobalFree(hDIB);
            
            // Reselect the original palette
            SelectPalette(hDC,hPal,0);
            ReleaseDC(0,hDC);
            return 0;
      }
      
      // Get the bitmap bits
      lpbi = (LPBITMAPINFOHEADER)hDIB;
      
      // FINALLY get the DIB
      int bGotBits = GetDIBits( hDC, (HBITMAP)bitmap.GetSafeHandle(),
            0L,                                           // Start scan line
            (DWORD)bi.biHeight,                   // # of scan lines
            (LPBYTE)lpbi                              // address for bitmap bits
            + (bi.biSize + DIBNumColors((char*)&bi) * sizeof(RGBQUAD)),
            (LPBITMAPINFO)lpbi,                   // address of bitmapinfo
            (DWORD)DIB_RGB_COLORS);             // Use RGB for color table
      
      if( !bGotBits )
      {
            GlobalFree(hDIB);
            SelectPalette(hDC,hPal,0);
            ReleaseDC(0,hDC);
            return 0;
      }
      
      SelectPalette(hDC,hPal,0);
      ReleaseDC(0,hDC);
      return hDIB;
}


int CScreenCapture::Capture( CWnd *pWnd )
{
      CBitmap   bitmap;
      CWindowDC  dc(pWnd);
      CDC memDC;
      CRect rect;
             
      // Free the memory allocated by DDBToDIB for the DIB
      if (m_pvDIB)
            GlobalFree( m_pvDIB );
      m_pvDIB = 0;

      memDC.CreateCompatibleDC(&dc);
      pWnd->GetWindowRect(rect);
      bitmap.CreateCompatibleBitmap(&dc, rect.Width(),rect.Height() );                                    
      CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);
      memDC.BitBlt(0, 0, rect.Width(),rect.Height(), &dc, 0, 0, SRCCOPY);
             
      // Create logical palette if device support a palette
      CPalette pal;
      if( dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE )
      {
            unsigned nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256);
            LOGPALETTE *pLP = (LOGPALETTE *) new unsigned char[nSize];
            pLP->palVersion = 0x300;
            pLP->palNumEntries = GetSystemPaletteEntries( dc, 0, 255, pLP->palPalEntry );
            
            // Create the palette
            pal.CreatePalette( pLP );
            delete[] pLP;
      }
        
      memDC.SelectObject(pOldBitmap);
             
      // Convert the bitmap to a DIB
      m_pvDIB = DDBToDIB( bitmap, BI_RGB, &pal );
      if( m_pvDIB == 0 )
            return 0;
             
      return 1;
}


nil_dib
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
cternoeyAuthor Commented:
nil_dib:
Thanks!
0
nil_dibCommented:
you got it?
0
cternoeyAuthor Commented:
nil_dib:
yes, want some points?
0
cternoeyAuthor Commented:
nil_dib:
Sorry, I am fumbling a bit with the system as a newbie to the process...
0
nil_dibCommented:
no prob ;-)
thanks
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.