Innnards: Can I render very, very large images with gd?

As the author of the WWW FAQ, I regularly answer questions about the workings of the Web. If a question is frequently asked, I simply add an article to the FAQ. But sometimes a question is more detailed, more in-depth— not really a FAQ, but still of interest to others. You'll find those questions, with my answers, here in Innards along with commentary on other web-technology-related topics.

2008-08-14

Q. I'm wondering if GD has any problems when creating very large images, and if it has been tested in this way. An application we are working on will need to create some high resolution poster size images, which will be memory eating monsters. We'll probably use GD-Sharp, if this is feasible.

A. What do you consider "very large?"

Truecolor images take up four bytes per pixel. Palette-based images require up one byte per pixel.

A truecolor image which is 4,000 pixels on a side therefore requires 4,000x4,000 = 16 million pixels, for a total of 64 million bytes (64mb).

If you really need to "paint" freely on the entire image with gdImageLine and friends, then gd is pretty much doing it right, and you'll just have to make sure you are in a position to allocate that much memory (assuming your images are really that big... the math improves very quickly as images get smaller). You mentioned C#; there's no inherent memory limit in C# other than the resources of your system, but if you're using C# in the context of a web server it's possible that there are limits that have been set to prevent runaway scripts from using lots of memory. So you might have to tweak a setting and redefine "lots." Similarly, PHP users who use gd for large images will need to alter the default memory limits for a single PHP script, which are usually set quite low in php.ini.

If you are generating an image that could be generated one horizontal line at a time, you can take advantage of enormous memory economies by using the Independent JPEG Group or libpng libraries directly and generating your image a line at a time, never actually allocating a big memory buffer for the whole thing. If this doesn't make sense to you, it's probably not suitable for your application.

There is a hybrid strategy: painting broad "stripes" of the image at a time. This was a common strategy for rendering graphics in PostScript printers before memory got so darn cheap.

You can still implement that strategy today, using gd to draw segments of the image (adding an appropriate offset on the Y axis to every gd call), then pasting the resulting images together with a utility that works row by row. Something like pnmcat or, once again, using the libjpeg or libpng libraries directly. Of course, rendering the same drawing function calls several times for several slices in this way is slow. Compressing and uncompressing images repeatedly is slow, too, although you could avoid that problem by adding PPM output to gd (not very hard, since it's a deliberately simple format). Still, gd isn't designed to do super-efficient clipping, so it will spend a lot of time calculating pixels that don't get drawn.

But if you're simply asking "as long as we have the memory, can gd cope with crazy-big images?" the answer is yes. Just do the math first— and consider queueing the requests so two images are never generated simultaneously in response to separate web requests or instances of the same program. Semaphores, synchronization locks and even good ol' lockfiles or database locks can help you accomplish this job.

Also be sure to destroy any gd images as soon as you're done with them. Many coders create several versions of a gd image, write them all to disk, and never set the variables to null or, when coding directly in C, call gdImageDestroy until the program ends... then wonder why they are running out of memory so soon.

Hope this is helpful!


Follow us on Twitter | Contact Us

Copyright 1994-2012 Boutell.Com, Inc. All Rights Reserved.