24#ifndef DUMUX_RASTER_IMAGE_READER_HH
25#define DUMUX_RASTER_IMAGE_READER_HH
37#include <dune/common/exceptions.hh>
76 class Result :
private std::vector<T>
78 using Parent = std::vector<T>;
94 : Parent(std::move(data))
95 , header_(std::move(
header))
102 using Parent::operator[];
118 static const auto format = []{
119 std::map<std::string, Format> format;
120 format[
"P1"] =
Format{
"P1",
"Portable BitMap",
"ASCII"};
121 format[
"P2"] =
Format{
"P2",
"Portable GrayMap",
"ASCII"};
122 format[
"P3"] =
Format{
"P3",
"Portable PixMap",
"ASCII"};
123 format[
"P4"] =
Format{
"P4",
"Portable BitMap",
"binary"};
124 format[
"P5"] =
Format{
"P5",
"Portable GrayMap",
"binary"};
125 format[
"P6"] =
Format{
"P6",
"Portable PixMap",
"binary"};
129 const std::string& magicNumber = std::string(firstLineTokes[0]);
131 if (!format.count(magicNumber))
132 DUNE_THROW(Dune::IOError, magicNumber <<
" is not a valid magic number for the Netpbm format");
134 return format.at(magicNumber);
147 std::ifstream infile(fileName, std::ios::binary);
150 DUNE_THROW(Dune::IOError,
"Raster data file not found or corrupt");
153 std::vector<bool> values;
156 values = readPBMDataASCII_(infile, headerData);
158 values = readPBMDataBinary_(infile, headerData);
160 DUNE_THROW(Dune::IOError, headerData.
format.
magicNumber <<
" not supported. Use readPBM for P1 and P4 or readPGM for P2 and P5");
162 Result<bool> result(std::move(values), std::move(headerData));
165 if (useDuneGridOrdering)
183 template<
class ValueType = std::u
int8_t>
186 std::ifstream infile(fileName, std::ios::binary);
189 DUNE_THROW(Dune::IOError,
"Raster data file not found or corrupt");
192 std::vector<ValueType> values;
195 values = NetPBMReader::template readPGMDataASCII_<ValueType>(infile, headerData);
197 values = NetPBMReader::template readPGMDataBinary_<ValueType>(infile, headerData);
199 DUNE_THROW(Dune::IOError, headerData.
format.
magicNumber <<
" not supported. Use readPBM for P1 and P4 or readPGM for P2 and P5");
204 if (useDuneGridOrdering)
218 std::string inputLine;
219 std::size_t lineNumber = 0;
222 std::getline(infile, inputLine);
225 const auto firstLineTokens =
tokenize(inputLine,
" ");
230 if (firstLineTokens.size() > 2)
232 if (isBlackAndWhite_(magicNumber) && firstLineTokens.size() != 3)
233 DUNE_THROW(Dune::IOError,
"Could not read first line for B/W image");
235 headerData.
nCols = std::stoi(std::string(firstLineTokens[1]));
236 headerData.
nRows = std::stoi(std::string(firstLineTokens[2]));
238 if (isGrayScale_(magicNumber))
240 if (firstLineTokens.size() == 4)
241 headerData.
maxValue = std::stoi(std::string(firstLineTokens[3]));
242 if (firstLineTokens.size() > 4)
243 DUNE_THROW(Dune::IOError,
"Could not read first line for grayscale image");
249 while (!infile.eof())
251 std::getline(infile, inputLine);
255 if (isComment_(inputLine))
258 const auto tokens =
tokenize(inputLine,
" ");
261 if (tokens.size() != 2)
262 DUNE_THROW(Dune::IOError,
"Expecting " << [](
auto size){
return size < 2 ?
"both" :
"only"; }(tokens.size()) <<
" dimensions (2 numbers) in line " << lineNumber);
264 headerData.
nCols = std::stoi(std::string(tokens[0]));
265 headerData.
nRows = std::stoi(std::string(tokens[1]));
268 if (isGrayScale_(magicNumber))
270 std::getline(infile, inputLine);
273 const auto token =
tokenize(inputLine,
" ");
274 if (token.size() != 1)
275 DUNE_THROW(Dune::IOError,
"Expecting" << [](
auto size){
return size == 0 ?
"" :
" only"; }(token.size()) <<
" intensity (one number) in line " << lineNumber);
277 headerData.
maxValue = std::stoi(std::string(token[0]));
296 for (std::size_t i = 0; i < result.size(); i += result.
header().nCols)
297 std::swap_ranges((result.begin() + i), (result.begin() + i + result.
header().
nCols), (tmp.end() - i - result.
header().
nCols));
309 std::cout <<
"Reading " << format.
type <<
" file (" << format.
encoding <<
")" << std::endl;
311 std::cout <<
"Maximum value : " << result.
header().
maxValue << std::endl;
321 template<
class Image,
class T>
326 using RowType = std::decay_t<
decltype(image[0])>;
327 image.resize(nRows, RowType(nCols));
329 std::size_t rowIdx = 0;
330 std::size_t colIdx = 0;
331 for (
const auto val : result)
333 image[rowIdx][colIdx] = val;
336 if (++colIdx == nCols)
349 template<
class Image>
352 using OutputValueType = std::decay_t<
decltype(image[0][0])>;
354 std::vector<OutputValueType> data;
355 data.reserve(image.size()*image[0].size());
356 for (
const auto& row: image)
357 for (
const auto col : row)
365 static bool isBlackAndWhite_(
const std::string& magicNumber)
367 return magicNumber ==
"P1" || magicNumber ==
"P4";
370 static bool isGrayScale_(
const std::string& magicNumber)
372 return magicNumber ==
"P2" || magicNumber ==
"P5";
383 static std::vector<bool> readPBMDataASCII_(std::ifstream& infile,
384 const HeaderData& headerData)
386 std::string inputLine;
387 std::vector<bool> data;
388 data.reserve(numPixel_(headerData));
390 while (!infile.eof())
392 std::getline(infile, inputLine);
393 if (!isComment_(inputLine))
395 inputLine.erase(std::remove_if(inputLine.begin(), inputLine.end(), [](
unsigned char c){ return std::isspace(c); }), inputLine.end());
396 if (!inputLine.empty())
398 for (
const auto& value : inputLine)
400 assert(value ==
'0' || value ==
'1');
401 data.push_back(value -
'0');
418 static std::vector<bool> readPBMDataBinary_(std::ifstream& infile,
419 const HeaderData& headerData)
421 std::vector<bool> data(numPixel_(headerData));
429 std::string inputLine;
430 while (!infile.eof())
433 const auto lastPos = infile.tellg();
434 std::getline(infile, inputLine);
437 if (!isComment_(inputLine))
439 infile.seekg(lastPos);
445 std::size_t nBytes = 0;
446 std::size_t bitIndex = 0;
447 using Bit = std::uint8_t;
449 for (std::size_t j = 0; j < headerData.nRows; j++)
451 for (std::size_t i = 0; i < headerData.nCols; i++)
456 infile.read(&tmp, 1);
457 b =
static_cast<Bit
>(tmp);
459 DUNE_THROW(Dune::IOError,
"Failed reading byte " << nBytes);
464 const Bit k = 7 - (i % 8);
465 data[bitIndex++] =
static_cast<bool>((b >> k) & 1);
484 template<
class ValueType = std::u
int8_t>
485 static std::vector<ValueType> readPGMDataASCII_(std::ifstream& infile,
486 const HeaderData& headerData)
488 std::string inputLine;
490 std::vector<ValueType> data;
491 data.reserve(numPixel_(headerData));
493 while (!infile.eof())
495 std::getline(infile, inputLine);
496 if (inputLine.empty())
500 if (inputLine.find(
" ") != std::string::npos)
502 std::istringstream iss(inputLine);
503 std::vector<std::string> tokens;
504 std::copy(std::istream_iterator<std::string>(iss),
505 std::istream_iterator<std::string>(),
506 std::back_inserter(tokens));
508 for (
const auto& t : tokens)
509 data.push_back(std::stoi(t));
512 data.push_back(std::stoi(inputLine));
530 template<
class ValueType = std::u
int8_t>
531 static std::vector<ValueType> readPGMDataBinary_(std::ifstream& infile,
532 const HeaderData& headerData)
534 std::string inputLine;
537 const auto curPos = infile.tellg();
538 infile.seekg(0, std::ios::end);
539 const auto endPos = infile.tellg();
540 const auto size = endPos - curPos;
541 if (size != numPixel_(headerData))
542 DUNE_THROW(Dune::IOError,
"Binary file size does not match with raster image size");
545 infile.seekg(curPos, std::ios::beg);
548 std::vector<std::uint8_t> data(size);
549 infile.read(
reinterpret_cast<char*
>(&data[0]), size);
552 return std::vector<ValueType>(data.begin(), data.end());
560 static std::size_t numPixel_(
const HeaderData& headerData)
562 return headerData.nRows*headerData.nCols;
568 static bool isComment_(
const std::string_view
line)
570 return line[0] ==
'#';
Helpers for working with strings.
std::vector< std::string_view > tokenize(std::string_view str, std::string_view delim)
Definition: stringutilities.hh:50
constexpr Line line
Definition: couplingmanager1d3d_line.hh:43
A simple reader class for the Netpbm format (https://en.wikipedia.org/wiki/Netpbm_format)....
Definition: rasterimagereader.hh:48
static HeaderData readHeader(std::ifstream &infile)
Returns the header data of the image file.
Definition: rasterimagereader.hh:215
static void fillImage(Image &image, const Result< T > &result)
Fill a pre-defined 2D image object, e.g. std::vector<std::vector<bool>>, with the pixel values stored...
Definition: rasterimagereader.hh:322
static Format getFormat(const std::vector< std::string_view > &firstLineTokes)
A helper function to retrieve the format from tokens of the file's first line.
Definition: rasterimagereader.hh:116
static Result< bool > readPBM(const std::string &fileName, const bool useDuneGridOrdering=true)
Reads a *pbm (black and white) in ASCII or binary encoding. Returns a struct that contains both the p...
Definition: rasterimagereader.hh:145
static auto flattenImageToVector(const Image &image)
Flattens a 2D image object to a 1D container.
Definition: rasterimagereader.hh:350
static void applyDuneGridOrdering(Result< T > &result)
Change the ordering of the pixels according to Dune's convention, shifting the origin from upper left...
Definition: rasterimagereader.hh:293
static Result< ValueType > readPGM(const std::string &fileName, const bool useDuneGridOrdering=true)
Reads a *.pgm (grayscale) in ASCII or binary encoding. Returns a struct that contains both the pixel ...
Definition: rasterimagereader.hh:184
static void printInfo(const Result< T > &result)
Print the data contained in the header.
Definition: rasterimagereader.hh:306
A struct that holds all information of the image format.
Definition: rasterimagereader.hh:54
std::string encoding
Definition: rasterimagereader.hh:57
std::string magicNumber
Definition: rasterimagereader.hh:55
std::string type
Definition: rasterimagereader.hh:56
A struct that contains all header data of the image.
Definition: rasterimagereader.hh:64
Format format
Definition: rasterimagereader.hh:65
std::size_t maxValue
Definition: rasterimagereader.hh:68
std::size_t nCols
Definition: rasterimagereader.hh:66
std::size_t nRows
Definition: rasterimagereader.hh:67
The return type of the reading functions. Holds the actual pixel values and the header data.
Definition: rasterimagereader.hh:77
const HeaderData & header() const
Returns the header data.
Definition: rasterimagereader.hh:99
Result(const std::vector< T > &data, const HeaderData &header)
Contruct from data and header by copy.
Definition: rasterimagereader.hh:85
Result(std::vector< T > &&data, HeaderData &&header)
Contruct from data and header by move.
Definition: rasterimagereader.hh:93