git.haldean.org plotter / master lib / pixels.hpp
master

Tree @master (Download .tar.gz)

pixels.hpp @masterraw · history · blame

#pragma once

#include "array2d.hpp"
#include "lodepng.h"

#include <vector>

using namespace std;

template<typename T>
struct pixels {
  array2d<T> r;
  array2d<T> g;
  array2d<T> b;
  size_t n;
  size_t w;
  size_t h;

  pixels(size_t w, size_t h) noexcept
    : r(w, h)
    , g(w, h)
    , b(w, h)
    , n(w * h)
    , w(w)
    , h(h)
  {}

  pixels() : pixels(0, 0) {};
  pixels(const pixels&) = delete;
  pixels(pixels&&) = default;
  pixels<T>& operator=(pixels<T> &&o) = default;

  operator bool() const {
    return n > 0;
  }
};

pair<pixels<uint8_t>*, bool> from_png(char *fname) {
  // 4 components per pixel, rgba
  vector<uint8_t> rawdata;
  uint32_t width, height;

  auto err = lodepng::decode(rawdata, width, height, fname);
  if (err) {
    cout << "couldn't load png: " << err << endl;
    return make_pair(nullptr, false);
  }
  if (rawdata.size() % 4 != 0) {
    cout << "bad size for rawdata " << rawdata.size() << endl;
    return make_pair(nullptr, false);
  }

  pixels<uint8_t> * const inpx = new pixels<uint8_t>(width, height);

  #pragma omp parallel for
  for (size_t i = 0; i < inpx->n; i++) {
    inpx->r(i) = rawdata[4 * i + 0];
    inpx->g(i) = rawdata[4 * i + 1];
    inpx->b(i) = rawdata[4 * i + 2];
  }

  return make_pair(inpx, true);
}

bool to_png(string fname, const pixels<uint8_t> &img) {
  uint8_t *data = (uint8_t*) malloc(3 * img.n);
  for (size_t i = 0; i < img.n; i++) {
    data[3 * i + 0] = img.r(i);
    data[3 * i + 1] = img.g(i);
    data[3 * i + 2] = img.b(i);
  }

  auto err = lodepng::encode(fname, data, img.w, img.h, LCT_RGB);
  if (err) {
    cout << "couldn't save pixel image: " << err << endl;
    return false;
  }
  return true;
}