#include #import #import "CFHandle.hpp" using CGImageHandle = CFHandle; using CFDataHandle = CFHandle; using CGImageSourceHandle = CFHandle; using CGDataProviderHandle = CFHandle; using CGColorSpaceHandle = CFHandle; using CGContextHandle = CFHandle; CGImageRef CGImageCreateWithMLNPremultipliedImage(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; const auto bitmapInfo = static_cast(kCGBitmapByteOrderDefault) | static_cast(kCGImageAlphaPremultipliedLast); return CGImageCreate(src.size.width, src.size.height, bitsPerComponent, bitsPerPixel, bytesPerRow, *colorSpace, bitmapInfo, *provider, NULL, false, kCGRenderingIntentDefault); } mbgl::PremultipliedImage MLNPremultipliedImageFromCGImage(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; const auto bitmapInfo = static_cast(kCGBitmapByteOrderDefault) | static_cast(kCGImageAlphaPremultipliedLast); CGContextHandle context(CGBitmapContextCreate(image.data.get(), width, height, bitsPerComponent, bytesPerRow, *colorSpace, bitmapInfo)); 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 MLNPremultipliedImageFromCGImage(*image); } } // namespace mbgl