CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 7 of 7
  1. #1
    Join Date
    Apr 2005
    Posts
    41

    Writing a CDC to a jpeg file

    Hi all
    I've been trying all day to sort this out so I was hoping someone could help!!

    Basically, I am trying to write the contents of a CDC to a JPEG file and I am trying to use libjpeg.lib. Below is a simplified snippet of the code I am using at present. What I am intending the code to do is to create a picture with a square and a circle and then write this to a JPEG file. It manages to create a JPEG file with the right size however it is completely black so obviously I am doing something wrong! Any help would be greatly appreciated.

    Thanks very much for reading,

    Robbie

    (ps. I am using Visual C++ v6 and am trying to do this within a MFC dialog based project)
    Code:
    void CNucPlot::SaveFile()
    {
    	CDC myDC;
    	HBITMAP myBMP;
    	myDC.CreateCompatibleDC(NULL);
    
    	//  Set pictures size;
    	int Width = 500;
    	int Height = 500;
    
    	// Draw rectangle and an ellipse to myDC ..
    	CBrush newColour(RGB(10,10,10));
    	myDC.SelectObject(newColour);
    	CPen lColourPen (PS_SOLID, 1,RGB(50,100,150));
    	myDC.SelectObject(&lColourPen); // 100
    
    	myDC.SetBkColor(RGB(255,255,255));
    	myDC.Rectangle(10,20,100,90);
    	CRect Rect;
    	Rect.left   = 10;
    	Rect.top    = 20;
    	Rect.right  = 100;
    	Rect.bottom = 90;
    	myDC.Ellipse(Rect);
    
    	myBMP = CreateCompatibleBitmap(myDC,Width,Height);
    	SelectObject(myDC,myBMP);
    
    	struct jpeg_compress_struct cinfo;
    	struct jpeg_error_mgr jerr;
    	FILE * outfile;
    	JSAMPLE* scanline;
    	COLORREF pixel;
    
    	cinfo.err = jpeg_std_error(&jerr);
    	jpeg_create_compress(&cinfo);
    
    	outfile = fopen("robbie.jpg", "wb");
    	if(outfile == NULL) return;
    
    	jpeg_stdio_dest(&cinfo, outfile);
    	cinfo.image_width = Width;
    	cinfo.image_height = Height;
    	cinfo.input_components = 3;
    	cinfo.in_color_space = JCS_RGB;	
    	jpeg_set_defaults(&cinfo);
    
    	int quality = 90;
    	if(quality < 0) quality = 0;
    	if(quality > 100) quality = 100;
    
    	jpeg_set_quality(&cinfo, quality, FALSE);
    	jpeg_start_compress(&cinfo, TRUE);
    	scanline = new JSAMPLE[Width*3];
    
    	for(int posy = 0; posy < Height; posy++) 
    	{
    		for(int posx = 0; posx < Width; posx++)
    		{
    			pixel = GetPixel(myDC, posx, posy);
    			scanline[posx*3+0] = GetRValue(pixel);
    			scanline[posx*3+1] = GetGValue(pixel);
    			scanline[posx*3+2] = GetBValue(pixel);
    
    		}
    		jpeg_write_scanlines(&cinfo, &scanline, 1);
    	}
    	jpeg_finish_compress(&cinfo);
    	jpeg_destroy_compress(&cinfo);
    
    	delete scanline;
    	fclose(outfile);
    }
    Last edited by robbiegregg; June 5th, 2009 at 01:11 PM.

  2. #2
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: Writing a CDC to a jpeg file

    Please put [code][/code] tags around your code and indent it properly to make it more readable.

    Try painting the entire DC white before you paint something else on it.
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

  3. #3
    Join Date
    Apr 2005
    Posts
    41

    Re: Writing a CDC to a jpeg file

    Hi, I've edited my original post with the tags. I've also added the line myDC.SetBkColor(RGB(255,255,255)); but the JPEG image created is still black!

    Any other ideas anyone?

    Thanks

  4. #4
    Join Date
    Aug 2000
    Location
    New York, NY, USA
    Posts
    5,656

    Re: Writing a CDC to a jpeg file

    You have a lot of reading to do about GDI…
    First, ignore the JPEG stuff for now.
    A newly created DC has a 1x1 monochrome bitmap selected into it.
    All your drawings have no effect on that DC,
    CreateCompatibleBitmap() creates bitmap *compatible* to that DC (also monochrome), so colored output to that makes a little sense anyway.
    The steps should be:
    • create DC compatible to a screen;
    • create bitmap with a required size, also compatible to a screen;
    • select that bitmap into DC;
    • NOW draw whatever you want on that DC;
    • and don’t forget to clean up after yourself.

    I would like to suggest a great GDI debugging tool that let you examine content of your GDI objects (memory DC, bitmap, etc.) while you debug your code, line-by-line.
    Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
    Convenience and productivity tools for Microsoft Visual Studio:
    FeinWindows - replacement windows manager for Visual Studio, and more...

  5. #5
    Join Date
    Apr 2005
    Posts
    41

    Re: Writing a CDC to a jpeg file

    Thanks VladimirF

    I've taken your advice and re-wrote the code as shown below:

    Code:
    void CNucPlot::SaveFile()
    {
    	CPaintDC dc(this); // device context for painting
    	//  Set pictures size;
    	int Width = 700;
    	int Height = 700;
    
      //  get the area to draw in.
    	CRect rcClient;
    	rcClient.top = 0;
    	rcClient.left = 0;
    	rcClient.bottom = Height;
    	rcClient.right = Width;
    
      //  create a memory dc for double buffering.
    	CMemDC myDC(&dc, &rcClient);
    
    	myDC.SetBkColor(RGB(255,255,255)); 
    	int nFontHeight = Height / 80.0f;
    	CBrush newColour(RGB(255,199,10));
    	myDC.SelectObject(newColour);
    	CPen lColourPen (PS_SOLID, 5,RGB(50,100,150));
    	myDC.SelectObject(&lColourPen); // 100
    
    	myDC.Rectangle(10,10,Width-10,Height-10);
    	myDC.Ellipse(10,10,Width-10,Height-10);
    
    	// JPEG Saving ..
    	struct jpeg_compress_struct cinfo;
    	struct jpeg_error_mgr jerr;
    	FILE * outfile;
    	JSAMPLE* scanline;
    	COLORREF pixel;
    
    	cinfo.err = jpeg_std_error(&jerr);
    	jpeg_create_compress(&cinfo);
    
    	outfile = fopen("robbie.jpg", "wb");
    	if(outfile == NULL) return;
    
    	jpeg_stdio_dest(&cinfo, outfile);
    	cinfo.image_width = Width;
    	cinfo.image_height = Height;
    	cinfo.input_components = 3;
    	cinfo.in_color_space = JCS_RGB;	
    	jpeg_set_defaults(&cinfo);
    
    	int quality = 90;
    	if(quality < 0) quality = 0;
    	if(quality > 100) quality = 100;
    
    	jpeg_set_quality(&cinfo, quality, FALSE);
    	jpeg_start_compress(&cinfo, TRUE);
    	scanline = new JSAMPLE[Width*3];
    //	MessageBox("Finished setting up JPEG - now go through each JPEG line\n");
    
    	for(int posy = 0; posy < Height; posy++) 
    	{
    		for(int posx = 0; posx < Width; posx++)
    		{
    			pixel = GetPixel(myDC, posx, posy);
    			scanline[posx*3+0] = GetRValue(pixel);
    			scanline[posx*3+1] = GetGValue(pixel);
    			scanline[posx*3+2] = GetBValue(pixel);
    
    		}
    		jpeg_write_scanlines(&cinfo, &scanline, 1);
    	}
    	jpeg_finish_compress(&cinfo);
    	jpeg_destroy_compress(&cinfo);
    
    	delete scanline;
    	fclose(outfile);
    }
    Now it writes correctly to a JPEG file. My problem with this code is that the picture displays on screen as well. Does anyone know how I can modify the code so that it only generates the JPEG file?

    Also, when I try to generate a really big JPEG (say 2000 x 2000), it takes along time to complete. It might just be that it is a CPU intensive task to create a big JPEG. However does anyone know a better way of reading the CDC and dumping it to a JPEG file?

    Thanks

    Robbie

  6. #6
    Join Date
    Feb 2005
    Posts
    2,160

    Re: Writing a CDC to a jpeg file

    From my experience, GetPixel() is probably the bottleneck in your code. It is best to grab a pointer to the buffer directly and iterate through it directly than calling GetPixel for every pixel. Use GetDIBits() to grab a pointer to the raw buffer, but keep in mind that the buffer is a bottom-up bitmap so you have to iterate backwards.

  7. #7
    Join Date
    Jun 2009
    Posts
    7

    Re: Writing a CDC to a jpeg file

    what about this

    #include //For Image
    using namespace Gdiplus; //For Image

    void BitmapUtils::SaveBitmapToFile(HDC hdc,CRect rect)
    {
    HDC hMemDC = CreateCompatibleDC(hdc);
    HBITMAP hBitmap = CreateCompatibleBitmap(hdc,rect.right, rect.Height() + rect.bottom);
    if (hBitmap)
    {
    HBITMAP hOld = (HBITMAP) SelectObject(hMemDC, hBitmap);
    BitBlt(hMemDC, 0, 0, rect.right, rect.Height() + rect.bottom, hdc, 0, 0, SRCCOPY);
    SelectObject(hMemDC, hOld);
    DeleteDC(hMemDC);
    ::ReleaseDC(NULL, hdc);
    }
    CImage im;
    im.Attach(hBitmap);
    im.Save( "c:\\image.jpg", ImageFormatJPEG);
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured