JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_GIFLoader.cpp
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
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.
22
23 ==============================================================================
24*/
25
26namespace juce
27{
28
29#if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && JUCE_USE_COREIMAGE_LOADER
30 Image juce_loadWithCoreImage (InputStream& input);
31#else
32
33JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6385)
34
35//==============================================================================
37{
38public:
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)
45 {
47 if (! getSizeFromHeader (imageWidth, imageHeight))
48 return;
49
50 uint8 buf [16];
51 if (in.read (buf, 3) != 3)
52 return;
53
54 int numColours = 2 << (buf[0] & 7);
55 int transparent = -1;
56
57 if ((buf[0] & 0x80) != 0)
58 readPalette (numColours);
59
60 for (;;)
61 {
62 if (input.read (buf, 1) != 1 || buf[0] == ';')
63 break;
64
65 if (buf[0] == '!')
66 {
67 if (readExtension (transparent))
68 continue;
69
70 break;
71 }
72
73 if (buf[0] != ',')
74 continue;
75
76 if (input.read (buf, 9) == 9)
77 {
80
81 numColours = 2 << (buf[8] & 7);
82
83 if ((buf[8] & 0x80) != 0)
84 if (! readPalette (numColours))
85 break;
86
87 image = Image (transparent >= 0 ? Image::ARGB : Image::RGB,
89
90 image.getProperties()->set ("originalImageHadAlpha", transparent >= 0);
91
92 readImage ((buf[8] & 0x40) != 0, transparent);
93 }
94
95 break;
96 }
97 }
98
99 Image image;
100
101private:
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;
115
116 bool getSizeFromHeader (int& w, int& h)
117 {
118 // Add an extra byte for the zero terminator
119 char b[7]{};
120
121 if (input.read (b, 6) == 6
122 && (strncmp ("GIF87a", b, 6) == 0
123 || strncmp ("GIF89a", b, 6) == 0))
124 {
125 if (input.read (b, 4) == 4)
126 {
128 h = (int) ByteOrder::littleEndianShort (b + 2);
129 return w > 0 && h > 0;
130 }
131 }
132
133 return false;
134 }
135
136 bool readPalette (const int numCols)
137 {
138 for (int i = 0; i < numCols; ++i)
139 {
140 uint8 rgb[4];
141 input.read (rgb, 3);
142
143 palette[i].setARGB (0xff, rgb[0], rgb[1], rgb[2]);
144 palette[i].premultiply();
145 }
146
147 return true;
148 }
149
150 int readDataBlock (uint8* const dest)
151 {
152 uint8 n;
153 if (input.read (&n, 1) == 1)
154 {
155 dataBlockIsZero = (n == 0);
156
157 if (dataBlockIsZero || (input.read (dest, n) == n))
158 return n;
159 }
160
161 return -1;
162 }
163
164 int readExtension (int& transparent)
165 {
166 uint8 type;
167 if (input.read (&type, 1) != 1)
168 return false;
169
170 uint8 b [260];
171 int n = 0;
172
173 if (type == 0xf9)
174 {
175 n = readDataBlock (b);
176 if (n < 0)
177 return 1;
178
179 if ((b[0] & 1) != 0)
180 transparent = b[3];
181 }
182
183 do
184 {
185 n = readDataBlock (b);
186 }
187 while (n > 0);
188
189 return n >= 0;
190 }
191
192 void clearTable()
193 {
194 int i;
195 for (i = 0; i < clearCode; ++i)
196 {
197 table[0][i] = 0;
198 table[1][i] = i;
199 }
200
201 for (; i < maxGifCode; ++i)
202 {
203 table[0][i] = 0;
204 table[1][i] = 0;
205 }
206 }
207
208 void initialise (const int inputCodeSize)
209 {
210 setCodeSize = inputCodeSize;
211 codeSize = setCodeSize + 1;
212 clearCode = 1 << setCodeSize;
213 endCode = clearCode + 1;
214 maxCodeSize = 2 * clearCode;
215 maxCode = clearCode + 2;
216
217 getCode (0, true);
218
219 fresh = true;
220 clearTable();
221 sp = stack;
222 }
223
224 int readLZWByte()
225 {
226 if (fresh)
227 {
228 fresh = false;
229
230 for (;;)
231 {
232 firstcode = oldcode = getCode (codeSize, false);
233
234 if (firstcode != clearCode)
235 return firstcode;
236 }
237 }
238
239 if (sp > stack)
240 return *--sp;
241
242 int code;
243
244 while ((code = getCode (codeSize, false)) >= 0)
245 {
246 if (code == clearCode)
247 {
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;
255 }
256 else if (code == endCode)
257 {
258 if (dataBlockIsZero)
259 return -2;
260
261 uint8 buf [260];
262 int n;
263
264 while ((n = readDataBlock (buf)) > 0)
265 {}
266
267 if (n != 0)
268 return -2;
269 }
270
271 const int incode = code;
272
273 if (code >= maxCode)
274 {
275 *sp++ = firstcode;
276 code = oldcode;
277 }
278
279 while (code >= clearCode)
280 {
281 *sp++ = table[1][code];
282 if (code == table[0][code])
283 return -2;
284
285 code = table[0][code];
286 }
287
288 *sp++ = firstcode = table[1][code];
289
290 if ((code = maxCode) < maxGifCode)
291 {
292 table[0][code] = oldcode;
293 table[1][code] = firstcode;
294 ++maxCode;
295
296 if (maxCode >= maxCodeSize && maxCodeSize < maxGifCode)
297 {
298 maxCodeSize <<= 1;
299 ++codeSize;
300 }
301 }
302
303 oldcode = incode;
304
305 if (sp > stack)
306 return *--sp;
307 }
308
309 return code;
310 }
311
312 int getCode (const int codeSize_, const bool shouldInitialise)
313 {
315 {
316 currentBit = 0;
317 lastBit = 0;
318 finished = false;
319 return 0;
320 }
321
322 if ((currentBit + codeSize_) >= lastBit)
323 {
324 if (finished)
325 return -1;
326
327 buffer[0] = buffer [jmax (0, lastByteIndex - 2)];
328 buffer[1] = buffer [jmax (0, lastByteIndex - 1)];
329
330 const int n = readDataBlock (buffer + 2);
331
332 if (n == 0)
333 finished = true;
334
335 lastByteIndex = 2 + n;
336 currentBit = (currentBit - lastBit) + 16;
337 lastBit = (2 + n) * 8 ;
338 }
339
340 int result = 0;
341 int i = currentBit;
342
343 for (int j = 0; j < codeSize_; ++j)
344 {
345 result |= ((buffer[i >> 3] & (1 << (i & 7))) != 0) << j;
346 ++i;
347 }
348
349 currentBit += codeSize_;
350 return result;
351 }
352
353 bool readImage (const int interlace, const int transparent)
354 {
355 uint8 c;
356 if (input.read (&c, 1) != 1)
357 return false;
358
359 initialise (c);
360
361 if (transparent >= 0)
362 palette [transparent].setARGB (0, 0, 0, 0);
363
364 int xpos = 0, ypos = 0, yStep = 8, pass = 0;
365
366 const Image::BitmapData destData (image, Image::BitmapData::writeOnly);
367 uint8* p = destData.getPixelPointer (0, 0);
368 const bool hasAlpha = image.hasAlphaChannel();
369
370 for (;;)
371 {
372 const int index = readLZWByte();
373 if (index < 0)
374 break;
375
376 if (hasAlpha)
377 ((PixelARGB*) p)->set (palette [index]);
378 else
379 ((PixelRGB*) p)->set (palette [index]);
380
381 p += destData.pixelStride;
382
383 if (++xpos == destData.width)
384 {
385 xpos = 0;
386
387 if (interlace)
388 {
389 ypos += yStep;
390
391 while (ypos >= destData.height)
392 {
393 switch (++pass)
394 {
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;
399 }
400 }
401 }
402 else
403 {
404 if (++ypos >= destData.height)
405 break;
406 }
407
408 p = destData.getPixelPointer (xpos, ypos);
409 }
410 }
411
412 return true;
413 }
414
416};
417
418JUCE_END_IGNORE_WARNINGS_MSVC
419
420#endif
421
422//==============================================================================
423GIFImageFormat::GIFImageFormat() {}
424GIFImageFormat::~GIFImageFormat() {}
425
427bool GIFImageFormat::usesFileExtension (const File& f) { return f.hasFileExtension ("gif"); }
428
430{
431 char header [4];
432
433 return (in.read (header, sizeof (header)) == (int) sizeof (header))
434 && header[0] == 'G'
435 && header[1] == 'I'
436 && header[2] == 'F';
437}
438
440{
441 #if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && JUCE_USE_COREIMAGE_LOADER
442 return juce_loadWithCoreImage (in);
443 #else
445 return loader->image;
446 #endif
447}
448
449bool GIFImageFormat::writeImageToStream (const Image& /*sourceImage*/, OutputStream& /*destStream*/)
450{
451 jassertfalse; // writing isn't implemented for GIFs!
452 return false;
453}
454
455} // namespace juce
static constexpr uint16 littleEndianShort(const void *bytes) noexcept
Turns 2 bytes into a little-endian integer.
Represents a local file or directory.
Definition juce_File.h:45
bool hasFileExtension(StringRef extensionToTest) const
Checks whether the file has a given extension.
String getFormatName() override
Returns a description of this file format.
bool usesFileExtension(const File &) override
Returns true if this format uses the file extension of the given file.
bool canUnderstand(InputStream &) override
Returns true if the given stream seems to contain data that this format understands.
bool writeImageToStream(const Image &, OutputStream &) override
Attempts to write an image to a stream.
Image decodeImage(InputStream &) override
Tries to decode and return an image from the given stream.
Retrieves a section of an image as raw pixel data, so it can be read or written to.
Definition juce_Image.h:310
int pixelStride
The number of bytes between each pixel.
Definition juce_Image.h:355
uint8 * getPixelPointer(int x, int y) const noexcept
Returns a pointer to a pixel in the image.
Definition juce_Image.h:334
Holds a fixed-size bitmap.
Definition juce_Image.h:58
@ ARGB
< each pixel is a 4-byte ARGB premultiplied colour value.
Definition juce_Image.h:67
@ RGB
< each pixel is a 3-byte packed RGB colour value.
Definition juce_Image.h:66
The base class for streams that read data.
virtual int read(void *destBuffer, int maxBytesToRead)=0
Reads some data from the stream into a memory buffer.
The base class for streams that write data to some kind of destination.
Represents a 32-bit INTERNAL pixel with premultiplied alpha, and can perform compositing operations w...
void setARGB(uint8 a, uint8 r, uint8 g, uint8 b) noexcept
Sets the pixel's colour from individual components.
forcedinline void premultiply() noexcept
Premultiplies the pixel's RGB values by its alpha.
Represents a 24-bit RGB pixel, and can perform compositing operations on it.
The JUCE String class!
Definition juce_String.h:53
#define JUCE_DECLARE_NON_COPYABLE(className)
This is a shorthand macro for deleting a class's copy constructor and copy assignment operator.
#define jassertfalse
This will always cause an assertion failure.
typedef int
JUCE Namespace.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
unsigned char uint8
A platform-independent 8-bit unsigned integer type.
strncmp