summaryrefslogtreecommitdiffstats
path: root/src/PNG.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/PNG.cpp')
-rw-r--r--src/PNG.cpp85
1 files changed, 81 insertions, 4 deletions
diff --git a/src/PNG.cpp b/src/PNG.cpp
index 1e25712..0154f61 100644
--- a/src/PNG.cpp
+++ b/src/PNG.cpp
@@ -28,17 +28,19 @@
#include <cerrno>
#include <cstdio>
+#include <cstring>
#include <system_error>
#include <png.h>
namespace MinedMap {
+namespace PNG {
-void writePNG(const char *filename, const uint32_t *data, size_t width, size_t height) {
+void write(const char *filename, const uint8_t *data, size_t width, size_t height) {
std::FILE *f = std::fopen(filename, "wb");
if (!f)
- throw std::system_error(errno, std::generic_category(), "unable to open output file");
+ throw std::system_error(errno, std::generic_category(), "unable to open PNG file");
png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (!png_ptr)
@@ -63,13 +65,88 @@ void writePNG(const char *filename, const uint32_t *data, size_t width, size_t h
uint8_t *row_pointers[height];
for (size_t i = 0; i < height; i++)
- row_pointers[i] = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&data[i*width]));
+ row_pointers[i] = const_cast<uint8_t*>(&data[4*i*width]);
png_set_rows(png_ptr, info_ptr, row_pointers);
- png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
+ png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, nullptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
std::fclose(f);
}
+void read(const char *filename, uint8_t *data, size_t width, size_t height) {
+ std::FILE *f = std::fopen(filename, "rb");
+ if (!f)
+ throw std::system_error(errno, std::generic_category(), "unable to open PNG file");
+
+ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
+ if (!png_ptr)
+ throw std::runtime_error("unable to create PNG read struct");
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr) {
+ png_destroy_read_struct(&png_ptr, nullptr, nullptr);
+ throw std::runtime_error("unable to create PNG info struct");
+ }
+
+ png_infop end_info = png_create_info_struct(png_ptr);
+ if (!end_info) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
+ throw std::runtime_error("unable to create PNG info struct");
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+ fclose(f);
+ throw std::runtime_error("unable to read PNG file");
+ }
+
+ png_init_io(png_ptr, f);
+
+ png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, nullptr);
+
+ if (png_get_image_width(png_ptr, info_ptr) != width
+ || png_get_image_height(png_ptr, info_ptr) != height
+ || png_get_bit_depth(png_ptr, info_ptr) != 8
+ || png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_RGB_ALPHA)
+ longjmp(png_jmpbuf(png_ptr), 1);
+
+ uint8_t **row_pointers = png_get_rows(png_ptr, info_ptr);
+ for (size_t i = 0; i < height; i++)
+ std::memcpy(&data[4*i*width], row_pointers[i], 4*width);
+
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+ std::fclose(f);
+}
+
+static void readScaled(uint8_t *data, size_t offset_w, size_t offset_h, const char *file, size_t width, size_t height) {
+ if (!file)
+ return;
+
+ uint8_t input[4*width*height];
+ read(file, input, width, height);
+
+ for (size_t h = 0; h < width/2; h++) {
+ for (size_t w = 0; w < width/2; w++) {
+ for (size_t c = 0; c < 4; c++) {
+ size_t i = 8*width*h + 8*w + c;
+ data[4*width*(offset_h+h) + 4*(offset_w+w) + c] = (input[i] + input[i+4] + input[i+4*width] + input[i+4*width+4])/4;
+ }
+ }
+ }
+}
+
+void mipmap(const char *output, size_t width, size_t height, const char *nw, const char *ne, const char *sw, const char *se) {
+ uint8_t data[4*width*height];
+ std::memset(data, 0, sizeof(data));
+
+ readScaled(data, 0, 0, nw, width, height);
+ readScaled(data, width/2, 0, ne, width, height);
+ readScaled(data, 0, height/2, sw, width, height);
+ readScaled(data, width/2, height/2, se, width, height);
+
+ write(output, data, width, height);
+}
+
+}
}