summaryrefslogtreecommitdiff
path: root/platform/darwin/src/image.mm
diff options
context:
space:
mode:
Diffstat (limited to 'platform/darwin/src/image.mm')
-rw-r--r--platform/darwin/src/image.mm173
1 files changed, 77 insertions, 96 deletions
diff --git a/platform/darwin/src/image.mm b/platform/darwin/src/image.mm
index 3a707d4a36..57b680fbdb 100644
--- a/platform/darwin/src/image.mm
+++ b/platform/darwin/src/image.mm
@@ -1,126 +1,107 @@
-#include <mbgl/util/image.hpp>
+#include <mbgl/util/image+MGLAdditions.hpp>
#import <ImageIO/ImageIO.h>
-#if TARGET_OS_IPHONE
-#import <MobileCoreServices/MobileCoreServices.h>
-#else
-#import <CoreServices/CoreServices.h>
-#endif
-
-namespace mbgl {
-
-std::string encodePNG(const PremultipliedImage& src) {
- CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, src.data.get(), src.bytes(), NULL);
+namespace {
+
+template <typename T, typename S, void (*Releaser)(S)>
+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<CGImageRef, CGImageRef, CGImageRelease>;
+using CFDataHandle = CFHandle<CFDataRef, CFTypeRef, CFRelease>;
+using CGImageSourceHandle = CFHandle<CGImageSourceRef, CFTypeRef, CFRelease>;
+using CGDataProviderHandle = CFHandle<CGDataProviderRef, CGDataProviderRef, CGDataProviderRelease>;
+using CGColorSpaceHandle = CFHandle<CGColorSpaceRef, CGColorSpaceRef, CGColorSpaceRelease>;
+using CGContextHandle = CFHandle<CGContextRef, CGContextRef, CGContextRelease>;
+
+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<const decltype(src.data)::element_type*>(data);
+ }));
if (!provider) {
- return "";
+ return nil;
}
- CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB();
- if (!color_space) {
- CGDataProviderRelease(provider);
- return "";
- }
+ // If we successfully created the provider, it will take over management of the memory segment.
+ src.data.release();
- CGImageRef image =
- CGImageCreate(src.size.width, src.size.height, 8, 32, 4 * src.size.width, color_space,
- kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast, provider, NULL,
- false, kCGRenderingIntentDefault);
- if (!image) {
- CGColorSpaceRelease(color_space);
- CGDataProviderRelease(provider);
- return "";
+ CGColorSpaceHandle colorSpace(CGColorSpaceCreateDeviceRGB());
+ if (!colorSpace) {
+ return nil;
}
- CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
- if (!data) {
- CGImageRelease(image);
- CGColorSpaceRelease(color_space);
- CGDataProviderRelease(provider);
- return "";
- }
+ 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;
- CGImageDestinationRef image_destination = CGImageDestinationCreateWithData(data, kUTTypePNG, 1, NULL);
- if (!image_destination) {
- CFRelease(data);
- CGImageRelease(image);
- CGColorSpaceRelease(color_space);
- CGDataProviderRelease(provider);
- return "";
+ 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<uint32_t>(width), static_cast<uint32_t>(height) });
+
+ CGColorSpaceHandle colorSpace(CGColorSpaceCreateDeviceRGB());
+ if (!colorSpace) {
+ throw std::runtime_error("CGColorSpaceCreateDeviceRGB failed");
}
- CGImageDestinationAddImage(image_destination, image, NULL);
- CGImageDestinationFinalize(image_destination);
+ constexpr const size_t bitsPerComponent = 8;
+ constexpr const size_t bytesPerPixel = 4;
+ const size_t bytesPerRow = bytesPerPixel * width;
- const std::string result {
- reinterpret_cast<const char *>(CFDataGetBytePtr(data)),
- static_cast<size_t>(CFDataGetLength(data))
- };
+ CGContextHandle context(CGBitmapContextCreate(
+ image.data.get(), width, height, bitsPerComponent, bytesPerRow, *colorSpace,
+ kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast));
+ if (!context) {
+ throw std::runtime_error("CGBitmapContextCreate failed");
+ }
- CFRelease(image_destination);
- CFRelease(data);
- CGImageRelease(image);
- CGColorSpaceRelease(color_space);
- CGDataProviderRelease(provider);
+ CGContextSetBlendMode(*context, kCGBlendModeCopy);
+ CGContextDrawImage(*context, CGRectMake(0, 0, width, height), src);
- return result;
+ return image;
}
-PremultipliedImage decodeImage(const std::string &source_data) {
- CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, reinterpret_cast<const unsigned char *>(source_data.data()), source_data.size(), kCFAllocatorNull);
+namespace mbgl {
+
+PremultipliedImage decodeImage(const std::string& source) {
+ CFDataHandle data(CFDataCreateWithBytesNoCopy(
+ kCFAllocatorDefault, reinterpret_cast<const unsigned char*>(source.data()), source.size(),
+ kCFAllocatorNull));
if (!data) {
throw std::runtime_error("CFDataCreateWithBytesNoCopy failed");
}
- CGImageSourceRef image_source = CGImageSourceCreateWithData(data, NULL);
- if (!image_source) {
- CFRelease(data);
+ CGImageSourceHandle imageSource(CGImageSourceCreateWithData(*data, NULL));
+ if (!imageSource) {
throw std::runtime_error("CGImageSourceCreateWithData failed");
}
- CGImageRef image = CGImageSourceCreateImageAtIndex(image_source, 0, NULL);
+ CGImageHandle image(CGImageSourceCreateImageAtIndex(*imageSource, 0, NULL));
if (!image) {
- CFRelease(image_source);
- CFRelease(data);
throw std::runtime_error("CGImageSourceCreateImageAtIndex failed");
}
- CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB();
- if (!color_space) {
- CGImageRelease(image);
- CFRelease(image_source);
- CFRelease(data);
- throw std::runtime_error("CGColorSpaceCreateDeviceRGB failed");
- }
-
- PremultipliedImage result({ static_cast<uint32_t>(CGImageGetWidth(image)),
- static_cast<uint32_t>(CGImageGetHeight(image)) });
-
- CGContextRef context =
- CGBitmapContextCreate(result.data.get(), result.size.width, result.size.height, 8,
- result.stride(), color_space, kCGImageAlphaPremultipliedLast);
- if (!context) {
- CGColorSpaceRelease(color_space);
- CGImageRelease(image);
- CFRelease(image_source);
- CFRelease(data);
- throw std::runtime_error("CGBitmapContextCreate failed");
- }
-
- CGContextSetBlendMode(context, kCGBlendModeCopy);
-
- CGRect rect = { { 0, 0 },
- { static_cast<CGFloat>(result.size.width),
- static_cast<CGFloat>(result.size.height) } };
- CGContextDrawImage(context, rect, image);
-
- CGContextRelease(context);
- CGColorSpaceRelease(color_space);
- CGImageRelease(image);
- CFRelease(image_source);
- CFRelease(data);
-
- return result;
+ return MGLPremultipliedImageFromCGImage(*image);
}
-}
+} // namespace mbgl