[core][ios][osx][android] make SpriteImage accept PremultipliedImage

the SpriteImage constructor signature changes from

SpriteImage(
        uint16_t width, uint16_t height, float pixelRatio,
        std::string&& data, bool sdf = false);

to

SpriteImage(PremultipliedImage&&, float pixelRatio, bool sdf = false)
This commit is contained in:
Ansis Brammanis
2016-01-15 17:39:08 -08:00
parent 26faa6a5ad
commit d34f8eb674
20 changed files with 160 additions and 168 deletions

View File

@@ -16,7 +16,7 @@ using namespace mbgl;
std::shared_ptr<SpriteImage> namedMarker(const std::string &name) {
PremultipliedImage image = decodeImage(util::read_file("test/fixtures/sprites/" + name));
return std::make_shared<SpriteImage>(image.width, image.height, 1.0, std::string(reinterpret_cast<char*>(image.data.get()), image.size()));
return std::make_shared<SpriteImage>(std::move(image), 1.0);
}
namespace {

View File

@@ -89,6 +89,7 @@ Server::~Server() {
}
}
// from https://gist.github.com/ArtemGr/997887
uint64_t crc64(const char* data, size_t size) {
boost::crc_optimal<64, 0x04C11DB7, 0, 0, false, false> crc;
@@ -100,6 +101,10 @@ uint64_t crc64(const std::string& str) {
return crc64(str.data(), str.size());
}
uint64_t crc64(const PremultipliedImage &image) {
return crc64(reinterpret_cast<const char*>(image.data.get()), image.size());
}
PremultipliedImage render(Map& map, std::chrono::milliseconds timeout) {
std::promise<PremultipliedImage> promise;
map.renderStill([&](std::exception_ptr, PremultipliedImage&& image) {

View File

@@ -33,6 +33,7 @@ private:
uint64_t crc64(const char*, size_t);
uint64_t crc64(const std::string&);
uint64_t crc64(const PremultipliedImage&);
PremultipliedImage render(Map&,
std::chrono::milliseconds timeout = std::chrono::milliseconds(1000));

View File

@@ -34,11 +34,11 @@ TEST(Sprite, SpriteAtlas) {
EXPECT_EQ(0, metro.pos.y);
EXPECT_EQ(20, metro.pos.w);
EXPECT_EQ(20, metro.pos.h);
EXPECT_EQ(18, metro.texture->width);
EXPECT_EQ(18, metro.texture->height);
EXPECT_EQ(18, metro.texture->pixelWidth);
EXPECT_EQ(18, metro.texture->pixelHeight);
EXPECT_EQ(1.0f, metro.texture->pixelRatio);
EXPECT_EQ(18, metro.spriteImage->getWidth());
EXPECT_EQ(18, metro.spriteImage->getHeight());
EXPECT_EQ(18, metro.spriteImage->image.width);
EXPECT_EQ(18, metro.spriteImage->image.height);
EXPECT_EQ(1.0f, metro.spriteImage->pixelRatio);
EXPECT_TRUE(atlas.getData());
@@ -96,11 +96,11 @@ TEST(Sprite, SpriteAtlasSize) {
EXPECT_EQ(0, metro.pos.y);
EXPECT_EQ(16, metro.pos.w);
EXPECT_EQ(16, metro.pos.h);
EXPECT_EQ(18, metro.texture->width);
EXPECT_EQ(18, metro.texture->height);
EXPECT_EQ(18, metro.texture->pixelWidth);
EXPECT_EQ(18, metro.texture->pixelHeight);
EXPECT_EQ(1.0f, metro.texture->pixelRatio);
EXPECT_EQ(18, metro.spriteImage->getWidth());
EXPECT_EQ(18, metro.spriteImage->getHeight());
EXPECT_EQ(18, metro.spriteImage->image.width);
EXPECT_EQ(18, metro.spriteImage->image.height);
EXPECT_EQ(1.0f, metro.spriteImage->pixelRatio);
const size_t bytes = atlas.getTextureWidth() * atlas.getTextureHeight() * 4;
const auto hash = test::crc64(reinterpret_cast<const char*>(atlas.getData()), bytes);
@@ -122,24 +122,28 @@ TEST(Sprite, SpriteAtlasUpdates) {
EXPECT_EQ(32, atlas.getTextureWidth());
EXPECT_EQ(32, atlas.getTextureHeight());
store.setSprite("one", std::make_shared<SpriteImage>(16, 12, 1, std::string(16 * 12 * 4, '\x00')));
store.setSprite("one", std::make_shared<SpriteImage>(PremultipliedImage(16, 12), 1));
auto one = *atlas.getImage("one", false);
EXPECT_EQ(0, one.pos.x);
EXPECT_EQ(0, one.pos.y);
EXPECT_EQ(20, one.pos.w);
EXPECT_EQ(16, one.pos.h);
EXPECT_EQ(16, one.texture->width);
EXPECT_EQ(12, one.texture->height);
EXPECT_EQ(16, one.texture->pixelWidth);
EXPECT_EQ(12, one.texture->pixelHeight);
EXPECT_EQ(1.0f, one.texture->pixelRatio);
EXPECT_EQ(16, one.spriteImage->getWidth());
EXPECT_EQ(12, one.spriteImage->getHeight());
EXPECT_EQ(16, one.spriteImage->image.width);
EXPECT_EQ(12, one.spriteImage->image.height);
EXPECT_EQ(1.0f, one.spriteImage->pixelRatio);
const size_t bytes = atlas.getTextureWidth() * atlas.getTextureHeight() * 4;
const auto hash = test::crc64(reinterpret_cast<const char*>(atlas.getData()), bytes);
EXPECT_EQ(0x0000000000000000u, hash) << std::hex << hash;
// Update sprite
auto newSprite = std::make_shared<SpriteImage>(16, 12, 1, std::string(16 * 12 * 4, '\xFF'));
PremultipliedImage image2(16, 12);
for (size_t i = 0; i < image2.size(); i++) {
image2.data.get()[i] = 255;
}
auto newSprite = std::make_shared<SpriteImage>(std::move(image2), 1);
store.setSprite("one", newSprite);
ASSERT_EQ(newSprite, store.getSprite("one"));

View File

@@ -1,13 +1,15 @@
#include "../fixtures/util.hpp"
#include <mbgl/sprite/sprite_image.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/util/exception.hpp>
using namespace mbgl;
TEST(Sprite, SpriteImageZeroWidth) {
PremultipliedImage image(0, 16);
try {
SpriteImage(0, 16, 2, "");
SpriteImage(std::move(image), 2.0);
FAIL() << "Expected exception";
} catch (util::SpriteImageException& ex) {
EXPECT_STREQ("Sprite image dimensions may not be zero", ex.what());
@@ -15,8 +17,9 @@ TEST(Sprite, SpriteImageZeroWidth) {
}
TEST(Sprite, SpriteImageZeroHeight) {
PremultipliedImage image(16, 0);
try {
SpriteImage(16, 0, 2, "");
SpriteImage(std::move(image), 2.0);
FAIL() << "Expected exception";
} catch (util::SpriteImageException& ex) {
EXPECT_STREQ("Sprite image dimensions may not be zero", ex.what());
@@ -24,41 +27,31 @@ TEST(Sprite, SpriteImageZeroHeight) {
}
TEST(Sprite, SpriteImageZeroRatio) {
PremultipliedImage image(16, 16);
try {
SpriteImage(16, 16, 0, "");
SpriteImage(std::move(image), 0.0);
FAIL() << "Expected exception";
} catch (util::SpriteImageException& ex) {
EXPECT_STREQ("Sprite image pixel count mismatch", ex.what());
}
}
TEST(Sprite, SpriteImageMismatchedData) {
try {
SpriteImage(16, 16, 2, "");
FAIL() << "Expected exception";
} catch (util::SpriteImageException& ex) {
EXPECT_STREQ("Sprite image pixel count mismatch", ex.what());
EXPECT_STREQ("Sprite pixelRatio may not be <= 0", ex.what());
}
}
TEST(Sprite, SpriteImage) {
std::string pixels(32 * 24 * 4, '\0');
SpriteImage sprite(32, 24, 2, std::move(pixels));
EXPECT_EQ(16, sprite.width);
EXPECT_EQ(32, sprite.pixelWidth);
EXPECT_EQ(12, sprite.height);
EXPECT_EQ(24, sprite.pixelHeight);
PremultipliedImage image(32, 24);
SpriteImage sprite(std::move(image), 2.0);
EXPECT_EQ(16, sprite.getWidth());
EXPECT_EQ(32, sprite.image.width);
EXPECT_EQ(12, sprite.getHeight());
EXPECT_EQ(24, sprite.image.height);
EXPECT_EQ(2, sprite.pixelRatio);
EXPECT_EQ(32u * 24 * 4, sprite.data.size());
}
TEST(Sprite, SpriteImageFractionalRatio) {
std::string pixels(20 * 12 * 4, '\0');
SpriteImage sprite(20, 12, 1.5, std::move(pixels));
EXPECT_EQ(14, sprite.width);
EXPECT_EQ(20, sprite.pixelWidth);
EXPECT_EQ(8, sprite.height);
EXPECT_EQ(12, sprite.pixelHeight);
PremultipliedImage image(20, 12);
SpriteImage sprite(std::move(image), 1.5);
EXPECT_EQ(float(20.0 / 1.5), sprite.getWidth());
EXPECT_EQ(20, sprite.image.width);
EXPECT_EQ(float(12.0 / 1.5), sprite.getHeight());
EXPECT_EQ(12, sprite.image.height);
EXPECT_EQ(1.5, sprite.pixelRatio);
EXPECT_EQ(20u * 12 * 4, sprite.data.size());
}

View File

@@ -43,34 +43,34 @@ TEST(Sprite, SpriteImageCreation1x) {
{ // "museum_icon":{"x":177,"y":187,"width":18,"height":18,"pixelRatio":1,"sdf":false}
const auto sprite = createSpriteImage(image_1x, 177, 187, 18, 18, 1, false);
ASSERT_TRUE(sprite.get());
EXPECT_EQ(18, sprite->width);
EXPECT_EQ(18, sprite->height);
EXPECT_EQ(18, sprite->pixelWidth);
EXPECT_EQ(18, sprite->pixelHeight);
EXPECT_EQ(18, sprite->getWidth());
EXPECT_EQ(18, sprite->getHeight());
EXPECT_EQ(18, sprite->image.width);
EXPECT_EQ(18, sprite->image.height);
EXPECT_EQ(1, sprite->pixelRatio);
EXPECT_EQ(0x7FCC5F263D1FFE16u, test::crc64(sprite->data));
EXPECT_EQ(0x7FCC5F263D1FFE16u, test::crc64(sprite->image));
}
{ // outside image == blank
const auto sprite = createSpriteImage(image_1x, 200, 0, 16, 16, 1, false);
ASSERT_TRUE(sprite.get());
EXPECT_EQ(16, sprite->width);
EXPECT_EQ(16, sprite->height);
EXPECT_EQ(16, sprite->pixelWidth);
EXPECT_EQ(16, sprite->pixelHeight);
EXPECT_EQ(16, sprite->getWidth());
EXPECT_EQ(16, sprite->getHeight());
EXPECT_EQ(16, sprite->image.width);
EXPECT_EQ(16, sprite->image.height);
EXPECT_EQ(1, sprite->pixelRatio);
EXPECT_EQ(0x0000000000000000u, test::crc64(sprite->data)) << std::hex << test::crc64(sprite->data);
EXPECT_EQ(0x0000000000000000u, test::crc64(sprite->image)) << std::hex << test::crc64(sprite->image);
}
{ // outside image == blank
const auto sprite = createSpriteImage(image_1x, 0, 300, 16, 16, 1, false);
ASSERT_TRUE(sprite.get());
EXPECT_EQ(16, sprite->width);
EXPECT_EQ(16, sprite->height);
EXPECT_EQ(16, sprite->pixelWidth);
EXPECT_EQ(16, sprite->pixelHeight);
EXPECT_EQ(16, sprite->getWidth());
EXPECT_EQ(16, sprite->getHeight());
EXPECT_EQ(16, sprite->image.width);
EXPECT_EQ(16, sprite->image.height);
EXPECT_EQ(1, sprite->pixelRatio);
EXPECT_EQ(0x0000000000000000u, test::crc64(sprite->data)) << std::hex << test::crc64(sprite->data);
EXPECT_EQ(0x0000000000000000u, test::crc64(sprite->image)) << std::hex << test::crc64(sprite->image);
}
}
@@ -80,12 +80,12 @@ TEST(Sprite, SpriteImageCreation2x) {
// "museum_icon":{"x":354,"y":374,"width":36,"height":36,"pixelRatio":2,"sdf":false}
const auto sprite = createSpriteImage(image_2x, 354, 374, 36, 36, 2, false);
ASSERT_TRUE(sprite.get());
EXPECT_EQ(18, sprite->width);
EXPECT_EQ(18, sprite->height);
EXPECT_EQ(36, sprite->pixelWidth);
EXPECT_EQ(36, sprite->pixelHeight);
EXPECT_EQ(18, sprite->getWidth());
EXPECT_EQ(18, sprite->getHeight());
EXPECT_EQ(36, sprite->image.width);
EXPECT_EQ(36, sprite->image.height);
EXPECT_EQ(2, sprite->pixelRatio);
EXPECT_EQ(0x85F345098DD4F9E3u, test::crc64(sprite->data));
EXPECT_EQ(0x85F345098DD4F9E3u, test::crc64(sprite->image));
}
TEST(Sprite, SpriteImageCreation1_5x) {
@@ -94,22 +94,22 @@ TEST(Sprite, SpriteImageCreation1_5x) {
// "museum_icon":{"x":354,"y":374,"width":36,"height":36,"pixelRatio":2,"sdf":false}
const auto sprite = createSpriteImage(image_2x, 354, 374, 36, 36, 1.5, false);
ASSERT_TRUE(sprite.get());
EXPECT_EQ(24, sprite->width);
EXPECT_EQ(24, sprite->height);
EXPECT_EQ(36, sprite->pixelWidth);
EXPECT_EQ(36, sprite->pixelHeight);
EXPECT_EQ(24, sprite->getWidth());
EXPECT_EQ(24, sprite->getHeight());
EXPECT_EQ(36, sprite->image.width);
EXPECT_EQ(36, sprite->image.height);
EXPECT_EQ(1.5, sprite->pixelRatio);
EXPECT_EQ(0x85F345098DD4F9E3u, test::crc64(sprite->data));
EXPECT_EQ(0x85F345098DD4F9E3u, test::crc64(sprite->image));
// "hospital_icon":{"x":314,"y":518,"width":36,"height":36,"pixelRatio":2,"sdf":false}
const auto sprite2 = createSpriteImage(image_2x, 314, 518, 35, 35, 1.5, false);
ASSERT_TRUE(sprite2.get());
EXPECT_EQ(24, sprite2->width);
EXPECT_EQ(24, sprite2->height);
EXPECT_EQ(35, sprite2->pixelWidth);
EXPECT_EQ(35, sprite2->pixelHeight);
EXPECT_EQ(float(35 / 1.5), sprite2->getWidth());
EXPECT_EQ(float(35 / 1.5), sprite2->getHeight());
EXPECT_EQ(35, sprite2->image.width);
EXPECT_EQ(35, sprite2->image.height);
EXPECT_EQ(1.5, sprite2->pixelRatio);
EXPECT_EQ(14312995667113444493u, test::crc64(sprite2->data));
EXPECT_EQ(14312995667113444493u, test::crc64(sprite2->image));
}
TEST(Sprite, SpriteParsing) {
@@ -199,12 +199,12 @@ TEST(Sprite, SpriteParsing) {
{
auto sprite = images.find("generic-metro")->second;
EXPECT_EQ(18, sprite->width);
EXPECT_EQ(18, sprite->height);
EXPECT_EQ(18, sprite->pixelWidth);
EXPECT_EQ(18, sprite->pixelHeight);
EXPECT_EQ(18, sprite->getWidth());
EXPECT_EQ(18, sprite->getHeight());
EXPECT_EQ(18, sprite->image.width);
EXPECT_EQ(18, sprite->image.height);
EXPECT_EQ(1, sprite->pixelRatio);
EXPECT_EQ(0xFF56F5F48F707147u, test::crc64(sprite->data));
EXPECT_EQ(0xFF56F5F48F707147u, test::crc64(sprite->image));
}
}

View File

@@ -13,9 +13,9 @@ using namespace mbgl;
TEST(SpriteStore, SpriteStore) {
FixtureLog log;
const auto sprite1 = std::make_shared<SpriteImage>(16, 16, 2, std::string(16 * 16 * 4, '\0'));
const auto sprite2 = std::make_shared<SpriteImage>(16, 16, 2, std::string(16 * 16 * 4, '\0'));
const auto sprite3 = std::make_shared<SpriteImage>(16, 16, 2, std::string(16 * 16 * 4, '\0'));
const auto sprite1 = std::make_shared<SpriteImage>(PremultipliedImage(16, 16), 2);
const auto sprite2 = std::make_shared<SpriteImage>(PremultipliedImage(16, 16), 2);
const auto sprite3 = std::make_shared<SpriteImage>(PremultipliedImage(16, 16), 2);
using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>;
SpriteStore store(1);
@@ -79,7 +79,7 @@ TEST(SpriteStore, SpriteStore) {
TEST(SpriteStore, OtherPixelRatio) {
FixtureLog log;
const auto sprite1 = std::make_shared<SpriteImage>(8, 8, 1, std::string(8 * 8 * 4, '\0'));
const auto sprite1 = std::make_shared<SpriteImage>(PremultipliedImage(8, 8), 1);
using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>;
SpriteStore store(1);
@@ -90,8 +90,8 @@ TEST(SpriteStore, OtherPixelRatio) {
}
TEST(SpriteStore, Multiple) {
const auto sprite1 = std::make_shared<SpriteImage>(16, 16, 2, std::string(16 * 16 * 4, '\0'));
const auto sprite2 = std::make_shared<SpriteImage>(16, 16, 2, std::string(16 * 16 * 4, '\0'));
const auto sprite1 = std::make_shared<SpriteImage>(PremultipliedImage(16, 16), 2);
const auto sprite2 = std::make_shared<SpriteImage>(PremultipliedImage(16, 16), 2);
using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>;
SpriteStore store(1);
@@ -109,8 +109,8 @@ TEST(SpriteStore, Multiple) {
TEST(SpriteStore, Replace) {
FixtureLog log;
const auto sprite1 = std::make_shared<SpriteImage>(16, 16, 2, std::string(16 * 16 * 4, '\0'));
const auto sprite2 = std::make_shared<SpriteImage>(16, 16, 2, std::string(16 * 16 * 4, '\0'));
const auto sprite1 = std::make_shared<SpriteImage>(PremultipliedImage(16, 16), 2);
const auto sprite2 = std::make_shared<SpriteImage>(PremultipliedImage(16, 16), 2);
using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>;
SpriteStore store(1);
@@ -126,8 +126,10 @@ TEST(SpriteStore, Replace) {
TEST(SpriteStore, ReplaceWithDifferentDimensions) {
FixtureLog log;
const auto sprite1 = std::make_shared<SpriteImage>(16, 16, 2, std::string(16 * 16 * 4, '\0'));
const auto sprite2 = std::make_shared<SpriteImage>(18, 18, 2, std::string(18 * 18 * 4, '\0'));
PremultipliedImage image(16, 16);
PremultipliedImage image2(18, 18);
const auto sprite1 = std::make_shared<SpriteImage>(PremultipliedImage(16, 16), 2);
const auto sprite2 = std::make_shared<SpriteImage>(PremultipliedImage(18, 18), 2);
using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>;
SpriteStore store(1);