12#ifndef DUMUX_RASTER_IMAGE_READER_HH 
   13#define DUMUX_RASTER_IMAGE_READER_HH 
   26#include <dune/common/exceptions.hh> 
   52    static Format 
getFormat(
const std::vector<std::string_view>& firstLineTokes)
 
   54        static const auto format = []{
 
   55            std::map<std::string, Format> format;
 
   56            format[
"P1"] = Format{
"P1", 
"Portable BitMap", 
"ASCII"};
 
   57            format[
"P2"] = Format{
"P2", 
"Portable GrayMap", 
"ASCII"};
 
   58            format[
"P3"] = Format{
"P3", 
"Portable PixMap", 
"ASCII"};
 
   59            format[
"P4"] = Format{
"P4", 
"Portable BitMap", 
"binary"};
 
   60            format[
"P5"] = Format{
"P5", 
"Portable GrayMap", 
"binary"};
 
   61            format[
"P6"] = Format{
"P6", 
"Portable PixMap", 
"binary"};
 
   65        const std::string& magicNumber = std::string(firstLineTokes[0]);
 
   67        if (!format.count(magicNumber))
 
   68            DUNE_THROW(Dune::IOError, magicNumber << 
" is not a valid magic number for the Netpbm format");
 
   70        return format.at(magicNumber);
 
 
   81    static Result<bool> 
readPBM(
const std::string& fileName, 
const bool useDuneGridOrdering = 
true)
 
   83        std::ifstream infile(fileName, std::ios::binary);
 
   86            DUNE_THROW(Dune::IOError, 
"Raster data file not found or corrupt");
 
   89        std::vector<bool> values;
 
   92            values = readPBMDataASCII_(infile, headerData);
 
   94            values = readPBMDataBinary_(infile, headerData);
 
   96            DUNE_THROW(Dune::IOError, headerData.
format.
magicNumber << 
" not supported. Use readPBM for P1 and P4 or readPGM for P2 and P5");
 
   98        Result<bool> result(std::move(values), std::move(headerData));
 
  101        if (useDuneGridOrdering)
 
 
  119    template<
class ValueType = std::u
int8_t>
 
  120    static Result<ValueType> 
readPGM(
const std::string& fileName, 
const bool useDuneGridOrdering = 
true)
 
  122        std::ifstream infile(fileName, std::ios::binary);
 
  125            DUNE_THROW(Dune::IOError, 
"Raster data file not found or corrupt");
 
  128        std::vector<ValueType> values;
 
  131            values = NetPBMReader::template readPGMDataASCII_<ValueType>(infile, headerData);
 
  133            values = NetPBMReader::template readPGMDataBinary_<ValueType>(infile, headerData);
 
  135            DUNE_THROW(Dune::IOError, headerData.
format.
magicNumber << 
" not supported. Use readPBM for P1 and P4 or readPGM for P2 and P5");
 
  137        Result<ValueType> result(std::move(values), std::move(headerData));
 
  140        if (useDuneGridOrdering)
 
 
  153        HeaderData headerData;
 
  154        std::string inputLine;
 
  155        std::size_t lineNumber = 0;
 
  158        std::getline(infile, inputLine);
 
  161        const auto firstLineTokens = 
tokenize(inputLine, 
" ");
 
  166        if (firstLineTokens.size() > 2)
 
  168            if (isBlackAndWhite_(magicNumber) && firstLineTokens.size() != 3)
 
  169                DUNE_THROW(Dune::IOError, 
"Could not read first line for B/W image");
 
  171            headerData.
nCols = std::stoi(std::string(firstLineTokens[1]));
 
  172            headerData.
nRows = std::stoi(std::string(firstLineTokens[2]));
 
  174            if (isGrayScale_(magicNumber))
 
  176                if (firstLineTokens.size() == 4)
 
  177                    headerData.
maxValue = std::stoi(std::string(firstLineTokens[3]));
 
  178                if (firstLineTokens.size() > 4)
 
  179                    DUNE_THROW(Dune::IOError, 
"Could not read first line for grayscale image");
 
  185            while (!infile.eof())
 
  187                std::getline(infile, inputLine);
 
  191                if (isComment_(inputLine))
 
  194                const auto tokens = 
tokenize(inputLine, 
" ");
 
  197                if (tokens.size() != 2)
 
  198                    DUNE_THROW(Dune::IOError, 
"Expecting " << [](
auto size){ 
return size < 2 ? 
"both" : 
"only"; }(tokens.size()) << 
" dimensions (2 numbers) in line " << lineNumber);
 
  200                headerData.
nCols = std::stoi(std::string(tokens[0]));
 
  201                headerData.
nRows = std::stoi(std::string(tokens[1]));
 
  204                if (isGrayScale_(magicNumber))
 
  206                    std::getline(infile, inputLine);
 
  209                    const auto token = 
tokenize(inputLine, 
" ");
 
  210                    if (token.size() != 1)
 
  211                        DUNE_THROW(Dune::IOError, 
"Expecting" << [](
auto size){ 
return size == 0 ? 
"" : 
" only"; }(token.size()) << 
" intensity (one number) in line " << lineNumber);
 
  213                    headerData.
maxValue = std::stoi(std::string(token[0]));
 
 
  232        for (std::size_t i = 0; i < result.size(); i += result.
header().nCols)
 
  233            std::swap_ranges((result.begin() + i), (result.begin() + i + result.
header().
nCols), (tmp.end() - i - result.
header().
nCols));
 
 
  245        std::cout << 
"Reading " << format.
type << 
" file (" << format.
encoding << 
")" << std::endl;
 
  247        std::cout << 
"Maximum value : " << result.
header().
maxValue << std::endl;
 
 
  257    template<
class Image, 
class T>
 
  258    static void fillImage(Image& image, 
const Result<T>& result)
 
  262        using RowType = std::decay_t<
decltype(image[0])>;
 
  263        image.resize(nRows, RowType(nCols));
 
  265        std::size_t rowIdx = 0;
 
  266        std::size_t colIdx = 0;
 
  267        for (
const auto val : result)
 
  269            image[rowIdx][colIdx] = val;
 
  272            if (++colIdx == nCols)
 
 
  285    template<
class Image>
 
  291        std::vector<std::decay_t<typename Image::value_type::value_type>> data;
 
  292        data.reserve(image.size()*image[0].size());
 
  293        for (
const auto& row : image)
 
  294            data.insert(data.end(), row.begin(), row.end());
 
 
  301    static bool isBlackAndWhite_(
const std::string& magicNumber)
 
  303        return magicNumber == 
"P1" || magicNumber == 
"P4";
 
  306    static bool isGrayScale_(
const std::string& magicNumber)
 
  308        return magicNumber == 
"P2" || magicNumber == 
"P5";
 
  319    static std::vector<bool> readPBMDataASCII_(std::ifstream& infile,
 
  320                                               const HeaderData& headerData)
 
  322        std::string inputLine;
 
  323        std::vector<bool> data;
 
  324        data.reserve(numPixel_(headerData));
 
  326        while (!infile.eof())
 
  328            std::getline(infile, inputLine);
 
  329            if (!isComment_(inputLine))
 
  331                inputLine.erase(std::remove_if(inputLine.begin(), inputLine.end(), [](
unsigned char c){ return std::isspace(c); }), inputLine.end());
 
  332                if (!inputLine.empty())
 
  334                    for (
const auto& value : inputLine)
 
  336                        assert(value == 
'0' || value == 
'1');
 
  337                        data.push_back(value - 
'0');  
 
  354    static std::vector<bool> readPBMDataBinary_(std::ifstream& infile,
 
  355                                                const HeaderData& headerData)
 
  357        std::vector<bool> data(numPixel_(headerData));
 
  365        std::string inputLine;
 
  366        while (!infile.eof())
 
  369            const auto lastPos = infile.tellg();
 
  370            std::getline(infile, inputLine);
 
  373            if (!isComment_(inputLine))
 
  375                infile.seekg(lastPos);
 
  381        std::size_t nBytes = 0;
 
  382        std::size_t bitIndex = 0;
 
  383        using Bit = std::uint8_t;
 
  385        for (std::size_t j = 0; j < headerData.nRows; j++)
 
  387            for (std::size_t i = 0; i < headerData.nCols; i++)
 
  392                    infile.read(&tmp, 1);
 
  393                    b = 
static_cast<Bit
>(tmp);
 
  395                        DUNE_THROW(Dune::IOError, 
"Failed reading byte " << nBytes);
 
  400                const Bit k = 7 - (i % 8);
 
  401                data[bitIndex++] = 
static_cast<bool>((b >> k) & 1);
 
  420    template<
class ValueType = std::u
int8_t>
 
  421    static std::vector<ValueType> readPGMDataASCII_(std::ifstream& infile,
 
  422                                                    const HeaderData& headerData)
 
  424        std::string inputLine;
 
  426        std::vector<ValueType> data;
 
  427        data.reserve(numPixel_(headerData));
 
  429        while (!infile.eof())
 
  431            std::getline(infile, inputLine);
 
  432            if (inputLine.empty())
 
  436            if (inputLine.find(
" ") != std::string::npos)
 
  438                std::istringstream iss(inputLine);
 
  439                std::vector<std::string> tokens;
 
  440                std::copy(std::istream_iterator<std::string>(iss),
 
  441                          std::istream_iterator<std::string>(),
 
  442                          std::back_inserter(tokens));
 
  444                for (
const auto& t : tokens)
 
  445                    data.push_back(std::stoi(t)); 
 
  448                data.push_back(std::stoi(inputLine));
 
  466    template<
class ValueType = std::u
int8_t>
 
  467    static std::vector<ValueType> readPGMDataBinary_(std::ifstream& infile,
 
  468                                                     const HeaderData& headerData)
 
  471        const auto curPos = infile.tellg();
 
  472        infile.seekg(0, std::ios::end);
 
  473        const auto endPos = infile.tellg();
 
  474        const auto size = endPos - curPos;
 
  475        if (size != numPixel_(headerData))
 
  476            DUNE_THROW(Dune::IOError, 
"Binary file size does not match with raster image size");
 
  479        infile.seekg(curPos, std::ios::beg);
 
  482        std::vector<std::uint8_t> data(size);
 
  483        infile.read(
reinterpret_cast<char*
>(&data[0]), size);
 
  486        return std::vector<ValueType>(data.begin(), data.end());
 
  494    static std::size_t numPixel_(
const HeaderData& headerData)
 
  496        return headerData.nRows*headerData.nCols;
 
  502    static bool isComment_(
const std::string_view line)
 
  504        return line[0] == 
'#';
 
 
The return type of the reading functions. Holds the actual pixel values and the header data.
Definition rasterimagedata.hh:48
const HeaderData & header() const
Returns the header data.
Definition rasterimagedata.hh:70
A simple reader class for the Netpbm format (https://en.wikipedia.org/wiki/Netpbm_format)....
Definition rasterimagereader.hh:38
static HeaderData readHeader(std::ifstream &infile)
Returns the header data of the image file.
Definition rasterimagereader.hh:151
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:258
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:52
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:81
static auto flattenImageToVector(const Image &image)
Flattens a 2D image object to a 1D container.
Definition rasterimagereader.hh:286
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:229
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:120
static void printInfo(const Result< T > &result)
Print the data contained in the header.
Definition rasterimagereader.hh:242
constexpr Line line
Definition couplingmanager1d3d_line.hh:31
std::vector< std::string_view > tokenize(std::string_view str, std::string_view delim)
Definition stringutilities.hh:38
A data class for raster image information.
Helpers for working with strings.