From f15b53eea4b7054826f79836e207751e86ba1cec Mon Sep 17 00:00:00 2001 From: Jonas Gunz Date: Sat, 4 May 2019 00:57:44 +0200 Subject: Reorganised folder structure --- src/bitmap.c | 160 ++++++++++++++++++++++++++++++++++++++ src/bitmap.h | 70 +++++++++++++++++ src/character.c | 10 +++ src/character.h | 12 +++ src/color.c | 74 ++++++++++++++++++ src/color.h | 33 ++++++++ src/m.c | 22 ++++++ src/m.h | 14 ++++ src/main.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 630 insertions(+) create mode 100644 src/bitmap.c create mode 100644 src/bitmap.h create mode 100644 src/character.c create mode 100644 src/character.h create mode 100644 src/color.c create mode 100644 src/color.h create mode 100644 src/m.c create mode 100644 src/m.h create mode 100644 src/main.c (limited to 'src') diff --git a/src/bitmap.c b/src/bitmap.c new file mode 100644 index 0000000..bb88b46 --- /dev/null +++ b/src/bitmap.c @@ -0,0 +1,160 @@ +#include "bitmap.h" + +uint32_t bitmap_flip_byte(unsigned char* _v, int _c) +{ + uint32_t ret = 0; + uint32_t counter = (_c-1) * 8; + + for(int i = 0; i < _c; i++) + { + ret |= (uint32_t)(_v[i] << (counter)); + counter -= 8; + } + + return ret; +}//flip + +struct bitmap_pixel_data bitmap_read(char *_file) +{ + struct bitmap_pixel_data ret; + struct bitmap_file_header header; + + ret.R = ret.G = ret.B = NULL; + ret.error = 1; + + FILE *bitmap = fopen(_file,"rb"); + + if(!bitmap) + return ret; + + header = bitmap_read_file_header(bitmap); + + if(header.error) + return ret; + + if(header.biBitCount != 24) + return ret; + + if(header.biCompression != 0) + return ret; + + ret = bitmap_read_pixel_data(bitmap, header); + + + free(header.tables); + fclose(bitmap); + + ret.error = 0; + return ret; +} + +struct bitmap_file_header bitmap_read_file_header(FILE *_file) +{ + struct bitmap_file_header ret; + unsigned char fileheader[_HEADER_SIZE]; + uint32_t read_counter = 0; + + ret.error = 1; + + size_t tt = fread((void*)&fileheader, sizeof(char), _HEADER_SIZE, _file); + read_counter += _HEADER_SIZE; + + if(!tt) + return ret; + + //Copy file header + ret.bfType = (uint16_t) bitmap_flip_byte(&fileheader[BF_TYPE], sizeof(ret.bfType)); + + if(ret.bfType != (uint16_t)IDENTIFIER) + return ret; + + ret.bfSize = (uint32_t) bitmap_flip_byte(&fileheader[BF_SIZE], sizeof(ret.bfSize)); + ret.bfOffBits = *(uint32_t*) &fileheader[BF_OFF_BITS]; + ret.biSize = *(uint32_t*) &fileheader[BI_SIZE]; + ret.biWidth = *(int32_t*) &fileheader[BI_WIDTH]; + ret.biHeight = *(int32_t*) &fileheader[BI_HEIGHT]; + ret.biBitCount = *(uint16_t*) &fileheader[BI_BIT_COUNT]; + ret.biCompression = (uint32_t) bitmap_flip_byte(&fileheader[BI_COMPRESSION], sizeof(ret.biCompression)); + ret.biSizeImage = *(uint32_t*) &fileheader[BI_SIZE_IMAGE]; + ret.biClrUsed = (uint32_t) bitmap_flip_byte(&fileheader[BI_CLR_USED], sizeof(ret.biClrUsed)); + ret.biClrImportant = (uint32_t) bitmap_flip_byte(&fileheader[BI_CLR_IMPORTANT], sizeof(ret.biClrImportant)); + + + //Read to start of Pixel block + //This block contains Colormasks and Colortables. + ret.tablesc = ret.bfOffBits - read_counter; + ret.tables = malloc(sizeof(char)* ret.tablesc); + fread(ret.tables, sizeof(char), ret.tablesc, _file); + ////////// + + ret.error = 0; + return ret; +} + +struct bitmap_pixel_data bitmap_read_pixel_data(FILE *_file, struct bitmap_file_header _header) +{ + uint32_t **bitmap_buff; + + struct bitmap_pixel_data ret; + + uint32_t row_size = _header.biWidth * 3; + while(row_size%4) + row_size++; + + ret.x = _header.biWidth; + ret.y = _header.biHeight < 0 ? -_header.biHeight: _header.biHeight; + + //If biHeight > 0 Data starts with last row!! + + //Allocate 2D array + //!! + //bitmap_buff indeces are flipped!! [y][x]!!!!! + bitmap_buff = malloc(sizeof(*bitmap_buff) * _header.biHeight); + for(int i = 0; i < ret.y; i++) + { + bitmap_buff[i] = malloc(sizeof(*bitmap_buff[i]) * _header.biWidth); + } + + //Copy Bitmap into bitmap_buff + for(int row = 0; row < _header.biHeight; row++) + { + //printf("Row %i\n", row); + //fread(bitmap_buff[row], sizeof(char), row_size, bitmap); + for(int col = 0; col < _header.biWidth; col++) + fread(&bitmap_buff[row][col], 1, 3, _file); + + for(int i = 0; i < row_size - (_header.biWidth * 3); i++) //read excess NULL-Bytes + fgetc(_file); + } + + ret.x = _header.biWidth; + ret.y = _header.biHeight < 0 ? -_header.biHeight: _header.biHeight; + + ret.R = malloc(sizeof(*ret.R) * ret.x); + ret.G = malloc(sizeof(*ret.G) * ret.x); + ret.B = malloc(sizeof(*ret.B) * ret.x); + for(int i = 0; i < ret.x; i++) + { + ret.R[i] = malloc(sizeof(*ret.R[i]) * ret.y); + ret.G[i] = malloc(sizeof(*ret.G[i]) * ret.y); + ret.B[i] = malloc(sizeof(*ret.B[i]) * ret.y); + } + + for(int y = 0; y < ret.y; y++) + { + for(int x = 0; x < ret.x; x++) + { + int row = _header.biHeight > 0 ? (ret.y - 1) - y : y; + + ret.R[x][y] = (bitmap_buff[row][x] & 0xff0000)>>16; + ret.G[x][y] = (bitmap_buff[row][x] & 0x00ff00)>>8; + ret.B[x][y] = (bitmap_buff[row][x] & 0x0000ff); + } + } + + for(int i = 0; i < ret.y; i++) + free(bitmap_buff[i]); + free(bitmap_buff); + + return ret; +} diff --git a/src/bitmap.h b/src/bitmap.h new file mode 100644 index 0000000..d222ffb --- /dev/null +++ b/src/bitmap.h @@ -0,0 +1,70 @@ +#ifndef _BITMAP_H_ +#define _BITMAP_H_ + +#include +#include +#include + +#define _HEADER_SIZE 54 //Fileheader + infoheader +#define IDENTIFIER 0x424d //BM BitMap identifier + +//Address Definitions +#define BF_TYPE 0x00 +#define BF_SIZE 0x02 +#define BF_OFF_BITS 0x0a + +#define BI_SIZE 0x0e +#define BI_WIDTH 0x12 +#define BI_HEIGHT 0x16 +#define BI_BIT_COUNT 0x1c +#define BI_COMPRESSION 0x1e +#define BI_SIZE_IMAGE 0x22 +#define BI_CLR_USED 0x2e +#define BI_CLR_IMPORTANT 0x32 + +#define R(x) (0xff0000 & x) >> 16 +#define G(x) (0x00ff00 & x) >> 8 +#define B(x) (0x0000ff & x) + +struct bitmap_file_header +{ + uint8_t error; + + uint16_t bfType; + uint32_t bfSize; + uint32_t bfOffBits; + + uint32_t biSize; + int32_t biWidth; + int32_t biHeight; + uint16_t biBitCount; + uint32_t biCompression; + uint32_t biSizeImage; + uint32_t biClrUsed; + uint32_t biClrImportant; + + unsigned char *tables; + uint32_t tablesc; +}; + +struct bitmap_pixel_data +{ + unsigned int x,y; + uint8_t **R; + uint8_t **G; + uint8_t **B; + + uint8_t error; +}; + + +uint32_t bitmap_flip_byte(unsigned char* _v, int _c); + +struct bitmap_pixel_data bitmap_read(char *_file); + +struct bitmap_file_header bitmap_read_file_header(FILE *_file); + +struct bitmap_pixel_data bitmap_read_pixel_data(FILE *_file, struct bitmap_file_header _header); + + +#endif /* end of include guard: _BITMAP_H_ */ diff --git a/src/character.c b/src/character.c new file mode 100644 index 0000000..658f0be --- /dev/null +++ b/src/character.c @@ -0,0 +1,10 @@ +#include "character.h" + +const char character_luminance_map [] = {' ', ' ', '.', ',', '`', '-', '~', '"', '*', ':', ';', '<', '!', '/', '?', '%', '&', '=', '$', '#'}; +//const char map[] = {' ', '`', '.', ',', ':', ';', '\"', '+', '#', '@'}; + +char calc_char(uint8_t _c , uint8_t _min, uint8_t _max) +{ + float c = (float)(_c) / (_max - _min); + return character_luminance_map [(int)((sizeof(character_luminance_map)-1) * (c))]; +} diff --git a/src/character.h b/src/character.h new file mode 100644 index 0000000..7e17cd7 --- /dev/null +++ b/src/character.h @@ -0,0 +1,12 @@ +#ifndef _CHARACTER_H_ +#define _CHARACTER_H_ + +#include + +//Both maps produce very different results +const char character_luminance_map [] ; + +//Select Char based on 1B brightness Value +char calc_char(uint8_t _c, uint8_t _min, uint8_t _max); + +#endif //_CHARACTER_H_ diff --git a/src/color.c b/src/color.c new file mode 100644 index 0000000..d822d56 --- /dev/null +++ b/src/color.c @@ -0,0 +1,74 @@ +#include "color.h" + +struct console_color colors[] = { //Standard VGA colors + {0, 0, 0, "30"}, //Black + {170, 0, 0, "31"}, //red + {0, 170, 0, "32"}, //Green + {170, 85, 0, "33"}, //Brown + {0, 0, 170, "34"}, //blue + {170, 0, 170, "35"}, //Magenta + {0, 170, 170, "36"}, //Cyan + {170,170,170, "37"}, //Grey + {85,85,85, "30;1"}, + {255,85,85, "31;1"}, + {85,255,85, "32;1"}, + {255,255,85, "33;1"}, + {85,85,255, "34;1"}, + {255,85,255, "35;1"}, + {85,255,255, "36;1"}, + {255, 255, 255, "37;1"} +}; + +uint8_t rgb_avg(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; + + return ret; +} + +char* calc_col(uint8_t R, uint8_t G, uint8_t B) +{ + unsigned int nearest_num = 0; + uint8_t a2[3]; + a2[0] = colors[0].R; + a2[1] = colors[0].G; + a2[2] = colors[0].B; + + uint8_t a1[] = {R,G,B}; + + //Normalize the color + //Does not really work all that well + /*while(a1[0] < 255 && a1[1] < 255 && a1[2] < 255) + { + a1[0]++; + a1[1]++; + a1[2]++; + }*/ + + float nearest_val = distance( a1, a2 ); + + for( unsigned int i = 1; i < _COLORS_SIZE; i++) + { + a2[0] = colors[i].R; + a2[1] = colors[i].G; + a2[2] = colors[i].B; + + float dist = distance(a1, a2); + if(dist < nearest_val){ + nearest_num = i; + nearest_val = dist; + } + } + return colors[ nearest_num ].no; +} +char* calc_col_ansi(uint8_t R, uint8_t G, uint8_t B) +{ + 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 ); + + return c; +} diff --git a/src/color.h b/src/color.h new file mode 100644 index 0000000..10d376e --- /dev/null +++ b/src/color.h @@ -0,0 +1,33 @@ +#ifndef _COLOR_H_ +#define _COLOR_H_ + +#include +#include +#include +#include + +#include "m.h" + +#define _COLORS_SIZE 16u + +struct console_color +{ + uint8_t R; + uint8_t G; + uint8_t B; + + char *no; +}; + +struct console_color colors[ _COLORS_SIZE ]; + +//Calculate luminance +//Order LSB first: BGR +uint8_t rgb_avg(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); + +#endif //_COLOR_H_ diff --git a/src/m.c b/src/m.c new file mode 100644 index 0000000..b1401f1 --- /dev/null +++ b/src/m.c @@ -0,0 +1,22 @@ +#include "m.h" + +uint8_t avg(int argc, uint8_t *argv) +{ + uint8_t ret = 0; + uint64_t sum = 0; + + for(int i = 0; i < argc; i++) + sum += (uint64_t)argv[i]; + + ret = (char)(sum / argc); + + return ret; +}//avg + + +float distance(uint8_t _1[3], uint8_t _2[3]) +{ + return fabs( sqrt( pow((double)_2[0] - (double)_1[0], 2) + + pow((double)_2[1] - (double)_1[1], 2) + + pow((double)_2[2] - (double)_1[2], 2) ) ); +} diff --git a/src/m.h b/src/m.h new file mode 100644 index 0000000..25aff9e --- /dev/null +++ b/src/m.h @@ -0,0 +1,14 @@ +#ifndef _M_H_ +#define _M_H_ + +#include +#include + + +//Calculate average +uint8_t avg(int argc, uint8_t *argv); + +//Distance of 2 3d vectors +float distance(uint8_t _1[3], uint8_t _2[3]); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..b8bf074 --- /dev/null +++ b/src/main.c @@ -0,0 +1,235 @@ +#include +#include +#include +#include +#include + +#include "bitmap.h" +#include "character.h" +#include "m.h" +#include "color.h" + +#ifdef _DEBUG +#warning "Compiling with DEBUG" +#define DEBUG_PRINTF(...) { printf(__VA_ARGS__); } +#else +#define DEBUG_PRINTF(...) { } +#endif + +#define CHAR_SIZE_X 2 //How many pixels should form one ASCII char? +#define CHAR_SIZE_Y (2 * CHAR_SIZE_X) + +struct prog_param +{ + char *filename; + unsigned int charsize_x; + unsigned int charsize_y; + uint8_t color; +}; + +struct prog_param parse_args(int argc, char *argv[]); + +void print_help( void ); + +int main(int argc, char *argv[]) +{ + struct prog_param args = parse_args(argc, argv); + + //Stores a luminance array + uint8_t **ascii_buff; + //Stores a color array + char* **col_buff; + + uint8_t b_max = 0x00; + uint8_t b_min = 0xff; + + struct bitmap_pixel_data bitmap; + + bitmap = bitmap_read(args.filename); + + if(bitmap.error) { + printf("Error reading file\n"); + return 1; + } + + //x and y size of ASCII-image + unsigned int size_x,size_y; + 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); + + //Where the chars are stored + ascii_buff = malloc(sizeof(*ascii_buff) * size_x); + for (int i = 0; i < size_x; i++) + ascii_buff[i] = malloc(sizeof(ascii_buff[i]) * size_y); + + //Where the color is stored, if activated + 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); + } + + //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++) { + uint8_t brightness [ args.charsize_x ][ args.charsize_y ]; //Average brightness of every pixel + uint8_t cc[ 3 ][ args.charsize_x * args.charsize_y ]; //RGB Values of Pixels + unsigned int cc_counter = 0; + + //Iterate through Pixel block + 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_avg( + bitmap.R[col][row], + bitmap.G[col][row], + bitmap.B[col][row]); + + if(args.color) { + cc[0][cc_counter] = bitmap.R[col][row]; + cc[1][cc_counter] = bitmap.G[col][row]; + cc[2][cc_counter] = bitmap.B[col][row]; + cc_counter++; + }//if + }//for col_c + }//for row_c + + ascii_buff[x][y] = avg(args.charsize_x * args.charsize_y, *brightness); + if(args.color == 1) { + col_buff[x][y] = calc_col( + (uint8_t)avg(args.charsize_x * args.charsize_y, cc[0]), + (uint8_t)avg(args.charsize_x * args.charsize_y, cc[1]), + (uint8_t)avg(args.charsize_x * args.charsize_y, cc[2])); + } else if(args.color == 2) { + col_buff[x][y] = calc_col_ansi( + (uint8_t)avg(args.charsize_x * args.charsize_y, cc[0]), + (uint8_t)avg(args.charsize_x * args.charsize_y, cc[1]), + (uint8_t)avg(args.charsize_x * args.charsize_y, cc[2])); + } + + if((uint8_t)ascii_buff[x][y] < b_min) + b_min = ascii_buff[x][y]; + if((uint8_t)ascii_buff[x][y] > b_max) + b_max = ascii_buff[x][y]; + }//for y + }//for x + + DEBUG_PRINTF("Brightness Values: Min: %u Max: %u\n", b_min, b_max); + + if(args.color) + printf("\e[0m");//Default colors + + //Print buffer + for(int y = 0; y