#include #import namespace { template struct CFHandle { CFHandle(T t_): t(t_) {} ~CFHandle() { Releaser(t); } T operator*() { return t; } operator bool() { return t; } private: T t; }; } // namespace using CGImageHandle = CFHandle; using CFDataHandle = CFHandle; using CGImageSourceHandle = CFHandle; using CGDataProviderHandle = CFHandle; using CGColorSpaceHandle = CFHandle; using CGContextHandle = CFHandle; CGImageRef CGImageFromMGLPremultipliedImage(mbgl::PremultipliedImage&& src) { // We're converting the PremultipliedImage's backing store to a CGDataProvider, and are taking // over ownership of the memory. CGDataProviderHandle provider(CGDataProviderCreateWithData( NULL, src.data.get(), src.bytes(), [](void*, const void* data, size_t) { delete[] reinterpret_cast(data); })); if (!provider) { return nil; } // If we successfully created the provider, it will take over management of the memory segment. src.data.release(); CGColorSpaceHandle colorSpace(CGColorSpaceCreateDeviceRGB()); if (!colorSpace) { return nil; } constexpr const size_t bitsPerComponent = 8; constexpr const size_t bytesPerPixel = 4; constexpr const size_t bitsPerPixel = bitsPerComponent * bytesPerPixel; const size_t bytesPerRow = bytesPerPixel * src.size.width; return CGImageCreate(src.size.width, src.size.height, bitsPerComponent, bitsPerPixel, bytesPerRow, *colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast, *provider, NULL, false, kCGRenderingIntentDefault); } mbgl::PremultipliedImage MGLPremultipliedImageFromCGImage(CGImageRef src) { const size_t width = CGImageGetWidth(src); const size_t height = CGImageGetHeight(src); mbgl::PremultipliedImage image({ static_cast(width), static_cast(height) }); CGColorSpaceHandle colorSpace(CGColorSpaceCreateDeviceRGB()); if (!colorSpace) { throw std::runtime_error("CGColorSpaceCreateDeviceRGB failed"); } constexpr const size_t bitsPerComponent = 8; constexpr const size_t bytesPerPixel = 4; const size_t bytesPerRow = bytesPerPixel * width; CGContextHandle context(CGBitmapContextCreate( image.data.get(), width, height, bitsPerComponent, bytesPerRow, *colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast)); if (!context) { throw std::runtime_error("CGBitmapContextCreate failed"); } CGContextSetBlendMode(*context, kCGBlendModeCopy); CGContextDrawImage(*context, CGRectMake(0, 0, width, height), src); return image; } namespace mbgl { PremultipliedImage decodeImage(const std::string& source) { CFDataHandle data(CFDataCreateWithBytesNoCopy( kCFAllocatorDefault, reinterpret_cast(source.data()), source.size(), kCFAllocatorNull)); if (!data) { throw std::runtime_error("CFDataCreateWithBytesNoCopy failed"); } CGImageSourceHandle imageSource(CGImageSourceCreateWithData(*data, NULL)); if (!imageSource) { throw std::runtime_error("CGImageSourceCreateWithData failed"); } CGImageHandle image(CGImageSourceCreateImageAtIndex(*imageSource, 0, NULL)); if (!image) { throw std::runtime_error("CGImageSourceCreateImageAtIndex failed"); } return MGLPremultipliedImageFromCGImage(*image); } } // namespace mbgl