I'm implementing Inter-App Audio in my iPad app, and I need to pull the host app's icon to display in my interface when it's connected. Looking through Juce's CoreGraphicsImage class I've pieced together the following:
UIImage* uiImage = (UIImage*) deviceManager.getCurrentAudioDevice()->getHostIcon(); // this is a method I added that retreives the UIImage from the host app and returns a void*, hence the cast
CGImageRef loadedImage = uiImage.CGImage;
if (loadedImage != 0)
{
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo (loadedImage);
const bool hasAlphaChan = (alphaInfo != kCGImageAlphaNone
&& alphaInfo != kCGImageAlphaNoneSkipLast
&& alphaInfo != kCGImageAlphaNoneSkipFirst);
int width = (int) CGImageGetWidth (loadedImage);
int height = (int) CGImageGetHeight (loadedImage);
Image image (NativeImageType().create (Image::ARGB,
width,
height,
hasAlphaChan));
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
Image::BitmapData bitmap (image, Image::BitmapData::readWrite);
int pixelStride = 4;
int lineStride = (pixelStride * jmax (1, width) + 3) & ~3;
CGContextRef context = CGBitmapContextCreate(bitmap.data, (size_t) width, (size_t) height, 8, (size_t) lineStride, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), loadedImage);
CGContextFlush(context);
image.getProperties()->set ("originalImageHadAlpha", hasAlphaChan);
return image;
}
This retrieves the image, but the coloring is messed up. For example the Garageband icon should look like:
Solved. I made a simplified copy of the CoreGraphicsImage class with only the methods I need, which allowed me to closer mimic the juce_loadWithCoreImage method. Here it is:
class CoreGraphicsImageSimple : public ImagePixelData
{
public:
CoreGraphicsImageSimple (const Image::PixelFormat format, const int w, const int h, const bool clearImage)
: ImagePixelData (format, w, h), cachedImageRef (0)
{
pixelStride = format == Image::RGB ? 3 : ((format == Image::ARGB) ? 4 : 1);
lineStride = (pixelStride * jmax (1, width) + 3) & ~3;
imageData.allocate ((size_t) (lineStride * jmax (1, height)), clearImage);
CGColorSpaceRef colourSpace = (format == Image::SingleChannel) ? CGColorSpaceCreateDeviceGray()
: CGColorSpaceCreateDeviceRGB();
context = CGBitmapContextCreate (imageData, (size_t) width, (size_t) height, 8, (size_t) lineStride,
colourSpace, getCGImageFlags (format));
CGColorSpaceRelease (colourSpace);
}
~CoreGraphicsImageSimple()
{
freeCachedImageRef();
CGContextRelease (context);
}
//==============================================================================
CGContextRef context;
CGImageRef cachedImageRef;
HeapBlock<uint8> imageData;
int pixelStride, lineStride;
private:
void freeCachedImageRef()
{
if (cachedImageRef != 0)
{
CGImageRelease (cachedImageRef);
cachedImageRef = 0;
}
}
static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format)
{
#if JUCE_BIG_ENDIAN
return format == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big) : kCGBitmapByteOrderDefault;
#else
return format == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little) : kCGBitmapByteOrderDefault;
#endif
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreGraphicsImageSimple)
};
Image HostIconRetreiver::getHostIcon(AudioDeviceManager& deviceManager)
{
UIImage* uiImage = (UIImage*) deviceManager.getCurrentAudioDevice()->getHostIcon();
CGImageRef loadedImage = uiImage.CGImage;
if (loadedImage != 0)
{
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo (loadedImage);
const bool hasAlphaChan = (alphaInfo != kCGImageAlphaNone
&& alphaInfo != kCGImageAlphaNoneSkipLast
&& alphaInfo != kCGImageAlphaNoneSkipFirst);
Image image (NativeImageType().create (Image::ARGB, // (CoreImage doesn't work with 24-bit images)
(int) CGImageGetWidth (loadedImage),
(int) CGImageGetHeight (loadedImage),
hasAlphaChan));
CoreGraphicsImageSimple* const cgImage = static_cast<CoreGraphicsImageSimple*> (image.getPixelData());
jassert (cgImage != nullptr); // if USE_COREGRAPHICS_RENDERING is set, the CoreGraphicsImageSimple class should have been used.
CGContextDrawImage (cgImage->context, CGRectMake(0, 0, image.getWidth(), image.getHeight()), loadedImage);
CGContextFlush (cgImage->context);
#if ! JUCE_IOS
CFRelease (loadedImage);
#endif
// Because it's impossible to create a truly 24-bit CG image, this flag allows a user
// to find out whether the file they just loaded the image from had an alpha channel or not.
image.getProperties()->set ("originalImageHadAlpha", hasAlphaChan);
return image;
}
return Image::null;
}