| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2015 - ROLI Ltd.
 - 
 -    Permission is granted to use this software under the terms of either:
 -    a) the GPL v2 (or any later version)
 -    b) the Affero GPL v3
 - 
 -    Details of these licenses can be found at: www.gnu.org/licenses
 - 
 -    JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
 -    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 -    A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 - 
 -    ------------------------------------------------------------------------------
 - 
 -    To release a closed-source product which uses JUCE, commercial licenses are
 -    available: visit www.juce.com for more information.
 - 
 -   ==============================================================================
 - */
 - 
 - #if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && JUCE_USE_COREIMAGE_LOADER
 -  Image juce_loadWithCoreImage (InputStream& input);
 - #else
 - 
 - //==============================================================================
 - class GIFLoader
 - {
 - public:
 -     GIFLoader (InputStream& in)
 -         : input (in),
 -           dataBlockIsZero (false), fresh (false), finished (false),
 -           currentBit (0), lastBit (0), lastByteIndex (0),
 -           codeSize (0), setCodeSize (0), maxCode (0), maxCodeSize (0),
 -           firstcode (0), oldcode (0), clearCode (0), endCode (0)
 -     {
 -         int imageWidth, imageHeight;
 -         if (! getSizeFromHeader (imageWidth, imageHeight))
 -             return;
 - 
 -         uint8 buf [16];
 -         if (in.read (buf, 3) != 3)
 -             return;
 - 
 -         int numColours = 2 << (buf[0] & 7);
 -         int transparent = -1;
 - 
 -         if ((buf[0] & 0x80) != 0)
 -             readPalette (numColours);
 - 
 -         for (;;)
 -         {
 -             if (input.read (buf, 1) != 1 || buf[0] == ';')
 -                 break;
 - 
 -             if (buf[0] == '!')
 -             {
 -                 if (readExtension (transparent))
 -                     continue;
 - 
 -                 break;
 -             }
 - 
 -             if (buf[0] != ',')
 -                 continue;
 - 
 -             if (input.read (buf, 9) == 9)
 -             {
 -                 imageWidth  = (int) ByteOrder::littleEndianShort (buf + 4);
 -                 imageHeight = (int) ByteOrder::littleEndianShort (buf + 6);
 - 
 -                 numColours = 2 << (buf[8] & 7);
 - 
 -                 if ((buf[8] & 0x80) != 0)
 -                     if (! readPalette (numColours))
 -                         break;
 - 
 -                 image = Image (transparent >= 0 ? Image::ARGB : Image::RGB,
 -                                imageWidth, imageHeight, transparent >= 0);
 - 
 -                 image.getProperties()->set ("originalImageHadAlpha", transparent >= 0);
 - 
 -                 readImage ((buf[8] & 0x40) != 0, transparent);
 -             }
 - 
 -             break;
 -         }
 -     }
 - 
 -     Image image;
 - 
 - private:
 -     InputStream& input;
 -     uint8 buffer [260];
 -     PixelARGB palette [256];
 -     bool dataBlockIsZero, fresh, finished;
 -     int currentBit, lastBit, lastByteIndex;
 -     int codeSize, setCodeSize;
 -     int maxCode, maxCodeSize;
 -     int firstcode, oldcode;
 -     int clearCode, endCode;
 -     enum { maxGifCode = 1 << 12 };
 -     int table [2] [maxGifCode];
 -     int stack [2 * maxGifCode];
 -     int* sp;
 - 
 -     bool getSizeFromHeader (int& w, int& h)
 -     {
 -         char b[6];
 - 
 -         if (input.read (b, 6) == 6
 -              && (strncmp ("GIF87a", b, 6) == 0
 -                   || strncmp ("GIF89a", b, 6) == 0))
 -         {
 -             if (input.read (b, 4) == 4)
 -             {
 -                 w = (int) ByteOrder::littleEndianShort (b);
 -                 h = (int) ByteOrder::littleEndianShort (b + 2);
 -                 return w > 0 && h > 0;
 -             }
 -         }
 - 
 -         return false;
 -     }
 - 
 -     bool readPalette (const int numCols)
 -     {
 -         for (int i = 0; i < numCols; ++i)
 -         {
 -             uint8 rgb[4];
 -             input.read (rgb, 3);
 - 
 -             palette[i].setARGB (0xff, rgb[0], rgb[1], rgb[2]);
 -             palette[i].premultiply();
 -         }
 - 
 -         return true;
 -     }
 - 
 -     int readDataBlock (uint8* const dest)
 -     {
 -         uint8 n;
 -         if (input.read (&n, 1) == 1)
 -         {
 -             dataBlockIsZero = (n == 0);
 - 
 -             if (dataBlockIsZero || (input.read (dest, n) == n))
 -                 return n;
 -         }
 - 
 -         return -1;
 -     }
 - 
 -     int readExtension (int& transparent)
 -     {
 -         uint8 type;
 -         if (input.read (&type, 1) != 1)
 -             return false;
 - 
 -         uint8 b [260];
 -         int n = 0;
 - 
 -         if (type == 0xf9)
 -         {
 -             n = readDataBlock (b);
 -             if (n < 0)
 -                 return 1;
 - 
 -             if ((b[0] & 1) != 0)
 -                 transparent = b[3];
 -         }
 - 
 -         do
 -         {
 -             n = readDataBlock (b);
 -         }
 -         while (n > 0);
 - 
 -         return n >= 0;
 -     }
 - 
 -     void clearTable()
 -     {
 -         int i;
 -         for (i = 0; i < clearCode; ++i)
 -         {
 -             table[0][i] = 0;
 -             table[1][i] = i;
 -         }
 - 
 -         for (; i < maxGifCode; ++i)
 -         {
 -             table[0][i] = 0;
 -             table[1][i] = 0;
 -         }
 -     }
 - 
 -     void initialise (const int inputCodeSize)
 -     {
 -         setCodeSize = inputCodeSize;
 -         codeSize = setCodeSize + 1;
 -         clearCode = 1 << setCodeSize;
 -         endCode = clearCode + 1;
 -         maxCodeSize = 2 * clearCode;
 -         maxCode = clearCode + 2;
 - 
 -         getCode (0, true);
 - 
 -         fresh = true;
 -         clearTable();
 -         sp = stack;
 -     }
 - 
 -     int readLZWByte()
 -     {
 -         if (fresh)
 -         {
 -             fresh = false;
 - 
 -             for (;;)
 -             {
 -                 firstcode = oldcode = getCode (codeSize, false);
 - 
 -                 if (firstcode != clearCode)
 -                     return firstcode;
 -             }
 -         }
 - 
 -         if (sp > stack)
 -             return *--sp;
 - 
 -         int code;
 - 
 -         while ((code = getCode (codeSize, false)) >= 0)
 -         {
 -             if (code == clearCode)
 -             {
 -                 clearTable();
 -                 codeSize = setCodeSize + 1;
 -                 maxCodeSize = 2 * clearCode;
 -                 maxCode = clearCode + 2;
 -                 sp = stack;
 -                 firstcode = oldcode = getCode (codeSize, false);
 -                 return firstcode;
 -             }
 -             else if (code == endCode)
 -             {
 -                 if (dataBlockIsZero)
 -                     return -2;
 - 
 -                 uint8 buf [260];
 -                 int n;
 - 
 -                 while ((n = readDataBlock (buf)) > 0)
 -                 {}
 - 
 -                 if (n != 0)
 -                     return -2;
 -             }
 - 
 -             const int incode = code;
 - 
 -             if (code >= maxCode)
 -             {
 -                 *sp++ = firstcode;
 -                 code = oldcode;
 -             }
 - 
 -             while (code >= clearCode)
 -             {
 -                 *sp++ = table[1][code];
 -                 if (code == table[0][code])
 -                     return -2;
 - 
 -                 code = table[0][code];
 -             }
 - 
 -             *sp++ = firstcode = table[1][code];
 - 
 -             if ((code = maxCode) < maxGifCode)
 -             {
 -                 table[0][code] = oldcode;
 -                 table[1][code] = firstcode;
 -                 ++maxCode;
 - 
 -                 if (maxCode >= maxCodeSize && maxCodeSize < maxGifCode)
 -                 {
 -                     maxCodeSize <<= 1;
 -                     ++codeSize;
 -                 }
 -             }
 - 
 -             oldcode = incode;
 - 
 -             if (sp > stack)
 -                 return *--sp;
 -         }
 - 
 -         return code;
 -     }
 - 
 -     int getCode (const int codeSize_, const bool shouldInitialise)
 -     {
 -         if (shouldInitialise)
 -         {
 -             currentBit = 0;
 -             lastBit = 0;
 -             finished = false;
 -             return 0;
 -         }
 - 
 -         if ((currentBit + codeSize_) >= lastBit)
 -         {
 -             if (finished)
 -                 return -1;
 - 
 -             buffer[0] = buffer [lastByteIndex - 2];
 -             buffer[1] = buffer [lastByteIndex - 1];
 - 
 -             const int n = readDataBlock (buffer + 2);
 - 
 -             if (n == 0)
 -                 finished = true;
 - 
 -             lastByteIndex = 2 + n;
 -             currentBit = (currentBit - lastBit) + 16;
 -             lastBit = (2 + n) * 8 ;
 -         }
 - 
 -         int result = 0;
 -         int i = currentBit;
 - 
 -         for (int j = 0; j < codeSize_; ++j)
 -         {
 -             result |= ((buffer[i >> 3] & (1 << (i & 7))) != 0) << j;
 -             ++i;
 -         }
 - 
 -         currentBit += codeSize_;
 -         return result;
 -     }
 - 
 -     bool readImage (const int interlace, const int transparent)
 -     {
 -         uint8 c;
 -         if (input.read (&c, 1) != 1)
 -             return false;
 - 
 -         initialise (c);
 - 
 -         if (transparent >= 0)
 -             palette [transparent].setARGB (0, 0, 0, 0);
 - 
 -         int xpos = 0, ypos = 0, yStep = 8, pass = 0;
 - 
 -         const Image::BitmapData destData (image, Image::BitmapData::writeOnly);
 -         uint8* p = destData.getPixelPointer (0, 0);
 -         const bool hasAlpha = image.hasAlphaChannel();
 - 
 -         for (;;)
 -         {
 -             const int index = readLZWByte();
 -             if (index < 0)
 -                 break;
 - 
 -             if (hasAlpha)
 -                 ((PixelARGB*) p)->set (palette [index]);
 -             else
 -                 ((PixelRGB*)  p)->set (palette [index]);
 - 
 -             p += destData.pixelStride;
 - 
 -             if (++xpos == destData.width)
 -             {
 -                 xpos = 0;
 - 
 -                 if (interlace)
 -                 {
 -                     ypos += yStep;
 - 
 -                     while (ypos >= destData.height)
 -                     {
 -                         switch (++pass)
 -                         {
 -                             case 1:     ypos = 4; yStep = 8; break;
 -                             case 2:     ypos = 2; yStep = 4; break;
 -                             case 3:     ypos = 1; yStep = 2; break;
 -                             default:    return true;
 -                         }
 -                     }
 -                 }
 -                 else
 -                 {
 -                     if (++ypos >= destData.height)
 -                         break;
 -                 }
 - 
 -                 p = destData.getPixelPointer (xpos, ypos);
 -             }
 -         }
 - 
 -         return true;
 -     }
 - 
 -     JUCE_DECLARE_NON_COPYABLE (GIFLoader)
 - };
 - 
 - #endif
 - 
 - //==============================================================================
 - GIFImageFormat::GIFImageFormat() {}
 - GIFImageFormat::~GIFImageFormat() {}
 - 
 - String GIFImageFormat::getFormatName()                  { return "GIF"; }
 - bool GIFImageFormat::usesFileExtension (const File& f)  { return f.hasFileExtension ("gif"); }
 - 
 - bool GIFImageFormat::canUnderstand (InputStream& in)
 - {
 -     char header [4];
 - 
 -     return (in.read (header, sizeof (header)) == sizeof (header))
 -              && header[0] == 'G'
 -              && header[1] == 'I'
 -              && header[2] == 'F';
 - }
 - 
 - Image GIFImageFormat::decodeImage (InputStream& in)
 - {
 -    #if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && JUCE_USE_COREIMAGE_LOADER
 -     return juce_loadWithCoreImage (in);
 -    #else
 -     const ScopedPointer<GIFLoader> loader (new GIFLoader (in));
 -     return loader->image;
 -    #endif
 - }
 - 
 - bool GIFImageFormat::writeImageToStream (const Image& /*sourceImage*/, OutputStream& /*destStream*/)
 - {
 -     jassertfalse; // writing isn't implemented for GIFs!
 -     return false;
 - }
 
 
  |