Browse Source

Adds png support

master
Joshua Moerman 11 years ago
parent
commit
f206ad4c77
  1. 115
      include/basics.hpp
  2. 191
      include/png.hpp

115
include/basics.hpp

@ -0,0 +1,115 @@
//
// basics.hpp
// ImageStreams
//
// Created by Joshua Moerman on 9/7/12.
// Copyright (c) 2012 Vadovas. All rights reserved.
//
#ifndef ImageStreams_basics_hpp
#define ImageStreams_basics_hpp
/*
A PixelFormat p should have the following constructors (depending on number
of colors):
p(int r, int g, int b, int a)
p(double r, double g, double b, double a)
p(int v)
p(double v)
The order in the ctor is rgb even though the internal structure may be
different
It should be trivially copyable (for memcpy).
Furthermore it should have a static const size_t num_colors indicating the
number of colors and a static const size_t bit_per_color indicating the
number of bits per color (TODO: what to do with encodings like 565 ?)
*/
#include <cstdint>
#include <algorithm>
namespace pixel_formats {
inline uint8_t clamp(int n){
return std::min(255, std::max(0, n));
}
struct gray {
static const size_t num_colors = 1;
static const size_t bits_per_color = 8;
gray() : value(0) {}
gray(double intensity) : value(clamp(255*intensity)) {}
gray(int intensity) : value(clamp(intensity)) {}
private:
uint8_t value;
};
struct rgb {
static const size_t num_colors = 3;
static const size_t bits_per_color = 8;
rgb()
: red(0)
, green(0)
, blue(0)
{}
rgb(double red, double green, double blue)
: red(clamp(255*red))
, green(clamp(255*green))
, blue(clamp(255*blue))
{}
rgb(int red, int green, int blue)
: red(clamp(red))
, green(clamp(green))
, blue(clamp(blue))
{}
private:
uint8_t red;
uint8_t green;
uint8_t blue;
};
struct bgr{
static const size_t num_colors = 3;
static const size_t bits_per_color = 8;
bgr()
: blue(0)
, green(0)
, red(0)
{}
bgr(double red, double green, double blue)
: blue(clamp(255*blue))
, green(clamp(255*green))
, red(clamp(255*red))
{}
bgr(int red, int green, int blue)
: blue(clamp(blue))
, green(clamp(green))
, red(clamp(red))
{}
private:
uint8_t blue;
uint8_t green;
uint8_t red;
};
template <typename PixelType>
struct traits {
static const size_t num_colors = PixelType::num_colors;
static const size_t bits_per_color = PixelType::bits_per_color;
static const size_t bits_per_pixel = num_colors * bits_per_color;
};
}
#endif

191
include/png.hpp

@ -0,0 +1,191 @@
//
// png.hpp
// ImageStreams
//
// Created by Joshua Moerman on 9/7/12.
// Copyright (c) 2012 Vadovas. All rights reserved.
//
#ifndef ImageStreams_png_hpp
#define ImageStreams_png_hpp
#include <cstdio>
#include <stdexcept>
#include <vector>
#include <png.h>
#include "basics.hpp"
namespace png{
template <typename P>
int color_type(){
int num_colors = pixel_formats::traits<P>::num_colors;
switch (num_colors) {
case 1: return PNG_COLOR_TYPE_GRAY;
case 2: return PNG_COLOR_TYPE_GRAY_ALPHA;
case 3: return PNG_COLOR_TYPE_RGB;
case 4: return PNG_COLOR_TYPE_RGB_ALPHA;
default: return PNG_COLOR_TYPE_RGB;
}
}
template <typename P = pixel_formats::rgb>
struct ostream{
typedef P pixel;
ostream() = delete;
ostream(ostream const &) = delete;
ostream & operator=(ostream const &) = delete;
ostream(uint32_t width, uint32_t height, std::string filename)
: fp(0)
, png_ptr(0)
, info_ptr(0)
, row(width)
, x(0)
{
fp = fopen(filename.c_str(), "wb");
if(!fp) throw std::runtime_error("Could not open file");
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
if(!png_ptr) throw std::runtime_error("PNG structure could not be allocated");
info_ptr = png_create_info_struct(png_ptr);
if(!info_ptr) throw std::runtime_error("PNG information structure could not be allocated");
png_init_io(png_ptr, fp);
png_set_IHDR(png_ptr, info_ptr, width, height, pixel_formats::traits<pixel>::bits_per_color, color_type<pixel>(), PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_set_compression_level(png_ptr, 9);
png_write_info(png_ptr, info_ptr);
}
~ostream(){
// NOTE: the pnglib already checks for us whether all pixels are written
png_write_end(png_ptr, info_ptr);
png_destroy_info_struct(png_ptr, &info_ptr);
fclose(fp);
}
ostream& operator<<(pixel const & p){
row[x] = p;
++x;
if(x >= row.size()){
png_write_row(png_ptr, reinterpret_cast<unsigned char const*>(row.data()));
x = 0;
}
return *this;
}
private:
FILE* fp;
png_structp png_ptr;
png_infop info_ptr;
std::vector<pixel> row;
uint32_t x;
};
typedef ostream<> colored_ostream;
typedef ostream<pixel_formats::gray> gray_ostream;
struct istream{
//typedef pixel pixel;
istream(std::string filename)
: fp(0)
, png_ptr(0)
, info_ptr(0)
, valid(true)
, row()
, stride(0)
, x(0)
, y(0)
, height(0)
{
fp = fopen(filename.c_str(), "rb");
if(!fp) throw std::runtime_error(filename + " could not be opened");
png_byte header[8];
fread(header, 1, 8, fp);
if(png_sig_cmp(header, 0, 8) != 0) throw std::runtime_error("File is not a PNG file.");
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
if(!png_ptr) throw std::runtime_error("PNG structure could not be allocated");
info_ptr = png_create_info_struct(png_ptr);
if(!info_ptr) throw std::runtime_error("PNG information structure could not be allocated");
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
if(png_get_interlace_type(png_ptr, info_ptr) != PNG_INTERLACE_NONE)
throw std::runtime_error("Interalced PNG's are not supported");
height = png_get_image_height(png_ptr, info_ptr);
auto width = png_get_image_width(png_ptr, info_ptr);
auto bit_depth = png_get_bit_depth(png_ptr, info_ptr);
auto channels = png_get_channels(png_ptr, info_ptr);
// number of bytes in one row
stride = bit_depth * channels / 8;
size_t row_size = width * stride;
if(bit_depth < 8) throw std::runtime_error("Bitdepths lower than 8 are not supported (yet)");
row.resize(row_size);
png_read_row(png_ptr, (png_bytep)row.data(), 0);
}
~istream(){
png_read_end(png_ptr, 0);
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
fclose(fp);
}
template <typename Pixel>
istream& operator>>(Pixel & p){
if( y >= height){
valid = false;
return *this;
}
p = row[x];
if(++x >= get_width()){
x = 0;
++y;
if(y < height)
png_read_row(png_ptr, (png_bytep)row.data(), 0);
}
return *this;
}
operator bool() const {
return valid;
}
uint32_t get_width() const { return row.size(); }
uint32_t get_height() const { return height; }
private:
FILE* fp;
png_structp png_ptr;
png_infop info_ptr;
bool valid;
std::vector<char> row;
uint32_t stride;
uint32_t x;
uint32_t y;
uint32_t height;
};
}
#endif