Plug more leaks (in the test, not the core)
[gnash.git] / libbase / GnashImage.cpp
blobb93ace2c2a8bc7e3edb7939732fefd9fc8cf38fb
1 // Image.cpp: image data class for Gnash.
2 //
3 // Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software
4 // Foundation, Inc
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 // Based on the public domain work of Thatcher Ulrich <tu@tulrich.com> 2002
23 #include "GnashImage.h"
25 #include <memory>
26 #include <boost/scoped_array.hpp>
27 #include <boost/shared_ptr.hpp>
28 #include <algorithm>
30 #ifdef USE_PNG
31 # include "GnashImagePng.h"
32 #endif
33 #ifdef USE_GIF
34 # include "GnashImageGif.h"
35 #endif
36 #include "GnashEnums.h"
37 #include "GnashImageJpeg.h"
38 #include "IOChannel.h"
39 #include "log.h"
40 #include "GnashNumeric.h"
42 namespace gnash {
43 namespace image {
45 namespace {
46 void processAlpha(GnashImage::iterator imageData, size_t pixels);
49 GnashImage::GnashImage(iterator data, size_t width, size_t height,
50 ImageType type, ImageLocation location)
52 _type(type),
53 _location(location),
54 _width(width),
55 _height(height),
56 _data(data)
60 /// Create an image allocating a buffer of height*pitch bytes
61 GnashImage::GnashImage(size_t width, size_t height, ImageType type,
62 ImageLocation location)
64 _type(type),
65 _location(location),
66 _width(width),
67 _height(height)
69 const size_t max = std::numeric_limits<boost::int32_t>::max();
70 if (size() > max) {
71 throw std::bad_alloc();
73 _data.reset(new value_type[size()]);
76 void
77 GnashImage::update(const_iterator data)
79 std::copy(data, data + size(), _data.get());
82 void
83 GnashImage::update(const GnashImage& from)
85 assert(size() <= from.size());
86 assert(width() == from.width());
87 assert(_type == from._type);
88 assert(_location == from._location);
89 std::copy(from.begin(), from.begin() + size(), begin());
92 ImageRGB::ImageRGB(size_t width, size_t height)
94 GnashImage(width, height, TYPE_RGB)
98 ImageRGB::~ImageRGB()
102 ImageRGBA::ImageRGBA(size_t width, size_t height)
104 GnashImage(width, height, TYPE_RGBA)
108 ImageRGBA::~ImageRGBA()
112 void
113 ImageRGBA::setPixel(size_t x, size_t y, value_type r, value_type g,
114 value_type b, value_type a)
116 assert(x < _width);
117 assert(y < _height);
119 iterator data = scanline(*this, y) + 4 * x;
121 *data = r;
122 *(data + 1) = g;
123 *(data + 2) = b;
124 *(data + 3) = a;
128 void
129 mergeAlpha(ImageRGBA& im, GnashImage::const_iterator alphaData,
130 const size_t bufferLength)
132 assert(bufferLength * 4 <= im.size());
134 // Point to the first alpha byte
135 GnashImage::iterator p = im.begin();
137 // Premultiplication is also done at rendering time (at least by the
138 // agg renderer).
139 // TODO: use BitmapData.loadBitmap to check whether it's also done here.
140 for (size_t i = 0; i < bufferLength; ++i, ++alphaData) {
141 *p = std::min(*p, *alphaData);
142 ++p;
143 *p = std::min(*p, *alphaData);
144 ++p;
145 *p = std::min(*p, *alphaData);
146 ++p;
147 *p = *alphaData;
148 ++p;
153 // utility
156 // Write the given image to the given out stream, in jpeg format.
157 void
158 Output::writeImageData(FileType type,
159 boost::shared_ptr<IOChannel> out, const GnashImage& image, int quality)
162 const size_t width = image.width();
163 const size_t height = image.height();
165 quality = clamp<int>(quality, 0, 100);
167 std::auto_ptr<Output> outChannel;
169 switch (type) {
170 #ifdef USE_PNG
171 case GNASH_FILETYPE_PNG:
172 outChannel = createPngOutput(out, width, height, quality);
173 break;
174 #endif
175 case GNASH_FILETYPE_JPEG:
176 outChannel = JpegOutput::create(out, width, height, quality);
177 break;
178 default:
179 log_error("Requested to write image as unsupported filetype");
180 break;
183 switch (image.type()) {
184 case TYPE_RGB:
185 outChannel->writeImageRGB(image.begin());
186 break;
187 case TYPE_RGBA:
188 outChannel->writeImageRGBA(image.begin());
189 break;
190 default:
191 break;
196 // See GnashEnums.h for file types.
197 std::auto_ptr<GnashImage>
198 Input::readImageData(boost::shared_ptr<IOChannel> in, FileType type)
200 std::auto_ptr<GnashImage> im;
201 std::auto_ptr<Input> inChannel;
203 switch (type) {
204 #ifdef USE_PNG
205 case GNASH_FILETYPE_PNG:
206 inChannel = createPngInput(in);
207 break;
208 #endif
209 #ifdef USE_GIF
210 case GNASH_FILETYPE_GIF:
211 inChannel = createGifInput(in);
212 break;
213 #endif
214 case GNASH_FILETYPE_JPEG:
215 inChannel = JpegInput::create(in);
216 break;
217 default:
218 break;
221 if (!inChannel.get()) return im;
223 const size_t height = inChannel->getHeight();
224 const size_t width = inChannel->getWidth();
226 try {
227 switch (inChannel->imageType()) {
228 case TYPE_RGB:
229 im.reset(new ImageRGB(width, height));
230 break;
231 case TYPE_RGBA:
232 im.reset(new ImageRGBA(width, height));
233 break;
234 default:
235 log_error("Invalid image returned");
236 return im;
239 catch (std::bad_alloc& e) {
240 // This should be caught here because ~JpegInput can also
241 // throw an exception on stack unwinding and this confuses
242 // remote catchers.
243 log_error("Out of memory while trying to create %dx%d image",
244 width, height);
245 return im;
249 for (size_t i = 0; i < height; ++i) {
250 inChannel->readScanline(scanline(*im, i));
253 // The renderers expect RGBA data to be preprocessed. JPEG images are
254 // never transparent, but the addition of alpha data stored elsewhere
255 // in the SWF is possible; in that case, the processing happens during
256 // mergeAlpha().
257 if (im->type() == TYPE_RGBA) {
258 processAlpha(im->begin(), width * height);
260 return im;
263 // For reading SWF JPEG3-style image data, like ordinary JPEG,
264 // but stores the data in ImageRGBA format.
265 std::auto_ptr<ImageRGBA>
266 Input::readSWFJpeg3(boost::shared_ptr<IOChannel> in)
269 std::auto_ptr<ImageRGBA> im;
271 // Calling with headerBytes as 0 has a special effect...
272 std::auto_ptr<JpegInput> j_in(
273 JpegInput::createSWFJpeg2HeaderOnly(in, 0));
275 // If this isn't true, we should have thrown.
276 assert(j_in.get());
278 j_in->read();
280 const size_t height = j_in->getHeight();
281 const size_t width = j_in->getWidth();
283 im.reset(new ImageRGBA(width, height));
285 boost::scoped_array<GnashImage::value_type> line(
286 new GnashImage::value_type[3 * width]);
288 for (size_t y = 0; y < height; ++y) {
289 j_in->readScanline(line.get());
291 GnashImage::iterator data = scanline(*im, y);
292 for (size_t x = 0; x < width; ++x) {
293 data[4*x+0] = line[3*x+0];
294 data[4*x+1] = line[3*x+1];
295 data[4*x+2] = line[3*x+2];
296 data[4*x+3] = 255;
300 return im;
303 namespace {
305 void
306 processAlpha(GnashImage::iterator imageData, size_t pixels)
308 GnashImage::iterator p = imageData;
309 for (size_t i = 0; i < pixels; ++i) {
310 GnashImage::value_type alpha = *(p + 3);
311 *p = std::min(*p, alpha);
312 ++p;
313 *p = std::min(*p, alpha);
314 ++p;
315 *p = std::min(*p, alpha);
316 p += 2;
320 } // anonymous namespace
321 } // namespace image
322 } // namespace gnash