Dumping a SDL_Surface to a file?

How do I properly dump a SDL_Surface to a file? I’ve tried several diffrent methods, but I only get 60 bytes of dumped data. I mean, that couldn’t possible contain the entire chunk of pixel data, or
could it? What am I doing wrong?

-Johan
:^)v""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""“
±--------+ * Get your own Jmail account.|URL= http://www.jmail.co.jp
|–jmail–| * Get your own home page. |URL= http://www.servance.jp
±--------+ * Get your own domain. |URL= http://domaintorou.com
”""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""v(^:

If dump only the fields of the structure, you won’t save the dynamic part of
the surface, like the pixels data. To save the pixels data you should have a
line like this : fwrite(data,sizeofdata,1,myfile), where data is a pointer
to the pixels data.

Send your code and it will be easier to give you help.

Julien> ----- Original Message -----

From: tokikenshi@fish.co.jp (Johan Persson)
To:
Sent: Monday, February 17, 2003 1:42 PM
Subject: [SDL] Dumping a SDL_Surface to a file?

How do I properly dump a SDL_Surface to a file? I’ve tried several
diffrent methods, but I only get 60 bytes of dumped data. I mean, that
couldn’t possible contain the entire chunk of pixel data, or
could it? What am I doing wrong?

-Johan
:^)v""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""“
±--------+ * Get your own Jmail account.|URL= http://www.jmail.co.jp
|–jmail–| * Get your own home page. |URL= http://www.servance.jp
±--------+ * Get your own domain. |URL= http://domaintorou.com
”""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""v(^:


SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl

Well, there’s more than one memory block to save - but before we start
talking about that kind of stuff; what do you actually want to do?
Why not just save the surface as an image file of some standard
format? SDL_SaveBMP() is one way.

//David Olofson - Programmer, Composer, Open Source Advocate

.- The Return of Audiality! --------------------------------.
| Free/Open Source Audio Engine for use in Games or Studio. |
| RT and off-line synth. Scripting. Sample accurate timing. |
`---------------------------> http://olofson.net/audiality -’
http://olofson.nethttp://www.reologica.se —On Monday 17 February 2003 13.42, Johan Persson wrote:

How do I properly dump a SDL_Surface to a file? I’ve tried several
diffrent methods, but I only get 60 bytes of dumped data. I mean,
that couldn’t possible contain the entire chunk of pixel data, or
could it? What am I doing wrong?

Why not write it as a png, using libpng? Here’s a quick hack I did to add
this to my world demo. Just make a .c file out of this, copy it to the
"worlds" directory, and make. This writes the OpenGL surface after getting it with
glReadPixels. Making it work without OpenGL and without my demo framework
should be trivial.

#include “world.h”
#include <png.h>

int write_png(char *file_name, png_bytep *rows, int w, int h, int colortype, int bitdepth)
{
png_structp png_ptr;
png_infop info_ptr;
FILE *fp = fopen(file_name, “wb”);
char *doing = “open for writing”;
if (!(fp = fopen(file_name, “wb”))) goto fail;
doing = “create png write struct”;
if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) goto fail;
doing = “create png info struct”;
if (!(info_ptr = png_create_info_struct(png_ptr))) goto fail;
if (setjmp(png_jmpbuf(png_ptr))) goto fail;
doing = “init IO”;
png_init_io(png_ptr, fp);
doing = “write header”;
png_set_IHDR(png_ptr, info_ptr, w, h, bitdepth, colortype, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
doing = “write info”;
png_write_info(png_ptr, info_ptr);
doing = “write image”;
png_write_image(png_ptr, rows);
doing = “write end”;
png_write_end(png_ptr, NULL);
return 0;

fail: printf(“Write_png: could not %s\n”, doing);
return -1;
}

static int filter(SDL_Event *event)
{
if (event->type != SDL_KEYDOWN) return 0;

if (event->key.keysym.sym == SDLK_p)
{
	int i;
	int w = 640, h = 480;
	unsigned rowbytes = w*4;
	unsigned char screenbuf[h][rowbytes], *rows[h];

	glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, screenbuf);
	for (i = 0; i < h; i++) rows[i] = screenbuf[h - i - 1];
	write_png("foo.png", rows, w, h, PNG_COLOR_TYPE_RGBA, 8);
	return 1;
}

return 0;

}

struct world world = { .filter = filter };On Mon 17 Feb 03 14:49, David Olofson wrote:

On Monday 17 February 2003 13.42, Johan Persson wrote:

How do I properly dump a SDL_Surface to a file? I’ve tried several
diffrent methods, but I only get 60 bytes of dumped data. I mean,
that couldn’t possible contain the entire chunk of pixel data, or
could it? What am I doing wrong?

Well, there’s more than one memory block to save - but before we start
talking about that kind of stuff; what do you actually want to do?
Why not just save the surface as an image file of some standard
format? SDL_SaveBMP() is one way.

I suppose that is because you’re dumping the SDL_Surface struct itself and
not the pixel data it points to.

Regards,

DanielOn Mon 17 Feb 03 13:42, Johan Persson wrote:

How do I properly dump a SDL_Surface to a file? I’ve tried several diffrent
methods, but I only get 60 bytes of dumped data. I mean, that couldn’t
possible contain the entire chunk of pixel data, or could it? What am I
doing wrong?

[…]

Why not write it as a png, using libpng? Here’s a quick hack I did
to add this to my world demo. Just make a .c file out of this,
copy it to the “worlds” directory, and make. This writes the
OpenGL surface after getting it with glReadPixels. Making it work
without OpenGL and without my demo framework should be trivial.
[…]

Well, not as trivial as just using SDL_SaveBMP() but the PNG file
format is definitely a lot nicer. :slight_smile:

//David Olofson - Programmer, Composer, Open Source Advocate

.- The Return of Audiality! --------------------------------.
| Free/Open Source Audio Engine for use in Games or Studio. |
| RT and off-line synth. Scripting. Sample accurate timing. |
`---------------------------> http://olofson.net/audiality -’
http://olofson.nethttp://www.reologica.se —On Monday 17 February 2003 23.00, Daniel Phillips wrote:

True. Try “man libpng” and give yourself a good scare :wink:

On the other hand, once it’s in the form of a simple write_png function,
it’s pretty easy. I suppose it needs a shell around it that initializes the
pointer array. After that, it would be dead simple to use.

There are a couple of oversights in my code:

  • I need to destroy some png data structures on the error path (i.e.,
    the posted version will leak a little on error)

  • I need to declare all write_png’s local variables “volatile” so the
    values are guaranteed to be valid after a longjmp on error. As it is,
    it’s probably ok, but it’s better to be paranoid.

Regards,

DanielOn Mon 17 Feb 03 16:33, you wrote:

On Monday 17 February 2003 23.00, Daniel Phillips wrote:
[…]

Why not write it as a png, using libpng? Here’s a quick hack I did
to add this to my world demo. Just make a .c file out of this,
copy it to the “worlds” directory, and make. This writes the
OpenGL surface after getting it with glReadPixels. Making it work
without OpenGL and without my demo framework should be trivial.

[…]

Well, not as trivial as just using SDL_SaveBMP() but the PNG file
format is definitely a lot nicer. :slight_smile:

[…PNG writer…]

There are a couple of oversights in my code:

  • I need to destroy some png data structures on the error path
    (i.e., the posted version will leak a little on error)

Yeah… Simple, but always messy. I never use goto these days, but
instead either use nested if()s, or a “conditional cleanup” function.

  • I need to declare all write_png’s local variables “volatile” so
    the values are guaranteed to be valid after a longjmp on error. As
    it is, it’s probably ok, but it’s better to be paranoid.

Especially if you’re going for the “conditional cleanup” thing. (Or
you might leak anyway, or worse.)

Either way, do you actually have to use setjmp/longjmp with libpng?
Seems a bit nasty to me…

//David Olofson - Programmer, Composer, Open Source Advocate

.- The Return of Audiality! --------------------------------.
| Free/Open Source Audio Engine for use in Games or Studio. |
| RT and off-line synth. Scripting. Sample accurate timing. |
`---------------------------> http://olofson.net/audiality -’
http://olofson.nethttp://www.reologica.se —On Monday 17 February 2003 23.51, Daniel Phillips wrote:

Yes, that’s how libpng is designed and the manpage makes it clear you’re
expected to do it this way. All in all, libpng’s interface is more complex
than necessary, and I will make a note to complain to Andreas about that,
not that it’s going to change anything at this point. Still, when you actually
use the libpng interface, it’s just a one-time cost to deal with the complexity
and bury it in a utility function. And it is really hard to complain about the
quality of the results.

OK, here’s the new, improved error handling, which I think is right, but I
haven’t actually forced any errors to check that. I stand by my use of gotos
here, in this case they actually help clarify the code flow rather than
obfuscate it. The real reason the code hurts the eyes a little is that we’re
doing resource management that would be done automatically and nicely hidden
away in C++, but because it’s C, all the gory details have to be written out
by hand. On the bright side, at least you can see what you’re getting.

I didn’t put in the volatiles because I strongly suspect it doesn’t matter, and that
the compiler thoughtfully takes care of making sure no locals are destroyed by
a longjmp, i.e., it sees the longjmp and prudently doesn’t create any register
variables. Nothing else would make sense, since none of the examples of
libpng usage out there bother to declare volatiles. On the other hand, the
compiler is really noisy about warning when the volatile attributes get stripped
off by being passed to subfunctions, which means I’d have to put in more casts,
and make the code less type-safe. Sigh. Anybody who thinks these variables
need to be declared volatile, please provide evidence :wink:

int write_png(char *file_name, png_bytep *rows, int w, int h, int colortype, int bitdepth)
{
png_structp png_ptr;
png_infop info_ptr;
FILE *fp = fopen(file_name, “wb”);
char *doing = “open for writing”;
int error = 0;

if (!(fp = fopen(file_name, "wb"))) goto fail;
doing = "create png write struct";
if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) goto fail;
doing = "create png info struct";
if (!(info_ptr = png_create_info_struct(png_ptr))) goto fail;
if (setjmp(png_jmpbuf(png_ptr))) goto fail;
doing = "init IO";
png_init_io(png_ptr, fp);
doing = "write header";
png_set_IHDR(png_ptr, info_ptr, w, h, bitdepth, colortype, PNG_INTERLACE_NONE,
	     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
doing = "write info";
png_write_info(png_ptr, info_ptr);
doing = "write image";
png_write_image(png_ptr, rows);
doing = "write end";
png_write_end(png_ptr, NULL);

out: if (png_ptr) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
if (fp) fclose(fp);
return error;

fail: printf(“Write_png: could not %s\n”, doing);
error = -1;
goto out;
}On Mon 17 Feb 03 17:36, you wrote:

Either way, do you actually have to use setjmp/longjmp with libpng?
Seems a bit nasty to me…

“file_name” and “rows” should be declared const.

Making a wrapper for SDL surfaces would be useful, especially if it was
included in SDL_image. It’d take work to make it generic, though (eg.
palettes, etc).On Tue, Feb 18, 2003 at 01:42:01AM +0100, Daniel Phillips wrote:

int write_png(char *file_name, png_bytep *rows, int w, int h, int colortype, int bitdepth)


Glenn Maynard

int write_png(char *file_name, png_bytep *rows, int w, int h, int
colortype, int bitdepth)

“file_name” and “rows” should be declared const.

Yes, file_name works fine as a const. Unfortunately, const png_bytep *rows
generates a warning, because libpng doesn’t declare it as a const. It’s too
bad, but as a compiler feature, const is messed up to an almost unusable
degree (doesn’t play well with inlines, for example). It’s better to leave
the const out than to put in a cast to suppress the warning, and lose all
type safety.

I suppose libpng could be updated to declare row_pointers const, without
breaking anything.

Making a wrapper for SDL surfaces would be useful, especially if it was
included in SDL_image.

Maybe this is headed towards being a patch submission at some point, or
maybe it’s better to just let applications use libpng as they see fit. The
main argument for making it part of SDL proper would be, png is so much nicer
than bmp as an image format, it would be a shame if it didn’t have equal
status.

Note that the BMP routines are in SDL proper, not in SDL_image as they
probably should be. Does that mean that png routines would belong in SDL
proper as well?

It’d take work to make it generic, though (eg. palettes, etc).

Yes, work, but not that much work. Png supports indexed color of course.

Regards,

DanielOn Mon 17 Feb 03 20:15, Glenn Maynard wrote:

On Tue, Feb 18, 2003 at 01:42:01AM +0100, Daniel Phillips wrote:

Yes, file_name works fine as a const. Unfortunately, const png_bytep *rows
generates a warning, because libpng doesn’t declare it as a const. It’s too
bad, but as a compiler feature, const is messed up to an almost unusable
degree (doesn’t play well with inlines, for example). It’s better to leave
the const out than to put in a cast to suppress the warning, and lose all
type safety.

I’d be interested in an example of how casting in a const for "rows"
would break something, if libpng isn’t modifying it, which it certainly
shouldn’t be.

How doesn’t const play well with inlines?

I use const whenever possible, and I’ve never had any problems at all, except
where library writers forgot to use it and forced me to add a lot of const
casts (which has never broken anything for me; it’s just annoying).

Const rarely has an impact on code generation; it’s mostly just a form
of type safety, and it’s OK to force type safety when you know better
than the compiler, such as in this case where you know libpng won’t
modify the buffer but the compiler doesn’t.

(If you’re willing to answer, it should probably be off-list, of course;
the only reason I’m replying on-list is for below.)

Note that the BMP routines are in SDL proper, not in SDL_image as they
probably should be. Does that mean that png routines would belong in SDL
proper as well?

SDL_image (usually) already links to libpng; SDL itself doesn’t.

It’d be nice to have this in SDL_image, since it’s annoying to have to
link apps against extra libraries: it’s much nicer to simply call a
function in a library you’re linking against anyway than to have to
maintain more linkage (eg. autoconf and so on).On Tue, Feb 18, 2003 at 03:52:22AM +0100, Daniel Phillips wrote:


Glenn Maynard

Yes, file_name works fine as a const. Unfortunately, const png_bytep
*rows generates a warning, because libpng doesn’t declare it as a const.
It’s too bad, but as a compiler feature, const is messed up to an almost
unusable degree (doesn’t play well with inlines, for example). It’s
better to leave the const out than to put in a cast to suppress the
warning, and lose all type safety.

I’d be interested in an example of how casting in a const for "rows"
would break something, if libpng isn’t modifying it, which it certainly
shouldn’t be.

The cast doesn’t care what kind of pointer you hand it, whatever you give it
will get cast to (png_bytep *), in other words, you have no type protection
any more. Anyway, think of what you’re trying to tell the compiler: “the
data object I promised nobody was ever going to modify, may now be modified,
regardless”. Better just to forget about the const, life is not perfect.

How doesn’t const play well with inlines?

Consider this perfectly valid program:

inline char *frob(char *s) { return s + 1; }

int main(void)
{
const char *foo = “hello”;
char bar[6] = “world”;
*frob(bar) = ‘x’;
printf("%s\n", frob(foo));
printf("%s\n", frob(bar));
return 0;
}

Now find some combination of const qualifiers on the parameter and result of
frob that lets it compile without warnings. You can’t. In other words, you
can’t write this reasonable-looking address operation generically - you have
to have more than one flavor of frob, which makes very little sense.
Conclusion: the semantics of C’s const qualifiers weren’t thought all the
way through.

I use const whenever possible, and I’ve never had any problems at all,
except where library writers forgot to use it and forced me to add a lot of
const casts (which has never broken anything for me; it’s just annoying).

Yes, well I use inlines a lot more than most people do, and I try to use them
exclusively instead of macros, since they have the advantages of type-safety
and being self-documenting. There are some places where it just doesn’t
work because of language deficiencies, and this is one of them.

Const rarely has an impact on code generation; it’s mostly just a form
of type safety, and it’s OK to force type safety when you know better
than the compiler, such as in this case where you know libpng won’t
modify the buffer but the compiler doesn’t.

(If you’re willing to answer, it should probably be off-list, of course;
the only reason I’m replying on-list is for below.)

Sneaky :slight_smile:

Anyway, you have my reply privately

Note that the BMP routines are in SDL proper, not in SDL_image as they
probably should be. Does that mean that png routines would belong in SDL
proper as well?

SDL_image (usually) already links to libpng; SDL itself doesn’t.

It’d be nice to have this in SDL_image, since it’s annoying to have to
link apps against extra libraries: it’s much nicer to simply call a
function in a library you’re linking against anyway than to have to
maintain more linkage (eg. autoconf and so on).

Yes, killer argument.

Regards, DanielOn Mon 17 Feb 03 21:21, Glenn Maynard wrote:

On Tue, Feb 18, 2003 at 03:52:22AM +0100, Daniel Phillips wrote:

I’d like to load an image, manipulate it and then dump the entire allocated SDL_Surface structure onto a file. Not to save the image as a bitmap since I need to dump other data as well in the same
file. The thing is that everytime I do this legally with fwrite(), I only get 60 bytes of data in the file.
Thanks for the suggestions, by the way. :slight_smile:
:^)v""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""“
±--------+ * Get your own Jmail account.|URL= http://www.jmail.co.jp
|–jmail–| * Get your own home page. |URL= http://www.servance.jp
±--------+ * Get your own domain. |URL= http://domaintorou.com
”""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""v(^:>On Monday 17 February 2003 13.42, Johan Persson wrote:

How do I properly dump a SDL_Surface to a file? I’ve tried several
diffrent methods, but I only get 60 bytes of dumped data. I mean,
that couldn’t possible contain the entire chunk of pixel data, or
could it? What am I doing wrong?

Well, there’s more than one memory block to save - but before we start
talking about that kind of stuff; what do you actually want to do?
Why not just save the surface as an image file of some standard
format? SDL_SaveBMP() is one way.

//David Olofson - Programmer, Composer, Open Source Advocate

Hello Johan,

Tuesday, February 18, 2003, 1:40:22 PM, you wrote:

JP> I’d like to load an image, manipulate it and then dump the entire
JP> allocated SDL_Surface structure onto a file. Not to save the image
JP> as a bitmap since I need to dump other data as well in the same
JP> file. The thing is that everytime I do this legally with fwrite(),
JP> I only get 60 bytes of data in the file.
JP> Thanks for the suggestions, by the way. :slight_smile:

Are you locking the surface before accessing it?–
Lynx,
http://dotNet.lv mailto:@Anatoly_R

[…]

I’d like to load an image, manipulate it and then dump the entire
allocated SDL_Surface structure onto a file. Not to save the image
as a bitmap since I need to dump other data as well in the same
file. The thing is that everytime I do this legally with fwrite(),
I only get 60 bytes of data in the file. Thanks for the
suggestions, by the way. :slight_smile:

Actually, saving a struct to a file isn’t a very nice thing to do, for
a number of reasons. The struct may look different on different
platforms, and it’s fields will differ between little and big
endian architectures. (Some store the lowest byte first; others last.
Some older platforms even store 32 bit values in 0-2-1-3 order and
things like that - although I don’t think any of those are still in
use.)

In this case, there’s another problem: The struct contains a number of
pointers to other structs or arrays. (SDL_Surface::pixels is the one
you’d be particularly interested in, since that’s where the actual
image is.) Storing a pointer in a file is about as useless as it
gets; you’d have to convert it into a file offset or something like
that.

As to dumping various types of data in the same file, consider using
SDL_RWops together with SDL_Load/SaveBMP or something. You can read
and write through libz, libbz2 or whatever that way, or just
implement a primitive “access files by index” archive format. There
are various libs that do this already, so you probably don’t need to
roll your own RWops implementation.

//David Olofson - Programmer, Composer, Open Source Advocate

.- The Return of Audiality! --------------------------------.
| Free/Open Source Audio Engine for use in Games or Studio. |
| RT and off-line synth. Scripting. Sample accurate timing. |
`---------------------------> http://olofson.net/audiality -’
http://olofson.nethttp://www.reologica.se —On Tuesday 18 February 2003 12.40, Johan Persson wrote:

I’ll check the SDL_image source. Anyway, I found a way around the problem. Thanks for the help! :slight_smile:
:^)v""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""“
±--------+ * Get your own Jmail account.|URL= http://www.jmail.co.jp
|–jmail–| * Get your own home page. |URL= http://www.servance.jp
±--------+ * Get your own domain. |URL= http://domaintorou.com
”""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""v(^:>On Tue, Feb 18, 2003 at 01:42:01AM +0100, Daniel Phillips wrote:

int write_png(char *file_name, png_bytep *rows, int w, int h, int colortype, int bitdepth)

“file_name” and “rows” should be declared const.

Making a wrapper for SDL surfaces would be useful, especially if it was
included in SDL_image. It’d take work to make it generic, though (eg.
palettes, etc).


Glenn Maynard

Johan Persson wrote:

How do I properly dump a SDL_Surface to a file? I’ve tried several
diffrent methods, but I only get 60 bytes of dumped data. I mean, that
couldn’t possible contain the entire chunk of pixel data, or
could it? What am I doing wrong?

In my game engine I use tiles to draw some of the graphics, lots of
tiles are stored in a single image file. I wanted to keep a record of
tile sizes, number of tiles in an image, alpha blending values and
colour key info with the image data. To do this I read in the relevant
image file using SDL_LoadBMP(…), then save out the RGB values, tile
sizes etc all to one file. If you like, you can write several image
files with tile sizes etc to one large game assets file.

If you only use >8 BPP bitmap images the you don’t need to save the
palette information, only RGB values.

The RGB values for each pixel can be obtained from the loaded BMP image
by using pixel_format->Rshift, Gshift, Bshift and pixel_format->Rmask,
Gmask and Bmask from the SDL_Surface structure returned by
SDL_LoadBMP(…) on each pixel.

see http://www.libsdl.org/intro/usingvideo.html
and http://games.linux.sk/docs/sdl/guidevideo.html for some hints on
packing and unpacking the RGB values.

also see:
http://sdldoc.csn.ul.ie/sdlpixelformat.php
http://sdldoc.csn.ul.ie/sdlsurface.php

You can read the RGB values back in from the file and the use
SDL_CreateRGBSurface(…) to create a blank surface in the same format as
your main display, the RGB values can then be inserted back into this
surface using the Rmask, Gmask, Rshift, Gshift etc etc.

see http://sdldoc.csn.ul.ie/sdlcreatergbsurface.php for create surface
information

An alterntive to packing the pixels using Rshift etc yourself, is to use
SDL_MapRGB and SDL_GetRGB, but for my engine i’m not using these.

I do not think it is a good idea to use fwrite() to write out the raw
pixel data straight from the loaded surface, because the raw data is
platform specific. i.e on another machine the ‘endian-ness’ (is that
the right word) could be different, and you will just get a garbled
image when you read in the pixel data. Or, you may save out 16 bit
pixel data and try to load that back into a machine that only supports
24 bit surfaces. Anything could happen :slight_smile:

I did originally use the fwrite() method, saved the whole pixel_format
structure along with the image data and used
SDL_CreateRGBSurfaceFrom(…). If your screen is a different format when
you load back in, then I think SDL has to convert the data on each
blit which could/would slow things down.

HTH,

Tom.