diff options
| author | Mel <einebeere@gmail.com> | 2022-10-08 03:18:18 +0200 |
|---|---|---|
| committer | Mel <einebeere@gmail.com> | 2022-10-08 03:18:18 +0200 |
| commit | 799c06e0387e01bdb8a10019be6192f9db00a824 (patch) | |
| tree | f590ee7cb6a6b3b191ba080ddb88199cefdba7e8 /src/Image/PPMParser.cpp | |
| parent | 56c86cefa3233bdc94aa1c62ec04dada501c1ccf (diff) | |
| download | meowcraft-799c06e0387e01bdb8a10019be6192f9db00a824.tar.zst meowcraft-799c06e0387e01bdb8a10019be6192f9db00a824.zip | |
Parse PPM images
Diffstat (limited to 'src/Image/PPMParser.cpp')
| -rw-r--r-- | src/Image/PPMParser.cpp | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/src/Image/PPMParser.cpp b/src/Image/PPMParser.cpp new file mode 100644 index 0000000..0a9da54 --- /dev/null +++ b/src/Image/PPMParser.cpp @@ -0,0 +1,164 @@ +#include <cctype> +#include <string> +#include <iostream> +#include "PPMParser.hpp" + +namespace MC::Image { + +RawImage PPMParser::parse() { + auto header = parse_header(); + + std::cout << header.type << " " << header.width << " " << header.height << " " << (uint64_t)header.max_color << std::endl; + + if (header.max_color != 255) { + throw std::logic_error("PPM max color values other than 255 are not implemented."); + } + + if (header.type != P3) { + throw std::logic_error("Raw PPM not implemented."); + } + + auto pixel_count = header.width * header.height; + + RawImage image(pixel_count); + for (uint64_t pixel_index = 0; pixel_index < pixel_count; pixel_index++) { + RawImage::Pixel pixel = parse_pixel(header.max_color); + image.add(pixel); + } + + return image; +} + +PPMParser::PPMHeader PPMParser::parse_header() { + PPMHeader header{}; + + skip_whitespace(); + + auto type_part = chomp_part(); + skip_whitespace(); + + if (type_part == "P3") { + header.type = P3; + } else if (type_part == "P6") { + header.type = P6; + } else { + throw std::runtime_error("Unknown PPM type."); + } + + auto width_part = chomp_number(); + skip_whitespace(); + header.width = width_part; + + auto height_part = chomp_number(); + skip_whitespace(); + header.height = height_part; + + auto max_color_part = chomp_number(); + skip_whitespace(); + header.max_color = max_color_part; + + return header; +} + +RawImage::Pixel PPMParser::parse_pixel(uint8_t max_color) { + auto r_sample = parse_sample(); + auto g_sample = parse_sample(); + auto b_sample = parse_sample(); + + if (r_sample > max_color || g_sample > max_color || b_sample > max_color) { + throw std::runtime_error("Sample can not be greater than Maxval."); + } + + auto map_to_range = [=](uint64_t s) -> uint8_t { return (s * 255) / max_color; }; + + RawImage::Pixel pixel{}; + pixel.r = map_to_range(r_sample); + pixel.g = map_to_range(g_sample); + pixel.b = map_to_range(b_sample); + + return pixel; +} + +uint64_t PPMParser::parse_sample() { + skip_whitespace(); + auto sample = chomp_number(); + skip_whitespace(); + return sample; +} + +uint64_t PPMParser::chomp_number() { + auto raw = chomp_part(); + + uint64_t number = 0; + for (uint8_t digit_ascii : raw) { + if (digit_ascii < '0' || digit_ascii > '9') { + throw std::runtime_error("Number contains non ASCII digits."); + } + + uint8_t digit = digit_ascii - '0'; + + std::cout << "digit_ascii: " << digit_ascii << std::endl; + std::cout << "digit: " << (uint64_t)digit << std::endl; + + number *= 10; + number += digit; + + std::cout << "number: " << (uint64_t)number << std::endl; + } + + std::cout << "chomp number: " << number << std::endl; + return number; +} + +std::string_view PPMParser::chomp_part() { + uint64_t length = 0; + + while (!is_eof()) { + auto c = m_source[m_cursor + length]; + if (std::isspace(c)) { + break; + } + + length++; + } + + auto part = m_source.substr(m_cursor, length); + m_cursor += length; + + std::cout << "chomped: " << part << std::endl; + return part; +} + +void PPMParser::skip_whitespace() { + uint8_t c; + while (!is_eof()) { + c = m_source[m_cursor]; + if (c == '#') { + skip_comment(); + continue; + } + + if (!std::isspace(c)) { + break; + } + + m_cursor++; + } +} + +void PPMParser::skip_comment() { + uint8_t c = m_source[m_cursor]; + if (c != '#') { + return; + } + + while (c != '\n' && !is_eof()) { + c = m_source[++m_cursor]; + } +} + +bool PPMParser::is_eof() { + return m_cursor >= m_source.size(); +} + +} \ No newline at end of file |
