summaryrefslogtreecommitdiff
path: root/platform/default/src/mbgl/util/png_writer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'platform/default/src/mbgl/util/png_writer.cpp')
-rw-r--r--platform/default/src/mbgl/util/png_writer.cpp77
1 files changed, 77 insertions, 0 deletions
diff --git a/platform/default/src/mbgl/util/png_writer.cpp b/platform/default/src/mbgl/util/png_writer.cpp
new file mode 100644
index 0000000000..b89e253f85
--- /dev/null
+++ b/platform/default/src/mbgl/util/png_writer.cpp
@@ -0,0 +1,77 @@
+#include <mbgl/util/compression.hpp>
+#include <mbgl/util/image.hpp>
+#include <mbgl/util/premultiply.hpp>
+
+#include <boost/crc.hpp>
+
+#include <cassert>
+#include <cstring>
+
+#define NETWORK_BYTE_UINT32(value) \
+ char(value >> 24), char(value >> 16), char(value >> 8), char(value >> 0)
+
+namespace {
+
+void addChunk(std::string& png, const char* type, const char* data = "", const uint32_t size = 0) {
+ assert(strlen(type) == 4);
+
+ // Checksum encompasses type + data
+ boost::crc_32_type checksum;
+ checksum.process_bytes(type, 4);
+ checksum.process_bytes(data, size);
+
+ const char length[4] = { NETWORK_BYTE_UINT32(size) };
+ const char crc[4] = { NETWORK_BYTE_UINT32(checksum.checksum()) };
+
+ png.reserve(png.size() + 4 /* length */ + 4 /* type */ + size + 4 /* CRC */);
+ png.append(length, 4);
+ png.append(type, 4);
+ png.append(data, size);
+ png.append(crc, 4);
+}
+
+} // namespace
+
+namespace mbgl {
+
+// Encode PNGs without libpng.
+std::string encodePNG(const PremultipliedImage& pre) {
+ // Make copy of the image so that we can unpremultiply it.
+ const auto src = util::unpremultiply(pre.clone());
+
+ // PNG magic bytes
+ const char preamble[8] = { char(0x89), 'P', 'N', 'G', '\r', '\n', 0x1a, '\n' };
+
+ // IHDR chunk for our RGBA image.
+ const char ihdr[13] = {
+ NETWORK_BYTE_UINT32(src.size.width), // width
+ NETWORK_BYTE_UINT32(src.size.height), // height
+ 8, // bit depth == 8 bits
+ 6, // color type == RGBA
+ 0, // compression method == deflate
+ 0, // filter method == default
+ 0, // interlace method == none
+ };
+
+ // Prepare the (compressed) data chunk.
+ const auto stride = src.stride();
+ std::string idat;
+ for (uint32_t y = 0; y < src.size.height; y++) {
+ // Every scanline needs to be prefixed with one byte that indicates the filter type.
+ idat.append(1, 0); // filter type 0
+ idat.append((const char*)(src.data.get() + y * stride), stride);
+ }
+ idat = util::compress(idat);
+
+ // Assemble the PNG.
+ std::string png;
+ png.reserve((8 /* preamble */) + (12 + 13 /* IHDR */) +
+ (12 + idat.size() /* IDAT */) + (12 /* IEND */));
+ png.append(preamble, 8);
+ addChunk(png, "IHDR", ihdr, 13);
+ addChunk(png, "IDAT", idat.data(), static_cast<uint32_t>(idat.size()));
+ addChunk(png, "IEND");
+ return png;
+}
+
+} // namespace mbgl