From f688471fa4900855af71efd5621ded62e27b116d Mon Sep 17 00:00:00 2001 From: GeorgH93 Date: Tue, 15 Dec 2020 22:54:26 +0100 Subject: [PATCH] Add basic pnm support --- openVulkanoCpp/IO/Files/Pnm.hpp | 121 ++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 openVulkanoCpp/IO/Files/Pnm.hpp diff --git a/openVulkanoCpp/IO/Files/Pnm.hpp b/openVulkanoCpp/IO/Files/Pnm.hpp new file mode 100644 index 0000000..bd8a606 --- /dev/null +++ b/openVulkanoCpp/IO/Files/Pnm.hpp @@ -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 +#include +#include +#include +#include + +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(color) - 1]; + } + + constexpr std::string_view GetFileExtension() const + { + return FILE_EXT[static_cast(color) - 1]; + } + + std::string ToString() const + { + std::stringstream headerStream; + headerStream << *this; + return headerStream.str(); + } + + constexpr uint8_t GetMagicNumberValue() const + { + uint8_t value = static_cast(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(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> ReadImage(std::istream& inStream) + { + std::pair> 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(size); + inStream.read(image.second.get(), size); + return image; + }; + }; +}