mirror of
https://github.com/aicodix/dsp.git
synced 2026-04-27 14:30:36 +00:00
added reader and writer for Netpbm P5 and P6 files
This commit is contained in:
parent
3242f2dee8
commit
87eb83eef0
3 changed files with 222 additions and 0 deletions
|
|
@ -146,6 +146,14 @@ Interface for reading and writing [PCM](https://en.wikipedia.org/wiki/Pulse-code
|
|||
|
||||
Read and write [WAV](https://en.wikipedia.org/wiki/WAV) files
|
||||
|
||||
### [pel.hh](pel.hh)
|
||||
|
||||
Interface for reading and writing [pixel](https://en.wikipedia.org/wiki/Pixel) data
|
||||
|
||||
### [netpbm.hh](netpbm.hh)
|
||||
|
||||
Read and write [Netpbm](https://en.wikipedia.org/wiki/Netpbm) files
|
||||
|
||||
### [spline.hh](spline.hh)
|
||||
|
||||
* Algorithm for computing uniform and [natural cubic splines](https://en.wikipedia.org/wiki/Spline_(mathematics)#Algorithm_for_computing_natural_cubic_splines)
|
||||
|
|
|
|||
180
netpbm.hh
Normal file
180
netpbm.hh
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
Read and write Netpbm files
|
||||
|
||||
Copyright 2020 Ahmet Inan <inan@aicodix.de>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include "pel.hh"
|
||||
|
||||
namespace DSP {
|
||||
|
||||
template <typename TYPE>
|
||||
class ReadPNM : public ReadPEL<TYPE>
|
||||
{
|
||||
std::ifstream is;
|
||||
int width_, height_, maxval_;
|
||||
bool mono_;
|
||||
|
||||
TYPE linear(int val)
|
||||
{
|
||||
int K0 = std::nearbyint(0.03928 * maxval_);
|
||||
TYPE phi(12.92 * maxval_), a(0.055 * maxval_), gamma(2.4);
|
||||
return val <= K0 ? val / phi : std::pow((val + a) / (maxval_ + a), gamma);
|
||||
}
|
||||
static bool space(int c)
|
||||
{
|
||||
return c == ' ' || c == '\n' || c == '\t';
|
||||
}
|
||||
static bool newline(int c)
|
||||
{
|
||||
return c == '\n';
|
||||
}
|
||||
static bool digit(int c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
static int value(int c)
|
||||
{
|
||||
return c - '0';
|
||||
}
|
||||
public:
|
||||
ReadPNM(const char *name) : is(name, std::ios::binary)
|
||||
{
|
||||
if (is.get() != 'P')
|
||||
return;
|
||||
int c = is.get();
|
||||
if (!digit(c))
|
||||
return;
|
||||
int number = value(c);
|
||||
if (number == 5)
|
||||
mono_ = true;
|
||||
else if (number == 6)
|
||||
mono_ = false;
|
||||
else
|
||||
return;
|
||||
c = is.get();
|
||||
if (!space(c))
|
||||
return;
|
||||
int num[3];
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (newline(c))
|
||||
for (c = is.get(); c == '#'; c = is.get())
|
||||
while (is.good() && !newline(is.get()));
|
||||
while (space(c))
|
||||
c = is.get();
|
||||
for (num[i] = 0; digit(c); c = is.get())
|
||||
num[i] = 10 * num[i] + value(c);
|
||||
}
|
||||
if (!space(c))
|
||||
return;
|
||||
width_ = num[0];
|
||||
height_ = num[1];
|
||||
maxval_ = num[2];
|
||||
}
|
||||
void read(TYPE *buf, int num, int stride = -1)
|
||||
{
|
||||
if (mono_) {
|
||||
if (stride < 0)
|
||||
stride = 1;
|
||||
for (int i = 0; i < num; ++i) {
|
||||
int G = is.get();
|
||||
buf[stride*i] = linear(G);
|
||||
}
|
||||
} else {
|
||||
if (stride < 0)
|
||||
stride = 3;
|
||||
for (int i = 0; i < num; ++i) {
|
||||
int R = is.get();
|
||||
int G = is.get();
|
||||
int B = is.get();
|
||||
buf[stride*i+0] = linear(R);
|
||||
buf[stride*i+1] = linear(G);
|
||||
buf[stride*i+2] = linear(B);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool good()
|
||||
{
|
||||
return is.good();
|
||||
}
|
||||
bool mono()
|
||||
{
|
||||
return mono_;
|
||||
}
|
||||
int width()
|
||||
{
|
||||
return width_;
|
||||
}
|
||||
int height()
|
||||
{
|
||||
return height_;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TYPE>
|
||||
class WritePNM : public WritePEL<TYPE>
|
||||
{
|
||||
std::ofstream os;
|
||||
int width_, height_, maxval_;
|
||||
bool mono_;
|
||||
|
||||
int srgb(TYPE val)
|
||||
{
|
||||
TYPE K0(0.03928), a(0.055), phi(12.92), gamma(2.4);
|
||||
val = std::min(std::max(val, TYPE(0)), TYPE(1));
|
||||
val = val <= K0 / phi ? val * phi : (1 + a) * std::pow(val, 1 / gamma) - a;
|
||||
return std::nearbyint(maxval_ * val);
|
||||
}
|
||||
public:
|
||||
WritePNM(const char *name, int width, int height, bool mono = false, int maxval = 255) :
|
||||
os(name, std::ios::binary | std::ios::trunc),
|
||||
width_(width), height_(height), maxval_(maxval), mono_(mono)
|
||||
{
|
||||
int number = mono ? 5 : 6;
|
||||
os << 'P' << number << ' ' << width << ' ' << height << ' ' << maxval << '\n';
|
||||
}
|
||||
void write(const TYPE *buf, int num, int stride = -1)
|
||||
{
|
||||
if (mono_) {
|
||||
if (stride < 0)
|
||||
stride = 1;
|
||||
for (int i = 0; i < num; ++i) {
|
||||
int G = srgb(buf[stride*i]);
|
||||
os.put(G);
|
||||
}
|
||||
} else {
|
||||
if (stride < 0)
|
||||
stride = 3;
|
||||
for (int i = 0; i < num; ++i) {
|
||||
int R = srgb(buf[stride*i+0]);
|
||||
int G = srgb(buf[stride*i+1]);
|
||||
int B = srgb(buf[stride*i+2]);
|
||||
os.put(R);
|
||||
os.put(G);
|
||||
os.put(B);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool good()
|
||||
{
|
||||
return os.good();
|
||||
}
|
||||
bool mono()
|
||||
{
|
||||
return mono_;
|
||||
}
|
||||
int width()
|
||||
{
|
||||
return width_;
|
||||
}
|
||||
int height()
|
||||
{
|
||||
return height_;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
34
pel.hh
Normal file
34
pel.hh
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
Interface for reading and writing pixel data
|
||||
|
||||
Copyright 2020 Ahmet Inan <inan@aicodix.de>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace DSP {
|
||||
|
||||
template <typename TYPE>
|
||||
struct WritePEL
|
||||
{
|
||||
virtual void write(const TYPE *, int, int = -1) = 0;
|
||||
virtual bool good() = 0;
|
||||
virtual bool mono() = 0;
|
||||
virtual int width() = 0;
|
||||
virtual int height() = 0;
|
||||
virtual ~WritePEL() = default;
|
||||
};
|
||||
|
||||
template <typename TYPE>
|
||||
struct ReadPEL
|
||||
{
|
||||
virtual void read(TYPE *, int, int = -1) = 0;
|
||||
virtual bool good() = 0;
|
||||
virtual bool mono() = 0;
|
||||
virtual int width() = 0;
|
||||
virtual int height() = 0;
|
||||
virtual ~ReadPEL() = default;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue