diff --git a/tests/make_png/bitmap.c b/tests/make_png/bitmap.c index f00618457..0f7278c06 100644 --- a/tests/make_png/bitmap.c +++ b/tests/make_png/bitmap.c @@ -1,5 +1,8 @@ #include "bitmap.h" +/* Functions to generate MurmurHash3 values of the bitmap image */ +/*data with a constant as the seed */ + HASH_128 * Generate_Hash_x64_128( FT_Bitmap * bitmap, HASH_128 * murmur) { @@ -12,7 +15,7 @@ HASH_128 * Generate_Hash_x64_128( FT_Bitmap * bitmap, return murmur; } - +/*Not used*/ HASH_128 * Generate_Hash_x86_128( FT_Bitmap * bitmap, HASH_128 * murmur) { @@ -25,7 +28,7 @@ HASH_128 * Generate_Hash_x86_128( FT_Bitmap * bitmap, return murmur; } - +/*Not used*/ HASH_32 * Generate_Hash_x86_32( FT_Bitmap * bitmap, HASH_32 * murmur) { @@ -39,117 +42,17 @@ HASH_32 * Generate_Hash_x86_32( FT_Bitmap * bitmap, return murmur; } +/* This function takes in the IMAGE data and returns the pointer */ +/* to the pixel at co-ordinates (x,y). This is used to access the */ +/* pixel data */ + PIXEL * Pixel_At (IMAGE * bitmap, int x, int y) { return bitmap->pixels + bitmap->width * y + x; } - -int Generate_PNG (IMAGE *bitmap, - const char *path, - int render_mode) -{ - FILE * fp; - png_structp png_ptr = NULL; - png_infop info_ptr = NULL; - - size_t x, y; - png_byte ** row_pointers = NULL; - - int status = -1; - - int pixel_size = 4; - int depth = 8; - - fp = fopen (path, "wb"); - if (! fp) { - goto fopen_failed; - } - - png_ptr = png_create_write_struct ( PNG_LIBPNG_VER_STRING, - NULL, - NULL, - NULL); - if (png_ptr == NULL) { - goto png_create_write_struct_failed; - } - - info_ptr = png_create_info_struct (png_ptr); - if (info_ptr == NULL) { - goto png_create_info_struct_failed; - } - - if (setjmp (png_jmpbuf (png_ptr))) { - goto png_failure; - } - - png_set_IHDR (png_ptr, - info_ptr, - bitmap->width, - bitmap->height, - depth, - PNG_COLOR_TYPE_RGBA, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); - - row_pointers = png_malloc ( png_ptr, - bitmap->height * sizeof (png_byte *)); - for (y = 0; y < bitmap->height; y++) { - - png_byte *row = - png_malloc(png_ptr, sizeof(uint8_t) * bitmap->width * pixel_size); - row_pointers[y] = row; - - for (x = 0; x < bitmap->width; x++) { - - PIXEL * pixel = Pixel_At (bitmap, x, y); - - if (render_mode == 3 || render_mode == 5) - { - *row++ = pixel->blue; - *row++ = pixel->green; - *row++ = pixel->red; - *row++ = pixel->alpha; - continue; - } - - *row++ = pixel->red; - *row++ = pixel->green; - *row++ = pixel->blue; - *row++ = pixel->alpha; - } - } - - png_init_io ( png_ptr, - fp); - - png_set_rows (png_ptr, - info_ptr, - row_pointers); - - png_write_png ( png_ptr, - info_ptr, - PNG_TRANSFORM_IDENTITY, - NULL); - - status = 0; - - for (y = 0; y < bitmap->height; y++) { - png_free (png_ptr, row_pointers[y]); - } - png_free (png_ptr, row_pointers); - - free (bitmap->pixels); - - png_failure: - png_create_info_struct_failed: - png_destroy_write_struct (&png_ptr, &info_ptr); - png_create_write_struct_failed: - fclose (fp); - fopen_failed: - return status; -} +/* Here we take the FT_Bitmap structure and make an IMAGE structure */ +/* with pixel data from the FT_Bitmap buffer */ void Make_PNG(FT_Bitmap* bitmap,IMAGE* fruit,int i,int render_mode){ @@ -161,26 +64,29 @@ void Make_PNG(FT_Bitmap* bitmap,IMAGE* fruit,int i,int render_mode){ switch(render_mode){ - case 0 : fruit->width = bitmap->width; /* MONO and GRAY */ + case 0 : fruit->width = bitmap->width; /* MONO */ fruit->height = bitmap->rows; - + /* Allocate Memory to the IMAGE structure as per the */ + /* dimensions of the FT_Bitmap image*/ fruit->pixels = calloc ( fruit->width * fruit->height, sizeof (PIXEL)); for (y = 0; y < fruit->height; y++) { for (x = 0; x < fruit->width; x++) { - + /* Access pixel by co-ordinates */ PIXEL * pixel = Pixel_At ( fruit, x, y); p = (y * bitmap->pitch ) + x; value = bitmap->buffer[p]; - + /* If there is some colour, make it white */ + /* else, make it black */ if ( value != 0x00 ){ value = 0xff; }else{ value = 0x00; } - + /* Invert the colours to make the background white*/ + /* and the character black */ pixel->red = 255- value; pixel->green = 255- value; pixel->blue = 255- value; @@ -188,7 +94,7 @@ void Make_PNG(FT_Bitmap* bitmap,IMAGE* fruit,int i,int render_mode){ } } break; - case 1 : fruit->width = bitmap->width; /* MONO and GRAY */ + case 1 : fruit->width = bitmap->width; /* GRAY */ fruit->height = bitmap->rows; fruit->pixels = calloc ( fruit->width * fruit->height, @@ -200,8 +106,9 @@ void Make_PNG(FT_Bitmap* bitmap,IMAGE* fruit,int i,int render_mode){ PIXEL * pixel = Pixel_At ( fruit, x, y); p = (y * bitmap->pitch ) + x; + /* Access the image data from the buffer */ value = bitmap->buffer[p]; - + /* R=G=B for Grayscale images */ pixel->red = 255- value; pixel->green = 255- value; pixel->blue = 255- value; @@ -210,6 +117,12 @@ void Make_PNG(FT_Bitmap* bitmap,IMAGE* fruit,int i,int render_mode){ } break; +/********************************************************************/ +/* FT_Bitmap has 'width' three times the size of glyph in case of */ +/* LCD rendering i.e. three adjacent values in bitmap buffer row */ +/* correspond to one RGB triplet. Accessing the buffer accordingly */ +/* and filling the RGB values of the IMAGE structure */ +/********************************************************************/ case 2 : case 3 : fruit->width = bitmap->width / 3; /* LCD */ fruit->height = bitmap->rows; @@ -238,7 +151,12 @@ void Make_PNG(FT_Bitmap* bitmap,IMAGE* fruit,int i,int render_mode){ } } break; - +/********************************************************************/ +/* FT_Bitmap has 'height' three times the size of glyph in case of */ +/* LCD_v rendering i.e. three adjacent values in bitmap buffer */ +/* column correspond to one RGB triplet. Accessing the buffer */ +/* accordingly and filling the RGB values of the IMAGE structure */ +/********************************************************************/ case 4 : case 5 : fruit->width = bitmap->width; /* LCD_V */ fruit->height = bitmap->rows / 3; @@ -274,167 +192,123 @@ void Make_PNG(FT_Bitmap* bitmap,IMAGE* fruit,int i,int render_mode){ } } -void Read_PNG(char *filename, IMAGE * after_effect) { - - int width, height, x, y; - png_bytep *row_pointers; - - FILE *fp = fopen(filename, "rb"); - - png_structp png = png_create_read_struct( PNG_LIBPNG_VER_STRING, - NULL, - NULL, - NULL); - if(!png) abort(); - - png_infop info = png_create_info_struct(png); - if(!info) abort(); - - if(setjmp(png_jmpbuf(png))) abort(); - - png_init_io(png, fp); - - png_set_user_limits(png, 0x7fffffffL, 0x7fffffffL); - - png_read_info(png, info); +/********************************************************************/ +/* This function generates the PNG file taking the IMAGE structure */ +/* , path to the file and the render_mode. ( Using libpng ) */ +/* 32-bit RGBA images are generated. Each channel is 8-bit with */ +/* alpha channel set to 255. Transparency can be set accordingly */ +/********************************************************************/ +int Generate_PNG (IMAGE *bitmap, + const char *path, + int render_mode) +{ + FILE * fp; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; - width = png_get_image_width(png, info); - height = png_get_image_height(png, info); + size_t x, y; + png_byte ** row_pointers = NULL; - after_effect->width = width; - after_effect->height = height; + int status = -1; - row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height); - for( y = 0; y < height; y++) { - row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png,info)); + int pixel_size = 4; /* Each pixel is 4-byte */ + int depth = 8; /* Each colour is 8-bit*/ + + fp = fopen (path, "wb"); + if (! fp) { + goto fopen_failed; } - png_read_image(png, row_pointers); - - after_effect->pixels = - (PIXEL*) malloc( width * height * sizeof(PIXEL)); - - for( y = 0; y < height; y++) { - - png_bytep row = row_pointers[y]; - - for( x = 0; x < width; x++ ) { - - png_bytep px = &(row[x * 4]); - - PIXEL * pixel = Pixel_At ( after_effect, x, y); - - pixel->red = px[0]; - pixel->green = px[1]; - pixel->blue = px[2]; - pixel->alpha = px[3]; - } + png_ptr = png_create_write_struct ( PNG_LIBPNG_VER_STRING, + NULL, + NULL, + NULL); + if (png_ptr == NULL) { + goto png_create_write_struct_failed; + } + + info_ptr = png_create_info_struct (png_ptr); + if (info_ptr == NULL) { + goto png_create_info_struct_failed; } - fclose(fp); -} - -int Add_effect(IMAGE* base, IMAGE* test, IMAGE* out, int Effect_ID) -{ - int pixel_diff = 0; - int x,y; + if (setjmp (png_jmpbuf (png_ptr))) { + goto png_failure; + } - out->width = base->width; - out->height = base->height; - out->pixels = - (PIXEL*)malloc(base->width * base->height * sizeof(PIXEL)); + png_set_IHDR (png_ptr, + info_ptr, + bitmap->width, + bitmap->height, + depth, + PNG_COLOR_TYPE_RGBA, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); - for( y = 0; y < base->height; y++) { - for( x = 0; x < base->width; x++ ) { + row_pointers = png_malloc ( png_ptr, + bitmap->height * sizeof (png_byte *)); - PIXEL * pixel_base = Pixel_At ( base, x, y); - PIXEL * pixel_test = Pixel_At ( test, x, y); - PIXEL * pixel_out = Pixel_At ( out, x, y); + for (y = 0; y < bitmap->height; y++) { - if (Effect_ID == 1) - { - if (pixel_base->red == 255 && - pixel_base->green == 255 && - pixel_base->blue == 255 && - pixel_base->alpha == 255 ) - { - pixel_out->red = 255; - pixel_out->green = 255; - pixel_out->blue = 255; - pixel_out->alpha = 255; - }else{ - pixel_out->red = 127; - pixel_out->green = 127; - pixel_out->blue = 127; - pixel_out->alpha = 255; - } - } + png_byte *row = + png_malloc(png_ptr, sizeof(uint8_t) * bitmap->width * pixel_size); + row_pointers[y] = row; - if (pixel_base->red != pixel_test->red || - pixel_base->green != pixel_test->green || - pixel_base->blue != pixel_test->blue || - pixel_base->alpha != pixel_test->alpha ) - { - pixel_out->red = 255; - pixel_out->green = 0; - pixel_out->blue = 0; - pixel_out->alpha = 255; + for (x = 0; x < bitmap->width; x++) { - pixel_diff++; + PIXEL * pixel = Pixel_At (bitmap, x, y); - }else{ - if (Effect_ID == 2) - { - pixel_out->red = pixel_base->red; - pixel_out->green = pixel_base->green; - pixel_out->blue = pixel_base->blue; - pixel_out->alpha = pixel_base->alpha; + if (render_mode == 3 || render_mode == 5) + { /* For BGRA images */ + *row++ = pixel->blue; + *row++ = pixel->green; + *row++ = pixel->red; + *row++ = pixel->alpha; + continue; } - } + /* For RGBA images */ + *row++ = pixel->red; + *row++ = pixel->green; + *row++ = pixel->blue; + *row++ = pixel->alpha; } - } - return pixel_diff; -} - -void Stitch(IMAGE* left, IMAGE* right, IMAGE* result){ - - int x, y; + } - result->width = left->width + right->width; - result->height = MAX(left->height, right->height); + png_init_io ( png_ptr, + fp); - result->pixels = - (PIXEL*)calloc(result->width * result->height, sizeof(PIXEL)); + png_set_rows (png_ptr, + info_ptr, + row_pointers); - for ( y = 0; y < left->height; ++y) - { - for ( x = 0; x < left->width; ++x) - { - PIXEL * pixel_left = Pixel_At ( left, x, y); - PIXEL * pixel_result = Pixel_At ( result, x, y); + png_write_png ( png_ptr, + info_ptr, + PNG_TRANSFORM_IDENTITY, + NULL); - pixel_result->red = pixel_left->red; - pixel_result->green = pixel_left->green; - pixel_result->blue = pixel_left->blue; - pixel_result->alpha = pixel_left->alpha; - } + status = 0; + + for (y = 0; y < bitmap->height; y++) { + png_free (png_ptr, row_pointers[y]); } + png_free (png_ptr, row_pointers); + + free (bitmap->pixels); - for ( y = 0; y < right->height; ++y) - { - for ( x = left->width; x < result->width; ++x) - { - PIXEL * pixel_right = Pixel_At ( right, x - left->width, y); - PIXEL * pixel_result = Pixel_At ( result, x, y); - - pixel_result->red = pixel_right->red; - pixel_result->green = pixel_right->green; - pixel_result->blue = pixel_right->blue; - pixel_result->alpha = pixel_right->alpha; - } - } + png_failure: + png_create_info_struct_failed: + png_destroy_write_struct (&png_ptr, &info_ptr); + png_create_write_struct_failed: + fclose (fp); + fopen_failed: + return status; } +/********************************************************************/ +/* Compare the MurmurHash3 values ( x64_128 bit implemented ) */ +/* Returns 1 if they are different and 0 if identical. */ +/********************************************************************/ int Compare_Hash(HASH_128* hash_b, HASH_128* hash_t){ if (hash_b->hash[0] != hash_t->hash[0] || hash_b->hash[1] != hash_t->hash[1] || @@ -446,17 +320,11 @@ int Compare_Hash(HASH_128* hash_b, HASH_128* hash_t){ return 0; } -void Print_Row( FILE* fp, int index, char* name, int diff ) -{ - fprintf(fp, - "\n\ - %04d\n\ - %s\n\ - %04d\n\ - \n\ - \n", index, name, diff, name); -} - +/********************************************************************/ +/* Returns the index of the first-column to have a coloured pixel. */ +/* 'Coloured' means the pixel isn't in the background */ +/* Background Colour RGB = ( 255,255,255 ) */ +/********************************************************************/ int First_Column(IMAGE* input){ int x, y; @@ -481,6 +349,7 @@ int First_Column(IMAGE* input){ return input->width; } +/* Returns the index of the first-row to have a coloured pixel. */ int First_Row(IMAGE* input){ int x, y; @@ -505,8 +374,16 @@ int First_Row(IMAGE* input){ return input->height; } +/********************************************************************/ +/* The following two functions takes two IMAGES with different */ +/* dimensions and aligns the two images based on the first pixel */ +/* that isn't in the background i.e. RGB != ( 255,255,255 ). */ +/* The first argument is the one which has smaller height/width. */ +/* Columns/Rows are appended to the smaller image to match the */ +/* dimensions. */ +/********************************************************************/ IMAGE* Append_Columns(IMAGE* small, IMAGE* big){ - + /* small->width < big->width */ int x, y; IMAGE* result = (IMAGE*)malloc(sizeof(IMAGE)); @@ -518,12 +395,12 @@ IMAGE* Append_Columns(IMAGE* small, IMAGE* big){ int first_col = First_Column(big); - for ( x = 0; x < first_col; ++x) + for ( x = 0; x < first_col; ++x) /* Filling White columns */ { for ( y = 0; y < result->height; ++y) { PIXEL * pixel_result = Pixel_At ( result, x, y); - + /* Filling White columns */ pixel_result->red = 255; pixel_result->green = 255; pixel_result->blue = 255; @@ -531,13 +408,13 @@ IMAGE* Append_Columns(IMAGE* small, IMAGE* big){ } } - for ( y = 0; y < result->height; ++y) + for ( y = 0; y < result->height; ++y) { for ( x = first_col; x < first_col + small->width; ++x) { PIXEL * pixel_small = Pixel_At ( small, (x - first_col), y); PIXEL * pixel_result = Pixel_At ( result, x, y); - + /* Putting the original IMAGE data */ pixel_result->red = pixel_small->red; pixel_result->green = pixel_small->green; pixel_result->blue = pixel_small->blue; @@ -550,7 +427,7 @@ IMAGE* Append_Columns(IMAGE* small, IMAGE* big){ for ( y = 0; y < result->height; ++y) { PIXEL * pixel_result = Pixel_At ( result, x, y); - + /* Filling White columns */ pixel_result->red = 255; pixel_result->green = 255; pixel_result->blue = 255; @@ -562,7 +439,7 @@ IMAGE* Append_Columns(IMAGE* small, IMAGE* big){ } IMAGE* Append_Rows(IMAGE* small, IMAGE* big){ - + /* small->height < big->height */ int x, y; IMAGE* result = (IMAGE*)malloc(sizeof(IMAGE)); @@ -576,10 +453,10 @@ IMAGE* Append_Rows(IMAGE* small, IMAGE* big){ for ( y = 0; y < first_row; ++y) { - for ( x = 0; x < result->width; ++x) + for ( x = 0; x < result->width; ++x) { PIXEL * pixel_result = Pixel_At ( result, x, y); - + /* Filling White rows */ pixel_result->red = 255; pixel_result->green = 255; pixel_result->blue = 255; @@ -590,10 +467,10 @@ IMAGE* Append_Rows(IMAGE* small, IMAGE* big){ for ( y = first_row; y < first_row + small->height; ++y) { for ( x = 0; x < result->width; ++x) - { + { PIXEL * pixel_small = Pixel_At ( small, x, y - first_row); PIXEL * pixel_result = Pixel_At ( result, x, y); - + /* Putting the original IMAGE data */ pixel_result->red = pixel_small->red; pixel_result->green = pixel_small->green; pixel_result->blue = pixel_small->blue; @@ -606,7 +483,7 @@ IMAGE* Append_Rows(IMAGE* small, IMAGE* big){ for ( x = 0; x < result->width; ++x) { PIXEL * pixel_result = Pixel_At ( result, x, y); - + /* Filling White rows */ pixel_result->red = 255; pixel_result->green = 255; pixel_result->blue = 255; @@ -617,6 +494,146 @@ IMAGE* Append_Rows(IMAGE* small, IMAGE* big){ return result; } +/********************************************************************/ +/* This fuction visually highlights the differences between the two */ +/* images generated for the same glyph. There are two effects each */ +/* given an Effect_ID. */ +/* This function generates a new IMAGE structure after comparing and*/ +/* adding the desired effect. */ +/* */ +/* Effect_ID =1 means that the differences in pixels are highlighted*/ +/* and the pixels that are same are in GRAY (RGB = (128,128,128)) */ +/* */ +/* Effect_ID =2 means that the differences in pixels are highlighted*/ +/* over the 'base' version's rendered image */ +/* */ +/* Highlighting is done in RED colour i.e. RGB=( 255, 0, 0) for */ +/* mono, grayscale and RGB-LCD displays and for BGR-LCD displays */ +/* is is done in BLUE colour i.e. RGB = ( 0, 0, 255). */ +/********************************************************************/ +int Add_effect(IMAGE* base, IMAGE* test, IMAGE* out, int Effect_ID) +{ + int pixel_diff = 0; + int x,y; + /* new IMAGE */ + out->width = base->width; + out->height = base->height; + out->pixels = + (PIXEL*)malloc(base->width * base->height * sizeof(PIXEL)); + + for( y = 0; y < base->height; y++) { + for( x = 0; x < base->width; x++ ) { + + PIXEL * pixel_base = Pixel_At ( base, x, y); + PIXEL * pixel_test = Pixel_At ( test, x, y); + PIXEL * pixel_out = Pixel_At ( out, x, y); + + if (Effect_ID == 1) + { /* If colour is white */ + if (pixel_base->red == 255 && + pixel_base->green == 255 && + pixel_base->blue == 255 && + pixel_base->alpha == 255 ) + { + pixel_out->red = 255; /* White*/ + pixel_out->green = 255; + pixel_out->blue = 255; + pixel_out->alpha = 255; + }else{ + pixel_out->red = 127; /* Gray */ + pixel_out->green = 127; + pixel_out->blue = 127; + pixel_out->alpha = 255; + } + } + /* if colour is different*/ + if (pixel_base->red != pixel_test->red || + pixel_base->green != pixel_test->green || + pixel_base->blue != pixel_test->blue || + pixel_base->alpha != pixel_test->alpha ) + { /* Highlighting pixels */ + pixel_out->red = 255; + pixel_out->green = 0; + pixel_out->blue = 0; + pixel_out->alpha = 255; + + pixel_diff++; + + }else{ + if (Effect_ID == 2) + { + pixel_out->red = pixel_base->red; + pixel_out->green = pixel_base->green; + pixel_out->blue = pixel_base->blue; + pixel_out->alpha = pixel_base->alpha; + } + } + } + } + return pixel_diff; +} + +/********************************************************************/ +/* This function takes two IMAGE structures and stitches the images */ +/* horizontally to make one IMAGE. */ +/* i.e. ( result->width = left->width + right->width ) */ +/* The first argument forms the left part of the image and the */ +/* second forms the right part. */ +/* This returns the pointer to the stitched image */ +/********************************************************************/ + +void Stitch(IMAGE* left, IMAGE* right, IMAGE* result){ + + int x, y; + + result->width = left->width + right->width; + result->height = MAX(left->height, right->height); + + result->pixels = + (PIXEL*)calloc(result->width * result->height, sizeof(PIXEL)); + + for ( y = 0; y < left->height; ++y) + { + for ( x = 0; x < left->width; ++x) + { + PIXEL * pixel_left = Pixel_At ( left, x, y); + PIXEL * pixel_result = Pixel_At ( result, x, y); + /* Filling Left part of the image*/ + pixel_result->red = pixel_left->red; + pixel_result->green = pixel_left->green; + pixel_result->blue = pixel_left->blue; + pixel_result->alpha = pixel_left->alpha; + } + } + + for ( y = 0; y < right->height; ++y) + { + for ( x = left->width; x < result->width; ++x) + { + PIXEL * pixel_right = Pixel_At ( right, x - left->width, y); + PIXEL * pixel_result = Pixel_At ( result, x, y); + /* Filling right part of the image*/ + pixel_result->red = pixel_right->red; + pixel_result->green = pixel_right->green; + pixel_result->blue = pixel_right->blue; + pixel_result->alpha = pixel_right->alpha; + } + } +} + +/* This prints a row to the HTML file for the list-view page. */ +void Print_Row( FILE* fp, int index, char* name, int diff ) +{ + fprintf(fp, + "\n\ + %04d\n\ + %s\n\ + %04d\n\ + \n\ + \n", index, name, diff, name); +} + +/* To calculate the Difference-Metric used in the list-view page */ int Image_Diff( IMAGE* base, IMAGE* test){ int diff = 0; @@ -632,3 +649,4 @@ int Image_Diff( IMAGE* base, IMAGE* test){ return diff; } +/* For more information on the list-view page, go to README */