change bzr to git
[gnash.git] / libbase / GnashImageGif.cpp
blobf6d1b0a9e0d582594ae5e7cebd0b7c63f4e26adb
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 void
107 GifInput::read()
109 _gif = DGifOpen(_inStream.get(), &readData);
111 GifRecordType record;
113 // Parse the (first?) image into memory.
114 // Is there a multi-dimensional smart array? It's silly to
115 // have to allocate each row separately and can mean a lot
116 // of reallocation.
117 do {
119 if (DGifGetRecordType(_gif, &record) != GIF_OK) {
120 throw ParserException(_("GIF: Error retrieving record type"));
123 switch (record) {
125 case IMAGE_DESC_RECORD_TYPE:
127 // Fill the _gif->Image fields
128 if (DGifGetImageDesc(_gif) != GIF_OK) {
129 throw ParserException(_("GIF: Error retrieving image "
130 "description"));
132 const int backgroundColor = _gif->SBackGroundColor;
134 // Set the height dimension of the array
135 _gifData.reset(new PixelRow[getHeight()]);
137 // The GIF 'screen' width and height
138 const size_t screenWidth = getWidth();
139 const size_t screenHeight = getHeight();
141 // Set all the pixels to the background colour.
142 for (size_t i = 0; i < screenHeight; ++i) {
143 // Set the width dimension of the array
144 _gifData[i].reset(new GifPixelType[screenWidth]);
145 // Fill all the pixels with the background color.
146 std::fill_n(_gifData[i].get(), screenWidth,
147 backgroundColor);
150 // The position of the image on the GIF 'screen'
151 const size_t imageHeight = _gif->Image.Height;
152 const size_t imageWidth = _gif->Image.Width;
153 const size_t imageTop = _gif->Image.Top;
154 const size_t imageLeft = _gif->Image.Left;
156 if (imageHeight + imageTop > screenHeight ||
157 imageWidth + imageLeft > screenWidth) {
158 throw ParserException(_("GIF: invalid image data "
159 "(bounds outside GIF screen)"));
162 // Handle interlaced data in four passes.
163 if (_gif->Image.Interlace) {
164 log_debug(_("Found interlaced GIF (%d x %d)"),
165 screenWidth, screenHeight);
167 // The order of interlaced GIFs.
168 const int interlacedOffsets[] = { 0, 4, 2, 1 };
169 const int interlacedJumps[] = { 8, 8, 4, 2 };
171 for (size_t i = 0; i < 4; ++i) {
173 for (size_t j = imageTop + interlacedOffsets[i];
174 j < imageTop + imageHeight;
175 j += interlacedJumps[i]) {
177 if (DGifGetLine(_gif, &_gifData[j][imageLeft],
178 imageWidth) != GIF_OK) {
180 throw ParserException(_("GIF: failed reading "
181 "pixel data"));
186 break;
189 // Non-interlaced data.
190 log_debug(_("Found non-interlaced GIF (%d x %d)"),
191 screenWidth, screenHeight);
193 for (size_t i = imageTop; i < imageHeight; ++i) {
194 // Read the gif data into the gif array.
195 if (DGifGetLine(_gif, &_gifData[i][imageLeft], imageWidth)
196 != GIF_OK) {
197 throw ParserException(_("GIF: failed reading "
198 "pixel data"));
201 break;
203 case EXTENSION_RECORD_TYPE:
204 // Skip all extension records.
205 GifByteType* extension;
206 int extCode;
207 DGifGetExtension(_gif, &extCode, &extension);
208 while (extension) {
209 if (DGifGetExtensionNext(_gif, &extension) == GIF_ERROR) {
210 break;
213 break;
214 default:
215 break;
217 } while (record != TERMINATE_RECORD_TYPE);
219 // Set the type to RGB
220 // TODO: implement RGBA!
221 _type = TYPE_RGB;
225 } // namespace image
226 } // namespace gnash
228 // Local Variables:
229 // mode: C++
230 // c-basic-offset: 8
231 // tab-width: 8
232 // indent-tabs-mode: t
233 // End: