/* * 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/. */ #include "ImageLoaderPnm.hpp" #include #include namespace OpenVulkano::Image { std::unique_ptr ImageLoaderPnm::loadFromFile(const std::string& filePath) { std::ifstream file(filePath, std::ios::binary); if (!file.is_open()) { throw std::runtime_error("Failed to open file: " + filePath); } std::vector buffer((std::istreambuf_iterator(file)), std::istreambuf_iterator()); return loadFromMemory(buffer); } std::unique_ptr ImageLoaderPnm::loadFromMemory(const std::vector& buffer) { std::istringstream stream(std::string(buffer.begin(), buffer.end())); PnmHeader header = parseHeader(stream); std::unique_ptr result = std::make_unique(); result->resolution.x = header.width; result->resolution.y = header.height; result->resolution.z = 1; if (header.magic == 1 || header.magic == 2 || header.magic == 3) { result->data = readTextData(stream, header); } else if (header.magic == 4 || header.magic == 5 || header.magic == 6) { result->data = readBinaryData(stream, header); } else { throw std::runtime_error("Unsupported format: P" + (header.magic + '0')); } if (header.magic == 1 || header.magic == 2 || header.magic == 4 || header.magic == 5) { result->dataFormat = DataFormat::Format::R8_UINT; } else { result->dataFormat = DataFormat::Format::R8G8B8_UINT; } return result; } Math::Vector2i ImageLoaderPnm::GetImageDimensions(const std::string& filename) { std::ifstream file(filename, std::ios::binary); if (!file.is_open()) { throw std::runtime_error("Failed to open file: " + filename); } PnmHeader header = parseHeader(file); return Math::Vector2i(header.width, header.height); } PnmHeader ImageLoaderPnm::parseHeader(std::istream& stream) { PnmHeader header; char pMagic; stream >> pMagic; if (pMagic != 'P') { throw std::runtime_error("Unsupported magic"); } stream >> header.magic; header.magic -= '0'; if (header.magic != 1 && header.magic != 2 && header.magic != 3 && header.magic != 4 && header.magic != 5 && header.magic != 6) { throw std::runtime_error("Unsupported magic number: P" + (header.magic + '0')); } stream >> header.width >> header.height; if (header.magic != 1 && header.magic != 4) { stream >> header.maxVal; } stream.ignore(std::numeric_limits::max(), '\n'); return header; } Array ImageLoaderPnm::readBinaryData(std::istream& stream, const PnmHeader& header) { size_t dataSize = header.width * header.height * ((header.magic == 6) ? 3 : 1); Array data(dataSize); if (header.magic == 4) { size_t rowBytes = (header.width + 7) / 8; Array rowBuffer(rowBytes); size_t index = 0; for (int y = 0; y < header.height; ++y) { stream.read(reinterpret_cast(rowBuffer.Data()), rowBytes); for (int x = 0; x < header.width; ++x) { size_t byteIndex = x / 8; size_t bitIndex = 7 - (x % 8); data[index++] = (rowBuffer[byteIndex] >> bitIndex) & 1 ? 255 : 0; } } } else { stream.read(reinterpret_cast(data.Data()), dataSize); } return data; } Array ImageLoaderPnm::readTextData(std::istream& stream, const PnmHeader& header) { Array data(header.width * header.height * ((header.magic == 3) ? 3 : 1)); for (size_t i = 0; i < data.Size(); ++i) { int value; stream >> value; if (header.magic == 1 || header.magic == 4) { data[i] = static_cast(value * 255); } else { data[i] = static_cast((value * 255) / header.maxVal); } } return data; } };