VST3: fetch midi mappings all at once, use it for note/sound-off
[carla.git] / source / modules / juce_graphics / image_formats / juce_GIFLoader.cpp
blobf2cd0d86b1d0e0d0af60e0cc5c6f65ed38459fe9
1 /*
2 ==============================================================================
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
23 ==============================================================================
26 namespace juce
29 #if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && JUCE_USE_COREIMAGE_LOADER
30 Image juce_loadWithCoreImage (InputStream& input);
31 #else
33 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6385)
35 //==============================================================================
36 class GIFLoader
38 public:
39 GIFLoader (InputStream& in)
40 : input (in),
41 dataBlockIsZero (false), fresh (false), finished (false),
42 currentBit (0), lastBit (0), lastByteIndex (0),
43 codeSize (0), setCodeSize (0), maxCode (0), maxCodeSize (0),
44 firstcode (0), oldcode (0), clearCode (0), endCode (0)
46 int imageWidth, imageHeight;
47 if (! getSizeFromHeader (imageWidth, imageHeight))
48 return;
50 uint8 buf [16];
51 if (in.read (buf, 3) != 3)
52 return;
54 int numColours = 2 << (buf[0] & 7);
55 int transparent = -1;
57 if ((buf[0] & 0x80) != 0)
58 readPalette (numColours);
60 for (;;)
62 if (input.read (buf, 1) != 1 || buf[0] == ';')
63 break;
65 if (buf[0] == '!')
67 if (readExtension (transparent))
68 continue;
70 break;
73 if (buf[0] != ',')
74 continue;
76 if (input.read (buf, 9) == 9)
78 imageWidth = (int) ByteOrder::littleEndianShort (buf + 4);
79 imageHeight = (int) ByteOrder::littleEndianShort (buf + 6);
81 numColours = 2 << (buf[8] & 7);
83 if ((buf[8] & 0x80) != 0)
84 if (! readPalette (numColours))
85 break;
87 image = Image (transparent >= 0 ? Image::ARGB : Image::RGB,
88 imageWidth, imageHeight, transparent >= 0);
90 image.getProperties()->set ("originalImageHadAlpha", transparent >= 0);
92 readImage ((buf[8] & 0x40) != 0, transparent);
95 break;
99 Image image;
101 private:
102 InputStream& input;
103 uint8 buffer [260];
104 PixelARGB palette [256];
105 bool dataBlockIsZero, fresh, finished;
106 int currentBit, lastBit, lastByteIndex;
107 int codeSize, setCodeSize;
108 int maxCode, maxCodeSize;
109 int firstcode, oldcode;
110 int clearCode, endCode;
111 enum { maxGifCode = 1 << 12 };
112 int table [2] [maxGifCode];
113 int stack [2 * maxGifCode];
114 int* sp;
116 bool getSizeFromHeader (int& w, int& h)
118 // Add an extra byte for the zero terminator
119 char b[7]{};
121 if (input.read (b, 6) == 6
122 && (strncmp ("GIF87a", b, 6) == 0
123 || strncmp ("GIF89a", b, 6) == 0))
125 if (input.read (b, 4) == 4)
127 w = (int) ByteOrder::littleEndianShort (b);
128 h = (int) ByteOrder::littleEndianShort (b + 2);
129 return w > 0 && h > 0;
133 return false;
136 bool readPalette (const int numCols)
138 for (int i = 0; i < numCols; ++i)
140 uint8 rgb[4];
141 input.read (rgb, 3);
143 palette[i].setARGB (0xff, rgb[0], rgb[1], rgb[2]);
144 palette[i].premultiply();
147 return true;
150 int readDataBlock (uint8* const dest)
152 uint8 n;
153 if (input.read (&n, 1) == 1)
155 dataBlockIsZero = (n == 0);
157 if (dataBlockIsZero || (input.read (dest, n) == n))
158 return n;
161 return -1;
164 int readExtension (int& transparent)
166 uint8 type;
167 if (input.read (&type, 1) != 1)
168 return false;
170 uint8 b [260];
171 int n = 0;
173 if (type == 0xf9)
175 n = readDataBlock (b);
176 if (n < 0)
177 return 1;
179 if ((b[0] & 1) != 0)
180 transparent = b[3];
185 n = readDataBlock (b);
187 while (n > 0);
189 return n >= 0;
192 void clearTable()
194 int i;
195 for (i = 0; i < clearCode; ++i)
197 table[0][i] = 0;
198 table[1][i] = i;
201 for (; i < maxGifCode; ++i)
203 table[0][i] = 0;
204 table[1][i] = 0;
208 void initialise (const int inputCodeSize)
210 setCodeSize = inputCodeSize;
211 codeSize = setCodeSize + 1;
212 clearCode = 1 << setCodeSize;
213 endCode = clearCode + 1;
214 maxCodeSize = 2 * clearCode;
215 maxCode = clearCode + 2;
217 getCode (0, true);
219 fresh = true;
220 clearTable();
221 sp = stack;
224 int readLZWByte()
226 if (fresh)
228 fresh = false;
230 for (;;)
232 firstcode = oldcode = getCode (codeSize, false);
234 if (firstcode != clearCode)
235 return firstcode;
239 if (sp > stack)
240 return *--sp;
242 int code;
244 while ((code = getCode (codeSize, false)) >= 0)
246 if (code == clearCode)
248 clearTable();
249 codeSize = setCodeSize + 1;
250 maxCodeSize = 2 * clearCode;
251 maxCode = clearCode + 2;
252 sp = stack;
253 firstcode = oldcode = getCode (codeSize, false);
254 return firstcode;
256 else if (code == endCode)
258 if (dataBlockIsZero)
259 return -2;
261 uint8 buf [260];
262 int n;
264 while ((n = readDataBlock (buf)) > 0)
267 if (n != 0)
268 return -2;
271 const int incode = code;
273 if (code >= maxCode)
275 *sp++ = firstcode;
276 code = oldcode;
279 while (code >= clearCode)
281 *sp++ = table[1][code];
282 if (code == table[0][code])
283 return -2;
285 code = table[0][code];
288 *sp++ = firstcode = table[1][code];
290 if ((code = maxCode) < maxGifCode)
292 table[0][code] = oldcode;
293 table[1][code] = firstcode;
294 ++maxCode;
296 if (maxCode >= maxCodeSize && maxCodeSize < maxGifCode)
298 maxCodeSize <<= 1;
299 ++codeSize;
303 oldcode = incode;
305 if (sp > stack)
306 return *--sp;
309 return code;
312 int getCode (const int codeSize_, const bool shouldInitialise)
314 if (shouldInitialise)
316 currentBit = 0;
317 lastBit = 0;
318 finished = false;
319 return 0;
322 if ((currentBit + codeSize_) >= lastBit)
324 if (finished)
325 return -1;
327 buffer[0] = buffer [lastByteIndex - 2];
328 buffer[1] = buffer [lastByteIndex - 1];
330 const int n = readDataBlock (buffer + 2);
332 if (n == 0)
333 finished = true;
335 lastByteIndex = 2 + n;
336 currentBit = (currentBit - lastBit) + 16;
337 lastBit = (2 + n) * 8 ;
340 int result = 0;
341 int i = currentBit;
343 for (int j = 0; j < codeSize_; ++j)
345 result |= ((buffer[i >> 3] & (1 << (i & 7))) != 0) << j;
346 ++i;
349 currentBit += codeSize_;
350 return result;
353 bool readImage (const int interlace, const int transparent)
355 uint8 c;
356 if (input.read (&c, 1) != 1)
357 return false;
359 initialise (c);
361 if (transparent >= 0)
362 palette [transparent].setARGB (0, 0, 0, 0);
364 int xpos = 0, ypos = 0, yStep = 8, pass = 0;
366 const Image::BitmapData destData (image, Image::BitmapData::writeOnly);
367 uint8* p = destData.getPixelPointer (0, 0);
368 const bool hasAlpha = image.hasAlphaChannel();
370 for (;;)
372 const int index = readLZWByte();
373 if (index < 0)
374 break;
376 if (hasAlpha)
377 ((PixelARGB*) p)->set (palette [index]);
378 else
379 ((PixelRGB*) p)->set (palette [index]);
381 p += destData.pixelStride;
383 if (++xpos == destData.width)
385 xpos = 0;
387 if (interlace)
389 ypos += yStep;
391 while (ypos >= destData.height)
393 switch (++pass)
395 case 1: ypos = 4; yStep = 8; break;
396 case 2: ypos = 2; yStep = 4; break;
397 case 3: ypos = 1; yStep = 2; break;
398 default: return true;
402 else
404 if (++ypos >= destData.height)
405 break;
408 p = destData.getPixelPointer (xpos, ypos);
412 return true;
415 JUCE_DECLARE_NON_COPYABLE (GIFLoader)
418 JUCE_END_IGNORE_WARNINGS_MSVC
420 #endif
422 //==============================================================================
423 GIFImageFormat::GIFImageFormat() {}
424 GIFImageFormat::~GIFImageFormat() {}
426 String GIFImageFormat::getFormatName() { return "GIF"; }
427 bool GIFImageFormat::usesFileExtension (const File& f) { return f.hasFileExtension ("gif"); }
429 bool GIFImageFormat::canUnderstand (InputStream& in)
431 char header [4];
433 return (in.read (header, sizeof (header)) == (int) sizeof (header))
434 && header[0] == 'G'
435 && header[1] == 'I'
436 && header[2] == 'F';
439 Image GIFImageFormat::decodeImage (InputStream& in)
441 #if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && JUCE_USE_COREIMAGE_LOADER
442 return juce_loadWithCoreImage (in);
443 #else
444 const std::unique_ptr<GIFLoader> loader (new GIFLoader (in));
445 return loader->image;
446 #endif
449 bool GIFImageFormat::writeImageToStream (const Image& /*sourceImage*/, OutputStream& /*destStream*/)
451 jassertfalse; // writing isn't implemented for GIFs!
452 return false;
455 } // namespace juce