Skip to content

Instantly share code, notes, and snippets.

@MCJack123
Last active December 25, 2017 03:15
Show Gist options
  • Save MCJack123/bc28b6b54f19cb24ebfe35231ab294b9 to your computer and use it in GitHub Desktop.
Save MCJack123/bc28b6b54f19cb24ebfe35231ab294b9 to your computer and use it in GitHub Desktop.
PNG box blur algorithm (requires libpng & png++)
#include <iostream>
#include <string>
#include <vector>
#include <utility>
#include <png++/png.hpp>
typedef std::vector<std::pair<size_t, size_t> > points_t;
bool verbose = false;
points_t get_points(size_t x, size_t y, png::uint_32 w, png::uint_32 h, int s) {
points_t retval;
if (verbose) std::cout << "For x=" << x << " & y=" << y << " (w=" << w << " & h=" << h << "):\n";
for (int xx = -((s-1)/2); xx <= ((s-1)/2); xx++) {
if ((int)x + xx < 0 || (int)x + xx >= w) continue;
for (int yy = -((s-1)/2); yy <= ((s-1)/2); yy++) {
if ((int)y + yy < 0 || (int)y + yy >= h) continue;
if (verbose) std::cout << x + xx << ", " << y + yy << std::endl;
retval.push_back(std::make_pair(x + xx, y + yy));
}
}
if (verbose) std::cout << std::endl;
return retval;
}
png::uint_32 avg32(std::vector<png::uint_32> a) {
png::uint_32 retval = 0;
for (png::uint_32 n : a) retval += n;
return retval/a.size();
}
std::vector<png::uint_32> split_pixels(std::vector<png::rgb_pixel> p, int c) {
std::vector<png::uint_32> retval;
if (c == 0) for (png::rgb_pixel l : p) retval.push_back(l.red);
else if (c == 1) for (png::rgb_pixel l : p) retval.push_back(l.green);
else for (png::rgb_pixel l : p) retval.push_back(l.blue);
return retval;
}
int main(int argc, const char * argv[]) {
if (argc < 4 || std::string(argv[1]) == "-h") {
std::cout << "Usage: " << argv[0] << " [-s size] [-l loops] [-n] [-v] -o <output> <image>\n";
return 1;
}
bool halt = false;
int loops = 1;
int size = 3;
const char * input = argv[argc-1];
const char * output;
for (int i = 1; i < argc - 1; i++) {
if (std::string(argv[i]) == "-s") {
size = stoi(std::string(argv[i+1]));
} else if (std::string(argv[i]) == "-l") {
loops = stoi(std::string(argv[i+1]));
} else if (std::string(argv[i]) == "-o") {
output = argv[i+1];
} else if (std::string(argv[i]) == "-n") {
halt = true;
} else if (std::string(argv[i]) == "-v") {
verbose = true;
}
}
if (size % 2 != 1 || size < 3) {
std::cout << "Error: The size given was not valid.";
if (halt) {
std::cout << std::endl;
return 2;
}
std::cout << " Continuing with size 3...\n";
size = 3;
}
png::image<png::rgb_pixel> in(input);
png::uint_32 width = in.get_width();
png::uint_32 height = in.get_height();
png::image<png::rgb_pixel> out(width, height);
for (int loop = 0; loop < loops; loop++) {
out = png::image<png::rgb_pixel>(width, height);
for (size_t x = 0; x < width; x++) {
for (size_t y = 0; y < height; y++) {
points_t l = get_points(x, y, width, height, size);
png::rgb_pixel o;
std::vector<png::rgb_pixel> c;
for (std::pair<size_t, size_t> n : l) c.push_back(in.get_pixel(n.first, n.second));
for (int i = 0; i < 3; i++) {
png::uint_32 a = avg32(split_pixels(c, i));
if (i == 0) o.red = a;
else if (i == 1) o.green = a;
else o.blue = a;
}
out.set_pixel(x, y, o);
}
}
in = out;
if (verbose) std::cout << "Finished loop " << loop + 1 << std::endl;
}
out.write(output);
return 0;
}
@MCJack123
Copy link
Author

This is available on my macOS Homebrew repo as mcjack123/pngblur.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment