From 567e0df2434b270411d3356b8e362fc881113335 Mon Sep 17 00:00:00 2001 From: Jonas Gunz Date: Sat, 29 Aug 2020 14:05:22 +0200 Subject: first working --- src/bitmap.c | 69 ++++++++++++++++++++++---- src/bitmap.h | 11 +++-- src/color.c | 9 ++-- src/color.h | 6 ++- src/dynalloc.c | 22 +++++++++ src/dynalloc.h | 12 +++++ src/main.c | 149 ++++++++++++--------------------------------------------- 7 files changed, 141 insertions(+), 137 deletions(-) create mode 100644 src/dynalloc.c create mode 100644 src/dynalloc.h diff --git a/src/bitmap.c b/src/bitmap.c index c64a4c0..6d72cb0 100644 --- a/src/bitmap.c +++ b/src/bitmap.c @@ -30,7 +30,7 @@ static uint32_t bitmap_flip_byte(unsigned char* _v, int _c) int bitmap_read(char *_file, struct bitmap_image *_bitmap) { - if (!_bitmap ) + if ( !_bitmap ) return 5; struct bitmap_file_header header; @@ -176,6 +176,7 @@ static struct bitmap_image bitmap_read_pixel_data(FILE *_file, struct bitmap_fil } int bitmap_copy ( struct bitmap_image *_input, struct bitmap_image *_output ) { + // TODO implement return 1; } @@ -183,10 +184,7 @@ int bitmap_convert_monochrome ( struct bitmap_image *_input, struct bitmap_image if ( !_input || !_output ) return 1; - uint8_t **monochrome_bitmap = malloc( sizeof (*monochrome_bitmap) * _input->x ); - for ( int i = 0; i < _input->y; i++ ) { - monochrome_bitmap[i] = malloc ( sizeof (**monochrome_bitmap) * _input->y ); - } + uint8_t **monochrome_bitmap = (uint8_t**) dynalloc_2d_array( _input->x, _input->y, sizeof(uint8_t)); for ( unsigned int x = 0; x < _input->x; x++ ) { for ( unsigned int y = 0; y < _input->y; y++ ) { @@ -198,16 +196,69 @@ int bitmap_convert_monochrome ( struct bitmap_image *_input, struct bitmap_image } _output->R = _output->G = _output->B = monochrome_bitmap; + _output->tags = BITMAP_MONOCHROME; + _output->x = _input->x; + _output->y = _input->y; + //TODO min/max brightness return 0; } -int bitmap_transform ( struct bitmap_image *_input, struct bitmap_image *_output ) { - return 1; +int bitmap_shrink ( struct bitmap_image *_input, struct bitmap_image *_output, unsigned int _factor_x, unsigned int _factor_y ) { + if ( !_input || !_output ) + return 1; + + /* New Size */ + _output->x = _input->x / _factor_x; + _output->y = _input->y / _factor_y; + _output->tags = _input->tags; + + /* Allocate memory */ + if ( _input->tags & BITMAP_MONOCHROME ) { + _output->R = _output->G = _output->B = + (uint8_t**) dynalloc_2d_array ( _output->x, _output->y, sizeof ( uint8_t) ); + } else { + _output->R = (uint8_t**) dynalloc_2d_array ( _output->x, _output->y, sizeof ( uint8_t) ); + _output->G = (uint8_t**) dynalloc_2d_array ( _output->x, _output->y, sizeof ( uint8_t) ); + _output->B = (uint8_t**) dynalloc_2d_array ( _output->x, _output->y, sizeof ( uint8_t) ); + } + + for(unsigned int x = 0; x < _output->x; x++) { + for(unsigned int y = 0; y < _output->y; y++) { + // Unsafe for > 2^56 Pixels (Hopefully unrealistic) + uint64_t color_sum[3] = {0,0,0}; + const uint64_t pixel_count = _factor_x * _factor_y; + + // Average Pixel block + for(unsigned int row_c = 0; row_c < _factor_y; row_c++) { + unsigned int row = y * _factor_y + row_c; //Offset + + for(unsigned int col_c = 0; col_c < _factor_x; col_c++) { + unsigned int col = x * _factor_x + col_c; //Offset + + color_sum[0] += (uint64_t) _input->R[col][row]; + color_sum[1] += (uint64_t) _input->G[col][row]; + color_sum[2] += (uint64_t) _input->B[col][row]; + }//for col_c + }//for row_c + + _output->R[x][y] = (uint8_t) (color_sum[0] / pixel_count); + _output->G[x][y] = (uint8_t) (color_sum[1] / pixel_count); + _output->B[x][y] = (uint8_t) (color_sum[2] / pixel_count); + }//for y + }//for x + + return 0; } -static uint8_t bitmap_rgb_luminance(uint8_t R, uint8_t G, uint8_t B) -{ +int bitmap_fit_to_width ( struct bitmap_image *_input, struct bitmap_image *_output, unsigned int _width ) { + unsigned int factor_x = (unsigned int)((float)_input->x / (float) _width ); + unsigned int factor_y = (unsigned int)(((float)_input->y / (float)_input->x ) * (float) factor_x * 2); + + return bitmap_shrink ( _input, _output, factor_x, factor_y ); +} + +static uint8_t bitmap_rgb_luminance(uint8_t R, uint8_t G, uint8_t B) { uint8_t ret; ret = sqrt( 0.299*pow(R,2) + 0.587*pow(G,2) + 0.114*pow(B,2) ); //(char)(R+R+B+G+G+G)/6; diff --git a/src/bitmap.h b/src/bitmap.h index 3b942a7..48fd1ac 100644 --- a/src/bitmap.h +++ b/src/bitmap.h @@ -1,5 +1,4 @@ -/* - * src/bitmap.h +/* * src/bitmap.h * (c) 2020 Jonas Gunz * License: MIT */ @@ -12,6 +11,8 @@ #include #include +#include "dynalloc.h" + #define _HEADER_SIZE 54 //Fileheader + infoheader #define IDENTIFIER 0x424d //BM BitMap identifier @@ -65,6 +66,8 @@ struct bitmap_image uint8_t **B; uint8_t tags; + uint8_t monochrome_maximum_brightness; + uint8_t monochrome_minimum_brightness; }; int bitmap_read ( char *_file, struct bitmap_image *_bitmap ); @@ -73,6 +76,8 @@ int bitmap_copy ( struct bitmap_image *_input, struct bitmap_image *_output ); int bitmap_convert_monochrome ( struct bitmap_image *_input, struct bitmap_image *_output ); -int bitmap_transform ( struct bitmap_image *_input, struct bitmap_image *_output ); +int bitmap_shrink ( struct bitmap_image *_input, struct bitmap_image *_output, unsigned int _factor_x, unsigned int _factor_y ); + +int bitmap_fit_to_width ( struct bitmap_image *_input, struct bitmap_image *_output, unsigned int _width ); #endif /* end of include guard: _BITMAP_H_ */ diff --git a/src/color.c b/src/color.c index d0fbe1b..d7b3cdf 100644 --- a/src/color.c +++ b/src/color.c @@ -64,12 +64,13 @@ char* calc_col(uint8_t R, uint8_t G, uint8_t B) return colors[ nearest_num ].no; } //TODO consolidate -char* calc_col_ansi(uint8_t R, uint8_t G, uint8_t B) +char* calc_col_ansi(uint8_t R, uint8_t G, uint8_t B, uint8_t _mode) { + int mode = _mode == COLOR_BG ? 4 : 3; int num = 36 * (R/51) + 6 * (G/51) + (B/51); - char *c = malloc(9); - snprintf( c, 6, "38;5;" ); - snprintf( c + 5, 4, "%i", num + 16 ); + char *c = malloc(12); + snprintf( c, 8, "\e[%i8;5;", mode ); + snprintf( c + 7, 5, "%im", num + 16 ); return c; } diff --git a/src/color.h b/src/color.h index 70a8b16..a2f82d3 100644 --- a/src/color.h +++ b/src/color.h @@ -8,7 +8,9 @@ #include "m.h" -#define _COLORS_SIZE 16u +#define _COLORS_SIZE 16u +#define COLOR_FG 1 +#define COLOR_BG 2 struct console_color { @@ -28,7 +30,7 @@ uint8_t rgb_luminance(uint8_t R, uint8_t G, uint8_t B); //Get nearest printable color in console char *calc_col(uint8_t R, uint8_t G, uint8_t B); -char *calc_col_ansi(uint8_t R, uint8_t G, uint8_t B); +char *calc_col_ansi(uint8_t R, uint8_t G, uint8_t B, uint8_t _mode); char *calc_bg_col_ansi(uint8_t R, uint8_t G, uint8_t B); #endif //_COLOR_H_ diff --git a/src/dynalloc.c b/src/dynalloc.c new file mode 100644 index 0000000..ecce3e7 --- /dev/null +++ b/src/dynalloc.c @@ -0,0 +1,22 @@ +/* + * src/dynalloc.c + * (c) 2020 Jonas Gunz + * License: MIT +*/ +#include "dynalloc.h" + +void** dynalloc_2d_array ( unsigned int _x, unsigned int _y, unsigned int _sizeof ) { + void** ret = NULL; + + ret = malloc ( _x * sizeof ( void* ) ); + for ( int i = 0; i < _x; i++ ) + ret[i] = malloc ( _y * _sizeof ); + + return ret; +} + +void dynalloc_2d_array_free ( unsigned int _x, unsigned int _y, void** _array ) { + for ( int i = 0; i < _x; i++ ) + free ( _array[i] ); + free(_array); +} diff --git a/src/dynalloc.h b/src/dynalloc.h new file mode 100644 index 0000000..852f608 --- /dev/null +++ b/src/dynalloc.h @@ -0,0 +1,12 @@ +/* + * src/dynalloc.h + * (c) 2020 Jonas Gunz + * License: MIT +*/ +#pragma once + +#include + +void** dynalloc_2d_array ( unsigned int _x, unsigned int _y, unsigned int _sizeof ); + +void dynalloc_2d_array_free ( unsigned int _x, unsigned int _y, void** _array ); diff --git a/src/main.c b/src/main.c index e9e04e3..d73c58a 100644 --- a/src/main.c +++ b/src/main.c @@ -15,8 +15,6 @@ #include "m.h" #include "color.h" -// #define CLEANUP 1 - #ifdef _DEBUG #warning "Compiling with DEBUG" #define DEBUG_PRINTF(...) { printf(__VA_ARGS__); } @@ -48,123 +46,51 @@ int main(int argc, char *argv[]) { struct prog_param args = parse_args(argc, argv); - //Stores a luminance array - uint8_t **image_monochrome; - //Stores a color array - char* **col_buff; + struct bitmap_image bitmap; + struct bitmap_image shrunk_bitmap; + struct bitmap_image monochrome_bitmap; - uint8_t brightness_max = 0x00; - uint8_t brightness_min = 0xff; + uint8_t brightness_min = 0x00; + uint8_t brightness_max = 0xff; + + int size_x, size_y; - struct bitmap_image bitmap; if ( bitmap_read(args.filename, &bitmap) ) { printf("Error reading file\n"); return 1; } - // Character count in x and y in final ASCII image - unsigned int size_x,size_y; - if(args.fit_width > 0) { args.charsize_x = (unsigned int)((float)bitmap.x / (float)args.fit_width); args.charsize_y = (unsigned int)(((float)bitmap.y / (float)bitmap.x) * (float)args.charsize_x * 2); } - size_x = bitmap.x / args.charsize_x; - size_y = bitmap.y / args.charsize_y; - - DEBUG_PRINTF("Output size: %u x %u\n", size_x, size_y); - //Allocate character sotrage - image_monochrome = malloc(sizeof(*image_monochrome) * size_x); - for (int i = 0; i < size_x; i++) - image_monochrome[i] = malloc(sizeof(image_monochrome[i]) * size_y); + bitmap_shrink ( &bitmap, &shrunk_bitmap, args.charsize_x, args.charsize_y ); + bitmap_convert_monochrome ( &shrunk_bitmap, &monochrome_bitmap ); - //Allocate color storage if color enabled - if(args.color) { - col_buff = malloc(sizeof(*col_buff) * size_x); - for (int i = 0; i < size_x; i++) - col_buff[i] = malloc(sizeof(col_buff[i]) * size_y); + if( args.dynamic_range ) { + brightness_min = monochrome_bitmap.monochrome_minimum_brightness; + brightness_max = monochrome_bitmap.monochrome_maximum_brightness; + DEBUG_PRINTF("Dynamic Range: Brightness Values: Min: %u Max: %u\n", brightness_min, brightness_max); } - //Nest thine Lööps - //Very not optimal Variable names!!!!!!!!!!!!! - // - //For every size_x * size_y block: calculate average values of pixel blocks - for(unsigned int x = 0; x < size_x; x++) { - for(unsigned int y = 0; y < size_y; y++) { - /* Luminance for every pixel */ - uint8_t brightness [ args.charsize_x ][ args.charsize_y ]; - /* Color for every Pixel */ - uint8_t color_list[ 3 ][ args.charsize_x * args.charsize_y ]; //RGB Values of Pixels, used for averaging - unsigned int color_list_counter = 0; - - /* Iterate through pixel block, save brightness and color if set */ - for(unsigned int row_c = 0; row_c < args.charsize_y; row_c++) { - unsigned int row = y * args.charsize_y + row_c; //Actual position in Bitmap - - for(unsigned int col_c = 0; col_c < args.charsize_x; col_c++) { - unsigned int col = x * args.charsize_x + col_c; //Actual position in bitmap - - brightness[col_c][row_c] = rgb_luminance( - bitmap.R[col][row], - bitmap.G[col][row], - bitmap.B[col][row]); - - if(args.color) { - color_list[0][color_list_counter] = bitmap.R[col][row]; - color_list[1][color_list_counter] = bitmap.G[col][row]; - color_list[2][color_list_counter] = bitmap.B[col][row]; - color_list_counter++; - }//if - }//for col_c - }//for row_c - - /* Calculate average brightness in pixel block */ - image_monochrome[x][y] = avg(args.charsize_x * args.charsize_y, *brightness); - - /* Calculate average color in pixel block */ - if(args.color) { - if(args.use_whitespace) - col_buff[x][y] = calc_bg_col_ansi( - (uint8_t)avg(args.charsize_x * args.charsize_y, color_list[0]), - (uint8_t)avg(args.charsize_x * args.charsize_y, color_list[1]), - (uint8_t)avg(args.charsize_x * args.charsize_y, color_list[2])); - else - col_buff[x][y] = calc_col_ansi( - (uint8_t)avg(args.charsize_x * args.charsize_y, color_list[0]), - (uint8_t)avg(args.charsize_x * args.charsize_y, color_list[1]), - (uint8_t)avg(args.charsize_x * args.charsize_y, color_list[2])); - } // if args.color - - /* Save min and max brightness values for dynamic range */ - if((uint8_t)image_monochrome[x][y] < brightness_min) - brightness_min = image_monochrome[x][y]; - if((uint8_t)image_monochrome[x][y] > brightness_max) - brightness_max = image_monochrome[x][y]; - }//for y - }//for x - - /* Apply Default Colors */ if(args.color) printf("\e[0m"); - - if(! args.dynamic_range) { - brightness_min = 0; - brightness_max = 255; - } else { - DEBUG_PRINTF("Dynamic Range: Brightness Values: Min: %u Max: %u\n", brightness_min, brightness_max); - } /* Print the buffer */ - for(int y = 0; y