Krita Source Code Documentation
Loading...
Searching...
No Matches
QGIFLibHandler Class Reference

#include <qgiflibhandler.h>

+ Inheritance diagram for QGIFLibHandler:

Public Member Functions

bool canRead () const override
 
QVariant option (ImageOption option) const override
 
 QGIFLibHandler ()
 
bool read (QImage *image) override
 
void setOption (ImageOption option, const QVariant &value) override
 
bool supportsOption (ImageOption option) const override
 
bool write (const QImage &image) override
 

Static Public Member Functions

static bool canRead (QIODevice *device)
 

Private Attributes

QString m_description
 

Detailed Description

Definition at line 14 of file qgiflibhandler.h.

Constructor & Destructor Documentation

◆ QGIFLibHandler()

QGIFLibHandler::QGIFLibHandler ( )

Definition at line 32 of file qgiflibhandler.cpp.

33 : QImageIOHandler()
34{
35}

Member Function Documentation

◆ canRead() [1/2]

bool QGIFLibHandler::canRead ( ) const
override

Definition at line 37 of file qgiflibhandler.cpp.

38{
39 if (canRead(device())) {
40 setFormat("gif");
41 return true;
42 }
43 return false;
44}
bool canRead() const override

References canRead().

◆ canRead() [2/2]

bool QGIFLibHandler::canRead ( QIODevice * device)
static

Definition at line 209 of file qgiflibhandler.cpp.

210{
211 if (!device) {
212 qWarning("QGIFLibHandler::canRead() called with no device");
213 return false;
214 }
215
216 char head[6];
217 if (device->peek(head, sizeof(head)) == sizeof(head))
218 return qstrncmp(head, "GIF87a", 6) == 0
219 || qstrncmp(head, "GIF89a", 6) == 0;
220 return false;
221}

◆ option()

QVariant QGIFLibHandler::option ( ImageOption option) const
override
Todo
Todo

Definition at line 339 of file qgiflibhandler.cpp.

340{
341 switch (option)
342 {
343 case QImageIOHandler::ImageFormat:
344 return QVariant();
345 break;
346 case QImageIOHandler::Size:
347 return QVariant();
348 break;
349 case QImageIOHandler::Description:
350 return QVariant(m_description);
351 break;
352 default:
353 return QVariant();
354 }
355}
QString m_description
QVariant option(ImageOption option) const override

References m_description, and option().

◆ read()

bool QGIFLibHandler::read ( QImage * image)
override
Todo
is it correct to override default fill color?

Definition at line 46 of file qgiflibhandler.cpp.

47{
48 // The contents of this function are based on gif2rgb.c, from the giflib source.
49// qDebug("QGIFLibHandler::read into image with size %d x %d", image->size().width(), image->size().height());
50
51 int err;
52 GifFileType* gifFile = DGifOpen(device(), doInput, &err);
53 if (!gifFile) {
54 qWarning() << "Received error code" << err;
55 return false;
56 }
57// qDebug("dimensions %d x %d", gifFile->SWidth, gifFile->SHeight);
58
59 *image = QImage(gifFile->SWidth, gifFile->SHeight, QImage::Format_Indexed8);
60
61 GifRecordType recordType;
62 ColorMapObject* ColorMap;
63
64 int i, row, imageNum = 0, topRow, width, height;
65 int transColor = -1;
66 do
67 {
68 DGifGetRecordType(gifFile, &recordType);
69 switch (recordType)
70 {
71 case IMAGE_DESC_RECORD_TYPE:
72 if (DGifGetImageDesc(gifFile) == GIF_ERROR)
73 {
74 qWarning("QGIFLibHandler::read: error %d", gifFile->Error);
75 return false;
76 }
77 topRow = gifFile->Image.Top; /* Image Position relative to Screen. */
78 width = gifFile->Image.Width;
79 height = gifFile->Image.Height;
80 //qDebug("Image %d at (%d, %d) [%dx%d]", ++imageNum, gifFile->Image.Left, topRow, width, height);
81 if (gifFile->Image.Left + width > gifFile->SWidth ||
82 gifFile->Image.Top + height > gifFile->SHeight)
83 {
84 qWarning("Image %d is not confined to screen dimension, aborted.", imageNum);
85 return false;
86 }
87
88 // Pre-fill with background color
89// qDebug("background color is at index %d", gifFile->SBackGroundColor);
90 image->fill(gifFile->SBackGroundColor);
91
92 // Now read the image data
93 if (gifFile->Image.Interlace)
94 {
95 /* Need to perform 4 passes on the images: */
96 for (i = 0; i < 4; i++)
97 for (row = topRow + InterlacedOffset[i]; row < topRow + height;
98 row += InterlacedJumps[i])
99 {
100 if (DGifGetLine(gifFile, image->scanLine(row), width) == GIF_ERROR)
101 {
102 qWarning("QGIFLibHandler::read: error %d", gifFile->Error);
103 return false;
104 }
105 // else
106 // qDebug("got row %d: %d %d %d %d %d %d %d %d ...", row,
107 // image->scanLine(row)[0], image->scanLine(row)[1], image->scanLine(row)[2], image->scanLine(row)[3],
108 // image->scanLine(row)[4], image->scanLine(row)[5], image->scanLine(row)[6], image->scanLine(row)[7]);
109 }
110 }
111 else
112 {
113 for (row = 0; row < height; row++)
114 {
115 if (DGifGetLine(gifFile, image->scanLine(row), width) == GIF_ERROR)
116 {
117 qWarning("QGIFLibHandler::read: error %d", gifFile->Error);
118 return false;
119 }
120 // else
121 // qDebug("got row %d: %d %d %d %d %d %d %d %d ...", row,
122 // image->scanLine(row)[0], image->scanLine(row)[1], image->scanLine(row)[2], image->scanLine(row)[3],
123 // image->scanLine(row)[4], image->scanLine(row)[5], image->scanLine(row)[6], image->scanLine(row)[7]);
124 }
125 }
126 break;
127 case EXTENSION_RECORD_TYPE:
128 {
129 int extCode;
130 GifByteType* extData;
131 /* Skip any extension blocks in file: */
132 if (DGifGetExtension(gifFile, &extCode, &extData) == GIF_ERROR)
133 {
134 qWarning("QGIFLibHandler::read: error %d", gifFile->Error);
135 return false;
136 }
137 while (extData != NULL)
138 {
139 int len = extData[0];
140 switch (extCode)
141 {
142 case GRAPHICS_EXT_FUNC_CODE: // Graphics control extension
143// qDebug("graphics control: %x %x %x %x %x", extData[0], extData[1], extData[2], extData[3], extData[4]);
144 // Should be block size, packed fields, delay time,
145 // transparent color, block terminator
146 // see doc/gif89.txt in libgif source package
147 // If the trans bit is set in packed fields,
148 // then set the trans color to the one given
149 if (extData[1] & 0x01)
150 {
151 transColor = extData[3];
152// qDebug("transparent color is at index %d", transColor);
154 // image->fill(transColor);
155 }
156 break;
157 case COMMENT_EXT_FUNC_CODE:
158 {
159 QByteArray comment((char*)(extData + 1), len);
160 // qDebug("comment of len %d: \"%s\"", len, comment.constData());
161 image->setText("Description", comment);
162 }
163 break;
164 case PLAINTEXT_EXT_FUNC_CODE:
165 break;
166 }
167 if (DGifGetExtensionNext(gifFile, &extData) == GIF_ERROR)
168 {
169 qWarning("QGIFLibHandler::read: error %d", gifFile->Error);
170 return false;
171 }
172 }
173 }
174 break;
175 case TERMINATE_RECORD_TYPE:
176 break;
177 default:
178 break;
179 }
180 }
181 while (recordType != TERMINATE_RECORD_TYPE);
182
183 // BackGround = gifFile->SBackGroundColor;
184 ColorMap = (gifFile->Image.ColorMap
185 ? gifFile->Image.ColorMap
186 : gifFile->SColorMap);
187 if (!ColorMap)
188 {
189 qWarning("QGIFLibHandler::read: Image does not have a colormap");
190 return false;
191 }
192 int ccount = ColorMap->ColorCount;
193 image->setColorCount(ccount);
194 for (i = 0; i < ccount; ++i)
195 {
196 GifColorType gifColor = ColorMap->Colors[i];
197 QRgb color = gifColor.Blue | (gifColor.Green << 8) | (gifColor.Red << 16);
198 // If this is not the transparent color,
199 // set the alpha to opaque.
200 if (i != transColor)
201 color |= 0xff << 24;
202 // qDebug("color %d: 0x%X", i, color);
203 image->setColor(i, color);
204 }
205
206 return true;
207}
unsigned int QRgb
const uint16_t ColorMap
int doInput(GifFileType *gif, GifByteType *data, int i)
static const int InterlacedOffset[]
static const int InterlacedJumps[]

References doInput(), InterlacedJumps, and InterlacedOffset.

◆ setOption()

void QGIFLibHandler::setOption ( ImageOption option,
const QVariant & value )
override

Definition at line 332 of file qgiflibhandler.cpp.

333{
334 // qDebug("setOption given option %d, variant of type %d", option, value.type());
335 if (option == QImageIOHandler::Description)
336 m_description = value.toString();
337}
float value(const T *src, size_t ch)

References m_description, option(), and value().

◆ supportsOption()

bool QGIFLibHandler::supportsOption ( ImageOption option) const
override

Definition at line 315 of file qgiflibhandler.cpp.

316{
317 // qDebug("supportsOption %d", option);
318 switch (option)
319 {
320 // These are relevant only for reading
321 case QImageIOHandler::ImageFormat:
322 case QImageIOHandler::Size:
323 // This is relevant for both reading and writing
324 case QImageIOHandler::Description:
325 return true;
326 break;
327 default:
328 return false;
329 }
330}

References option().

◆ write()

bool QGIFLibHandler::write ( const QImage & image)
override
Todo
how to specify dithering method
Todo
based on colorCount (or not? we did ask for Format_Indexed8, so the data is always 8-bit, right?)
Todo
transparent GIFs (use alpha?)
Todo
write to m_device
Todo
how to specify which version, or decide based on features in use
Todo
how to specify background
Todo
foreach of multiple images in an animation...

Definition at line 223 of file qgiflibhandler.cpp.

224{
225 QImage toWrite(image);
227 if (toWrite.colorCount() == 0 || toWrite.colorCount() > 256)
228 toWrite = image.convertToFormat(QImage::Format_Indexed8);
229
230 QVector<QRgb> colorTable = toWrite.colorTable();
231 ColorMapObject cmap;
232 // colorCount must be a power of 2
233 int colorCount = 1 << GifBitSize(toWrite.colorCount());
234 cmap.ColorCount = colorCount;
235 cmap.BitsPerPixel = 8;
236 GifColorType* colorValues = (GifColorType*)malloc(cmap.ColorCount * sizeof(GifColorType));
237 cmap.Colors = colorValues;
238 int c = 0;
239 for(; c < toWrite.colorCount(); ++c)
240 {
241// qDebug("color %d has %02X%02X%02X", c, qRed(colorTable[c]), qGreen(colorTable[c]), qBlue(colorTable[c]));
242 colorValues[c].Red = qRed(colorTable[c]);
243 colorValues[c].Green = qGreen(colorTable[c]);
244 colorValues[c].Blue = qBlue(colorTable[c]);
245 }
246 // In case we had an actual number of colors that's not a power of 2,
247 // fill the rest with something (black perhaps).
248 for (; c < colorCount; ++c)
249 {
250 colorValues[c].Red = 0;
251 colorValues[c].Green = 0;
252 colorValues[c].Blue = 0;
253 }
255
256
258 int err;
259 GifFileType *gif = EGifOpen(device(), doOutput, &err);
260
262 // Because of this call, libgif is not reentrant
263 EGifSetGifVersion(gif, true);
264
266 if (EGifPutScreenDesc(gif, toWrite.width(), toWrite.height(), colorCount, 0, &cmap) == GIF_ERROR) {
267 qWarning("EGifPutScreenDesc returned error %d", gif->Error);
268 }
269
270 QVariant descText = option(QImageIOHandler::Description);
271 if (descText.type() == QVariant::String)
272 {
273 QString comment = descText.toString();
274 // Will be something like "Description: actual text" or just
275 // ": actual text", so remove everything leading up to and
276 // including the first colon and the space following it.
277 int idx = comment.indexOf(": ");
278 if (idx >= 0)
279 comment.remove(0, idx + 2);
280 // qDebug() << "comment:" << comment;
281 if (!comment.isEmpty())
282 EGifPutComment(gif, comment.toUtf8().constData());
283 }
284 // else
285 // qDebug("description is of qvariant type %d", descText.type());
286
288 if (EGifPutImageDesc(gif, 0, 0, toWrite.width(), toWrite.height(), 0, &cmap) == GIF_ERROR)
289 qWarning("EGifPutImageDesc returned error %d", gif->Error);
290
291 int lc = toWrite.height();
292
293 // NOTE: we suppose that the pixel size is exactly 1 byte, right now we
294 // cannot save anything else
295 int llen = toWrite.width();
296
297 // qDebug("will write %d lines, %d bytes each", lc, llen);
298
299 for (int l = 0; l < lc; ++l)
300 {
301 uchar* line = toWrite.scanLine(l);
302 if (EGifPutLine(gif, (GifPixelType*)line, llen) == GIF_ERROR)
303 {
304 int i = gif->Error;
305 qWarning("EGifPutLine returned error %d", i);
306 }
307 }
308
309 EGifCloseFile(gif, &err);
310 free(colorValues);
311
312 return true;
313}
int doOutput(GifFileType *gif, const GifByteType *data, int i)

References doOutput(), and option().

Member Data Documentation

◆ m_description

QString QGIFLibHandler::m_description
private

Definition at line 27 of file qgiflibhandler.h.


The documentation for this class was generated from the following files: