Add basic pnm support
This commit is contained in:
121
openVulkanoCpp/IO/Files/Pnm.hpp
Normal file
121
openVulkanoCpp/IO/Files/Pnm.hpp
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <memory>
|
||||
#include <cmath>
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
//TODO handle comments
|
||||
/**
|
||||
* Implements Portable Anymap file headers
|
||||
* See https://de.wikipedia.org/wiki/Portable_Anymap
|
||||
*/
|
||||
class PnmHeader
|
||||
{
|
||||
static constexpr std::string_view FILE_TYPES[] = { "PBM", "PGM", "PPM" };
|
||||
static constexpr std::string_view FILE_EXT[] = { ".pbm", ".pgm", ".ppm" };
|
||||
public:
|
||||
enum class ColorMode : uint8_t { BW = 1, GRAY, COLOR };
|
||||
|
||||
uint32_t width, height, maxValue;
|
||||
ColorMode color;
|
||||
bool ascii;
|
||||
|
||||
constexpr PnmHeader() : width(0), height(0), maxValue(0), color(ColorMode::GRAY), ascii(false) {}
|
||||
|
||||
constexpr PnmHeader(uint32_t width, uint32_t height, bool color, uint32_t maxValue = 255, bool ascii = false) :
|
||||
width(width), height(height), maxValue(maxValue), color(color ? ColorMode::COLOR : ColorMode::GRAY), ascii(ascii)
|
||||
{}
|
||||
|
||||
constexpr PnmHeader(uint32_t width, uint32_t height, ColorMode color = ColorMode::COLOR, uint32_t maxValue = 255, bool ascii = false) :
|
||||
width(width), height(height), maxValue(maxValue), color(color), ascii(ascii)
|
||||
{}
|
||||
|
||||
constexpr std::string_view GetFileType() const
|
||||
{
|
||||
return FILE_TYPES[static_cast<uint8_t>(color) - 1];
|
||||
}
|
||||
|
||||
constexpr std::string_view GetFileExtension() const
|
||||
{
|
||||
return FILE_EXT[static_cast<uint8_t>(color) - 1];
|
||||
}
|
||||
|
||||
std::string ToString() const
|
||||
{
|
||||
std::stringstream headerStream;
|
||||
headerStream << *this;
|
||||
return headerStream.str();
|
||||
}
|
||||
|
||||
constexpr uint8_t GetMagicNumberValue() const
|
||||
{
|
||||
uint8_t value = static_cast<uint8_t>(color);
|
||||
if (!ascii) value += 3;
|
||||
return value;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<< (std::ostream& outStream, const PnmHeader& pnmHeader)
|
||||
{
|
||||
outStream << 'P';
|
||||
outStream << ('0' + pnmHeader.GetMagicNumberValue());
|
||||
outStream << '\n';
|
||||
outStream << pnmHeader.width << ' ' << pnmHeader.height << '\n';
|
||||
outStream << pnmHeader.maxValue << '\n';
|
||||
return outStream;
|
||||
}
|
||||
|
||||
friend std::istream& operator>> (std::istream& inStream, PnmHeader& pnmHeader)
|
||||
{
|
||||
std::string marker;
|
||||
inStream >> marker;
|
||||
if (marker.length() != 2 || marker[0] != 'P') throw std::runtime_error("Malformed PNM header!");
|
||||
uint8_t val = marker[1] - '0';
|
||||
if (val > 6) throw std::runtime_error("Malformed PNM header!");
|
||||
pnmHeader.ascii = val < 4;
|
||||
pnmHeader.color = static_cast<ColorMode>(val & 0x11);
|
||||
inStream >> pnmHeader.width >> pnmHeader.height;
|
||||
inStream >> pnmHeader.maxValue;
|
||||
return inStream;
|
||||
}
|
||||
|
||||
constexpr size_t GetImageSize() const
|
||||
{
|
||||
size_t size = height * width;
|
||||
if (color == ColorMode::COLOR)
|
||||
{
|
||||
size *= 3;
|
||||
if (maxValue > 255) size *= 2;
|
||||
return size;
|
||||
}
|
||||
if (color == ColorMode::BW)
|
||||
{
|
||||
return std::ceil(size / 8.0);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static std::pair<PnmHeader, std::unique_ptr<char[]>> ReadImage(std::istream& inStream)
|
||||
{
|
||||
std::pair<PnmHeader, std::unique_ptr<char[]>> image;
|
||||
inStream >> image.first;
|
||||
|
||||
// TODO handle ascii mode
|
||||
if (image.first.ascii) throw std::runtime_error("ascii mode not supported!");
|
||||
|
||||
size_t size = image.first.GetImageSize();
|
||||
image.second = std::make_unique<char[]>(size);
|
||||
inStream.read(image.second.get(), size);
|
||||
return image;
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user