• Advertisement

Archived

This topic is now archived and is closed to further replies.

Saving screenshot to disk?

This topic is 5473 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello, i''m looking for a function to save the actual rendered screen to an image file. even better would be something where i could set some parameters, like i only want the part saved from screen coordiantes e.g. (200,300) to (328, 428) or something like this. thanx a lot!

Share this post


Link to post
Share on other sites
Advertisement
Look into glReadPixels(); it allows you specify a section of the screen to be saved into a buffer. However, you'll need to provide code to write that buffer into a valid image file. Since BMP has an easily implementable file structure, you might also want to see this topic on openglforums for sample code.

RapscallionGL - arriving soon.

[edited by - johnnie2 on February 8, 2003 2:31:54 PM]

Share this post


Link to post
Share on other sites
Got bored.




bool SaveGLScreenshot(RECT &Region, char *FileName)
{
// extract the height and width from the rectangle
unsigned long Width = Region.right-Region.left,
Height= Region.bottom-Region.top;

long ImageSize = Width*Height*3; // width*height*(bitdepth/bitsperbyte)

unsigned char *Data = new unsigned char[ImageSize]; // allocate some space

// read the data in RGB format from the color buffer
glReadPixels(Region.left, Region.top, Width, Height, GL_RGB, GL_UNSIGNED_BYTE, Data);

FILE *Bitmap = fopen(FileName, "wb"); // open up a file to write

if(!Bitmap) // bail if we couldn''t open the file (shouldn''t happen)
{
delete [] Data;
return false;
}

unsigned char temp;
// reorder RGB to standard bitmap ordering of BGR
for(int index = 0; index < ImageSize; index+=3)
{
temp = Data[index];
Data[index] = Data[index+2]; // swap reds
Data[index+2] = temp; // with blues
}

// prepare the file header
BITMAPFILEHEADER FileHeader;
// clear everything out so we can fill arbitrarily
memset(&FileHeader, 0, sizeof(BITMAPFILEHEADER));
// filetype is always "BM"
FileHeader.bfType = MAKEWORD(''B'',''M'');
// total size of our bitmap file
FileHeader.bfSize = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER) + ImageSize;
// offset from start of file to bitmap data
// NOTE: this is misdocumented in the MSDN
FileHeader.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);

// prepare the info header
BITMAPINFOHEADER InfoHeader;
// clear stuff
memset(&InfoHeader, 0, sizeof(BITMAPINFOHEADER));
// size of this structure
InfoHeader.biSize = sizeof(BITMAPINFOHEADER);
// width and height
InfoHeader.biWidth = Width;
InfoHeader.biHeight = Height;
// number of image planes - must be 1 in Windows
InfoHeader.biPlanes = 1;
// bitdepth is 24-bit (3 byte-sized components per pixel)
InfoHeader.biBitCount = 24;
// no compression - outut raw RGB data
InfoHeader.biCompression = BI_RGB;

// write to the file - yay.
fwrite(&FileHeader, sizeof(BITMAPFILEHEADER), 1, Bitmap);
fwrite(&InfoHeader, sizeof(BITMAPINFOHEADER), 1, Bitmap);
fwrite(Data, sizeof(unsigned char), ImageSize, Bitmap);

// perform some clean up
fclose(Bitmap);

delete [] Data;

// it''s all good.
return true;
}


As in,
// RECT coord order: left, top, right, bottom
RECT Area = {0, 0, 640, 480};
SaveGLScreenshot(Area, "scr.bmp");


Later,
ZE.

//email me.//zealouselixir software.//msdn.//n00biez.//
miscellaneous links

Share this post


Link to post
Share on other sites
Why not try it with DevIL?

may be a bit of an overkill but its veeeerryyy handy!
(also for textures )

mfg Phreak
--
"Input... need input!" - Johnny Five, Short Circuit.

Share this post


Link to post
Share on other sites
I think that with the JPEG library comes an example of how so save JPEGs on your disk.Just do this:

GLint v[4];

glGetIntegerv(GL_VIEWPORT,v);

GLubyte *data = (GLubyte*)malloc(v[2] * v[3] * 3);

glReadPixels(0,0,v[2],v[3],GL_RGB,GL_UNSIGNED_BYTE,data);

//WRITE THE DATA TO A FILE


The PAIN is coming...this summer!!!In cinemas everywhere.

Share this post


Link to post
Share on other sites
quote:
Original post by LousyPhreak
Why not try it with DevIL?

may be a bit of an overkill but its veeeerryyy handy!
(also for textures )



Because someone who has no clue how to get image data into an image file has no business using an all-powerful library that shelters them from all the guts. I''m not a sadist, but the trend, especially among indies, of taking middleware as a godsend that prevents one from actually tackling problems is a dangerous one.

Later,
ZE.

//email me.//zealouselixir software.//msdn.//n00biez.//
miscellaneous links

Share this post


Link to post
Share on other sites
thanx at all for the help. finally i got enough time yesterday to implement the stuff.

@ZealousElixir: your function seems to crash in some cases, like if the rectangle starts with x < 60. i don''t know why. one thing i thought it may be hasn''t changed that error.

i replaced:
fwrite(&FileHeader, sizeof(BITMAPFILEHEADER), 1, Bitmap);
in:
fwrite(&FileHeader, 1, sizeof(BITMAPFILEHEADER, Bitmap);

so i mixed around all of the functions i''ve found, and i''m now finally using this one, which hasn''t made any error (yet):



int SaveBMP (char *filename, int width, int height, unsigned char *BMP_Data) {
FILE *file_ptr;
BITMAPINFOHEADER bmp_infoh;
BITMAPFILEHEADER bmp_fileh;
unsigned int counter;
unsigned char tempRGB;

file_ptr = fopen (filename, "wb");
if (!file_ptr) {
return 0;
}

bmp_fileh.bfOffBits = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER);
bmp_fileh.bfReserved1 = 0;
bmp_fileh.bfReserved2 = 0;
bmp_fileh.bfSize = sizeof (BITMAPFILEHEADER);
bmp_fileh.bfType = 0x4D42;

bmp_infoh.biBitCount = 24;
bmp_infoh.biClrImportant = 0;
bmp_infoh.biClrUsed = 0;
bmp_infoh.biCompression = BI_RGB;
bmp_infoh.biHeight = height;
bmp_infoh.biPlanes = 1;
bmp_infoh.biSize = sizeof (BITMAPINFOHEADER);
bmp_infoh.biSizeImage = width * abs (height) * 3;
bmp_infoh.biWidth = width;
bmp_infoh.biXPelsPerMeter = 0;
bmp_infoh.biYPelsPerMeter = 0;

for (counter = 0; counter < bmp_infoh.biSizeImage; counter += 3) {
tempRGB = BMP_Data [counter];
BMP_Data [counter] = BMP_Data [counter + 2];
BMP_Data [counter + 2] = tempRGB;
}

fwrite (&bmp_fileh, 1, sizeof (BITMAPFILEHEADER), file_ptr);
fwrite (&bmp_infoh, 1, sizeof (BITMAPINFOHEADER), file_ptr);
fwrite (BMP_Data, 1, bmp_infoh.biSizeImage, file_ptr);

fclose (file_ptr);
return 1;
}

//this function make screenshot with previsius function for save BMP


void *BMPw_Data;
void SaveScreenshot (int startx, int starty, int width, int height, char *dateiname) {
BMPw_Data = malloc (width * height * 3);
memset (BMPw_Data, 0, width * height * 3);

glReadPixels (startx, starty, width, height, GL_RGB, GL_UNSIGNED_BYTE, BMPw_Data);
SaveBMP (dateiname, width, height, (unsigned char*)BMPw_Data);

free (BMPw_Data);
}


calling with this:
SaveScreenshot (0, 0, 1024, 768, "bla.bmp");

Share this post


Link to post
Share on other sites
woa! Found the perfect article! And that method is soooo much faster than those posted here

Instead of reading what has been rendered, you render DIRECTLY to the texture! :D

http://www.nvidia.com/dev_content/gdc2002/opengl_rendertexture_files/frame.htm

"No lies of sugar can sweeten the sournes of reality"

}+TITANIUM+{ A.K.A. DXnewbie[onMIRC]

Share this post


Link to post
Share on other sites
Seriema: What does that do? Render to a texture, then you STILL have to read the data back anyways... so I don''t understand what the point was.

Share this post


Link to post
Share on other sites

temp = Data[index];
Data[index] = Data[index+2];
Data[index+2] = temp;




I love it how people use temporary values to do swaps...
Try this instead sometime:




Data[index] ^= Data[index+2];
Data[index+2] ^= Data[index];
Data[index] ^= Data[index+2];


Voila! No temp variable. (I think I did that right)

"C makes it easy to shoot yourself in the foot; C++ makes it harder, but
when you do, it blows away your whole leg."

- Bjarne Stroustrup

Realm Games Company

Share this post


Link to post
Share on other sites
Hm. 3 assigns and an overhead-less 4-byte temp versus three XOR-assigns. You have any time-trials to show that your method is dazzlingly faster than mine?

edit : oh, and pardon me for overlooking the additional ADD and 2 pointer lookups that your method includes. Guess you really are just too clever for me. I bow down before you...

edit2 : by the way, your website link appears to be broken.

[edited by - zealouselixir on March 1, 2003 1:35:34 PM]

Share this post


Link to post
Share on other sites
I''m not sure if it is faster, but if you are pressed for memory, it does beat your method there.

hmm I musta made a typo in my link...(fixing)

Share this post


Link to post
Share on other sites
Pressed for memory? That''s about the shittiest excuse I''ve ever heard for someone not admitting they were wrong...

Share this post


Link to post
Share on other sites
If you can''t afford and extra byte of memory(or 4, not sure how it ends up), then you''ve got bigger things to worry about!

Share this post


Link to post
Share on other sites
Yeah, that was actually a mistake on my part. Turns out it's just one byte (though it may well wind up as 32 bits on the stack to help out the processor).

[edited by - zealouselixir on March 1, 2003 2:25:42 PM]

Share this post


Link to post
Share on other sites
Yes, I may be wrong, but I did show you a neat method... :D

(do it out on pen and paper to see the bits work their swapping magic)

and I correct the link my sig

"C makes it easy to shoot yourself in the foot; C++ makes it harder, but
when you do, it blows away your whole leg."

- Bjarne Stroustrup

Realm Games Company

Share this post


Link to post
Share on other sites
interesting concept, but i think it doesn't work. it's just too late now here to think about it calm (besided i had a birthday party some hours before...)

i write on this again
[you all wanted this posting, didn't you?]


[edited by - Win Elchtest on March 1, 2003 7:12:48 PM]

Share this post


Link to post
Share on other sites
Ready4Dis: Well... glReadPixels are ALOT slower than rendering directly to the texture If you look through the slides on the link you''ll see that''s the second slowest method (they suggest 5-6 methods I think).

Then saving to a file, well you can''t get away from that now can you?

"No lies of sugar can sweeten the sournes of reality"

}+TITANIUM+{ A.K.A. DXnewbie[onMIRC]

Share this post


Link to post
Share on other sites

  • Advertisement