Added convert logic and improved error handling
This commit is contained in:
parent
41facff9c5
commit
251d839a8b
9 changed files with 118 additions and 30 deletions
|
@ -1 +1 @@
|
||||||
Subproject commit 54a063d5e6ab8ea06b1101154574d2eaeebbde5f
|
Subproject commit 27ba3791017f33bb60cc9775c2d8a5a44f400a41
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue