|
-
June 5th, 2009, 11:04 AM
#1
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.
-
June 5th, 2009, 12:49 PM
#2
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
-
June 5th, 2009, 01:13 PM
#3
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
-
June 5th, 2009, 01:15 PM
#4
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...
-
June 6th, 2009, 02:44 AM
#5
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
-
June 6th, 2009, 08:53 AM
#6
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.
-
June 7th, 2009, 07:58 AM
#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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|