Adds png support
This commit is contained in:
parent
0853249e2d
commit
f206ad4c77
2 changed files with 306 additions and 0 deletions
115
include/basics.hpp
Normal file
115
include/basics.hpp
Normal file
|
@ -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
Normal file
191
include/png.hpp
Normal file
|
@ -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
|
Reference in a new issue