summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2014-10-29 19:58:34 -0400
committerKonstantin Käfer <mail@kkaefer.com>2014-10-30 12:02:28 -0400
commite3bc69b7e77aa6771c8db3695f12548447e1de51 (patch)
tree0c1a0bde928fea3e09b1d72222b400176c0936c7
parent7a13db9a863c9be58709e941f44eb2c370276e2a (diff)
downloadqtlocation-mapboxgl-e3bc69b7e77aa6771c8db3695f12548447e1de51.tar.gz
use CoreImage for decoding/encoding images on osx/ios
-rwxr-xr-xconfigure15
-rw-r--r--gyp/mbgl-core.gypi1
-rw-r--r--gyp/mbgl-ios.gypi9
-rw-r--r--gyp/mbgl-linux.gypi3
-rw-r--r--gyp/mbgl-osx.gypi9
-rw-r--r--include/mbgl/platform/default/headless_view.hpp2
-rw-r--r--include/mbgl/util/image.hpp4
-rw-r--r--platform/darwin/image.mm125
-rw-r--r--platform/default/headless_view.cpp4
-rw-r--r--platform/default/image.cpp (renamed from src/util/image.cpp)11
-rw-r--r--src/geometry/sprite_atlas.cpp13
-rw-r--r--test/headless.cpp14
12 files changed, 181 insertions, 29 deletions
diff --git a/configure b/configure
index afb94d4795..daf09eaeee 100755
--- a/configure
+++ b/configure
@@ -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);
}
}