#include #include #include #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wshadow" #include #pragma GCC diagnostic pop #include #include #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(idat.size())); addChunk(png, "IEND"); return png; } } // namespace mbgl