add OPENGL_CFLAGS to CPPFLAGS for OpenBSD
[gnash.git] / libbase / GnashImageGif.cpp
blob1b8557985963f7251f0059900e85fa2e8a7f1189
1 // GnashImageGif.cpp: gif_lib wrapper for Gnash.
2 //
3 // Copyright (C) 2005, 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 #include "GnashImageGif.h"
23 #include <sstream>
24 #include <algorithm>
25 #include <boost/scoped_array.hpp>
27 extern "C" {
28 #include <gif_lib.h>
31 #include "utility.h"
32 #include "log.h"
33 #include "GnashException.h"
34 #include "IOChannel.h"
37 namespace gnash {
38 namespace image {
40 namespace {
42 int
43 readData(GifFileType* ft, GifByteType* data, int length)
45 // Do not read until opened.
46 assert(ft);
47 IOChannel* in = reinterpret_cast<IOChannel*>(ft->UserData);
48 return in->read(reinterpret_cast<char*>(data), length);
53 GifInput::GifInput(boost::shared_ptr<IOChannel> in)
55 Input(in),
56 _gif(0),
57 _currentRow(0)
61 GifInput::~GifInput()
63 // Clean up allocated data.
64 DGifCloseFile(_gif);
67 size_t
68 GifInput::getHeight() const
70 assert (_gif);
71 return _gif->SHeight;
74 size_t
75 GifInput::getWidth() const
77 assert (_gif);
78 return _gif->SWidth;
81 void
82 GifInput::readScanline(unsigned char* rgbData)
85 const ColorMapObject* const colormap = (_gif->Image.ColorMap) ?
86 _gif->Image.ColorMap : _gif->SColorMap;
88 assert(colormap);
90 unsigned char* ptr = rgbData;
92 for (size_t i = 0, e = getWidth(); i < e; ++i) {
94 const GifColorType* const mapentry =
95 &colormap->Colors[_gifData[_currentRow][i]];
97 *ptr++ = mapentry->Red;
98 *ptr++ = mapentry->Green;
99 *ptr++ = mapentry->Blue;
102 _currentRow++;
106 bool
107 GifInput::processRecord(GifRecordType record)
109 switch (record) {
111 case IMAGE_DESC_RECORD_TYPE:
113 // Fill the _gif->Image fields
114 if (DGifGetImageDesc(_gif) != GIF_OK) {
115 throw ParserException(_("GIF: Error retrieving image "
116 "description"));
118 const int backgroundColor = _gif->SBackGroundColor;
120 // Set the height dimension of the array
121 _gifData.reset(new PixelRow[getHeight()]);
123 // The GIF 'screen' width and height
124 const size_t screenWidth = getWidth();
125 const size_t screenHeight = getHeight();
127 // Set all the pixels to the background colour.
128 for (size_t i = 0; i < screenHeight; ++i) {
129 // Set the width dimension of the array
130 _gifData[i].reset(new GifPixelType[screenWidth]);
131 // Fill all the pixels with the background color.
132 std::fill_n(_gifData[i].get(), screenWidth,
133 backgroundColor);
136 // The position of the image on the GIF 'screen'
137 const size_t imageHeight = _gif->Image.Height;
138 const size_t imageWidth = _gif->Image.Width;
139 const size_t imageTop = _gif->Image.Top;
140 const size_t imageLeft = _gif->Image.Left;
142 if (imageHeight + imageTop > screenHeight ||
143 imageWidth + imageLeft > screenWidth) {
144 throw ParserException(_("GIF: invalid image data "
145 "(bounds outside GIF screen)"));
148 // Handle interlaced data in four passes.
149 if (_gif->Image.Interlace) {
150 log_debug(_("Found interlaced GIF (%d x %d)"),
151 screenWidth, screenHeight);
153 // The order of interlaced GIFs.
154 const int interlacedOffsets[] = { 0, 4, 2, 1 };
155 const int interlacedJumps[] = { 8, 8, 4, 2 };
157 for (size_t i = 0; i < 4; ++i) {
159 for (size_t j = imageTop + interlacedOffsets[i];
160 j < imageTop + imageHeight;
161 j += interlacedJumps[i]) {
163 if (DGifGetLine(_gif, &_gifData[j][imageLeft],
164 imageWidth) != GIF_OK) {
166 throw ParserException(_("GIF: failed reading "
167 "pixel data"));
172 // One record is enough.
173 return true;
176 // Non-interlaced data.
177 log_debug(_("Found non-interlaced GIF (%d x %d)"),
178 screenWidth, screenHeight);
180 for (size_t i = imageTop; i < imageHeight; ++i) {
181 // Read the gif data into the gif array.
182 if (DGifGetLine(_gif, &_gifData[i][imageLeft], imageWidth)
183 != GIF_OK) {
184 throw ParserException(_("GIF: failed reading "
185 "pixel data"));
188 // One record is enough.
189 return true;
192 case EXTENSION_RECORD_TYPE:
193 // Skip all extension records.
194 GifByteType* extension;
195 int extCode;
196 DGifGetExtension(_gif, &extCode, &extension);
197 while (extension) {
198 if (DGifGetExtensionNext(_gif, &extension) == GIF_ERROR) {
199 break;
202 break;
203 default:
204 break;
206 return false;
209 void
210 GifInput::read()
212 _gif = DGifOpen(_inStream.get(), &readData);
214 GifRecordType record;
216 // Parse the (first?) image into memory.
217 // Is there a multi-dimensional smart array? It's silly to
218 // have to allocate each row separately and can mean a lot
219 // of reallocation.
220 do {
222 if (DGifGetRecordType(_gif, &record) != GIF_OK) {
223 throw ParserException(_("GIF: Error retrieving record type"));
225 if (processRecord(record)) break;
227 } while (record != TERMINATE_RECORD_TYPE);
229 // Set the type to RGB
230 // TODO: implement RGBA!
231 _type = TYPE_RGB;
235 } // namespace image
236 } // namespace gnash
238 // Local Variables:
239 // mode: C++
240 // c-basic-offset: 8
241 // tab-width: 8
242 // indent-tabs-mode: t
243 // End: