summaryrefslogtreecommitdiff
path: root/image.cpp
blob: 675e22f599b740bcd926430ba5a2735a0059fb56 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include "image.h"
#include <iostream>
#include <array>
#include <string>
#include <cstring>
#include <cassert>
#include <cmath>
#include <png.h>


static std::array<uint8_t, 3> render_pixel(double x) {
	const double red = 1 - std::pow(1 - x, 3);
	const double green = 1 - std::pow(1 - x, 3);
	const double blue = 1 - std::pow(1 - x, 6);
	return {(uint8_t)(red * 255), (uint8_t)(green * 255), (uint8_t)(blue * 255)};
}

HistImage::HistImage(size_t width, size_t height)
	: width{width}, height{height}, data(width * height, 0) {}

void HistImage::add(const HistImage &other) {
	assert(width == other.width && height == other.height);
	for (size_t i = 0; i < width * height; i++) data[i] += other.data[i];
}

void HistImage::render(const char *fname) const {
	uint64_t maxval = 0;
	for (size_t i = 0; i < width * height; i++) maxval = std::max(maxval, data[i]);
	const double maxvald = maxval;

	std::vector<uint8_t> buffer(3 * width * height);
	for (size_t i = 0; i < width * height; i++) {
		const std::array<uint8_t, 3> pix = render_pixel((double)data[i] / maxvald);
		memcpy(&buffer[3 * i], &pix[0], 3);
	}

	png_image png;
	memset(&png, 0, sizeof png);
	png.version = PNG_IMAGE_VERSION;
	png.width = width;
	png.height = height;
	png.format = PNG_FORMAT_RGB;

	int ret = png_image_write_to_file(&png, fname, 0, buffer.data(), 3 * width, NULL);
	if (ret != 0 && (png.warning_or_error & 2)) {
		std::string errmsg;
		char *p = (char*)memchr(png.message, ' ', sizeof png.message);
		if (p != NULL) { errmsg = std::string(png.message, p - png.message); }
		else errmsg = std::string(png.message, sizeof png.message);
		std::cerr << "PNG write failed: " << errmsg << std::endl;
	}

	png_image_free(&png);
}

// vim: set sw=4 ts=4 noet: