Added convert logic and improved error handling

This commit is contained in:
luna 2025-07-25 05:41:11 +02:00
parent 41facff9c5
commit 251d839a8b
9 changed files with 118 additions and 30 deletions

@ -1 +1 @@
Subproject commit 54a063d5e6ab8ea06b1101154574d2eaeebbde5f Subproject commit 27ba3791017f33bb60cc9775c2d8a5a44f400a41

View file

@ -1,9 +1,71 @@
#include "convert.h" #include "convert.h"
void lily_png::convert_to_R32G32B32A32(file_reader::buffer<unsigned char> &data, metadata &meta) std::expected<bool, lily_png::CONVERT_ERROR> lily_png::convert_to_R32G32B32A32(file_reader::buffer<unsigned char> &data, file_reader::buffer<unsigned char> &dest, metadata &meta)
{ {
if (meta.color_type != static_cast<char>(color::rgba)) if (meta.color_type != static_cast<char>(color::rgba))
{ return std::unexpected(CONVERT_ERROR::color_type_mismatch);
if (!(meta.bit_depth == 8 || meta.bit_depth == 16))
return std::unexpected(CONVERT_ERROR::non_standard_bit_depth);
size_t size = get_uncompressed_size(meta);
size_t dest_size = 0;
if (meta.bit_depth == 8)
{
dest_size = size * 4;
std::tuple<unsigned char, unsigned char, unsigned char, unsigned char> pixel;
constexpr std::size_t size_tup = std::tuple_size_v<decltype(pixel)>;
dest.allocate(dest_size);
size_t dest_index = 0;
for (int i = 0; i < size; i += 4)
{
file_reader::parsing_buffer par_buf(data);
par_buf.point = &par_buf.buf.data[i];
par_buf.consumed_size = 0;
read_comp(size_tup, par_buf, pixel);
color_rgba32 tmp{0};
tmp.r = std::get<0>(pixel);
tmp.g = std::get<1>(pixel);
tmp.b = std::get<2>(pixel);
tmp.a = std::get<3>(pixel);
memcpy(&dest.data[dest_index], &tmp.r, sizeof(unsigned int));
dest_index += sizeof(unsigned int);
memcpy(&dest.data[dest_index], &tmp.g, sizeof(unsigned int));
dest_index += sizeof(unsigned int);
memcpy(&dest.data[dest_index], &tmp.b, sizeof(unsigned int));
dest_index += sizeof(unsigned int);
memcpy(&dest.data[dest_index], &tmp.a, sizeof(unsigned int));
dest_index += sizeof(unsigned int);
}
} }
else if (meta.bit_depth == 16)
{
dest_size = size * 2;
std::tuple<unsigned short, unsigned short, unsigned short, unsigned short> pixel;
constexpr std::size_t size_tup = std::tuple_size_v<decltype(pixel)>;
dest.allocate(dest_size);
size_t dest_index = 0;
for (int i = 0; i < size; i += 4 * sizeof(unsigned short))
{
file_reader::parsing_buffer par_buf(data);
par_buf.point = &par_buf.buf.data[i];
par_buf.consumed_size = 0;
read_comp(size_tup, par_buf, pixel);
color_rgba32 tmp{0};
tmp.r = std::get<0>(pixel);
tmp.g = std::get<1>(pixel);
tmp.b = std::get<2>(pixel);
tmp.a = std::get<3>(pixel);
memcpy(&dest.data[dest_index], &tmp.r, sizeof(unsigned int));
dest_index += sizeof(unsigned int);
memcpy(&dest.data[dest_index], &tmp.g, sizeof(unsigned int));
dest_index += sizeof(unsigned int);
memcpy(&dest.data[dest_index], &tmp.b, sizeof(unsigned int));
dest_index += sizeof(unsigned int);
memcpy(&dest.data[dest_index], &tmp.a, sizeof(unsigned int));
dest_index += sizeof(unsigned int);
}
}
return true;
} }

View file

@ -1,8 +1,40 @@
#pragma once #pragma once
#include "../file_reader/src/buffer.h" #include "../file_reader/src/buffer.h"
#include "metadata.h" #include "metadata.h"
#include "utils.h"
#include <expected>
#include <vector>
namespace lily_png namespace lily_png
{ {
void convert_to_R32G32B32A32(file_reader::buffer<unsigned char> &data, metadata &meta); struct color_rgb
{
unsigned char r = 0;
unsigned char g = 0;
unsigned char b = 0;
};
struct color_rgba
{
unsigned char r = 0;
unsigned char g = 0;
unsigned char b = 0;
unsigned char a = 0;
};
struct color_rgba32
{
unsigned int r = 0;
unsigned int g = 0;
unsigned int b = 0;
unsigned int a = 0;
};
enum class CONVERT_ERROR
{
color_type_mismatch,
non_standard_bit_depth
};
std::expected<bool, CONVERT_ERROR> convert_to_R32G32B32A32(file_reader::buffer<unsigned char> &data, file_reader::buffer<unsigned char> &dest, metadata &meta);
} }

View file

@ -1,6 +1,6 @@
#include "filter.h" #include "filter.h"
void lily_png::filter_scanline(unsigned char *scanline, unsigned char *previous_scanline, unsigned char *dest, metadata &meta, unsigned char filter_type) std::expected<bool, lily_png::png_error> lily_png::filter_scanline(unsigned char *scanline, unsigned char *previous_scanline, unsigned char *dest, metadata &meta, unsigned char filter_type)
{ {
size_t pixel_size = get_pixel_bit_size(meta); size_t pixel_size = get_pixel_bit_size(meta);
size_t pixel_size_bytes = (pixel_size + 7)/8; size_t pixel_size_bytes = (pixel_size + 7)/8;
@ -37,13 +37,13 @@ void lily_png::filter_scanline(unsigned char *scanline, unsigned char *previous_
dest[i] = scanline[i] + paeth_predict(a, b, c); dest[i] = scanline[i] + paeth_predict(a, b, c);
break; break;
default: default:
std::println("Non standard filter"); return std::unexpected(png_error::non_standard_filter);
break;
} }
} }
return true;
} }
void lily_png::filter(file_reader::buffer<unsigned char> &data, file_reader::buffer<unsigned char> &dest , metadata &meta) std::expected<bool, lily_png::png_error> lily_png::filter(file_reader::buffer<unsigned char> &data, file_reader::buffer<unsigned char> &dest , metadata &meta)
{ {
unsigned long index = 0; unsigned long index = 0;
unsigned long index_dest = 0; unsigned long index_dest = 0;
@ -57,7 +57,9 @@ void lily_png::filter(file_reader::buffer<unsigned char> &data, file_reader::buf
{ {
unsigned char filter = data.data[index]; unsigned char filter = data.data[index];
std::println("Filter {}", filter); std::println("Filter {}", filter);
filter_scanline(&data.data[index + 1], previous_scanline, &dest.data[index_dest], meta, filter); auto res = filter_scanline(&data.data[index + 1], previous_scanline, &dest.data[index_dest], meta, filter);
if (!res)
return std::unexpected(res.error());
previous_scanline = &dest.data[index_dest]; previous_scanline = &dest.data[index_dest];
index += scanline_size + 1; index += scanline_size + 1;
index_dest += scanline_size; index_dest += scanline_size;

View file

@ -4,7 +4,7 @@
namespace lily_png namespace lily_png
{ {
void filter_scanline(unsigned char *scanline, unsigned char *previous_scanline, unsigned char *dest, metadata &meta, unsigned char filter_type); std::expected<bool, png_error> lily_png::filter_scanline(unsigned char *scanline, unsigned char *previous_scanline, unsigned char *dest, metadata &meta, unsigned char filter_type);
void filter(file_reader::buffer<unsigned char> &data, file_reader::buffer<unsigned char> &dest ,metadata &meta); std::expected<bool, png_error> filter(file_reader::buffer<unsigned char> &data, file_reader::buffer<unsigned char> &dest ,metadata &meta);
} }

View file

@ -153,6 +153,8 @@ std::expected<lily_png::metadata, lily_png::png_error> lily_png::read_png(const
apply_palette(tmp_data, dest_palette, meta); apply_palette(tmp_data, dest_palette, meta);
tmp_data = dest_palette; tmp_data = dest_palette;
} }
filter(tmp_data, data, meta); auto res = filter(tmp_data, data, meta);
if (!res)
return std::unexpected(res.error());
return meta; return meta;
} }

View file

@ -6,26 +6,11 @@
#include <format> #include <format>
#include "utils.h" #include "utils.h"
#include "filter.h" #include "filter.h"
#include "convert.h"
#include <zlib.h> #include <zlib.h>
namespace lily_png namespace lily_png
{ {
struct color_rgb
{
unsigned char r = 0;
unsigned char g = 0;
unsigned char b = 0;
};
enum class png_error
{
file_doesnt_exist,
read_failed,
file_is_not_a_png
};
std::expected<metadata, png_error> read_png(const std::string &file_path, file_reader::buffer<unsigned char> &data); std::expected<metadata, png_error> read_png(const std::string &file_path, file_reader::buffer<unsigned char> &data);
} }

View file

@ -4,7 +4,6 @@
size_t lily_png::get_pixel_bit_size(const metadata &meta) size_t lily_png::get_pixel_bit_size(const metadata &meta)
{ {
size_t ret = 0; size_t ret = 0;
std::println("Bit depth {} color {}", (int)meta.bit_depth, (int)meta.color_type);
switch (meta.color_type) switch (meta.color_type)
{ {
case static_cast<int>(color::grayscale): case static_cast<int>(color::grayscale):
@ -55,7 +54,6 @@ size_t lily_png::get_pixel_bit_size(const metadata &meta)
size_t lily_png::get_uncompressed_size(const metadata &meta) size_t lily_png::get_uncompressed_size(const metadata &meta)
{ {
std::println("metadata{{ width: {}, height: {}, bit_depth: {}, color_type: {}, compression: {}, filter: {}, interface: {} }}", meta.width, meta.height, (int)meta.bit_depth, (int)meta.color_type, (int)meta.compression, (int)meta.filter, (int)meta.interface);
size_t ret = (meta.width * get_pixel_bit_size(meta) + 7)/8; //ceil() but for bytes size_t ret = (meta.width * get_pixel_bit_size(meta) + 7)/8; //ceil() but for bytes
ret = (ret + 1) * meta.height; ret = (ret + 1) * meta.height;
std::println("Uncompressed size {}", ret); std::println("Uncompressed size {}", ret);

View file

@ -3,6 +3,13 @@
namespace lily_png namespace lily_png
{ {
enum class png_error
{
file_doesnt_exist,
read_failed,
file_is_not_a_png,
non_standard_filter
};
size_t get_pixel_bit_size(const metadata &meta); size_t get_pixel_bit_size(const metadata &meta);
size_t get_uncompressed_size(const metadata &meta); size_t get_uncompressed_size(const metadata &meta);
int paeth_predict(const int a, const int b, const int c); int paeth_predict(const int a, const int b, const int c);