Loading...
Searching...
No Matches
pfm.h
Go to the documentation of this file.
1#ifndef _BBM_PFM_H_
2#define _BBM_PFM_H_
3
4#include <array>
5#include <string>
6#include <cstddef>
7#include <fstream>
8#include <stdexcept>
9
10#include "core/Endian.h"
11#include "core/bitmap.h"
12#include "util/iterator_util.h"
13
14/************************************************************************/
15/*! \file pfm.h
16 \brief Read/write a bitmap to/from PFM
17*************************************************************************/
18
19namespace bbm {
20 namespace io {
21
22 /********************************************************************/
23 /*! \brief Export a bitmap to a PFM
24
25 \param filename = PFM filename to write to.
26 \param data = bitmap to export
27 \param channels = which channels to export to the PFM file (default {0,1,2})
28 use -1 to ignore (write 0)
29
30 Write a bitmap to a 3-channel little endian PFM file. Allows the
31 selection of channels to write out in case the bitmap contains more (or
32 less) than 3 channels.
33 *********************************************************************/
34 template<typename T>
35 void exportPFM(const std::string& filename, const bitmap<T>& data, const std::array<ptrdiff_t,3>& channels = {0,1,2})
36 {
37 // check for empty data
38 if(data.width() == 0 || data.height() == 0) throw std::runtime_error("io::exportPFM: No data in bitmap");
39
40 // open
41 std::ofstream ofs(filename.c_str(), std::ios::binary);
42
43 // write header: (3 channel, little endian only)
44 char header[3] = {'P', 'F', '\n'};
45 ofs.write(static_cast<char *>(header), 3);
46
47 // write image size
48 const unsigned int num_channels = 3;
49 ofs << data.width() << " " << data.height() << '\n';
50
51 // write endianess (little)
52 ofs << "-1.000000" << '\n';
53
54 // convert data to output format
55 size_t size = data.width()*data.height()*num_channels;
56 auto buffer = std::make_unique<float[]>(size);
57
58 auto buffer_ref = buffer.get();
59 for(size_t y=data.height()-1; /*y >= 0 &&*/ y < data.height(); y--)
60 for(size_t x=0; x < data.width(); x++, buffer_ref += 3)
61 {
62 auto data_ref = bbm::begin(data(x,y));
63 auto data_size = bbm::size(data(x,y));
64
65 for(size_t c = 0; c < num_channels; c++)
66 buffer_ref[c] = (channels[c] >= 0 && size_t(channels[c]) < data_size) ? bbm::cast<float>(data_ref[channels[c]]) : 0.0f;
67 }
68
69 // ensure the data is stored as little endian
70 endian::little(buffer.get(), buffer.get() + size);
71
72 // write buffer
73 ofs.write(reinterpret_cast<char*>(buffer.get()), size*sizeof(float));
74
75 // Done.
76 }
77
78
79 /********************************************************************/
80 /*! \brief Import a bitmap from a PFM
81
82 \param filename = PFM filename to read from
83 \param data = bitmap store the data in
84 \param channels = which channels in data to fill (default {0,1,2};
85 use -1 to ignore a channel from the PFM)
86
87 Read a bitmap from a PFM file (1 and 3 channels as well as little and
88 big endian PFMs are supported). Allows the selection of channels to
89 write out in in the bitmap.
90 *********************************************************************/
91 template<typename T, size_t N=3>
92 void importPFM(const std::string& filename, bitmap<T>& data, const std::array<ptrdiff_t,N>& channels = {0,1,2})
93 {
94 // open
95 std::ifstream ifs(filename.c_str(), std::ios::binary);
96
97 // scan header
98 char header[3];
99 ifs.read(static_cast<char *>(header), 3);
100 if(header[0] != 'P') throw std::runtime_error("io::importPFM: Not a recognized PFM format");
101 char type = header[1];
102
103 // skip comments
104 if(ifs.peek() == '#') ifs.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
105
106 // get width, and height
107 size_t width, height;
108 ifs >> width >> height;
109
110 // skip comments (again)
111 if(ifs.peek() == '#') ifs.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
112
113 // get endianess
114 float endianess;
115 ifs >> endianess;
116
117 bool bigEndian = (endianess > 0);
118
119 // Did we read too much?
120 ifs.unget();
121 while(ifs.get() != '0') ifs.unget();
122 ifs.get();
123
124 // determine number of channels in file
125 size_t num_channels = (type == 'f') ? 1 : 3;
126
127 // grab data from file
128 size_t size = width*height*num_channels;
129 auto buffer = std::make_unique<float[]>(size);
130 ifs.read(reinterpret_cast<char*>(buffer.get()), size*sizeof(float));
131
132 // convert PFM endian representation to machine endian representation
133 if(bigEndian) endian::big(buffer.get(), buffer.get() + size);
134 else endian::little(buffer.get(), buffer.get() + size);
135
136 // if same size; keep original bitmap and fill in
137 // if different size, reshape bitmap
138 if(data.width() != width || data.height() != height)
139 data.reshape(width, height);
140
141 // copy data into bitmap guided by channels
142 auto buffer_ref = buffer.get();
143 for(size_t y=height-1; /*y >= 0 &&*/ y < height; y--)
144 for(size_t x=0; x < width; x++, buffer_ref += num_channels)
145 {
146 auto data_ref = bbm::begin(data(x,y));
147 auto data_size = bbm::size(data(x,y));
148
149 for(size_t c = 0; c < std::min(N, num_channels); c++)
150 if(channels[c] >= 0 && channels[c] < data_size)
151 data_ref[channels[c]] = buffer_ref[c];
152 }
153
154 // Done.
155 }
156
157 } // end io namespace
158} // end bbm namespace
159
160#endif /* _BBM_PFM_H_ */
Detect Endianess of processor and conversion methods.
Minimal bitmap class.
Definition: bitmap.h:16
size_t width() const
Definition: bitmap.h:86
size_t height() const
Definition: bitmap.h:87
void reshape(size_t width, size_t height)
reshape the bitmap (loss of old data)
Definition: bitmap.h:67
Extensions for STL iterators/ranges.
T big(const T &value)
Definition: Endian.h:80
T little(const T &value)
Definition: Endian.h:62
void exportPFM(const std::string &filename, const bitmap< T > &data, const std::array< ptrdiff_t, 3 > &channels={0, 1, 2})
Export a bitmap to a PFM.
Definition: pfm.h:35
void importPFM(const std::string &filename, bitmap< T > &data, const std::array< ptrdiff_t, N > &channels={0, 1, 2})
Import a bitmap from a PFM.
Definition: pfm.h:92
Definition: aggregatebsdf.h:29
size_t size(T &&t)
Definition: iterator_util.h:22
auto begin(T &&t)
Definition: iterator_util.h:29