├── .gitignore ├── screenshot.png ├── src ├── dynalloc.h ├── dynalloc.c ├── character.h ├── character.c ├── bitmap.h ├── main.c └── bitmap.c ├── packaging └── pkgbuild │ └── PKGBUILD ├── Readme.md ├── Makefile └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.bmp 3 | *.txt 4 | build/* 5 | obj/* 6 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kompetenzbolzen/AsciiMap/HEAD/screenshot.png -------------------------------------------------------------------------------- /src/dynalloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/dynalloc.h 3 | * (c) 2020 Jonas Gunz 4 | * License: MIT 5 | */ 6 | #pragma once 7 | 8 | #include 9 | 10 | void** dynalloc_2d_array ( unsigned int _x, unsigned int _y, unsigned int _sizeof ); 11 | 12 | void dynalloc_2d_array_free ( unsigned int _x, unsigned int _y, void** _array ); 13 | -------------------------------------------------------------------------------- /src/dynalloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * src/dynalloc.c 3 | * (c) 2020 Jonas Gunz 4 | * License: MIT 5 | */ 6 | #include "dynalloc.h" 7 | 8 | void** dynalloc_2d_array ( unsigned int _x, unsigned int _y, unsigned int _sizeof ) { 9 | void** ret = NULL; 10 | 11 | ret = malloc ( _x * sizeof ( void* ) ); 12 | for ( int i = 0; i < _x; i++ ) 13 | ret[i] = malloc ( _y * _sizeof ); 14 | 15 | return ret; 16 | } 17 | 18 | void dynalloc_2d_array_free ( unsigned int _x, unsigned int _y, void** _array ) { 19 | for ( int i = 0; i < _x; i++ ) 20 | free ( _array[i] ); 21 | free(_array); 22 | } 23 | -------------------------------------------------------------------------------- /src/character.h: -------------------------------------------------------------------------------- 1 | #ifndef _CHARACTER_H_ 2 | #define _CHARACTER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define COLOR_FG 1 10 | #define COLOR_BG 2 11 | 12 | //Both maps produce very different results 13 | extern const char *default_character_map; 14 | 15 | //Select Char based on 1B brightness Value. 16 | //if _custom_map == NULL default map is used 17 | char calc_char(uint8_t _c, uint8_t _min, uint8_t _max, char *_custom_map); 18 | 19 | char *calc_col_ansi(uint8_t R, uint8_t G, uint8_t B, uint8_t _mode); 20 | 21 | #endif //_CHARACTER_H_ 22 | -------------------------------------------------------------------------------- /packaging/pkgbuild/PKGBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Joe User 2 | 3 | pkgname=asciimap 4 | pkgver=$(date +%y%m%d) 5 | pkgrel=1 6 | pkgdesc="Create ASCII art from Bitmap Images" 7 | arch=('i686' 'x86_64') 8 | url="https://github.com/kompetenzbolzen/AsciiMap" 9 | license=('MIT') 10 | groups=() 11 | depends=('glibc') 12 | makedepends=('clang') 13 | optdepends=() 14 | source=("git+https://github.com/kompetenzbolzen/AsciiMap") 15 | md5sums=('SKIP') 16 | 17 | build() { 18 | cd $srcdir/AsciiMap 19 | make 20 | } 21 | 22 | package() { 23 | cd $srcdir/AsciiMap 24 | mkdir -p $pkgdir/usr/bin 25 | make PREFIX="$pkgdir/usr/" install 26 | } 27 | -------------------------------------------------------------------------------- /src/character.c: -------------------------------------------------------------------------------- 1 | #include "character.h" 2 | 3 | const char *default_character_map=" .,-~\"*:;` average n x 2n pixels to one char 10 | 11 | * `-s ` print n characters wide to be able to fit in terminal window, independent from picture size. 12 | 13 | * `-i` use STDIN as file input 14 | 15 | * `-w` print whitespaces with background color instead of ASCII chars. Only useful with -c 16 | 17 | * `-d` activate dynamic brightness range 18 | 19 | * `-m ` use a custom ASCII character palette. From darkest to brightest 20 | 21 | To use with other image types, use imagemagick: `magick convert -depth 24 bmp:- | asciimap -i` 22 | 23 | License: MIT 24 | 25 | ![alt text](screenshot.png "Screenshot") 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = clang 2 | CFLAGS = -Wall 3 | LDFLAGS = -lm 4 | SOURCEDIR = src 5 | BUILDDIR = build 6 | OBJDIR = $(BUILDDIR)/obj 7 | OUTPUT = asciimap 8 | PREFIX = / 9 | 10 | FILE = 022.bmp 11 | SRCS = $(wildcard $(SOURCEDIR)/*.c) 12 | OBJT = $(SRCS:.c=.o) 13 | OBJ = $(OBJT:$(SOURCEDIR)/%=$(OBJDIR)/%) 14 | 15 | .PHONY: build 16 | build: dir $(OBJ) 17 | @echo [LINK] $(OBJ) 18 | @$(CC) $(CFLAGS) -o $(BUILDDIR)/$(OUTPUT) $(OBJ) $(LDFLAGS) 19 | 20 | dir: 21 | @mkdir -p $(OBJDIR) 22 | @mkdir -p $(BUILDDIR) 23 | 24 | debug: CFLAGS+= -g -D _DEBUG 25 | debug: build; 26 | 27 | gdb: debug 28 | gdb $(BUILDDIR)/$(OUTPUT) 29 | 30 | $(OBJDIR)/%.o: $(SOURCEDIR)/%.c 31 | @echo [ CC ] $< 32 | @$(CC) $(CFLAGS) -c $< -o $@ 33 | 34 | all: clean build 35 | 36 | .PHONY: clean 37 | clean: 38 | rm -Rdf $(OBJDIR) 39 | rm -Rdf $(BUILDDIR) 40 | 41 | run: build 42 | $(BUILDDIR)/$(OUTPUT) $(FILE) 43 | 44 | install: build 45 | @strip $(BUILDDIR)/$(OUTPUT) 46 | @cp $(BUILDDIR)/$(OUTPUT) $(PREFIX)/bin/$(OUTPUT) 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Jonas Gunz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/bitmap.h: -------------------------------------------------------------------------------- 1 | /* * src/bitmap.h 2 | * (c) 2020 Jonas Gunz 3 | * License: MIT 4 | */ 5 | 6 | #ifndef _BITMAP_H_ 7 | #define _BITMAP_H_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "dynalloc.h" 17 | 18 | #define _HEADER_SIZE 54 //Fileheader + infoheader 19 | #define IDENTIFIER 0x424d //BM BitMap identifier 20 | 21 | //Address Definitions 22 | #define BF_TYPE 0x00 23 | #define BF_SIZE 0x02 24 | #define BF_OFF_BITS 0x0a 25 | 26 | #define BI_SIZE 0x0e 27 | #define BI_WIDTH 0x12 28 | #define BI_HEIGHT 0x16 29 | #define BI_BIT_COUNT 0x1c 30 | #define BI_COMPRESSION 0x1e 31 | #define BI_SIZE_IMAGE 0x22 32 | #define BI_CLR_USED 0x2e 33 | #define BI_CLR_IMPORTANT 0x32 34 | 35 | #define R(x) (0xff0000 & x) >> 16 36 | #define G(x) (0x00ff00 & x) >> 8 37 | #define B(x) (0x0000ff & x) 38 | 39 | #define BITMAP_MONOCHROME 0x01 40 | 41 | struct bitmap_file_header { 42 | uint8_t error; 43 | 44 | uint16_t bfType; 45 | uint32_t bfSize; 46 | uint32_t bfOffBits; 47 | 48 | uint32_t biSize; 49 | int32_t biWidth; 50 | int32_t biHeight; 51 | uint16_t biBitCount; 52 | uint32_t biCompression; 53 | uint32_t biSizeImage; 54 | uint32_t biClrUsed; 55 | uint32_t biClrImportant; 56 | 57 | unsigned char *tables; 58 | uint32_t tablesc; 59 | }; 60 | 61 | struct bitmap_image { 62 | unsigned int x,y; 63 | 64 | uint8_t **R; 65 | uint8_t **G; 66 | uint8_t **B; 67 | 68 | uint8_t tags; 69 | uint8_t monochrome_maximum_brightness; 70 | uint8_t monochrome_minimum_brightness; 71 | }; 72 | 73 | int bitmap_read ( char *_file, struct bitmap_image *_bitmap ); 74 | 75 | int bitmap_copy ( struct bitmap_image *_input, struct bitmap_image *_output ); 76 | 77 | int bitmap_convert_monochrome ( struct bitmap_image *_input, struct bitmap_image *_output ); 78 | 79 | int bitmap_shrink ( struct bitmap_image *_input, struct bitmap_image *_output, unsigned int _factor_x, unsigned int _factor_y ); 80 | 81 | int bitmap_fit_to_width ( struct bitmap_image *_input, struct bitmap_image *_output, unsigned int _width ); 82 | 83 | char* bitmap_strerror( int _error ); 84 | 85 | #endif /* end of include guard: _BITMAP_H_ */ 86 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * src/main.c 3 | * (c) 2020 Jonas Gunz 4 | * License: MIT 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "bitmap.h" 14 | #include "character.h" 15 | 16 | #ifdef _DEBUG 17 | #warning "Compiling with DEBUG" 18 | #define DEBUG_PRINTF(...) { printf(__VA_ARGS__); } 19 | #else 20 | #define DEBUG_PRINTF(...) { } 21 | #endif 22 | 23 | #define CHAR_SIZE_X 2 //How many pixels should form one ASCII char? 24 | #define CHAR_SIZE_Y (2 * CHAR_SIZE_X) 25 | 26 | struct prog_param { 27 | char *filename; 28 | char *character_map; 29 | unsigned int charsize_x; 30 | unsigned int charsize_y; 31 | uint8_t color; 32 | uint8_t use_stdin; 33 | uint8_t use_whitespace; 34 | uint8_t fit_width; 35 | uint8_t dynamic_range; 36 | }; 37 | 38 | struct prog_param parse_args(int argc, char *argv[]); 39 | 40 | void print_help( char* _argv_0 ); 41 | 42 | int main(int argc, char *argv[]) { 43 | struct prog_param args = parse_args(argc, argv); 44 | 45 | struct bitmap_image bitmap; 46 | struct bitmap_image shrunk_bitmap; 47 | struct bitmap_image monochrome_bitmap; 48 | 49 | uint8_t brightness_min = 0x00; 50 | uint8_t brightness_max = 0xff; 51 | 52 | int ret = bitmap_read(args.filename, &bitmap); 53 | if ( ret ) { 54 | printf( "%s\n", bitmap_strerror(ret) ); 55 | return ret; 56 | } 57 | 58 | if(args.fit_width > 0) { 59 | args.charsize_x = (unsigned int)((float)bitmap.x / (float)args.fit_width); 60 | args.charsize_y = (unsigned int)(((float)bitmap.y / (float)bitmap.x) * (float)args.charsize_x * 2); 61 | } 62 | 63 | bitmap_shrink ( &bitmap, &shrunk_bitmap, args.charsize_x, args.charsize_y ); 64 | bitmap_convert_monochrome ( &shrunk_bitmap, &monochrome_bitmap ); 65 | 66 | if( args.dynamic_range ) { 67 | brightness_min = monochrome_bitmap.monochrome_minimum_brightness; 68 | brightness_max = monochrome_bitmap.monochrome_maximum_brightness; 69 | DEBUG_PRINTF("Dynamic Range: Brightness Values: Min: %u Max: %u\n", brightness_min, brightness_max); 70 | } 71 | 72 | /* Apply Default Colors */ 73 | if(args.color) 74 | printf("\e[0m"); 75 | 76 | /* Print the buffer */ 77 | uint8_t color_mode = args.use_whitespace ? COLOR_BG : COLOR_FG; 78 | for(int y = 0; y < monochrome_bitmap.y; y++) { 79 | for(int x = 0; x < monochrome_bitmap.x; x++) { 80 | char c = args.use_whitespace ? ' ' : calc_char(monochrome_bitmap.R[x][y], brightness_min, brightness_max, args.character_map); 81 | 82 | if(args.color) 83 | printf("%s", calc_col_ansi( 84 | shrunk_bitmap.R[x][y], 85 | shrunk_bitmap.G[x][y], 86 | shrunk_bitmap.B[x][y], 87 | color_mode ) ); 88 | printf("%c", c); 89 | } 90 | printf("\e[0m\n"); 91 | } 92 | 93 | /* Apply Default Colors */ 94 | if(args.color) 95 | printf("\e[0m"); 96 | 97 | DEBUG_PRINTF("Finished!\n"); 98 | 99 | return 0; 100 | }//main 101 | 102 | struct prog_param parse_args(int argc, char *argv[]) { 103 | struct prog_param ret; 104 | 105 | memset(&ret, 0, sizeof ret); 106 | 107 | ret.charsize_x = CHAR_SIZE_X; 108 | 109 | for (int i = 1; i < argc; i++) { 110 | if(argv[i][0] == '-') { 111 | int icpy = i; 112 | for(int o = 1; o < strlen(argv[icpy]); o++) { 113 | switch(argv[icpy][o]) { 114 | case 'h': 115 | print_help( argv[0] ); 116 | exit(0); 117 | break; 118 | case 'x': 119 | ret.charsize_x = atoi(argv[++i]); 120 | break; 121 | case 'y': 122 | ret.charsize_y = atoi(argv[++i]); 123 | break; 124 | case 'c': 125 | ret.color = 1; 126 | break; 127 | case 'i': 128 | ret.use_stdin = 1; 129 | break; 130 | case 'w': 131 | ret.use_whitespace = 1; 132 | break; 133 | case 's': 134 | ret.fit_width = atoi(argv[++i]); 135 | break; 136 | case 'd': 137 | ret.dynamic_range = 1; 138 | break; 139 | case 'm': 140 | ret.character_map = argv[++i]; 141 | break; 142 | default: 143 | printf("Unrecognized Option '%c'\n", argv[icpy][o]); 144 | print_help( argv[0] ); 145 | exit(1); 146 | };//switch 147 | }//for o 148 | }//if 149 | else if(ret.filename == NULL && !ret.use_stdin ) { 150 | ret.filename = argv[i]; 151 | } else { 152 | printf("Wrong number of arguments\n"); 153 | print_help( argv[0] ); 154 | exit(1); 155 | } 156 | }//for i 157 | 158 | if(ret.filename == NULL && !ret.use_stdin ) 159 | { 160 | printf("No input file. Use -i to read from stdin\n"); 161 | print_help( argv[0] ); 162 | exit(1); 163 | } 164 | 165 | if(ret.use_whitespace && !ret.color) { 166 | printf("use -w only with -c\n"); 167 | print_help( argv[0] ); 168 | exit(1); 169 | } 170 | 171 | if(!ret.charsize_y) 172 | ret.charsize_y = 2 * ret.charsize_x; 173 | 174 | return ret; 175 | } 176 | 177 | void print_help( char* _argv_0 ) { 178 | printf( 179 | "ASCIIMap\n" 180 | "(c) 2019 Jonas Gunz, github.com/kompetenzbolzen/AsciiMap\n" 181 | "ASCIIMap prints a ASCII representation of a bitmap image\n\n" 182 | "Usage: %s [OPTIONS] FILENAME\n" 183 | "Options:\n" 184 | " -h: Print this help message\n" 185 | " -x VAL: set the width of block wich makes up one character. Default: %i\n" 186 | " -y VAL: set the height of block wich makes up one character. Default: 2*x\n" 187 | " -c: Print in ANSI color mode. Default: OFF\n" 188 | " -i: Read from STDIN instead of file.\n" 189 | " -w: print only whitespaces with background color\n" 190 | " -d: Dynamic brightness range\n" 191 | " -m PALETTE: specify custom character palette from darkest to brightest\n", 192 | _argv_0, 193 | CHAR_SIZE_X 194 | ); 195 | } 196 | 197 | -------------------------------------------------------------------------------- /src/bitmap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bitmap.c 3 | * (c) 2020 Jonas Gunz 4 | * License: MIT 5 | */ 6 | 7 | #include "bitmap.h" 8 | 9 | static const int bitmap_errors_cnt = 5; 10 | static const char* bitmap_errors[] = { 11 | "OK.", 12 | "Error opening file.", // Use errno instead 13 | "Invalid or corrupted file.", 14 | "Unsupported bit depth.", 15 | "Compression not supported." 16 | }; 17 | 18 | static struct bitmap_file_header bitmap_read_file_header(FILE *_file); 19 | 20 | static struct bitmap_image bitmap_read_pixel_data(FILE *_file, struct bitmap_file_header _header); 21 | 22 | static uint32_t bitmap_flip_byte(unsigned char* _v, int _c); 23 | 24 | static uint8_t bitmap_rgb_luminance(uint8_t R, uint8_t G, uint8_t B); 25 | 26 | static uint32_t bitmap_flip_byte(unsigned char* _v, int _c) 27 | { 28 | uint32_t ret = 0; 29 | uint32_t counter = (_c-1) * 8; 30 | 31 | for(int i = 0; i < _c; i++) { 32 | ret |= (uint32_t)(_v[i] << (counter)); 33 | counter -= 8; 34 | } 35 | 36 | return ret; 37 | }//flip 38 | 39 | int bitmap_read(char *_file, struct bitmap_image *_bitmap) 40 | { 41 | if ( !_bitmap ) 42 | return 5; 43 | 44 | struct bitmap_file_header header; 45 | _bitmap->tags = 0x00; 46 | 47 | FILE *input_file; 48 | input_file = _file ? fopen(_file,"rb") : stdin; 49 | 50 | if(!input_file) 51 | return 1; 52 | 53 | header = bitmap_read_file_header(input_file); 54 | 55 | if(header.error) 56 | return 2; 57 | 58 | if(header.biBitCount != 24) 59 | return 3; 60 | 61 | if(header.biCompression != 0) 62 | return 4; 63 | 64 | *_bitmap = bitmap_read_pixel_data(input_file, header); 65 | 66 | free(header.tables); 67 | fclose(input_file); 68 | 69 | return 0; 70 | } 71 | 72 | static struct bitmap_file_header bitmap_read_file_header(FILE *_file) { 73 | struct bitmap_file_header ret; 74 | unsigned char fileheader[_HEADER_SIZE]; 75 | uint32_t read_counter = 0; 76 | 77 | ret.error = 1; 78 | 79 | size_t tt = fread((void*)&fileheader, sizeof(char), _HEADER_SIZE, _file); 80 | read_counter += _HEADER_SIZE; 81 | 82 | if(!tt) 83 | return ret; 84 | 85 | //Copy file header 86 | ret.bfType = (uint16_t) bitmap_flip_byte(&fileheader[BF_TYPE], sizeof(ret.bfType)); 87 | 88 | if(ret.bfType != (uint16_t)IDENTIFIER) 89 | return ret; 90 | 91 | ret.bfSize = (uint32_t) bitmap_flip_byte(&fileheader[BF_SIZE], sizeof(ret.bfSize)); 92 | ret.bfOffBits = *(uint32_t*) &fileheader[BF_OFF_BITS]; 93 | ret.biSize = *(uint32_t*) &fileheader[BI_SIZE]; 94 | ret.biWidth = *(int32_t*) &fileheader[BI_WIDTH]; 95 | ret.biHeight = *(int32_t*) &fileheader[BI_HEIGHT]; 96 | ret.biBitCount = *(uint16_t*) &fileheader[BI_BIT_COUNT]; 97 | ret.biCompression = (uint32_t) bitmap_flip_byte(&fileheader[BI_COMPRESSION], sizeof(ret.biCompression)); 98 | ret.biSizeImage = *(uint32_t*) &fileheader[BI_SIZE_IMAGE]; 99 | ret.biClrUsed = (uint32_t) bitmap_flip_byte(&fileheader[BI_CLR_USED], sizeof(ret.biClrUsed)); 100 | ret.biClrImportant = (uint32_t) bitmap_flip_byte(&fileheader[BI_CLR_IMPORTANT], sizeof(ret.biClrImportant)); 101 | 102 | 103 | //Read to start of Pixel block 104 | //This block contains Colormasks and Colortables. 105 | ret.tablesc = ret.bfOffBits - read_counter; 106 | ret.tables = malloc(sizeof(char)* ret.tablesc); 107 | fread(ret.tables, sizeof(char), ret.tablesc, _file); 108 | ////////// 109 | 110 | ret.error = 0; 111 | return ret; 112 | } 113 | 114 | static struct bitmap_image bitmap_read_pixel_data(FILE *_file, struct bitmap_file_header _header) { 115 | uint32_t **bitmap_buff; 116 | 117 | struct bitmap_image ret; 118 | 119 | uint32_t row_size = _header.biWidth * 3; 120 | while(row_size%4) 121 | row_size++; 122 | 123 | ret.x = _header.biWidth; 124 | ret.y = _header.biHeight < 0 ? -_header.biHeight: _header.biHeight; 125 | 126 | //If biHeight > 0 Data starts with last row!! 127 | 128 | //Allocate 2D array 129 | //!! 130 | //bitmap_buff indeces are flipped!! [y][x]!!!!! 131 | bitmap_buff = malloc(sizeof(*bitmap_buff) * _header.biHeight); 132 | for(int i = 0; i < ret.y; i++) 133 | { 134 | bitmap_buff[i] = malloc(sizeof(*bitmap_buff[i]) * _header.biWidth); 135 | } 136 | 137 | //Copy Bitmap into bitmap_buff 138 | for(int row = 0; row < _header.biHeight; row++) { 139 | //printf("Row %i\n", row); 140 | //fread(bitmap_buff[row], sizeof(char), row_size, bitmap); 141 | for(int col = 0; col < _header.biWidth; col++) 142 | fread(&bitmap_buff[row][col], 1, 3, _file); 143 | 144 | for(int i = 0; i < row_size - (_header.biWidth * 3); i++) //read excess NULL-Bytes 145 | fgetc(_file); 146 | } 147 | 148 | ret.x = _header.biWidth; 149 | ret.y = _header.biHeight < 0 ? -_header.biHeight: _header.biHeight; 150 | 151 | ret.R = malloc(sizeof(*ret.R) * ret.x); 152 | ret.G = malloc(sizeof(*ret.G) * ret.x); 153 | ret.B = malloc(sizeof(*ret.B) * ret.x); 154 | for(int i = 0; i < ret.x; i++) { 155 | ret.R[i] = malloc(sizeof(*ret.R[i]) * ret.y); 156 | ret.G[i] = malloc(sizeof(*ret.G[i]) * ret.y); 157 | ret.B[i] = malloc(sizeof(*ret.B[i]) * ret.y); 158 | } 159 | 160 | for(int y = 0; y < ret.y; y++) { 161 | for(int x = 0; x < ret.x; x++) { 162 | int row = _header.biHeight > 0 ? (ret.y - 1) - y : y; 163 | 164 | ret.R[x][y] = (bitmap_buff[row][x] & 0xff0000)>>16; 165 | ret.G[x][y] = (bitmap_buff[row][x] & 0x00ff00)>>8; 166 | ret.B[x][y] = (bitmap_buff[row][x] & 0x0000ff); 167 | } 168 | } 169 | 170 | for(int i = 0; i < ret.y; i++) 171 | free(bitmap_buff[i]); 172 | free(bitmap_buff); 173 | 174 | return ret; 175 | } 176 | 177 | int bitmap_copy ( struct bitmap_image *_input, struct bitmap_image *_output ) { 178 | // TODO implement 179 | return 1; 180 | } 181 | 182 | int bitmap_convert_monochrome ( struct bitmap_image *_input, struct bitmap_image *_output ) { 183 | if ( !_input || !_output ) 184 | return 1; 185 | 186 | uint8_t min_brightness = 0xff; 187 | uint8_t max_brightness = 0x00; 188 | uint8_t **monochrome_bitmap = (uint8_t**) dynalloc_2d_array( _input->x, _input->y, sizeof(uint8_t)); 189 | 190 | for ( unsigned int x = 0; x < _input->x; x++ ) { 191 | for ( unsigned int y = 0; y < _input->y; y++ ) { 192 | monochrome_bitmap[x][y] = bitmap_rgb_luminance ( 193 | _input->R[x][y], 194 | _input->G[x][y], 195 | _input->B[x][y] ); 196 | 197 | if (monochrome_bitmap[x][y] > max_brightness) 198 | max_brightness = monochrome_bitmap[x][y]; 199 | if (monochrome_bitmap[x][y] < min_brightness) 200 | min_brightness = monochrome_bitmap[x][y]; 201 | } 202 | } 203 | 204 | _output->R = _output->G = _output->B = monochrome_bitmap; 205 | _output->tags = BITMAP_MONOCHROME; 206 | _output->x = _input->x; 207 | _output->y = _input->y; 208 | _output->monochrome_maximum_brightness = max_brightness; 209 | _output->monochrome_minimum_brightness = min_brightness; 210 | 211 | return 0; 212 | } 213 | 214 | int bitmap_shrink ( struct bitmap_image *_input, struct bitmap_image *_output, unsigned int _factor_x, unsigned int _factor_y ) { 215 | if ( !_input || !_output ) 216 | return 1; 217 | 218 | /* New Size */ 219 | _output->x = _input->x / _factor_x; 220 | _output->y = _input->y / _factor_y; 221 | _output->tags = _input->tags; 222 | 223 | /* Allocate memory */ 224 | if ( _input->tags & BITMAP_MONOCHROME ) { 225 | _output->R = _output->G = _output->B = 226 | (uint8_t**) dynalloc_2d_array ( _output->x, _output->y, sizeof ( uint8_t) ); 227 | } else { 228 | _output->R = (uint8_t**) dynalloc_2d_array ( _output->x, _output->y, sizeof ( uint8_t) ); 229 | _output->G = (uint8_t**) dynalloc_2d_array ( _output->x, _output->y, sizeof ( uint8_t) ); 230 | _output->B = (uint8_t**) dynalloc_2d_array ( _output->x, _output->y, sizeof ( uint8_t) ); 231 | } 232 | 233 | for(unsigned int x = 0; x < _output->x; x++) { 234 | for(unsigned int y = 0; y < _output->y; y++) { 235 | // Unsafe for > 2^56 Pixels (Hopefully unrealistic) 236 | uint64_t color_sum[3] = {0,0,0}; 237 | const uint64_t pixel_count = _factor_x * _factor_y; 238 | 239 | // Average Pixel block 240 | for(unsigned int row_c = 0; row_c < _factor_y; row_c++) { 241 | unsigned int row = y * _factor_y + row_c; //Offset 242 | 243 | for(unsigned int col_c = 0; col_c < _factor_x; col_c++) { 244 | unsigned int col = x * _factor_x + col_c; //Offset 245 | 246 | color_sum[0] += (uint64_t) _input->R[col][row]; 247 | color_sum[1] += (uint64_t) _input->G[col][row]; 248 | color_sum[2] += (uint64_t) _input->B[col][row]; 249 | }//for col_c 250 | }//for row_c 251 | 252 | _output->R[x][y] = (uint8_t) (color_sum[0] / pixel_count); 253 | _output->G[x][y] = (uint8_t) (color_sum[1] / pixel_count); 254 | _output->B[x][y] = (uint8_t) (color_sum[2] / pixel_count); 255 | }//for y 256 | }//for x 257 | 258 | return 0; 259 | } 260 | 261 | int bitmap_fit_to_width ( struct bitmap_image *_input, struct bitmap_image *_output, unsigned int _width ) { 262 | unsigned int factor_x = (unsigned int)((float)_input->x / (float) _width ); 263 | unsigned int factor_y = (unsigned int)(((float)_input->y / (float)_input->x ) * (float) factor_x * 2); 264 | 265 | return bitmap_shrink ( _input, _output, factor_x, factor_y ); 266 | } 267 | 268 | static uint8_t bitmap_rgb_luminance(uint8_t R, uint8_t G, uint8_t B) { 269 | uint8_t ret; 270 | 271 | 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; 272 | 273 | return ret; 274 | } 275 | 276 | char* bitmap_strerror( int _error ) { 277 | if ( _error >= bitmap_errors_cnt || _error < 0) 278 | return "Unknown Error."; 279 | if ( _error == 1 ) 280 | return strerror(errno); 281 | 282 | return (char*) bitmap_errors[_error]; 283 | } 284 | --------------------------------------------------------------------------------