diff --git a/CMakeLists.txt b/CMakeLists.txt index 6658ae1..ca31db4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,8 @@ add_library(lily_png STATIC src/lily_png.cpp src/filter.cpp src/filter.h src/convert.cpp - src/convert.h) + src/convert.h + src/ascii.cpp + src/ascii.h) target_link_libraries(lily_png PRIVATE file_read ZLIB::ZLIB) diff --git a/src/ascii.cpp b/src/ascii.cpp new file mode 100644 index 0000000..c91f991 --- /dev/null +++ b/src/ascii.cpp @@ -0,0 +1,55 @@ +// +// Created by Luna on 27/7/25. +// + +#include "ascii.h" + +#include "convert.h" + +void lily_png::convert_to_ascii(file_reader::buffer &src, file_reader::buffer &dest, metadata &meta) +{ + auto pixel_size_ret = get_pixel_bit_size(meta); + if (!pixel_size_ret) + return ; + size_t pixel_size = pixel_size_ret.value(); + size_t pixel_size_bytes = (pixel_size + 7)/8; + float aspect_ratio = get_aspect_ratio(meta); + metadata new_meta = meta; + new_meta.width = 40; + new_meta.height = 40; + file_reader::buffer intermediate_resize{}; + auto resize_ret = resize_image(src, intermediate_resize, meta, new_meta); + if (!resize_ret) + return ; + size_t intermediate_size = resize_ret.value(); + size_t char_size = strlen("\033[38;2;255;255;255ma\033[0m "); + size_t width_char = char_size * new_meta.width; + size_t full_size = width_char * new_meta.height + new_meta.width; + + dest.allocate(full_size); + size_t dest_index = 0; + size_t line_done = 0; + + for (int i = 0; i < intermediate_size; i += pixel_size_bytes) + { + color_rgb tmp_color{}; + tmp_color.r = intermediate_resize.data[i]; + tmp_color.g = intermediate_resize.data[i + 1]; + tmp_color.b = intermediate_resize.data[i + 2]; + std::string format = std::format("\033[38;2;{};{};{}ma\033[0m ", tmp_color.r, tmp_color.g, tmp_color.b); + memcpy(&dest.data[dest_index], format.c_str(), format.size()); + dest_index += format.size(); + line_done++; + if (line_done == new_meta.width) + { + dest.data[dest_index] = '\n'; + dest_index++; + line_done = 0; + } + if (dest_index >= full_size) + { + dest.data[dest_index] = '\0'; + break; + } + } +} diff --git a/src/ascii.h b/src/ascii.h new file mode 100644 index 0000000..850a513 --- /dev/null +++ b/src/ascii.h @@ -0,0 +1,11 @@ +#pragma once + +#include "../file_reader/src/buffer.h" +#include "utils.h" +#include "metadata.h" +#include + +namespace lily_png +{ + void convert_to_ascii(file_reader::buffer &src, file_reader::buffer &dest, metadata &meta); +} diff --git a/src/lily_png.cpp b/src/lily_png.cpp index 9542cdd..3657b8d 100644 --- a/src/lily_png.cpp +++ b/src/lily_png.cpp @@ -154,6 +154,23 @@ static std::expected apply_palette(file_reader::buffe return true; } +std::expected lily_png::apply_to_pixel(file_reader::buffer &src, metadata &meta, std::function func) +{ + auto uncompress_ret = get_uncompressed_size(meta); + if (!uncompress_ret) + return std::unexpected(png_error::invalid_bit_depth); + size_t size = uncompress_ret.value(); + auto pixel_size_ret = get_pixel_bit_size(meta); + if (!pixel_size_ret) + return std::unexpected(pixel_size_ret.error()); + size_t pixel_size = pixel_size_ret.value(); + for (int i = 0; i < size; i += pixel_size) + { + func(&src.data[i], i, pixel_size); + } + return true; +} + std::expected lily_png::read_png(const std::string &file_path, file_reader::buffer &data) { file_reader::buffer tmp_data{}; diff --git a/src/lily_png.h b/src/lily_png.h index b1adaa4..73515cd 100644 --- a/src/lily_png.h +++ b/src/lily_png.h @@ -4,13 +4,16 @@ #include #include #include +#include #include "utils.h" #include "filter.h" +#include "ascii.h" #include "convert.h" #include namespace lily_png { + std::expected apply_to_pixel(file_reader::buffer &src, metadata &meta, std::function func); std::expected read_png(const std::string &file_path, file_reader::buffer &data); } diff --git a/src/utils.cpp b/src/utils.cpp index fb0d327..bbc8ed7 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -63,6 +63,37 @@ std::expected lily_png::get_uncompressed_size(const return ret; } +std::expected lily_png::resize_image(file_reader::buffer &src, + file_reader::buffer &dest, metadata &meta, metadata &new_meta) +{ + auto pixel_size_ret = get_pixel_bit_size(meta); + if (!pixel_size_ret) + return std::unexpected(pixel_size_ret.error()); + size_t pixel_size = pixel_size_ret.value(); + size_t pixel_size_bytes = (pixel_size + 7)/8; + int compressed_pixels_width = meta.width / new_meta.width; + int compressed_pixels_height = meta.height / new_meta.height; + auto uncompress_ret = get_uncompressed_size(new_meta); + if (!uncompress_ret) + return std::unexpected(uncompress_ret.error()); + dest.allocate(uncompress_ret.value()); + + for (int y = 0; y < new_meta.height; y++) + { + for (int x = 0; x < new_meta.width; x++) + { + int src_x = static_cast(x * compressed_pixels_width); + int src_y = static_cast(y * compressed_pixels_height); + + // Calculate the linear index for the source and destination buffers + size_t dest_index = (static_cast(y) * new_meta.width + x) * pixel_size_bytes; + size_t src_index = (static_cast(src_y) * meta.width + src_x) * pixel_size_bytes; + memcpy(&dest.data[dest_index], &src.data[src_index], pixel_size_bytes); + } + } + return uncompress_ret.value(); +} + int lily_png::paeth_predict(const int a, const int b, const int c) { const int pred = a+b-c; @@ -75,3 +106,15 @@ int lily_png::paeth_predict(const int a, const int b, const int c) return b; return c; } + +float lily_png::get_aspect_ratio(const metadata &meta) +{ + float aspect_ratio = 0.0f; + + if (meta.width > meta.height) + aspect_ratio = (float)meta.width / (float)meta.height; + else + aspect_ratio = (float)meta.height / (float)meta.width; + + return aspect_ratio; +} diff --git a/src/utils.h b/src/utils.h index a4f5d32..72abe27 100644 --- a/src/utils.h +++ b/src/utils.h @@ -15,5 +15,7 @@ namespace lily_png }; std::expected get_pixel_bit_size(const metadata &meta); std::expected get_uncompressed_size(const metadata &meta); + std::expected resize_image(file_reader::buffer &src, file_reader::buffer &dest, metadata &meta, metadata &new_meta); int paeth_predict(const int a, const int b, const int c); + float get_aspect_ratio(const metadata &meta); }