1 // Image.cpp: image data class for Gnash.
3 // Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software
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.
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.
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"
26 #include <boost/scoped_array.hpp>
27 #include <boost/shared_ptr.hpp>
31 # include "GnashImagePng.h"
34 # include "GnashImageGif.h"
36 #include "GnashEnums.h"
37 #include "GnashImageJpeg.h"
38 #include "IOChannel.h"
40 #include "GnashNumeric.h"
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
)
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
)
69 const size_t max
= std::numeric_limits
<boost::int32_t>::max();
71 throw std::bad_alloc();
73 _data
.reset(new value_type
[size()]);
77 GnashImage::update(const_iterator data
)
79 std::copy(data
, data
+ size(), _data
.get());
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
)
102 ImageRGBA::ImageRGBA(size_t width
, size_t height
)
104 GnashImage(width
, height
, TYPE_RGBA
)
108 ImageRGBA::~ImageRGBA()
113 ImageRGBA::setPixel(size_t x
, size_t y
, value_type r
, value_type g
,
114 value_type b
, value_type a
)
119 iterator data
= scanline(*this, y
) + 4 * x
;
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
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
);
143 *p
= std::min(*p
, *alphaData
);
145 *p
= std::min(*p
, *alphaData
);
156 // Write the given image to the given out stream, in jpeg format.
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
;
171 case GNASH_FILETYPE_PNG
:
172 outChannel
= PngOutput::create(out
, width
, height
, quality
);
175 case GNASH_FILETYPE_JPEG
:
176 outChannel
= JpegOutput::create(out
, width
, height
, quality
);
179 log_error("Requested to write image as unsupported filetype");
183 switch (image
.type()) {
185 outChannel
->writeImageRGB(image
.begin());
188 outChannel
->writeImageRGBA(image
.begin());
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
;
205 case GNASH_FILETYPE_PNG
:
206 inChannel
= PngInput::create(in
);
210 case GNASH_FILETYPE_GIF
:
211 inChannel
= GifInput::create(in
);
214 case GNASH_FILETYPE_JPEG
:
215 inChannel
= JpegInput::create(in
);
221 if (!inChannel
.get()) return im
;
223 const size_t height
= inChannel
->getHeight();
224 const size_t width
= inChannel
->getWidth();
227 switch (inChannel
->imageType()) {
229 im
.reset(new ImageRGB(width
, height
));
232 im
.reset(new ImageRGBA(width
, height
));
235 log_error("Invalid image returned");
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
243 log_error("Out of memory while trying to create %dx%d image",
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
257 if (im
->type() == TYPE_RGBA
) {
258 processAlpha(im
->begin(), width
* height
);
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.
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];
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
);
313 *p
= std::min(*p
, alpha
);
315 *p
= std::min(*p
, alpha
);
320 } // anonymous namespace