diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2014-10-29 19:58:34 -0400 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2014-10-30 12:02:28 -0400 |
commit | e3bc69b7e77aa6771c8db3695f12548447e1de51 (patch) | |
tree | 0c1a0bde928fea3e09b1d72222b400176c0936c7 | |
parent | 7a13db9a863c9be58709e941f44eb2c370276e2a (diff) | |
download | qtlocation-mapboxgl-e3bc69b7e77aa6771c8db3695f12548447e1de51.tar.gz |
use CoreImage for decoding/encoding images on osx/ios
-rwxr-xr-x | configure | 15 | ||||
-rw-r--r-- | gyp/mbgl-core.gypi | 1 | ||||
-rw-r--r-- | gyp/mbgl-ios.gypi | 9 | ||||
-rw-r--r-- | gyp/mbgl-linux.gypi | 3 | ||||
-rw-r--r-- | gyp/mbgl-osx.gypi | 9 | ||||
-rw-r--r-- | include/mbgl/platform/default/headless_view.hpp | 2 | ||||
-rw-r--r-- | include/mbgl/util/image.hpp | 4 | ||||
-rw-r--r-- | platform/darwin/image.mm | 125 | ||||
-rw-r--r-- | platform/default/headless_view.cpp | 4 | ||||
-rw-r--r-- | platform/default/image.cpp (renamed from src/util/image.cpp) | 11 | ||||
-rw-r--r-- | src/geometry/sprite_atlas.cpp | 13 | ||||
-rw-r--r-- | test/headless.cpp | 14 |
12 files changed, 181 insertions, 29 deletions
@@ -6,6 +6,10 @@ shopt -s expand_aliases CONFIG_FILE=${1:-config.gypi} +if [ `uname -s` = 'Darwin' ]; then + MASON_PLATFORM=${MASON_PLATFORM:-osx} +fi + function finish { >&2 echo -en "\033[0m"; } @@ -34,11 +38,16 @@ if [[ ! -d ~/.mason ]]; then fi alias mason='~/.mason/mason' - -case $MASON_PLATFORM in +case ${MASON_PLATFORM} in 'ios') SQLITE_VERSION=system - LIBPNG_VERSION=1.6.13 + LIBUV_VERSION=0.10.28 + ZLIB_VERSION=system + BOOST_VERSION=system + ;; + 'osx') + GLFW_VERSION=a21f2377 + SQLITE_VERSION=system LIBUV_VERSION=0.10.28 ZLIB_VERSION=system BOOST_VERSION=system diff --git a/gyp/mbgl-core.gypi b/gyp/mbgl-core.gypi index e49697388c..46ff762742 100644 --- a/gyp/mbgl-core.gypi +++ b/gyp/mbgl-core.gypi @@ -10,7 +10,6 @@ ], 'variables': { 'cflags_cc': [ - '<@(png_cflags)', '<@(uv_cflags)', '<@(sqlite3_cflags)', '<@(zlib_cflags)', diff --git a/gyp/mbgl-ios.gypi b/gyp/mbgl-ios.gypi index 755b3cc483..5566ca3a32 100644 --- a/gyp/mbgl-ios.gypi +++ b/gyp/mbgl-ios.gypi @@ -34,6 +34,7 @@ '../platform/darwin/log_nslog.mm', '../platform/darwin/string_nsstring.mm', '../platform/darwin/http_request_baton_cocoa.mm', + '../platform/darwin/image.mm', ], 'include_dirs': [ '../include', @@ -44,7 +45,13 @@ 'direct_dependent_settings': { 'include_dirs': [ '../include', - ] + ], + 'xcode_settings': { + 'OTHER_LDFLAGS': [ + '-framework ImageIO', + '-framework MobileCoreServices', + ], + }, }, }, ], diff --git a/gyp/mbgl-linux.gypi b/gyp/mbgl-linux.gypi index 337e98039e..2b166ea434 100644 --- a/gyp/mbgl-linux.gypi +++ b/gyp/mbgl-linux.gypi @@ -7,6 +7,7 @@ 'hard_dependency': 1, 'variables': { 'cflags_cc': [ + '<@(png_cflags)', '<@(uv_cflags)', '<@(curl_cflags)', ], @@ -14,6 +15,7 @@ '<@(uv_cflags)', ], 'ldflags': [ + '<@(png_ldflags)', '<@(uv_ldflags)', '<@(curl_ldflags)', ], @@ -23,6 +25,7 @@ '../platform/default/log_stderr.cpp', '../platform/default/string_stdlib.cpp', '../platform/default/http_request_baton_curl.cpp', + '../platform/default/image.cpp', ], 'include_dirs': [ '../include', diff --git a/gyp/mbgl-osx.gypi b/gyp/mbgl-osx.gypi index bee0325498..76c22f5ad6 100644 --- a/gyp/mbgl-osx.gypi +++ b/gyp/mbgl-osx.gypi @@ -10,6 +10,7 @@ '../platform/darwin/log_nslog.mm', '../platform/darwin/string_nsstring.mm', '../platform/darwin/http_request_baton_cocoa.mm', + '../platform/darwin/image.mm', ], 'include_dirs': [ '../include', @@ -20,7 +21,13 @@ 'direct_dependent_settings': { 'include_dirs': [ '../include', - ] + ], + 'xcode_settings': { + 'OTHER_LDFLAGS': [ + '-framework ImageIO', + '-framework CoreServices', + ], + }, }, }, ], diff --git a/include/mbgl/platform/default/headless_view.hpp b/include/mbgl/platform/default/headless_view.hpp index c0baddb884..f140338349 100644 --- a/include/mbgl/platform/default/headless_view.hpp +++ b/include/mbgl/platform/default/headless_view.hpp @@ -27,7 +27,7 @@ public: void createContext(); void resize(uint16_t width, uint16_t height, float pixelRatio); - const std::unique_ptr<uint32_t[]> readPixels(); + std::unique_ptr<uint32_t[]> readPixels(); void notify(); void notify_map_change(MapChange change, timestamp delay = 0); diff --git a/include/mbgl/util/image.hpp b/include/mbgl/util/image.hpp index cb7db6d6fc..b2f70e1442 100644 --- a/include/mbgl/util/image.hpp +++ b/include/mbgl/util/image.hpp @@ -7,12 +7,12 @@ namespace mbgl { namespace util { -std::string compress_png(int width, int height, void *rgba, bool flip = false); +std::string compress_png(int width, int height, void *rgba); class Image { public: - Image(const std::string &img, bool flip = false); + Image(const std::string &img); inline const char *getData() const { return img.get(); } inline uint32_t getWidth() const { return width; } diff --git a/platform/darwin/image.mm b/platform/darwin/image.mm new file mode 100644 index 0000000000..50c871533d --- /dev/null +++ b/platform/darwin/image.mm @@ -0,0 +1,125 @@ +#include <mbgl/util/image.hpp> + +#import <ImageIO/ImageIO.h> + +#if TARGET_OS_IPHONE +#import <MobileCoreServices/MobileCoreServices.h> +#else +#import <CoreServices/CoreServices.h> +#endif + +namespace mbgl { +namespace util { + +std::string compress_png(int width, int height, void *rgba) { + CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, rgba, width * height * 4, NULL); + if (!provider) { + return ""; + } + + CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB(); + if (!color_space) { + CGDataProviderRelease(provider); + return ""; + } + + CGImageRef image = CGImageCreate(width, height, 8, 32, 4 * width, color_space, + kCGBitmapByteOrderDefault | kCGImageAlphaLast, provider, NULL, false, + kCGRenderingIntentDefault); + if (!image) { + CGColorSpaceRelease(color_space); + CGDataProviderRelease(provider); + return ""; + } + + CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0); + if (!data) { + CGImageRelease(image); + CGColorSpaceRelease(color_space); + CGDataProviderRelease(provider); + return ""; + } + + CGImageDestinationRef image_destination = CGImageDestinationCreateWithData(data, kUTTypePNG, 1, NULL); + if (!image_destination) { + CFRelease(data); + CGImageRelease(image); + CGColorSpaceRelease(color_space); + CGDataProviderRelease(provider); + return ""; + } + + CGImageDestinationAddImage(image_destination, image, NULL); + CGImageDestinationFinalize(image_destination); + + const std::string result { + reinterpret_cast<const char *>(CFDataGetBytePtr(data)), + static_cast<size_t>(CFDataGetLength(data)) + }; + + CFRelease(image_destination); + CFRelease(data); + CGImageRelease(image); + CGColorSpaceRelease(color_space); + CGDataProviderRelease(provider); + + return result; +} + +Image::Image(const std::string &source_data) { + CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, reinterpret_cast<const unsigned char *>(source_data.data()), source_data.size(), kCFAllocatorNull); + if (!data) { + return; + } + + CGImageSourceRef image_source = CGImageSourceCreateWithData(data, NULL); + if (!image_source) { + CFRelease(data); + return; + } + + CGImageRef image = CGImageSourceCreateImageAtIndex(image_source, 0, NULL); + if (!image) { + CFRelease(image_source); + CFRelease(data); + return; + } + + CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB(); + if (!color_space) { + CGImageRelease(image); + CFRelease(image_source); + CFRelease(data); + return; + } + + width = CGImageGetWidth(image); + height = CGImageGetHeight(image); + CGRect rect = {{ 0, 0 }, { static_cast<CGFloat>(width), static_cast<CGFloat>(height) }}; + + img = ::std::unique_ptr<char[]>(new char[width * height * 4]()); + CGContextRef context = CGBitmapContextCreate(img.get(), width, height, 8, width * 4, + color_space, kCGImageAlphaPremultipliedLast); + if (!context) { + CGColorSpaceRelease(color_space); + CGImageRelease(image); + CFRelease(image_source); + CFRelease(data); + width = 0; + height = 0; + img.release(); + return; + } + + CGContextSetBlendMode(context, kCGBlendModeCopy); + CGContextDrawImage(context, rect, image); + + CGContextRelease(context); + CGColorSpaceRelease(color_space); + CGImageRelease(image); + CFRelease(image_source); + CFRelease(data); +} + +} +}
\ No newline at end of file diff --git a/platform/default/headless_view.cpp b/platform/default/headless_view.cpp index ec5c4aabec..71096beba0 100644 --- a/platform/default/headless_view.cpp +++ b/platform/default/headless_view.cpp @@ -181,11 +181,11 @@ void HeadlessView::resize(uint16_t width, uint16_t height, float pixelRatio) { make_inactive(); } -const std::unique_ptr<uint32_t[]> HeadlessView::readPixels() { +std::unique_ptr<uint32_t[]> HeadlessView::readPixels() { const unsigned int w = width_ * pixelRatio_; const unsigned int h = height_ * pixelRatio_; - std::unique_ptr<uint32_t[]> pixels(new uint32_t[w * h]); + auto pixels = std::unique_ptr<uint32_t[]>(new uint32_t[w * h]); make_active(); glReadPixels(0, 0, width_, height_, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get()); diff --git a/src/util/image.cpp b/platform/default/image.cpp index bd5d7b8913..5b1afec7aa 100644 --- a/src/util/image.cpp +++ b/platform/default/image.cpp @@ -1,5 +1,4 @@ #include <mbgl/util/image.hpp> -#include <mbgl/util/std.hpp> #include <png.h> @@ -11,7 +10,7 @@ namespace mbgl { namespace util { -std::string compress_png(int width, int height, void *rgba, bool flip) { +std::string compress_png(int width, int height, void *rgba) { png_voidp error_ptr = 0; png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, error_ptr, NULL, NULL); if (!png_ptr) { @@ -48,7 +47,7 @@ std::string compress_png(int width, int height, void *rgba, bool flip) { } pointers(height); for (int i = 0; i < height; i++) { - pointers.rows[flip ? height - 1 - i : i] = (png_bytep)((png_bytep)rgba + width * 4 * i); + pointers.rows[i] = (png_bytep)((png_bytep)rgba + width * 4 * i); } png_set_rows(png_ptr, info_ptr, pointers.rows); @@ -87,7 +86,7 @@ void warningHandler(png_structp, png_const_charp error_msg) { fprintf(stderr, "PNG: %s\n", error_msg); } -Image::Image(const std::string &data, bool flip) { +Image::Image(const std::string &data) { Buffer buffer(data); if (buffer.length < 8 || !png_check_sig((const png_bytep)buffer.data, 8)) { @@ -136,6 +135,8 @@ Image::Image(const std::string &data, bool flip) { if (png_get_gAMA(png, info, &gamma)) png_set_gamma(png, 2.2, gamma); + png_set_alpha_mode(png, PNG_ALPHA_PREMULTIPLIED, 2.2); + png_read_update_info(png, info); png_size_t rowbytes = png_get_rowbytes(png, info); @@ -152,7 +153,7 @@ Image::Image(const std::string &data, bool flip) { png_bytep *rows = nullptr; } pointers(height); for (unsigned i = 0; i < height; ++i) { - pointers.rows[flip ? height - 1 - i : i] = (png_bytep)(surface + (i * rowbytes)); + pointers.rows[i] = (png_bytep)(surface + (i * rowbytes)); } // Read image data diff --git a/src/geometry/sprite_atlas.cpp b/src/geometry/sprite_atlas.cpp index e5bad1eada..d7ef1e789b 100644 --- a/src/geometry/sprite_atlas.cpp +++ b/src/geometry/sprite_atlas.cpp @@ -72,18 +72,7 @@ void copy_bitmap(const uint32_t *src, const int src_stride, const int src_x, con dst += dst_y * dst_stride + dst_x; for (int y = 0; y < height; y++, src += src_stride, dst += dst_stride) { for (int x = 0; x < width; x++) { - const uint8_t *s = reinterpret_cast<const uint8_t *>(src + x); - uint8_t *d = reinterpret_cast<uint8_t *>(dst + x); - - // Premultiply the bitmap. - // Note: We don't need to clamp the component values to 0..255, since - // the source value is already 0..255 and the operation means they will - // stay within the range of 0..255 and won't overflow. - const uint8_t a = s[3]; - d[0] = s[0] * a / 255; - d[1] = s[1] * a / 255; - d[2] = s[2] * a / 255; - d[3] = a; + dst[x] = src[x]; } } } diff --git a/test/headless.cpp b/test/headless.cpp index e1bdbdc061..3837beb9a0 100644 --- a/test/headless.cpp +++ b/test/headless.cpp @@ -92,13 +92,25 @@ TEST_P(HeadlessTest, render) { map.setLonLatZoom(longitude, latitude, zoom); map.setBearing(bearing); + // Run the loop. It will terminate when we don't have any further listeners. map.run(); const unsigned int w = width * pixelRatio; const unsigned int h = height * pixelRatio; - const std::string image = util::compress_png(w, h, view.readPixels().get(), true); + auto pixels = view.readPixels(); + + const int stride = w * 4; + auto tmp = std::unique_ptr<char[]>(new char[stride]()); + char *rgba = reinterpret_cast<char *>(pixels.get()); + for (int i = 0, j = height - 2; i < j; i++, j--) { + memcpy(tmp.get(), rgba + i * stride, stride); + memcpy(rgba + i * stride, rgba + j * stride, stride); + memcpy(rgba + j * stride, tmp.get(), stride); + } + + const std::string image = util::compress_png(w, h, pixels.get()); util::write_file(actual_image, image); } } |