From 90b74fcdeeabe8e7e8d82d89612e9a04953920d0 Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Thu, 26 Aug 2010 18:25:24 +0100 Subject: [PATCH] Made image-loading use CoreImage on the Mac and iOS. --- Builds/MacOSX/Juce.xcodeproj/project.pbxproj | 2 - Builds/VisualStudio2005/Juce.vcproj | 1 - Builds/VisualStudio2008/Juce.vcproj | 1 - Builds/VisualStudio2008_DLL/Juce.vcproj | 1 - Builds/VisualStudio2010/Juce.vcxproj | 1 - Builds/VisualStudio2010/Juce.vcxproj.filters | 3 - Builds/iPhone/Juce.xcodeproj/project.pbxproj | 2 - Juce.jucer | 2 - juce_amalgamated.cpp | 821 ++++++++++-------- juce_amalgamated.h | 24 +- src/core/juce_StandardHeader.h | 2 +- .../image_file_formats/juce_GIFLoader.cpp | 651 +++++++------- .../image_file_formats/juce_GIFLoader.h | 81 -- .../image_file_formats/juce_JPEGLoader.cpp | 8 + .../image_file_formats/juce_PNGLoader.cpp | 8 + .../graphics/imaging/juce_ImageFileFormat.cpp | 37 - .../graphics/imaging/juce_ImageFileFormat.h | 23 +- .../mac/juce_mac_CoreGraphicsContext.mm | 38 + 18 files changed, 893 insertions(+), 813 deletions(-) delete mode 100644 src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.h diff --git a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj index 487722f683..5c968ac4b6 100644 --- a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj +++ b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj @@ -850,7 +850,6 @@ 2AA4DDD1F26188A570F4DBE2 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_RelativeCoordinate.cpp; path = ../../src/gui/graphics/geometry/juce_RelativeCoordinate.cpp; sourceTree = SOURCE_ROOT; }; 54D9BBB69BDA3837240F7749 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_RelativeCoordinate.h; path = ../../src/gui/graphics/geometry/juce_RelativeCoordinate.h; sourceTree = SOURCE_ROOT; }; 0F1C5770B363EF7DF64A876A = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_GIFLoader.cpp; path = ../../src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.cpp; sourceTree = SOURCE_ROOT; }; - EFBDB957445BD56D0458535D = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_GIFLoader.h; path = ../../src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.h; sourceTree = SOURCE_ROOT; }; 6619D27E74F623B1E8CE8F71 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_JPEGLoader.cpp; path = ../../src/gui/graphics/imaging/image_file_formats/juce_JPEGLoader.cpp; sourceTree = SOURCE_ROOT; }; EAF0F2EAB230F7539B91A7FB = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_PNGLoader.cpp; path = ../../src/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp; sourceTree = SOURCE_ROOT; }; 0337723C9D607B82CF8AA682 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CameraDevice.h; path = ../../src/gui/graphics/imaging/juce_CameraDevice.h; sourceTree = SOURCE_ROOT; }; @@ -1602,7 +1601,6 @@ 54D9BBB69BDA3837240F7749 ); name = geometry; sourceTree = ""; }; D71FD838B3FD1536FCA839A4 = { isa = PBXGroup; children = ( 0F1C5770B363EF7DF64A876A, - EFBDB957445BD56D0458535D, 6619D27E74F623B1E8CE8F71, EAF0F2EAB230F7539B91A7FB ); name = image_file_formats; sourceTree = ""; }; 36A6F90D0C87EA1D8FBE9EC0 = { isa = PBXGroup; children = ( diff --git a/Builds/VisualStudio2005/Juce.vcproj b/Builds/VisualStudio2005/Juce.vcproj index 72d02dce50..8cec0e60f9 100644 --- a/Builds/VisualStudio2005/Juce.vcproj +++ b/Builds/VisualStudio2005/Juce.vcproj @@ -766,7 +766,6 @@ - diff --git a/Builds/VisualStudio2008/Juce.vcproj b/Builds/VisualStudio2008/Juce.vcproj index a8ffbf0bc7..29722a3839 100644 --- a/Builds/VisualStudio2008/Juce.vcproj +++ b/Builds/VisualStudio2008/Juce.vcproj @@ -766,7 +766,6 @@ - diff --git a/Builds/VisualStudio2008_DLL/Juce.vcproj b/Builds/VisualStudio2008_DLL/Juce.vcproj index 7428441592..9134e904cf 100644 --- a/Builds/VisualStudio2008_DLL/Juce.vcproj +++ b/Builds/VisualStudio2008_DLL/Juce.vcproj @@ -768,7 +768,6 @@ - diff --git a/Builds/VisualStudio2010/Juce.vcxproj b/Builds/VisualStudio2010/Juce.vcxproj index c8548547ec..fd63953d0d 100644 --- a/Builds/VisualStudio2010/Juce.vcxproj +++ b/Builds/VisualStudio2010/Juce.vcxproj @@ -707,7 +707,6 @@ - diff --git a/Builds/VisualStudio2010/Juce.vcxproj.filters b/Builds/VisualStudio2010/Juce.vcxproj.filters index a91fde5a59..1d44545144 100644 --- a/Builds/VisualStudio2010/Juce.vcxproj.filters +++ b/Builds/VisualStudio2010/Juce.vcxproj.filters @@ -2043,9 +2043,6 @@ Juce\Source\gui\graphics\geometry - - Juce\Source\gui\graphics\imaging\image_file_formats - Juce\Source\gui\graphics\imaging diff --git a/Builds/iPhone/Juce.xcodeproj/project.pbxproj b/Builds/iPhone/Juce.xcodeproj/project.pbxproj index c48254e55a..752d134c36 100644 --- a/Builds/iPhone/Juce.xcodeproj/project.pbxproj +++ b/Builds/iPhone/Juce.xcodeproj/project.pbxproj @@ -850,7 +850,6 @@ 2AA4DDD1F26188A570F4DBE2 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_RelativeCoordinate.cpp; path = ../../src/gui/graphics/geometry/juce_RelativeCoordinate.cpp; sourceTree = SOURCE_ROOT; }; 54D9BBB69BDA3837240F7749 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_RelativeCoordinate.h; path = ../../src/gui/graphics/geometry/juce_RelativeCoordinate.h; sourceTree = SOURCE_ROOT; }; 0F1C5770B363EF7DF64A876A = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_GIFLoader.cpp; path = ../../src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.cpp; sourceTree = SOURCE_ROOT; }; - EFBDB957445BD56D0458535D = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_GIFLoader.h; path = ../../src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.h; sourceTree = SOURCE_ROOT; }; 6619D27E74F623B1E8CE8F71 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_JPEGLoader.cpp; path = ../../src/gui/graphics/imaging/image_file_formats/juce_JPEGLoader.cpp; sourceTree = SOURCE_ROOT; }; EAF0F2EAB230F7539B91A7FB = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_PNGLoader.cpp; path = ../../src/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp; sourceTree = SOURCE_ROOT; }; 0337723C9D607B82CF8AA682 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CameraDevice.h; path = ../../src/gui/graphics/imaging/juce_CameraDevice.h; sourceTree = SOURCE_ROOT; }; @@ -1602,7 +1601,6 @@ 54D9BBB69BDA3837240F7749 ); name = geometry; sourceTree = ""; }; D71FD838B3FD1536FCA839A4 = { isa = PBXGroup; children = ( 0F1C5770B363EF7DF64A876A, - EFBDB957445BD56D0458535D, 6619D27E74F623B1E8CE8F71, EAF0F2EAB230F7539B91A7FB ); name = image_file_formats; sourceTree = ""; }; 36A6F90D0C87EA1D8FBE9EC0 = { isa = PBXGroup; children = ( diff --git a/Juce.jucer b/Juce.jucer index e39ef89007..2a20c74b72 100644 --- a/Juce.jucer +++ b/Juce.jucer @@ -1129,8 +1129,6 @@ - loader (new GIFLoader (in)); - return loader->getImage(); - } - - bool writeImageToStream (const Image& /*sourceImage*/, OutputStream& /*destStream*/) - { - return false; - } -}; - ImageFileFormat* ImageFileFormat::findImageFormatForStream (InputStream& input) { static PNGImageFormat png; @@ -95976,255 +95887,195 @@ END_JUCE_NAMESPACE /*** Start of inlined file: juce_GIFLoader.cpp ***/ BEGIN_JUCE_NAMESPACE -GIFLoader::GIFLoader (InputStream& in) - : input (in), - dataBlockIsZero (false), - fresh (false), - finished (false) +#if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && ! DONT_USE_COREIMAGE_LOADER + const Image juce_loadWithCoreImage (InputStream& input); +#else + +class GIFLoader { - currentBit = lastBit = lastByteIndex = 0; - maxCode = maxCodeSize = codeSize = setCodeSize = 0; - firstcode = oldcode = 0; - clearCode = end_code = 0; +public: + GIFLoader (InputStream& in) + : input (in), + dataBlockIsZero (false), + fresh (false), + finished (false) + { + currentBit = lastBit = lastByteIndex = 0; + maxCode = maxCodeSize = codeSize = setCodeSize = 0; + firstcode = oldcode = 0; + clearCode = end_code = 0; - int imageWidth, imageHeight; - int transparent = -1; + int imageWidth, imageHeight; + int transparent = -1; - if (! getSizeFromHeader (imageWidth, imageHeight)) - return; + if (! getSizeFromHeader (imageWidth, imageHeight)) + return; - if ((imageWidth <= 0) || (imageHeight <= 0)) - return; + if ((imageWidth <= 0) || (imageHeight <= 0)) + return; - unsigned char buf [16]; - if (in.read (buf, 3) != 3) - return; + unsigned char buf [16]; + if (in.read (buf, 3) != 3) + return; - int numColours = 2 << (buf[0] & 7); + int numColours = 2 << (buf[0] & 7); - if ((buf[0] & 0x80) != 0) - readPalette (numColours); + if ((buf[0] & 0x80) != 0) + readPalette (numColours); - for (;;) - { - if (input.read (buf, 1) != 1) - break; - - if (buf[0] == ';') - break; - - if (buf[0] == '!') + for (;;) { - if (input.read (buf, 1) != 1) - break; - - if (processExtension (buf[0], transparent) < 0) + if (input.read (buf, 1) != 1 || buf[0] == ';') break; - continue; - } - - if (buf[0] != ',') - continue; + if (buf[0] == '!') + { + if (input.read (buf, 1) != 1) + break; - if (input.read (buf, 9) != 9) - break; + if (processExtension (buf[0], transparent) < 0) + break; - imageWidth = makeWord (buf[4], buf[5]); - imageHeight = makeWord (buf[6], buf[7]); + continue; + } - numColours = 2 << (buf[8] & 7); + if (buf[0] != ',') + continue; - if ((buf[8] & 0x80) != 0) - if (! readPalette (numColours)) + if (input.read (buf, 9) != 9) break; - image = Image ((transparent >= 0) ? Image::ARGB : Image::RGB, - imageWidth, imageHeight, (transparent >= 0)); + imageWidth = makeWord (buf[4], buf[5]); + imageHeight = makeWord (buf[6], buf[7]); - readImage ((buf[8] & 0x40) != 0, transparent); + numColours = 2 << (buf[8] & 7); - break; - } -} + if ((buf[8] & 0x80) != 0) + if (! readPalette (numColours)) + break; -GIFLoader::~GIFLoader() -{ -} + image = Image ((transparent >= 0) ? Image::ARGB : Image::RGB, + imageWidth, imageHeight, (transparent >= 0)); -bool GIFLoader::getSizeFromHeader (int& w, int& h) -{ - char b[8]; + readImage ((buf[8] & 0x40) != 0, transparent); - if (input.read (b, 6) == 6) - { - if ((strncmp ("GIF87a", b, 6) == 0) - || (strncmp ("GIF89a", b, 6) == 0)) - { - if (input.read (b, 4) == 4) - { - w = makeWord (b[0], b[1]); - h = makeWord (b[2], b[3]); - return true; - } + break; } } - return false; -} - -bool GIFLoader::readPalette (const int numCols) -{ - unsigned char rgb[4]; - - for (int i = 0; i < numCols; ++i) - { - input.read (rgb, 3); - - palette [i][0] = rgb[0]; - palette [i][1] = rgb[1]; - palette [i][2] = rgb[2]; - palette [i][3] = 0xff; - } - - return true; -} - -int GIFLoader::readDataBlock (unsigned char* const dest) -{ - unsigned char n; - - if (input.read (&n, 1) == 1) - { - dataBlockIsZero = (n == 0); + ~GIFLoader() {} - if (dataBlockIsZero || (input.read (dest, n) == n)) - return n; - } - - return -1; -} - -int GIFLoader::processExtension (const int type, int& transparent) -{ - unsigned char b [300]; - int n = 0; - - if (type == 0xf9) - { - n = readDataBlock (b); - if (n < 0) - return 1; + Image image; - if ((b[0] & 0x1) != 0) - transparent = b[3]; - } +private: + InputStream& input; + uint8 buffer [300]; + uint8 palette [256][4]; + bool dataBlockIsZero, fresh, finished; + int currentBit, lastBit, lastByteIndex; + int codeSize, setCodeSize; + int maxCode, maxCodeSize; + int firstcode, oldcode; + int clearCode, end_code; + enum { maxGifCode = 1 << 12 }; + int table [2] [maxGifCode]; + int stack [2 * maxGifCode]; + int *sp; - do + bool getSizeFromHeader (int& w, int& h) { - n = readDataBlock (b); - } - while (n > 0); + char b[8]; - return n; -} + if (input.read (b, 6) == 6) + { + if ((strncmp ("GIF87a", b, 6) == 0) + || (strncmp ("GIF89a", b, 6) == 0)) + { + if (input.read (b, 4) == 4) + { + w = makeWord (b[0], b[1]); + h = makeWord (b[2], b[3]); + return true; + } + } + } -int GIFLoader::getCode (const int codeSize_, const bool initialise) -{ - if (initialise) - { - currentBit = 0; - lastBit = 0; - finished = false; - return 0; + return false; } - if ((currentBit + codeSize_) >= lastBit) + bool readPalette (const int numCols) { - if (finished) - return -1; + unsigned char rgb[4]; - buffer[0] = buffer [lastByteIndex - 2]; - buffer[1] = buffer [lastByteIndex - 1]; - - const int n = readDataBlock (&buffer[2]); + for (int i = 0; i < numCols; ++i) + { + input.read (rgb, 3); - if (n == 0) - finished = true; + palette [i][0] = rgb[0]; + palette [i][1] = rgb[1]; + palette [i][2] = rgb[2]; + palette [i][3] = 0xff; + } - lastByteIndex = 2 + n; - currentBit = (currentBit - lastBit) + 16; - lastBit = (2 + n) * 8 ; + return true; } - int result = 0; - int i = currentBit; - - for (int j = 0; j < codeSize_; ++j) + int readDataBlock (unsigned char* dest) { - result |= ((buffer[i >> 3] & (1 << (i & 7))) != 0) << j; - ++i; - } + unsigned char n; - currentBit += codeSize_; + if (input.read (&n, 1) == 1) + { + dataBlockIsZero = (n == 0); - return result; -} + if (dataBlockIsZero || (input.read (dest, n) == n)) + return n; + } -int GIFLoader::readLZWByte (const bool initialise, const int inputCodeSize) -{ - int code, incode, i; + return -1; + } - if (initialise) + int processExtension (const int type, int& transparent) { - setCodeSize = inputCodeSize; - codeSize = setCodeSize + 1; - clearCode = 1 << setCodeSize; - end_code = clearCode + 1; - maxCodeSize = 2 * clearCode; - maxCode = clearCode + 2; - - getCode (0, true); - - fresh = true; + unsigned char b [300]; + int n = 0; - for (i = 0; i < clearCode; ++i) + if (type == 0xf9) { - table[0][i] = 0; - table[1][i] = i; + n = readDataBlock (b); + if (n < 0) + return 1; + + if ((b[0] & 0x1) != 0) + transparent = b[3]; } - for (; i < maxGifCode; ++i) + do { - table[0][i] = 0; - table[1][i] = 0; + n = readDataBlock (b); } + while (n > 0); - sp = stack; - - return 0; + return n; } - else if (fresh) + + int readLZWByte (const bool initialise, const int inputCodeSize) { - fresh = false; + int code, incode, i; - do + if (initialise) { - firstcode = oldcode - = getCode (codeSize, false); - } - while (firstcode == clearCode); + setCodeSize = inputCodeSize; + codeSize = setCodeSize + 1; + clearCode = 1 << setCodeSize; + end_code = clearCode + 1; + maxCodeSize = 2 * clearCode; + maxCode = clearCode + 2; - return firstcode; - } + getCode (0, true); - if (sp > stack) - return *--sp; + fresh = true; - while ((code = getCode (codeSize, false)) >= 0) - { - if (code == clearCode) - { for (i = 0; i < clearCode; ++i) { table[0][i] = 0; @@ -96237,158 +96088,276 @@ int GIFLoader::readLZWByte (const bool initialise, const int inputCodeSize) table[1][i] = 0; } - codeSize = setCodeSize + 1; - maxCodeSize = 2 * clearCode; - maxCode = clearCode + 2; sp = stack; - firstcode = oldcode = getCode (codeSize, false); - return firstcode; + return 0; } - else if (code == end_code) + else if (fresh) { - if (dataBlockIsZero) - return -2; - - unsigned char buf [260]; + fresh = false; - int n; - while ((n = readDataBlock (buf)) > 0) - {} + do + { + firstcode = oldcode + = getCode (codeSize, false); + } + while (firstcode == clearCode); - if (n != 0) - return -2; + return firstcode; } - incode = code; + if (sp > stack) + return *--sp; - if (code >= maxCode) + while ((code = getCode (codeSize, false)) >= 0) { - *sp++ = firstcode; - code = oldcode; - } + if (code == clearCode) + { + for (i = 0; i < clearCode; ++i) + { + table[0][i] = 0; + table[1][i] = i; + } - while (code >= clearCode) - { - *sp++ = table[1][code]; - if (code == table[0][code]) - return -2; + for (; i < maxGifCode; ++i) + { + table[0][i] = 0; + table[1][i] = 0; + } - code = table[0][code]; - } + codeSize = setCodeSize + 1; + maxCodeSize = 2 * clearCode; + maxCode = clearCode + 2; + sp = stack; + firstcode = oldcode = getCode (codeSize, false); + return firstcode; + + } + else if (code == end_code) + { + if (dataBlockIsZero) + return -2; - *sp++ = firstcode = table[1][code]; + unsigned char buf [260]; - if ((code = maxCode) < maxGifCode) - { - table[0][code] = oldcode; - table[1][code] = firstcode; - ++maxCode; + int n; + while ((n = readDataBlock (buf)) > 0) + {} + + if (n != 0) + return -2; + } - if ((maxCode >= maxCodeSize) - && (maxCodeSize < maxGifCode)) + incode = code; + + if (code >= maxCode) { - maxCodeSize <<= 1; - ++codeSize; + *sp++ = firstcode; + code = oldcode; } - } - oldcode = incode; + while (code >= clearCode) + { + *sp++ = table[1][code]; + if (code == table[0][code]) + return -2; - if (sp > stack) - return *--sp; - } + code = table[0][code]; + } - return code; -} + *sp++ = firstcode = table[1][code]; -bool GIFLoader::readImage (const int interlace, const int transparent) -{ - unsigned char c; + if ((code = maxCode) < maxGifCode) + { + table[0][code] = oldcode; + table[1][code] = firstcode; + ++maxCode; - if (input.read (&c, 1) != 1 - || readLZWByte (true, c) < 0) - return false; + if ((maxCode >= maxCodeSize) + && (maxCodeSize < maxGifCode)) + { + maxCodeSize <<= 1; + ++codeSize; + } + } - if (transparent >= 0) - { - palette [transparent][0] = 0; - palette [transparent][1] = 0; - palette [transparent][2] = 0; - palette [transparent][3] = 0; - } + oldcode = incode; - int index; - int xpos = 0, ypos = 0, pass = 0; + if (sp > stack) + return *--sp; + } - const Image::BitmapData destData (image, true); - uint8* p = destData.data; - const bool hasAlpha = image.hasAlphaChannel(); + return code; + } - while ((index = readLZWByte (false, c)) >= 0) + int getCode (const int codeSize_, const bool initialise) { - const uint8* const paletteEntry = palette [index]; + if (initialise) + { + currentBit = 0; + lastBit = 0; + finished = false; + return 0; + } - if (hasAlpha) + if ((currentBit + codeSize_) >= lastBit) { - ((PixelARGB*) p)->setARGB (paletteEntry[3], - paletteEntry[0], - paletteEntry[1], - paletteEntry[2]); + 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; - ((PixelARGB*) p)->premultiply(); + lastByteIndex = 2 + n; + currentBit = (currentBit - lastBit) + 16; + lastBit = (2 + n) * 8 ; } - else + + 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) + { + unsigned char c; + + if (input.read (&c, 1) != 1 + || readLZWByte (true, c) < 0) + return false; + + if (transparent >= 0) { - ((PixelRGB*) p)->setARGB (0, - paletteEntry[0], - paletteEntry[1], - paletteEntry[2]); + palette [transparent][0] = 0; + palette [transparent][1] = 0; + palette [transparent][2] = 0; + palette [transparent][3] = 0; } - p += destData.pixelStride; - ++xpos; + int index; + int xpos = 0, ypos = 0, pass = 0; - if (xpos == destData.width) + const Image::BitmapData destData (image, true); + uint8* p = destData.data; + const bool hasAlpha = image.hasAlphaChannel(); + + while ((index = readLZWByte (false, c)) >= 0) { - xpos = 0; + const uint8* const paletteEntry = palette [index]; - if (interlace) + if (hasAlpha) { - switch (pass) - { - case 0: - case 1: ypos += 8; break; - case 2: ypos += 4; break; - case 3: ypos += 2; break; - } + ((PixelARGB*) p)->setARGB (paletteEntry[3], + paletteEntry[0], + paletteEntry[1], + paletteEntry[2]); - while (ypos >= destData.height) - { - ++pass; + ((PixelARGB*) p)->premultiply(); + } + else + { + ((PixelRGB*) p)->setARGB (0, + paletteEntry[0], + paletteEntry[1], + paletteEntry[2]); + } + + p += destData.pixelStride; + ++xpos; + + if (xpos == destData.width) + { + xpos = 0; + if (interlace) + { switch (pass) { - case 1: ypos = 4; break; - case 2: ypos = 2; break; - case 3: ypos = 1; break; - default: return true; + case 0: + case 1: ypos += 8; break; + case 2: ypos += 4; break; + case 3: ypos += 2; break; + } + + while (ypos >= destData.height) + { + ++pass; + + switch (pass) + { + case 1: ypos = 4; break; + case 2: ypos = 2; break; + case 3: ypos = 1; break; + default: return true; + } } } - } - else - { - ++ypos; + else + { + ++ypos; + } + + p = destData.getPixelPointer (xpos, ypos); } - p = destData.getPixelPointer (xpos, ypos); + if (ypos >= destData.height) + break; } - if (ypos >= destData.height) - break; + return true; } - return true; + static inline int makeWord (const uint8 a, const uint8 b) { return (b << 8) | a; } + + GIFLoader (const GIFLoader&); + GIFLoader& operator= (const GIFLoader&); +}; + +#endif + +GIFImageFormat::GIFImageFormat() {} +GIFImageFormat::~GIFImageFormat() {} + +const String GIFImageFormat::getFormatName() { return "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'; +} + +const Image GIFImageFormat::decodeImage (InputStream& in) +{ + #if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && ! DONT_USE_COREIMAGE_LOADER + return juce_loadWithCoreImage (in); + #else + const ScopedPointer 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; } END_JUCE_NAMESPACE @@ -211445,8 +211414,15 @@ bool JPEGImageFormat::canUnderstand (InputStream& in) return false; } +#if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && ! DONT_USE_COREIMAGE_LOADER + const Image juce_loadWithCoreImage (InputStream& input); +#endif + const Image JPEGImageFormat::decodeImage (InputStream& in) { +#if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && ! DONT_USE_COREIMAGE_LOADER + return juce_loadWithCoreImage (in); +#else using namespace jpeglibNamespace; using namespace JPEGHelpers; @@ -211540,6 +211516,7 @@ const Image JPEGImageFormat::decodeImage (InputStream& in) } return image; +#endif } bool JPEGImageFormat::writeImageToStream (const Image& image, OutputStream& out) @@ -237122,8 +237099,15 @@ bool PNGImageFormat::canUnderstand (InputStream& in) && header[3] == 'G'; } +#if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && ! DONT_USE_COREIMAGE_LOADER + const Image juce_loadWithCoreImage (InputStream& input); +#endif + const Image PNGImageFormat::decodeImage (InputStream& in) { +#if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && ! DONT_USE_COREIMAGE_LOADER + return juce_loadWithCoreImage (in); +#else using namespace pnglibNamespace; Image image; @@ -237231,6 +237215,7 @@ const Image PNGImageFormat::decodeImage (InputStream& in) } return image; +#endif } bool PNGImageFormat::writeImageToStream (const Image& image, OutputStream& out) @@ -266979,6 +266964,43 @@ LowLevelGraphicsContext* CoreGraphicsImage::createLowLevelContext() return new CoreGraphicsContext (context, height); } +#if USE_COREGRAPHICS_RENDERING && ! DONT_USE_COREIMAGE_LOADER +const Image juce_loadWithCoreImage (InputStream& input) +{ + MemoryBlock data; + input.readIntoMemoryBlock (data, -1); + + CGDataProviderRef provider = CGDataProviderCreateWithData (0, data.getData(), data.getSize(), 0); + CGImageSourceRef imageSource = CGImageSourceCreateWithDataProvider (provider, 0); + CGDataProviderRelease (provider); + + if (imageSource != 0) + { + CGImageRef loadedImage = CGImageSourceCreateImageAtIndex (imageSource, 0, 0); + CFRelease (imageSource); + + if (loadedImage != 0) + { + const bool hasAlphaChan = CGImageGetAlphaInfo (loadedImage) != kCGImageAlphaNone; + Image image (hasAlphaChan ? Image::ARGB : Image::RGB, + (int) CGImageGetWidth (loadedImage), (int) CGImageGetHeight (loadedImage), + hasAlphaChan, Image::NativeImage); + + CoreGraphicsImage* const cgImage = dynamic_cast (image.getSharedImage()); + jassert (cgImage != 0); // if USE_COREGRAPHICS_RENDERING is set, the CoreGraphicsImage class should have been used. + + CGContextDrawImage (cgImage->context, CGRectMake (0, 0, image.getWidth(), image.getHeight()), loadedImage); + CGContextFlush (cgImage->context); + CFRelease (loadedImage); + + return image; + } + } + + return Image::null; +} +#endif + #endif /*** End of inlined file: juce_mac_CoreGraphicsContext.mm ***/ @@ -271610,6 +271632,43 @@ LowLevelGraphicsContext* CoreGraphicsImage::createLowLevelContext() return new CoreGraphicsContext (context, height); } +#if USE_COREGRAPHICS_RENDERING && ! DONT_USE_COREIMAGE_LOADER +const Image juce_loadWithCoreImage (InputStream& input) +{ + MemoryBlock data; + input.readIntoMemoryBlock (data, -1); + + CGDataProviderRef provider = CGDataProviderCreateWithData (0, data.getData(), data.getSize(), 0); + CGImageSourceRef imageSource = CGImageSourceCreateWithDataProvider (provider, 0); + CGDataProviderRelease (provider); + + if (imageSource != 0) + { + CGImageRef loadedImage = CGImageSourceCreateImageAtIndex (imageSource, 0, 0); + CFRelease (imageSource); + + if (loadedImage != 0) + { + const bool hasAlphaChan = CGImageGetAlphaInfo (loadedImage) != kCGImageAlphaNone; + Image image (hasAlphaChan ? Image::ARGB : Image::RGB, + (int) CGImageGetWidth (loadedImage), (int) CGImageGetHeight (loadedImage), + hasAlphaChan, Image::NativeImage); + + CoreGraphicsImage* const cgImage = dynamic_cast (image.getSharedImage()); + jassert (cgImage != 0); // if USE_COREGRAPHICS_RENDERING is set, the CoreGraphicsImage class should have been used. + + CGContextDrawImage (cgImage->context, CGRectMake (0, 0, image.getWidth(), image.getHeight()), loadedImage); + CGContextFlush (cgImage->context); + CFRelease (loadedImage); + + return image; + } + } + + return Image::null; +} +#endif + #endif /*** End of inlined file: juce_mac_CoreGraphicsContext.mm ***/ diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 0e87cecb43..25e0f8fc7d 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -64,7 +64,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 52 -#define JUCE_BUILDNUMBER 55 +#define JUCE_BUILDNUMBER 56 /** Current Juce version number. @@ -60797,7 +60797,7 @@ public: }; /** - A type of ImageFileFormat for reading and writing PNG files. + A subclass of ImageFileFormat for reading and writing PNG files. @see ImageFileFormat, JPEGImageFormat */ @@ -60815,7 +60815,7 @@ public: }; /** - A type of ImageFileFormat for reading and writing JPEG files. + A subclass of ImageFileFormat for reading and writing JPEG files. @see ImageFileFormat, PNGImageFormat */ @@ -60842,6 +60842,24 @@ private: float quality; }; +/** + A subclass of ImageFileFormat for reading GIF files. + + @see ImageFileFormat, PNGImageFormat, JPEGImageFormat +*/ +class JUCE_API GIFImageFormat : public ImageFileFormat +{ +public: + + GIFImageFormat(); + ~GIFImageFormat(); + + const String getFormatName(); + bool canUnderstand (InputStream& input); + const Image decodeImage (InputStream& input); + bool writeImageToStream (const Image& sourceImage, OutputStream& destStream); +}; + #endif // __JUCE_IMAGEFILEFORMAT_JUCEHEADER__ /*** End of inlined file: juce_ImageFileFormat.h ***/ diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h index c2e47d8a4a..b7cc2f66b2 100644 --- a/src/core/juce_StandardHeader.h +++ b/src/core/juce_StandardHeader.h @@ -33,7 +33,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 52 -#define JUCE_BUILDNUMBER 55 +#define JUCE_BUILDNUMBER 56 /** Current Juce version number. diff --git a/src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.cpp b/src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.cpp index d9635f8c01..b409095d18 100644 --- a/src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.cpp +++ b/src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.cpp @@ -27,260 +27,202 @@ BEGIN_JUCE_NAMESPACE -#include "juce_GIFLoader.h" +#include "../juce_ImageFileFormat.h" +#include "../../../../io/streams/juce_InputStream.h" #include "../../colour/juce_PixelFormats.h" //============================================================================== -GIFLoader::GIFLoader (InputStream& in) - : input (in), - dataBlockIsZero (false), - fresh (false), - finished (false) -{ - currentBit = lastBit = lastByteIndex = 0; - maxCode = maxCodeSize = codeSize = setCodeSize = 0; - firstcode = oldcode = 0; - clearCode = end_code = 0; - - int imageWidth, imageHeight; - int transparent = -1; +#if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && ! DONT_USE_COREIMAGE_LOADER + const Image juce_loadWithCoreImage (InputStream& input); +#else - if (! getSizeFromHeader (imageWidth, imageHeight)) - return; +//============================================================================== +class GIFLoader +{ +public: + GIFLoader (InputStream& in) + : input (in), + dataBlockIsZero (false), + fresh (false), + finished (false) + { + currentBit = lastBit = lastByteIndex = 0; + maxCode = maxCodeSize = codeSize = setCodeSize = 0; + firstcode = oldcode = 0; + clearCode = end_code = 0; - if ((imageWidth <= 0) || (imageHeight <= 0)) - return; + int imageWidth, imageHeight; + int transparent = -1; - unsigned char buf [16]; - if (in.read (buf, 3) != 3) - return; + if (! getSizeFromHeader (imageWidth, imageHeight)) + return; - int numColours = 2 << (buf[0] & 7); + if ((imageWidth <= 0) || (imageHeight <= 0)) + return; - if ((buf[0] & 0x80) != 0) - readPalette (numColours); + unsigned char buf [16]; + if (in.read (buf, 3) != 3) + return; - for (;;) - { - if (input.read (buf, 1) != 1) - break; + int numColours = 2 << (buf[0] & 7); - if (buf[0] == ';') - break; + if ((buf[0] & 0x80) != 0) + readPalette (numColours); - if (buf[0] == '!') + for (;;) { - if (input.read (buf, 1) != 1) - break; - - if (processExtension (buf[0], transparent) < 0) + if (input.read (buf, 1) != 1 || buf[0] == ';') break; - continue; - } - - if (buf[0] != ',') - continue; + if (buf[0] == '!') + { + if (input.read (buf, 1) != 1) + break; - if (input.read (buf, 9) != 9) - break; + if (processExtension (buf[0], transparent) < 0) + break; - imageWidth = makeWord (buf[4], buf[5]); - imageHeight = makeWord (buf[6], buf[7]); + continue; + } - numColours = 2 << (buf[8] & 7); + if (buf[0] != ',') + continue; - if ((buf[8] & 0x80) != 0) - if (! readPalette (numColours)) + if (input.read (buf, 9) != 9) break; - image = Image ((transparent >= 0) ? Image::ARGB : Image::RGB, - imageWidth, imageHeight, (transparent >= 0)); + imageWidth = makeWord (buf[4], buf[5]); + imageHeight = makeWord (buf[6], buf[7]); - readImage ((buf[8] & 0x40) != 0, transparent); + numColours = 2 << (buf[8] & 7); - break; - } -} + if ((buf[8] & 0x80) != 0) + if (! readPalette (numColours)) + break; -GIFLoader::~GIFLoader() -{ -} + image = Image ((transparent >= 0) ? Image::ARGB : Image::RGB, + imageWidth, imageHeight, (transparent >= 0)); -bool GIFLoader::getSizeFromHeader (int& w, int& h) -{ - char b[8]; + readImage ((buf[8] & 0x40) != 0, transparent); - if (input.read (b, 6) == 6) - { - if ((strncmp ("GIF87a", b, 6) == 0) - || (strncmp ("GIF89a", b, 6) == 0)) - { - if (input.read (b, 4) == 4) - { - w = makeWord (b[0], b[1]); - h = makeWord (b[2], b[3]); - return true; - } + break; } } - return false; -} - -bool GIFLoader::readPalette (const int numCols) -{ - unsigned char rgb[4]; - - for (int i = 0; i < numCols; ++i) + ~GIFLoader() {} + + Image image; + +private: + InputStream& input; + uint8 buffer [300]; + uint8 palette [256][4]; + bool dataBlockIsZero, fresh, finished; + int currentBit, lastBit, lastByteIndex; + int codeSize, setCodeSize; + int maxCode, maxCodeSize; + int firstcode, oldcode; + int clearCode, end_code; + enum { maxGifCode = 1 << 12 }; + int table [2] [maxGifCode]; + int stack [2 * maxGifCode]; + int *sp; + + bool getSizeFromHeader (int& w, int& h) { - input.read (rgb, 3); - - palette [i][0] = rgb[0]; - palette [i][1] = rgb[1]; - palette [i][2] = rgb[2]; - palette [i][3] = 0xff; - } - - return true; -} + char b[8]; -int GIFLoader::readDataBlock (unsigned char* const dest) -{ - unsigned char n; - - if (input.read (&n, 1) == 1) - { - dataBlockIsZero = (n == 0); + if (input.read (b, 6) == 6) + { + if ((strncmp ("GIF87a", b, 6) == 0) + || (strncmp ("GIF89a", b, 6) == 0)) + { + if (input.read (b, 4) == 4) + { + w = makeWord (b[0], b[1]); + h = makeWord (b[2], b[3]); + return true; + } + } + } - if (dataBlockIsZero || (input.read (dest, n) == n)) - return n; + return false; } - return -1; -} - -int GIFLoader::processExtension (const int type, int& transparent) -{ - unsigned char b [300]; - int n = 0; - - if (type == 0xf9) + bool readPalette (const int numCols) { - n = readDataBlock (b); - if (n < 0) - return 1; + unsigned char rgb[4]; - if ((b[0] & 0x1) != 0) - transparent = b[3]; - } - - do - { - n = readDataBlock (b); - } - while (n > 0); + for (int i = 0; i < numCols; ++i) + { + input.read (rgb, 3); - return n; -} + palette [i][0] = rgb[0]; + palette [i][1] = rgb[1]; + palette [i][2] = rgb[2]; + palette [i][3] = 0xff; + } -int GIFLoader::getCode (const int codeSize_, const bool initialise) -{ - if (initialise) - { - currentBit = 0; - lastBit = 0; - finished = false; - return 0; + return true; } - if ((currentBit + codeSize_) >= lastBit) + int readDataBlock (unsigned char* dest) { - if (finished) - return -1; + unsigned char n; - buffer[0] = buffer [lastByteIndex - 2]; - buffer[1] = buffer [lastByteIndex - 1]; - - const int n = readDataBlock (&buffer[2]); + if (input.read (&n, 1) == 1) + { + dataBlockIsZero = (n == 0); - if (n == 0) - finished = true; + if (dataBlockIsZero || (input.read (dest, n) == n)) + return n; + } - lastByteIndex = 2 + n; - currentBit = (currentBit - lastBit) + 16; - lastBit = (2 + n) * 8 ; + return -1; } - int result = 0; - int i = currentBit; - - for (int j = 0; j < codeSize_; ++j) + int processExtension (const int type, int& transparent) { - result |= ((buffer[i >> 3] & (1 << (i & 7))) != 0) << j; - ++i; - } - - currentBit += codeSize_; + unsigned char b [300]; + int n = 0; - return result; -} - -int GIFLoader::readLZWByte (const bool initialise, const int inputCodeSize) -{ - int code, incode, i; - - if (initialise) - { - setCodeSize = inputCodeSize; - codeSize = setCodeSize + 1; - clearCode = 1 << setCodeSize; - end_code = clearCode + 1; - maxCodeSize = 2 * clearCode; - maxCode = clearCode + 2; - - getCode (0, true); - - fresh = true; - - for (i = 0; i < clearCode; ++i) + if (type == 0xf9) { - table[0][i] = 0; - table[1][i] = i; + n = readDataBlock (b); + if (n < 0) + return 1; + + if ((b[0] & 0x1) != 0) + transparent = b[3]; } - for (; i < maxGifCode; ++i) + do { - table[0][i] = 0; - table[1][i] = 0; + n = readDataBlock (b); } + while (n > 0); - sp = stack; - - return 0; + return n; } - else if (fresh) + + int readLZWByte (const bool initialise, const int inputCodeSize) { - fresh = false; + int code, incode, i; - do + if (initialise) { - firstcode = oldcode - = getCode (codeSize, false); - } - while (firstcode == clearCode); + setCodeSize = inputCodeSize; + codeSize = setCodeSize + 1; + clearCode = 1 << setCodeSize; + end_code = clearCode + 1; + maxCodeSize = 2 * clearCode; + maxCode = clearCode + 2; - return firstcode; - } + getCode (0, true); - if (sp > stack) - return *--sp; + fresh = true; - while ((code = getCode (codeSize, false)) >= 0) - { - if (code == clearCode) - { for (i = 0; i < clearCode; ++i) { table[0][i] = 0; @@ -293,158 +235,277 @@ int GIFLoader::readLZWByte (const bool initialise, const int inputCodeSize) table[1][i] = 0; } - codeSize = setCodeSize + 1; - maxCodeSize = 2 * clearCode; - maxCode = clearCode + 2; sp = stack; - firstcode = oldcode = getCode (codeSize, false); - return firstcode; + return 0; } - else if (code == end_code) + else if (fresh) { - if (dataBlockIsZero) - return -2; - - unsigned char buf [260]; + fresh = false; - int n; - while ((n = readDataBlock (buf)) > 0) - {} + do + { + firstcode = oldcode + = getCode (codeSize, false); + } + while (firstcode == clearCode); - if (n != 0) - return -2; + return firstcode; } - incode = code; + if (sp > stack) + return *--sp; - if (code >= maxCode) + while ((code = getCode (codeSize, false)) >= 0) { - *sp++ = firstcode; - code = oldcode; - } + if (code == clearCode) + { + for (i = 0; i < clearCode; ++i) + { + table[0][i] = 0; + table[1][i] = i; + } - while (code >= clearCode) - { - *sp++ = table[1][code]; - if (code == table[0][code]) - return -2; + for (; i < maxGifCode; ++i) + { + table[0][i] = 0; + table[1][i] = 0; + } - code = table[0][code]; - } + codeSize = setCodeSize + 1; + maxCodeSize = 2 * clearCode; + maxCode = clearCode + 2; + sp = stack; + firstcode = oldcode = getCode (codeSize, false); + return firstcode; - *sp++ = firstcode = table[1][code]; + } + else if (code == end_code) + { + if (dataBlockIsZero) + return -2; - if ((code = maxCode) < maxGifCode) - { - table[0][code] = oldcode; - table[1][code] = firstcode; - ++maxCode; + unsigned char buf [260]; + + int n; + while ((n = readDataBlock (buf)) > 0) + {} + + if (n != 0) + return -2; + } + + incode = code; - if ((maxCode >= maxCodeSize) - && (maxCodeSize < maxGifCode)) + if (code >= maxCode) { - maxCodeSize <<= 1; - ++codeSize; + *sp++ = firstcode; + code = oldcode; } - } - oldcode = incode; + while (code >= clearCode) + { + *sp++ = table[1][code]; + if (code == table[0][code]) + return -2; - if (sp > stack) - return *--sp; - } + code = table[0][code]; + } - return code; -} + *sp++ = firstcode = table[1][code]; -bool GIFLoader::readImage (const int interlace, const int transparent) -{ - unsigned char c; + if ((code = maxCode) < maxGifCode) + { + table[0][code] = oldcode; + table[1][code] = firstcode; + ++maxCode; - if (input.read (&c, 1) != 1 - || readLZWByte (true, c) < 0) - return false; + if ((maxCode >= maxCodeSize) + && (maxCodeSize < maxGifCode)) + { + maxCodeSize <<= 1; + ++codeSize; + } + } - if (transparent >= 0) - { - palette [transparent][0] = 0; - palette [transparent][1] = 0; - palette [transparent][2] = 0; - palette [transparent][3] = 0; - } + oldcode = incode; - int index; - int xpos = 0, ypos = 0, pass = 0; + if (sp > stack) + return *--sp; + } - const Image::BitmapData destData (image, true); - uint8* p = destData.data; - const bool hasAlpha = image.hasAlphaChannel(); + return code; + } - while ((index = readLZWByte (false, c)) >= 0) + int getCode (const int codeSize_, const bool initialise) { - const uint8* const paletteEntry = palette [index]; + if (initialise) + { + currentBit = 0; + lastBit = 0; + finished = false; + return 0; + } - if (hasAlpha) + if ((currentBit + codeSize_) >= lastBit) { - ((PixelARGB*) p)->setARGB (paletteEntry[3], - paletteEntry[0], - paletteEntry[1], - paletteEntry[2]); + 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; - ((PixelARGB*) p)->premultiply(); + lastByteIndex = 2 + n; + currentBit = (currentBit - lastBit) + 16; + lastBit = (2 + n) * 8 ; } - else + + int result = 0; + int i = currentBit; + + for (int j = 0; j < codeSize_; ++j) { - ((PixelRGB*) p)->setARGB (0, - paletteEntry[0], - paletteEntry[1], - paletteEntry[2]); + result |= ((buffer[i >> 3] & (1 << (i & 7))) != 0) << j; + ++i; } - p += destData.pixelStride; - ++xpos; + currentBit += codeSize_; - if (xpos == destData.width) + return result; + } + + bool readImage (const int interlace, const int transparent) + { + unsigned char c; + + if (input.read (&c, 1) != 1 + || readLZWByte (true, c) < 0) + return false; + + if (transparent >= 0) { - xpos = 0; + palette [transparent][0] = 0; + palette [transparent][1] = 0; + palette [transparent][2] = 0; + palette [transparent][3] = 0; + } - if (interlace) + int index; + int xpos = 0, ypos = 0, pass = 0; + + const Image::BitmapData destData (image, true); + uint8* p = destData.data; + const bool hasAlpha = image.hasAlphaChannel(); + + while ((index = readLZWByte (false, c)) >= 0) + { + const uint8* const paletteEntry = palette [index]; + + if (hasAlpha) { - switch (pass) - { - case 0: - case 1: ypos += 8; break; - case 2: ypos += 4; break; - case 3: ypos += 2; break; - } + ((PixelARGB*) p)->setARGB (paletteEntry[3], + paletteEntry[0], + paletteEntry[1], + paletteEntry[2]); - while (ypos >= destData.height) - { - ++pass; + ((PixelARGB*) p)->premultiply(); + } + else + { + ((PixelRGB*) p)->setARGB (0, + paletteEntry[0], + paletteEntry[1], + paletteEntry[2]); + } + + p += destData.pixelStride; + ++xpos; + + if (xpos == destData.width) + { + xpos = 0; + if (interlace) + { switch (pass) { - case 1: ypos = 4; break; - case 2: ypos = 2; break; - case 3: ypos = 1; break; - default: return true; + case 0: + case 1: ypos += 8; break; + case 2: ypos += 4; break; + case 3: ypos += 2; break; + } + + while (ypos >= destData.height) + { + ++pass; + + switch (pass) + { + case 1: ypos = 4; break; + case 2: ypos = 2; break; + case 3: ypos = 1; break; + default: return true; + } } } - } - else - { - ++ypos; + else + { + ++ypos; + } + + p = destData.getPixelPointer (xpos, ypos); } - p = destData.getPixelPointer (xpos, ypos); + if (ypos >= destData.height) + break; } - if (ypos >= destData.height) - break; + return true; } - return true; + static inline int makeWord (const uint8 a, const uint8 b) { return (b << 8) | a; } + + GIFLoader (const GIFLoader&); + GIFLoader& operator= (const GIFLoader&); +}; + +#endif + +//============================================================================== +GIFImageFormat::GIFImageFormat() {} +GIFImageFormat::~GIFImageFormat() {} + +const String GIFImageFormat::getFormatName() { return "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'; +} + +const Image GIFImageFormat::decodeImage (InputStream& in) +{ + #if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && ! DONT_USE_COREIMAGE_LOADER + return juce_loadWithCoreImage (in); + #else + const ScopedPointer 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; } diff --git a/src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.h b/src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.h deleted file mode 100644 index 6d8082b098..0000000000 --- a/src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library - "Jules' Utility Class Extensions" - Copyright 2004-10 by Raw Material Software Ltd. - - ------------------------------------------------------------------------------ - - JUCE can be redistributed and/or modified under the terms of the GNU General - Public License (Version 2), as published by the Free Software Foundation. - A copy of the license is included in the JUCE distribution, or can be found - online 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.rawmaterialsoftware.com/juce for more information. - - ============================================================================== -*/ - -#ifndef __JUCE_GIFLOADER_JUCEHEADER__ -#define __JUCE_GIFLOADER_JUCEHEADER__ - -#ifndef DOXYGEN - -#include "../../../../io/streams/juce_InputStream.h" -#include "../juce_Image.h" - - -//============================================================================== -/** - Used internally by ImageFileFormat - don't use this class directly in your - application. - - @see ImageFileFormat -*/ -class GIFLoader -{ -public: - GIFLoader (InputStream& in); - ~GIFLoader(); - - const Image& getImage() const { return image; } - -private: - Image image; - InputStream& input; - uint8 buffer [300]; - uint8 palette [256][4]; - bool dataBlockIsZero, fresh, finished; - int currentBit, lastBit, lastByteIndex; - int codeSize, setCodeSize; - int maxCode, maxCodeSize; - int firstcode, oldcode; - int clearCode, end_code; - enum { maxGifCode = 1 << 12 }; - int table [2] [maxGifCode]; - int stack [2 * maxGifCode]; - int *sp; - - bool getSizeFromHeader (int& width, int& height); - bool readPalette (const int numCols); - int readDataBlock (unsigned char* dest); - int processExtension (int type, int& transparent); - int readLZWByte (bool initialise, int input_code_size); - int getCode (int code_size, bool initialise); - bool readImage (int interlace, int transparent); - static inline int makeWord (const uint8 a, const uint8 b) { return (b << 8) | a; } - - GIFLoader (const GIFLoader&); - GIFLoader& operator= (const GIFLoader&); -}; - -#endif // DOXYGEN - -#endif // __JUCE_GIFLOADER_JUCEHEADER__ diff --git a/src/gui/graphics/imaging/image_file_formats/juce_JPEGLoader.cpp b/src/gui/graphics/imaging/image_file_formats/juce_JPEGLoader.cpp index e96267ebae..755d4bbd04 100644 --- a/src/gui/graphics/imaging/image_file_formats/juce_JPEGLoader.cpp +++ b/src/gui/graphics/imaging/image_file_formats/juce_JPEGLoader.cpp @@ -249,8 +249,15 @@ bool JPEGImageFormat::canUnderstand (InputStream& in) return false; } +#if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && ! DONT_USE_COREIMAGE_LOADER + const Image juce_loadWithCoreImage (InputStream& input); +#endif + const Image JPEGImageFormat::decodeImage (InputStream& in) { +#if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && ! DONT_USE_COREIMAGE_LOADER + return juce_loadWithCoreImage (in); +#else using namespace jpeglibNamespace; using namespace JPEGHelpers; @@ -344,6 +351,7 @@ const Image JPEGImageFormat::decodeImage (InputStream& in) } return image; +#endif } bool JPEGImageFormat::writeImageToStream (const Image& image, OutputStream& out) diff --git a/src/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp b/src/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp index b90714a7ba..d35f308e50 100644 --- a/src/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp +++ b/src/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp @@ -148,8 +148,15 @@ bool PNGImageFormat::canUnderstand (InputStream& in) && header[3] == 'G'; } +#if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && ! DONT_USE_COREIMAGE_LOADER + const Image juce_loadWithCoreImage (InputStream& input); +#endif + const Image PNGImageFormat::decodeImage (InputStream& in) { +#if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && ! DONT_USE_COREIMAGE_LOADER + return juce_loadWithCoreImage (in); +#else using namespace pnglibNamespace; Image image; @@ -257,6 +264,7 @@ const Image PNGImageFormat::decodeImage (InputStream& in) } return image; +#endif } bool PNGImageFormat::writeImageToStream (const Image& image, OutputStream& out) diff --git a/src/gui/graphics/imaging/juce_ImageFileFormat.cpp b/src/gui/graphics/imaging/juce_ImageFileFormat.cpp index 36078f7340..4e06148cd5 100644 --- a/src/gui/graphics/imaging/juce_ImageFileFormat.cpp +++ b/src/gui/graphics/imaging/juce_ImageFileFormat.cpp @@ -31,43 +31,6 @@ BEGIN_JUCE_NAMESPACE #include "../../../io/streams/juce_MemoryInputStream.h" #include "../../../io/files/juce_FileInputStream.h" #include "../../../io/streams/juce_BufferedInputStream.h" -#include "image_file_formats/juce_GIFLoader.h" - - -//============================================================================== -class GIFImageFormat : public ImageFileFormat -{ -public: - GIFImageFormat() {} - ~GIFImageFormat() {} - - const String getFormatName() - { - return "GIF"; - } - - bool canUnderstand (InputStream& in) - { - const int bytesNeeded = 4; - char header [bytesNeeded]; - - return (in.read (header, bytesNeeded) == bytesNeeded) - && header[0] == 'G' - && header[1] == 'I' - && header[2] == 'F'; - } - - const Image decodeImage (InputStream& in) - { - const ScopedPointer loader (new GIFLoader (in)); - return loader->getImage(); - } - - bool writeImageToStream (const Image& /*sourceImage*/, OutputStream& /*destStream*/) - { - return false; - } -}; //============================================================================== diff --git a/src/gui/graphics/imaging/juce_ImageFileFormat.h b/src/gui/graphics/imaging/juce_ImageFileFormat.h index 043ae0700c..ab7c267b39 100644 --- a/src/gui/graphics/imaging/juce_ImageFileFormat.h +++ b/src/gui/graphics/imaging/juce_ImageFileFormat.h @@ -138,7 +138,7 @@ public: //============================================================================== /** - A type of ImageFileFormat for reading and writing PNG files. + A subclass of ImageFileFormat for reading and writing PNG files. @see ImageFileFormat, JPEGImageFormat */ @@ -159,7 +159,7 @@ public: //============================================================================== /** - A type of ImageFileFormat for reading and writing JPEG files. + A subclass of ImageFileFormat for reading and writing JPEG files. @see ImageFileFormat, PNGImageFormat */ @@ -188,6 +188,25 @@ private: float quality; }; +//============================================================================== +/** + A subclass of ImageFileFormat for reading GIF files. + + @see ImageFileFormat, PNGImageFormat, JPEGImageFormat +*/ +class JUCE_API GIFImageFormat : public ImageFileFormat +{ +public: + //============================================================================== + GIFImageFormat(); + ~GIFImageFormat(); + + //============================================================================== + const String getFormatName(); + bool canUnderstand (InputStream& input); + const Image decodeImage (InputStream& input); + bool writeImageToStream (const Image& sourceImage, OutputStream& destStream); +}; #endif // __JUCE_IMAGEFILEFORMAT_JUCEHEADER__ diff --git a/src/native/mac/juce_mac_CoreGraphicsContext.mm b/src/native/mac/juce_mac_CoreGraphicsContext.mm index 15972570f2..05a00b4fe4 100644 --- a/src/native/mac/juce_mac_CoreGraphicsContext.mm +++ b/src/native/mac/juce_mac_CoreGraphicsContext.mm @@ -770,4 +770,42 @@ LowLevelGraphicsContext* CoreGraphicsImage::createLowLevelContext() return new CoreGraphicsContext (context, height); } +//============================================================================== +#if USE_COREGRAPHICS_RENDERING && ! DONT_USE_COREIMAGE_LOADER +const Image juce_loadWithCoreImage (InputStream& input) +{ + MemoryBlock data; + input.readIntoMemoryBlock (data, -1); + + CGDataProviderRef provider = CGDataProviderCreateWithData (0, data.getData(), data.getSize(), 0); + CGImageSourceRef imageSource = CGImageSourceCreateWithDataProvider (provider, 0); + CGDataProviderRelease (provider); + + if (imageSource != 0) + { + CGImageRef loadedImage = CGImageSourceCreateImageAtIndex (imageSource, 0, 0); + CFRelease (imageSource); + + if (loadedImage != 0) + { + const bool hasAlphaChan = CGImageGetAlphaInfo (loadedImage) != kCGImageAlphaNone; + Image image (hasAlphaChan ? Image::ARGB : Image::RGB, + (int) CGImageGetWidth (loadedImage), (int) CGImageGetHeight (loadedImage), + hasAlphaChan, Image::NativeImage); + + CoreGraphicsImage* const cgImage = dynamic_cast (image.getSharedImage()); + jassert (cgImage != 0); // if USE_COREGRAPHICS_RENDERING is set, the CoreGraphicsImage class should have been used. + + CGContextDrawImage (cgImage->context, CGRectMake (0, 0, image.getWidth(), image.getHeight()), loadedImage); + CGContextFlush (cgImage->context); + CFRelease (loadedImage); + + return image; + } + } + + return Image::null; +} +#endif + #endif