1 // GnashImage.h: Base class for reading image data in Gnash.
2 //
3 //   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
4 //   Free Software 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
19 //
20 
21 // The GnashImage class and subclasses are partly based on the public domain
22 // work of Thatcher Ulrich <tu@tulrich.com> 2002
23 
24 #ifndef GNASH_GNASHIMAGE_H
25 #define GNASH_GNASHIMAGE_H
26 
27 #include <boost/noncopyable.hpp>
28 #include <cstdint>
29 #include <memory>
30 
31 #include "GnashEnums.h"
32 #include "log.h"
33 #include "dsodefs.h"
34 
35 // Forward declarations
36 namespace gnash {
37     class IOChannel;
38 }
39 
40 namespace gnash {
41 
42 /// Image handling functions and classes.
43 namespace image {
44 
45 /// The types of images handled in Gnash.
46 enum ImageType
47 {
48     GNASH_IMAGE_INVALID,
49     TYPE_RGB,
50     TYPE_RGBA
51 };
52 
53 /// The locations of images handled in Gnash.
54 enum ImageLocation
55 {
56     GNASH_IMAGE_CPU = 1,
57     GNASH_IMAGE_GPU
58 };
59 
60 inline size_t
numChannels(ImageType t)61 numChannels(ImageType t)
62 {
63     switch (t) {
64         case TYPE_RGBA:
65             return 4;
66         case TYPE_RGB:
67             return 3;
68         default:
69             std::abort();
70     }
71 }
72 
73 /// Base class for different types of bitmaps
74 //
75 /// 1. Bytes are packed in RGB(A) order.
76 /// 2. Rowstride is equal to channels * width
77 class DSOEXPORT GnashImage : boost::noncopyable
78 {
79 public:
80 
81     typedef std::uint8_t value_type;
82     typedef std::unique_ptr<value_type[]> container_type;
83     typedef value_type* iterator;
84     typedef const value_type* const_iterator;
85 
~GnashImage()86     virtual ~GnashImage() {}
87 
88     /// Return the ImageType of the image.
89     //
90     /// This saves guessing when dynamic_cast is used.
type()91     ImageType type() const {
92         return _type;
93     }
94 
95     /// Return the ImageLocation of the image.
96     //
97     /// This saves guessing when dynamic_cast is used.
location()98     ImageLocation location() const {
99         return _location;
100     }
101 
102     /// Get the size of the image buffer
103     //
104     /// @return     The size of the buffer in bytes
size()105     size_t size() const {
106         return stride() * _height;
107     }
108 
109     /// Get the pitch of the image buffer
110     //
111     /// @return     The rowstride of the buffer in bytes
stride()112     virtual size_t stride() const {
113         return _width * channels();
114     }
115 
116     /// Get the number of channels
117     //
118     /// @return     The number of channels
channels()119     size_t channels() const {
120         return numChannels(_type);
121     }
122 
123     /// Get the image's width
124     //
125     /// @return     The image's width in pixels.
width()126     size_t width() const {
127         return _width;
128     }
129 
130     /// Get the image's width
131     //
132     /// @return     The image's height in pixels.
height()133     size_t height() const {
134         return _height;
135     }
136 
137     /// Copy image data from a buffer.
138     //
139     /// Note that this buffer MUST have the same rowstride and type, or
140     /// unexpected things will happen. In general, it is only safe to copy
141     /// from another GnashImage or unexpected things will happen.
142     ///
143     /// @param data     buffer to copy data from.
144     void update(const_iterator data);
145 
146     /// Copy image data from another image data
147     //
148     /// Note that this buffer must have the same rowstride and type
149     ///
150     /// @param from     image to copy data from.
151     void update(const GnashImage& from);
152 
153     /// Access the raw data.
begin()154     virtual iterator begin() {
155         return _data.get();
156     }
157 
158     /// Access the raw data
begin()159     virtual const_iterator begin() const {
160         return _data.get();
161     }
162 
163     /// An iterator to the end of the data.
end()164     iterator end() {
165         return begin() + size();
166     }
167 
168     /// An iterator to the end of the data.
end()169     const_iterator end() const {
170         return begin() + size();
171     }
172 
173 protected:
174 
175     /// Construct a GnashImage from a data buffer, taking ownership of the data.
176     //
177     /// @param data     The raw image data. This class takes ownership.
178     /// @param width    The width of the image in pixels.
179     /// @param height   The height of the image in pixels.
180     /// @param pitch    The pitch (rowstride) of the image in bytes.
181     /// @param type     The ImageType of the image.
182     GnashImage(iterator data, size_t width, size_t height, ImageType type,
183             ImageLocation location = GNASH_IMAGE_CPU);
184 
185     /// Construct an empty GnashImage
186     //
187     /// Note: there is an arbitrary limit of std::int32_t::max bytes for the
188     /// total size of the bitmap constructed with this constructor.
189     //
190     /// @param width    The width of the image in pixels.
191     /// @param height   The height of the image in pixels.
192     /// @param type     The ImageType of the image.
193     GnashImage(size_t width, size_t height, ImageType type,
194                ImageLocation location = GNASH_IMAGE_CPU);
195 
196     /// The type of the image: RGBA or RGB.
197     const ImageType _type;
198 
199     /// Image data location (CPU or GPU)
200     const ImageLocation _location;
201 
202     /// Width of image, in pixels
203     const size_t _width;
204 
205     /// Height of image, in pixels
206     const size_t _height;
207 
208     /// Data if held in this class
209     container_type _data;
210 
211 };
212 
213 /// 24-bit RGB bitmap
214 //
215 /// Channels are in RGB order.
216 class DSOEXPORT ImageRGB : public GnashImage
217 {
218 public:
219 
220     /// Create an empty RGB image with uninitialized data.
221     ImageRGB(size_t width, size_t height);
222 
223     /// Create an ImageRGB taking ownership of the data.
ImageRGB(iterator data,size_t width,size_t height)224     ImageRGB(iterator data, size_t width, size_t height)
225         :
226         GnashImage(data, width, height, TYPE_RGB)
227     {}
228 
229     virtual ~ImageRGB();
230 };
231 
232 /// 32-bit RGBA bitmap
233 //
234 /// Channels are in RGBA order.
235 class DSOEXPORT ImageRGBA : public GnashImage
236 {
237 
238 public:
239 
240     /// Create an empty RGB image with uninitialized data.
241     ImageRGBA(size_t width, size_t height);
242 
ImageRGBA(iterator data,size_t width,size_t height)243     ImageRGBA(iterator data, size_t width, size_t height)
244         :
245         GnashImage(data, width, height, TYPE_RGBA)
246     {}
247 
248     ~ImageRGBA();
249 
250     /// Set pixel value
251     //
252     /// TODO: move in base class ?
253     ///
254     void setPixel(size_t x, size_t y, value_type r, value_type g, value_type b,
255             value_type a);
256 };
257 
258 /// The base class for reading image data.
259 class Input : boost::noncopyable
260 {
261 public:
262 
263     /// Construct an Input object to read from an IOChannel.
264     //
265     /// @param in   The stream to read data from. Ownership is shared
266     ///             between caller and Input, so it is freed
267     ///             automatically when the last owner is destroyed.
Input(std::shared_ptr<IOChannel> in)268     Input(std::shared_ptr<IOChannel> in)
269         :
270         _inStream(in),
271         _type(GNASH_IMAGE_INVALID)
272     {}
273 
~Input()274     virtual ~Input() {}
275 
276     /// Begin processing the image data.
277     virtual void read() = 0;
278 
279     /// Get the image's height in pixels.
280     //
281     /// @return     The height of the image in pixels.
282     virtual size_t getHeight() const = 0;
283 
284     /// Get the image's width in pixels.
285     //
286     /// @return     The width of the image in pixels.
287     virtual size_t getWidth() const = 0;
288 
289     /// Get number of components (channels)
290     //
291     /// @return     The number of components, e.g. 3 for RGB
292     virtual size_t getComponents() const = 0;
293 
294     /// Read a scanline's worth of image data into the given buffer.
295     //
296     /// @param rgbData  The buffer for writing raw RGB data to.
297     virtual void readScanline(unsigned char* rgbData) = 0;
298 
299     /// Get the ImageType of the image.
300     //
301     /// @return The type of the image. This is GNASH_IMAGE_INVALID
302     ///         at least until read() has been called and reads some
303     ///         valid data.
imageType()304     ImageType imageType() { return _type; }
305 
306     /// \brief
307     /// For reading SWF JPEG3-style image data, like ordinary JPEG,
308     /// but stores the data in ImageRGBA format.
309     DSOEXPORT static std::unique_ptr<ImageRGBA> readSWFJpeg3(
310             std::shared_ptr<gnash::IOChannel> in);
311 
312     /// Read image data from an IOChannel into an GnashImage.
313     //
314     /// @param in   The IOChannel to read the image from.
315     /// @param type The type of image to read.
316     /// @return     An GnashImage with the read image data. If type
317     ///             is an unsupported FileType or image reading fails,
318     ///             a NULL unique_ptr is returned.
319     DSOEXPORT static std::unique_ptr<GnashImage> readImageData(
320             std::shared_ptr<gnash::IOChannel> in, FileType type);
321 
322 protected:
323 
324     std::shared_ptr<IOChannel> _inStream;
325 
326     ImageType _type;
327 
328 };
329 
330 // Base class for writing image data.
331 class Output : boost::noncopyable
332 {
333 
334 public:
335 
336     /// Construct an Output for writing to an IOChannel
337     //
338     /// @param out      The gnash::IOChannel to write the image to. Ownership
339     ///                 is shared.
340     /// @param width    The width of the resulting image
341     /// @param height   The height of the resulting image.
Output(std::shared_ptr<IOChannel> out,size_t width,size_t height)342     Output(std::shared_ptr<IOChannel> out, size_t width, size_t height)
343         :
344         _width(width),
345         _height(height),
346         _outStream(out)
347     {}
348 
~Output()349     virtual ~Output() {}
350 
351     /// Write RGB image data using the parameters supplied at construction.
352     //
353     /// @param rgbData  The raw RGB image data to write as an image.
354     virtual void writeImageRGB(const unsigned char* rgbData) = 0;
355 
356     /// Write RGBA image data using the parameters supplied at construction.
357     //
358     /// @param rgbaData  The raw RGBA image data to write as an image.
writeImageRGBA(const unsigned char *)359     virtual void writeImageRGBA(const unsigned char* /*rgbaData*/)
360     {
361         log_error(_("This image format does not support writing RGBA images"));
362     }
363 
364     /// Write the given image to the given IOChannel in a specified format.
365     //
366     /// @param type     The image format to write in (see GnashEnums.h)
367     /// @param out      The IOChannel to write to.
368     /// @param image    The image to write.
369     /// @param quality  The quality of the image output, from 0..100. Values
370     ///                 outside this range will be clamped to the minimum or
371     ///                 maxium value. The quality is not used for all
372     ///                 formats.
373     DSOEXPORT static void writeImageData(FileType type,
374             std::shared_ptr<gnash::IOChannel> out, const GnashImage& image,
375             int quality);
376 
377 protected:
378 
379     const size_t _width;
380 
381     const size_t _height;
382 
383     std::shared_ptr<IOChannel> _outStream;
384 
385 };
386 
387 /// Get a pointer to a given row of any image.
388 //
389 /// @param row    The index of the required row.
390 /// @return     A pointer to the first byte of the specified row.
391 inline GnashImage::iterator
scanline(GnashImage & im,size_t row)392 scanline(GnashImage& im, size_t row)
393 {
394     assert(row < im.height());
395     return im.begin() + im.stride() * row;
396 }
397 
398 /// Get a read-only pointer to a given row of any image.
399 //
400 /// @param y    The index of the required row.
401 /// @return     A read-only pointer to the first byte of the specified row.
402 inline GnashImage::const_iterator
scanline(const GnashImage & im,size_t row)403 scanline(const GnashImage& im, size_t row)
404 {
405     assert(row < im.height());
406     return im.begin() + im.stride() * row;
407 }
408 
409 DSOEXPORT void mergeAlpha(ImageRGBA& im, GnashImage::const_iterator alphaData,
410         const size_t bufferLength);
411 
412 } // namespace image
413 } // namespace gnash
414 
415 #endif
416