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
|
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)
|
### [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)
|
* 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