Commit 6bed680f authored by Amir Mohammadi's avatar Amir Mohammadi
Browse files

initial attempt to replace netpbm with pnmio

parent 602d7adc
...@@ -20,23 +20,183 @@ ...@@ -20,23 +20,183 @@
#include <bob.io.base/File.h> #include <bob.io.base/File.h>
extern "C" { extern "C" {
// This header must come last, as it brings a lot of global stuff that messes up other headers... #include "pnmio.h"
#include <pam.h>
} }
typedef unsigned long sample;
struct pam {
/* This structure describes an open PAM image file. It consists
entirely of information that belongs in the header of a PAM image
and filesystem information. It does not contain any state
information about the processing of that image.
This is not considered to be an opaque object. The user of Netbpm
libraries is free to access and set any of these fields whenever
appropriate. The structure exists to make coding of function calls
easy.
*/
/* 'size' and 'len' are necessary in order to provide forward and
backward compatibility between library functions and calling programs
as this structure grows.
*/
unsigned int size;
/* The storage size of this entire structure, in bytes */
unsigned int len;
/* The length, in bytes, of the information in this structure.
The information starts in the first byte and is contiguous.
This cannot be greater than 'size'
*/
FILE *file;
int format;
/* The format code of the raw image. This is PAM_FORMAT
unless the PAM image is really a view of a PBM, PGM, or PPM
image. Then it's PBM_FORMAT, RPBM_FORMAT, etc.
*/
unsigned int plainformat;
/* Logical: the format above is a plain (text) format as opposed
to a raw (binary) format. This is entirely redundant with the
'format' member and exists as a separate member only for
computational speed.
*/
int height; /* Height of image in rows */
int width;
/* Width of image in number of columns (tuples per row) */
unsigned int depth;
/* Depth of image (number of samples in each tuple). */
sample maxval; /* Maximum defined value for a sample */
unsigned int bytes_per_sample;
/* Number of bytes used to represent each sample in the image file.
Note that this is strictly a function of 'maxval'. It is in a
a separate member for computational speed.
*/
char tuple_type[256];
/* The tuple type string from the image header. Netpbm does
not define any values for this except the following, which are
used for a PAM image which is really a view of a PBM, PGM,
or PPM image: PAM_PBM_TUPLETYPE, PAM_PGM_TUPLETYPE,
PAM_PPM_TUPLETYPE.
*/
};
// void overflow_add(int a, int b) {
// if( a > INT_MAX - b)
// boost::format m("(netpbm) object too large");
// throw std::runtime_error(m.str());
// }
// void overflow2(int a, int b) {
// if(a < 0 || b < 0)
// boost::format m("(netpbm) object too large");
// throw std::runtime_error(m.str());
// if(b == 0)
// return;
// if(a > INT_MAX / b)
// boost::format m("(netpbm) object too large");
// throw std::runtime_error(m.str());
// }
// void *malloc2(int a, int b) {
// overflow2(a, b);
// if(a*b == 0)
// boost::format m("(netpbm) Zero byte allocation");
// throw std::runtime_error(m.str());
// return malloc(a*b);
// }
static boost::shared_ptr<std::FILE> make_cfile(const char *filename, const char *flags) static boost::shared_ptr<std::FILE> make_cfile(const char *filename, const char *flags)
{ {
std::FILE* fp; std::FILE* fp;
if(strcmp(flags, "r") == 0) if(strcmp(flags, "r") == 0)
fp = pm_openr(filename); fp = fopen(filename, "r");
else // write else // write
fp = pm_openw(filename); fp = fopen(filename, "w");
if(fp == 0) { if(fp == 0) {
boost::format m("cannot open file `%s'"); boost::format m("cannot open file `%s'");
m % filename; m % filename;
throw std::runtime_error(m.str()); throw std::runtime_error(m.str());
} }
return boost::shared_ptr<std::FILE>(fp, pm_close); return boost::shared_ptr<std::FILE>(fp, fclose);
}
static void pnm_readpaminit(FILE *file, struct pam * const pamP, const int size) {
int pnm_type=0;
int x_dim=256, y_dim=256;
int enable_ascii=1, img_colors=1;
pamP->file = file;
pnm_type = get_pnm_type(pamP->file);
rewind(pamP->file);
// fprintf(stderr, "%d\n", pnm_type);
pamP->format = pnm_type;
/* Read the image file header (the input file has been rewinded). */
if ((pnm_type == PBM_ASCII) || (pnm_type == PBM_BINARY)) {
read_pbm_header(file, &x_dim, &y_dim, &enable_ascii);
pamP->bytes_per_sample = 1;
} else if ((pnm_type == PGM_ASCII) || (pnm_type == PGM_BINARY)) {
read_pgm_header(file, &x_dim, &y_dim, &img_colors, &enable_ascii);
if (img_colors >> 8 == 0) pamP->bytes_per_sample = 1;
else if (img_colors >> 16 == 0) pamP->bytes_per_sample = 2;
} else if ((pnm_type == PPM_ASCII) || (pnm_type == PPM_BINARY)) {
read_ppm_header(file, &x_dim, &y_dim, &img_colors, &enable_ascii);
if (img_colors >> 8 == 0) pamP->bytes_per_sample = 1;
else if (img_colors >> 16 == 0) pamP->bytes_per_sample = 2;
} else {
fprintf(stderr, "Error: Unknown PNM/PFM image format. Exiting...\n");
exit(1);
}
/* Perform operations. */
if ((pnm_type == PPM_ASCII) || (pnm_type == PPM_BINARY)) {
pamP->depth = 3;
} else {
pamP->depth = 1;
}
pamP->width = x_dim;
pamP->height = y_dim;
pamP->plainformat = enable_ascii;
pamP->maxval = img_colors;
}
static int * pnm_allocpam(struct pam * const pamP) {
int *img_data;
/* Perform operations. */
if ((pamP->format == PPM_ASCII) || (pamP->format == PPM_BINARY)) {
img_data = (int *) malloc((3 * pamP->width * pamP->height) * sizeof(int));
} else {
img_data = (int *) malloc((pamP->width * pamP->height) * sizeof(int));
}
return (img_data);
}
static void pnm_readpam(struct pam * const pamP, int *img_data) {
/* Read the image data. */
if ((pamP->format == PBM_ASCII) || (pamP->format == PBM_BINARY)) {
read_pbm_data(pamP->file, img_data, pamP->plainformat);
} else if ((pamP->format == PGM_ASCII) || (pamP->format == PGM_BINARY)) {
read_pgm_data(pamP->file, img_data, pamP->plainformat);
} else if ((pamP->format == PPM_ASCII) || (pamP->format == PPM_BINARY)) {
read_ppm_data(pamP->file, img_data, pamP->plainformat);
}
}
static void pnm_writepam(struct pam * const pamP, int *img_data) {
char * file_name="";
/* Write the output image file. */
if ((pamP->format == PBM_ASCII) || (pamP->format == PBM_BINARY)) {
write_pbm_file(pamP->file, img_data, file_name,
pamP->width, pamP->height, 1, 1, 32, pamP->plainformat
);
} else if ((pamP->format == PGM_ASCII) || (pamP->format == PGM_BINARY)) {
write_pgm_file(pamP->file, img_data, file_name,
pamP->width, pamP->height, 1, 1, pamP->maxval, 16, pamP->plainformat
);
} else if ((pamP->format == PPM_ASCII) || (pamP->format == PPM_BINARY)) {
write_ppm_file(pamP->file, img_data, file_name,
pamP->width, pamP->height, 1, 1, pamP->maxval, pamP->plainformat
);
}
} }
/** /**
...@@ -46,12 +206,7 @@ static void im_peek(const std::string& path, bob::io::base::array::typeinfo& inf ...@@ -46,12 +206,7 @@ static void im_peek(const std::string& path, bob::io::base::array::typeinfo& inf
struct pam in_pam; struct pam in_pam;
boost::shared_ptr<std::FILE> in_file = make_cfile(path.c_str(), "r"); boost::shared_ptr<std::FILE> in_file = make_cfile(path.c_str(), "r");
#ifdef PAM_STRUCT_SIZE
// For version >= 10.23
pnm_readpaminit(in_file.get(), &in_pam, PAM_STRUCT_SIZE(tuple_type));
#else
pnm_readpaminit(in_file.get(), &in_pam, sizeof(struct pam)); pnm_readpaminit(in_file.get(), &in_pam, sizeof(struct pam));
#endif
if( in_pam.depth != 1 && in_pam.depth != 3) if( in_pam.depth != 1 && in_pam.depth != 3)
{ {
...@@ -87,62 +242,56 @@ static void im_peek(const std::string& path, bob::io::base::array::typeinfo& inf ...@@ -87,62 +242,56 @@ static void im_peek(const std::string& path, bob::io::base::array::typeinfo& inf
template <typename T> static template <typename T> static
void im_load_gray(struct pam *in_pam, bob::io::base::array::interface& b) { void im_load_gray(struct pam *in_pam, bob::io::base::array::interface& b) {
const bob::io::base::array::typeinfo& info = b.type(); const bob::io::base::array::typeinfo& info = b.type();
int c=0;
T *element = static_cast<T*>(b.ptr()); T *element = static_cast<T*>(b.ptr());
tuple *tuplerow = pnm_allocpamrow(in_pam); int *img_data = pnm_allocpam(in_pam);
pnm_readpam(in_pam, img_data);
for(size_t y=0; y<info.shape[0]; ++y) for(size_t y=0; y<info.shape[0]; ++y)
{ {
pnm_readpamrow(in_pam, tuplerow);
for(size_t x=0; x<info.shape[1]; ++x) for(size_t x=0; x<info.shape[1]; ++x)
{ {
*element = tuplerow[x][0]; *element = img_data[c];
++element; ++element;
c++;
} }
} }
pnm_freepamrow(tuplerow); free(img_data);
}
template <typename T> static
void imbuffer_to_rgb(size_t size, const tuple* tuplerow, T* r, T* g, T* b) {
for (size_t k=0; k<size; ++k) {
r[k] = tuplerow[k][0];
g[k] = tuplerow[k][1];
b[k] = tuplerow[k][2];
}
} }
template <typename T> static template <typename T> static
void im_load_color(struct pam *in_pam, bob::io::base::array::interface& b) { void im_load_color(struct pam *in_pam, bob::io::base::array::interface& b) {
const bob::io::base::array::typeinfo& info = b.type(); const bob::io::base::array::typeinfo& info = b.type();
int c=0;
long unsigned int frame_size = info.shape[2] * info.shape[1]; long unsigned int frame_size = info.shape[2] * info.shape[1];
T *element_r = static_cast<T*>(b.ptr()); T *element_r = static_cast<T*>(b.ptr());
T *element_g = element_r+frame_size; T *element_g = element_r+frame_size;
T *element_b = element_g+frame_size; T *element_b = element_g+frame_size;
int row_color_stride = info.shape[2]; // row_stride for each component int *img_data = pnm_allocpam(in_pam);
tuple *tuplerow = pnm_allocpamrow(in_pam); pnm_readpam(in_pam, img_data);
for(size_t y=0; y<info.shape[1]; ++y) for(size_t y=0; y<info.shape[0]; ++y)
{ {
pnm_readpamrow(in_pam, tuplerow); for(size_t x=0; x<info.shape[1]; ++x)
imbuffer_to_rgb(row_color_stride, tuplerow, element_r, element_g, element_b); {
element_r += row_color_stride; element_r[x] = img_data[c+0];
element_g += row_color_stride; element_g[x] = img_data[c+1];
element_b += row_color_stride; element_b[x] = img_data[c+2];
++element_r;
++element_g;
++element_b;
c = c + 3;
}
} }
pnm_freepamrow(tuplerow); free(img_data);
} }
static void im_load (const std::string& filename, bob::io::base::array::interface& b) { static void im_load (const std::string& filename, bob::io::base::array::interface& b) {
struct pam in_pam; struct pam in_pam;
boost::shared_ptr<std::FILE> in_file = make_cfile(filename.c_str(), "r"); boost::shared_ptr<std::FILE> in_file = make_cfile(filename.c_str(), "r");
#ifdef PAM_STRUCT_SIZE
// For version >= 10.23
pnm_readpaminit(in_file.get(), &in_pam, PAM_STRUCT_SIZE(tuple_type));
#else
pnm_readpaminit(in_file.get(), &in_pam, sizeof(struct pam)); pnm_readpaminit(in_file.get(), &in_pam, sizeof(struct pam));
#endif
const bob::io::base::array::typeinfo& info = b.type(); const bob::io::base::array::typeinfo& info = b.type();
...@@ -179,48 +328,51 @@ static void im_load (const std::string& filename, bob::io::base::array::interfac ...@@ -179,48 +328,51 @@ static void im_load (const std::string& filename, bob::io::base::array::interfac
template <typename T> template <typename T>
static void im_save_gray(const bob::io::base::array::interface& b, struct pam *out_pam) { static void im_save_gray(const bob::io::base::array::interface& b, struct pam *out_pam) {
const bob::io::base::array::typeinfo& info = b.type(); const bob::io::base::array::typeinfo& info = b.type();
int c=0;
const T *element = static_cast<const T*>(b.ptr()); const T *element = static_cast<const T*>(b.ptr());
tuple *tuplerow = pnm_allocpamrow(out_pam); int *img_data = pnm_allocpam(out_pam);
for(size_t y=0; y<info.shape[0]; ++y) { for(size_t y=0; y<info.shape[0]; ++y)
for(size_t x=0; x<info.shape[1]; ++x) { {
tuplerow[x][0] = *element; for(size_t x=0; x<info.shape[1]; ++x)
{
img_data[c] = *element;
++element; ++element;
c++;
} }
pnm_writepamrow(out_pam, tuplerow);
} }
pnm_freepamrow(tuplerow); pnm_writepam(out_pam, img_data);
free(img_data);
} }
template <typename T> static
void rgb_to_imbuffer(size_t size, const T* r, const T* g, const T* b, tuple* tuplerow) {
for (size_t k=0; k<size; ++k) {
tuplerow[k][0] = r[k];
tuplerow[k][1] = g[k];
tuplerow[k][2] = b[k];
}
}
template <typename T> template <typename T>
static void im_save_color(const bob::io::base::array::interface& b, struct pam *out_pam) { static void im_save_color(const bob::io::base::array::interface& b, struct pam *out_pam) {
const bob::io::base::array::typeinfo& info = b.type(); const bob::io::base::array::typeinfo& info = b.type();
int c=0;
long unsigned int frame_size = info.shape[2] * info.shape[1]; long unsigned int frame_size = info.shape[2] * info.shape[1];
const T *element_r = static_cast<const T*>(b.ptr()); const T *element_r = static_cast<const T*>(b.ptr());
const T *element_g = element_r + frame_size; const T *element_g = element_r + frame_size;
const T *element_b = element_g + frame_size; const T *element_b = element_g + frame_size;
int row_color_stride = info.shape[2]; // row_stride for each component int *img_data = pnm_allocpam(out_pam);
tuple *tuplerow = pnm_allocpamrow(out_pam); for(size_t y=0; y<info.shape[0]; ++y)
for(size_t y=0; y<info.shape[1]; ++y) { {
rgb_to_imbuffer(row_color_stride, element_r, element_g, element_b, tuplerow); for(size_t x=0; x<info.shape[1]; ++x)
pnm_writepamrow(out_pam, tuplerow); {
element_r += row_color_stride; img_data[c+0] = element_r[x];
element_g += row_color_stride; img_data[c+1] = element_g[x];
element_b += row_color_stride; img_data[c+2] = element_b[x];
++element_r;
++element_g;
++element_b;
c = c + 3;
}
} }
pnm_freepamrow(tuplerow); pnm_writepam(out_pam, img_data);
free(img_data);
} }
static void im_save (const std::string& filename, const bob::io::base::array::interface& array) { static void im_save (const std::string& filename, const bob::io::base::array::interface& array) {
...@@ -235,12 +387,7 @@ static void im_save (const std::string& filename, const bob::io::base::array::in ...@@ -235,12 +387,7 @@ static void im_save (const std::string& filename, const bob::io::base::array::in
// Sets the parameters of the pam structure according to the bca::interface properties // Sets the parameters of the pam structure according to the bca::interface properties
out_pam.size = sizeof(out_pam); out_pam.size = sizeof(out_pam);
#ifdef PAM_STRUCT_SIZE
// For version >= 10.23
out_pam.len = PAM_STRUCT_SIZE(tuple_type);
#else
out_pam.len = out_pam.size; out_pam.len = out_pam.size;
#endif
out_pam.file = out_file.get(); out_pam.file = out_file.get();
out_pam.plainformat = 0; // writes in binary out_pam.plainformat = 0; // writes in binary
out_pam.height = (info.nd == 2 ? info.shape[0] : info.shape[1]); out_pam.height = (info.nd == 2 ? info.shape[0] : info.shape[1]);
...@@ -248,22 +395,18 @@ static void im_save (const std::string& filename, const bob::io::base::array::in ...@@ -248,22 +395,18 @@ static void im_save (const std::string& filename, const bob::io::base::array::in
out_pam.depth = (info.nd == 2 ? 1 : 3); out_pam.depth = (info.nd == 2 ? 1 : 3);
out_pam.maxval = (bob::io::base::array::t_uint8 ? 255 : 65535); out_pam.maxval = (bob::io::base::array::t_uint8 ? 255 : 65535);
out_pam.bytes_per_sample = (info.dtype == bob::io::base::array::t_uint8 ? 1 : 2); out_pam.bytes_per_sample = (info.dtype == bob::io::base::array::t_uint8 ? 1 : 2);
out_pam.format = PAM_FORMAT;
if( ext.compare(".pbm") == 0) if( ext.compare(".pbm") == 0)
{ {
out_pam.maxval = 1; out_pam.maxval = 1;
out_pam.format = PBM_FORMAT; out_pam.format = PBM_BINARY;
strcpy(out_pam.tuple_type, PAM_PBM_TUPLETYPE);
} }
else if( ext.compare(".pgm") == 0) else if( ext.compare(".pgm") == 0)
{ {
out_pam.format = PGM_FORMAT; out_pam.format = PGM_BINARY;
strcpy(out_pam.tuple_type, PAM_PGM_TUPLETYPE);
} }
else else
{ {
out_pam.format = PPM_FORMAT; out_pam.format = PPM_BINARY;
strcpy(out_pam.tuple_type, PAM_PPM_TUPLETYPE);
} }
if(out_pam.depth == 3 && ext.compare(".ppm")) { if(out_pam.depth == 3 && ext.compare(".ppm")) {
...@@ -271,7 +414,7 @@ static void im_save (const std::string& filename, const bob::io::base::array::in ...@@ -271,7 +414,7 @@ static void im_save (const std::string& filename, const bob::io::base::array::in
} }
// Writes header in file // Writes header in file
pnm_writepaminit(&out_pam); // pnm_writepaminit(&out_pam);
// Writes content // Writes content
if(info.dtype == bob::io::base::array::t_uint8) { if(info.dtype == bob::io::base::array::t_uint8) {
...@@ -415,12 +558,12 @@ class ImageNetpbmFile: public bob::io::base::File { ...@@ -415,12 +558,12 @@ class ImageNetpbmFile: public bob::io::base::File {
std::string ImageNetpbmFile::s_codecname = "bob.image_netpbm"; std::string ImageNetpbmFile::s_codecname = "bob.image_netpbm";
static bool netpbm_initialized = false; // static bool netpbm_initialized = false;
boost::shared_ptr<bob::io::base::File> make_netpbm_file (const char* path, char mode) { boost::shared_ptr<bob::io::base::File> make_netpbm_file (const char* path, char mode) {
if (!netpbm_initialized) { // if (!netpbm_initialized) {
pm_init("bob",0); // pm_init("bob",0);
netpbm_initialized = true; // netpbm_initialized = true;
} // }
return boost::make_shared<ImageNetpbmFile>(path, mode); return boost::make_shared<ImageNetpbmFile>(path, mode);
} }
This diff is collapsed.
/*
* File : pnmio.h
* Description: Header file for pnmio.c.
* Author : Nikolaos Kavvadias <nikolaos.kavvadias@gmail.com>
* Copyright : (C) Nikolaos Kavvadias 2012, 2013, 2014, 2015, 2016
* Website : http://www.nkavvadias.com
*
* This file is part of libpnmio, and is distributed under the terms of the
* Modified BSD License.
*
* A copy of the Modified BSD License is included with this distribution
* in the file LICENSE.
* libpnmio is free software: you can redistribute it and/or modify it under the
* terms of the Modified BSD License.
* libpnmio is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the Modified BSD License for more details.
*
* You should have received a copy of the Modified BSD License along with
* libpnmio. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PNMIO_H
#define PNMIO_H
#include <stdio.h>
/* PNM/PFM image data file format definitions. */
#define PBM_ASCII 1
#define PGM_ASCII 2
#define PPM_ASCII 3
#define PBM_BINARY 4
#define PGM_BINARY 5
#define PPM_BINARY 6
#define PAM 7 /* reserved */
/* 8-15: reserved */
#define PFM_RGB 16 /* F */
#define PFM_GREYSCALE 17 /* f */
#define IS_BIGENDIAN(x) ((*(char*)&x) == 0)
#define IS_LITTLE_ENDIAN (1 == *(unsigned char *)&(const int){1})
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
/* PNM/PFM API. */
int get_pnm_type(FILE *f);
void read_pbm_header(FILE *f, int *img_xdim, int *img_ydim, int *is_ascii);
void read_pgm_header(FILE *f, int *img_xdim, int *img_ydim, int *img_colors,
int *is_ascii);
void read_ppm_header(FILE *f, int *img_xdim, int *img_ydim, int *img_colors,
int *is_ascii);
void read_pfm_header(FILE *f, int *img_xdim, int *img_ydim, int *img_type,
int *endianess);
void read_pbm_data(FILE *f, int *img_in, int is_ascii);
void read_pgm_data(FILE *f, int *img_in, int is_ascii);
void read_ppm_data(FILE *f, int *img_in, int is_ascii);
void read_pfm_data(FILE *f, float *img_in, int img_type, int endianess);
void write_pbm_file(FILE *f, int *img_out, char *img_out_fname,
int x_size, int y_size, int x_scale_val, int y_scale_val, int linevals,
int is_ascii);
void write_pgm_file(FILE *f, int *img_out, char *img_out_fname,
int x_size, int y_size, int x_scale_val, int y_scale_val,
int img_colors, int linevals, int is_ascii);
void write_ppm_file(FILE *f, int *img_out, char *img_out_fname,
int x_size, int y_size, int x_scale_val, int y_scale_val,
int img_colors, int is_ascii);
void write_pfm_file(FILE *f, float *img_out, char *img_out_fname,
int x_size, int y_size, int img_type, int endianess);
/* Helper/auxiliary functions. */
int ReadFloat(FILE *fptr, float *f, int swap);
int WriteFloat(FILE *fptr, float *f, int swap);
int floatEqualComparison(float A, float B, float maxRelDiff);
float frand(void);
int log2ceil(int inpval);
#endif /* PNMIO_H */
...@@ -456,6 +456,7 @@ setup( ...@@ -456,6 +456,7 @@ setup(
"bob/io/image/png.cpp", "bob/io/image/png.cpp",
"bob/io/image/jpeg.cpp", "bob/io/image/jpeg.cpp",
"bob/io/image/bmp.cpp", "bob/io/image/bmp.cpp",
"bob/io/image/pnmio.c",
"bob/io/image/netpbm.cpp",