/*---------------------------------------------------------------------------- ** rgb_image.c ** ** **--------------------------------------------------------------------------- ** Copyright 2004 by CodeWeavers, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ** **--------------------------------------------------------------------------*/ #include #include #include #include #include #include "rgb_image.h" /*---------------------------------------------------------------------------- ** Initialize the pixel_format structure **--------------------------------------------------------------------------*/ void pixel_format_init(pixel_format *var) { var->r_mask = 0; var->g_mask = 0; var->b_mask = 0; var->r_count = 0; var->g_count = 0; var->b_count = 0; var->r_shift = -1; var->g_shift = -1; var->b_shift = -1; } /*---------------------------------------------------------------------------- ** Destroy the ximage structure and free the win_image structure **--------------------------------------------------------------------------*/ void win_image_destroy_ximage(win_image *var) { if(var->ximage != NULL) XDestroyImage(var->ximage); var->ximage = (XImage*) NULL; var->origin_x = 0; var->origin_y = 0; var->width = 0; var->height = 0; } /*---------------------------------------------------------------------------- ** Destroy the ximage structure and free the win_image structure **--------------------------------------------------------------------------*/ void win_image_destroy(win_image *var) { if(var != NULL) { win_image_destroy_ximage(var); free(var); var = NULL; } } /*---------------------------------------------------------------------------- ** Allocate and initialize memory for the win_image structure **--------------------------------------------------------------------------*/ win_image* win_image_init() { win_image *var; var = malloc(sizeof(win_image)); if(var == NULL) { fprintf(stderr,"Error: unable to allocate memory for win_image structure\n"); return(NULL); } var->ximage = (XImage *)NULL; pixel_format_init(&var->pformat); var->origin_x = 0; var->origin_y = 0; var->width = 0; var->height = 0; return(var); } /*---------------------------------------------------------------------------- ** Destroy the data memory allocated for the rgb_image **--------------------------------------------------------------------------*/ void rgb_image_destroy_data(rgb_image *var) { int x; /* free the columns of rgb */ for(x = 0; x < var->width; x++) free(var->data[x]); /* remember to free the row of pointers */ if(var->data != NULL) free(var->data); var->data = NULL; var->width = 0; var->height = 0; } /*---------------------------------------------------------------------------- ** Destroy the memory allocated for the rgb_image **--------------------------------------------------------------------------*/ void rgb_image_destroy(rgb_image *var) { if(var != NULL) { rgb_image_destroy_data(var); free(var); var = NULL; } } /*---------------------------------------------------------------------------- ** Allocate and initialize memory for the rgb_image structure **--------------------------------------------------------------------------*/ rgb_image* rgb_image_init() { rgb_image *var; var = malloc(sizeof(rgb_image)); if(var == NULL) { fprintf(stderr,"Error: unable to allocate memory for rgb_image structure\n"); return(NULL); } var->data = NULL; var->width = 0; var->height = 0; var->bit_depth = 0; return(var); } /*---------------------------------------------------------------------------- ** Allocate and initialize memory for the rgb_hist structure **--------------------------------------------------------------------------*/ rgb_hist* rgb_hist_init() { rgb_hist *var; int i; var = malloc(sizeof(rgb_hist)); if(var==NULL) { fprintf(stderr, "Error: unable to allocate memory for rgb_hist structure\n"); return(NULL); } for(i=0; i<256; i++) { var->r[i]=0; var->g[i]=0; var->b[i]=0; } var->total_count=0; return(var); } /*---------------------------------------------------------------------------- ** Destroy the memory allocated for the rgb_image **--------------------------------------------------------------------------*/ void rgb_hist_destroy(rgb_hist *var) { if(var != NULL) { free(var); var = NULL; } } /*---------------------------------------------------------------------------- ** Allocate the data array for the rgb_image w/given dimensions ** --if the correct mem size has already been allocated, do nothing and ** return success **--------------------------------------------------------------------------*/ int rgb_image_malloc(rgb_image *image, int width, int height) { int x; /*-------------------------------------------------------------------------- ** Make sure the dimensions passed are legitimate -- positive value **------------------------------------------------------------------------*/ if(width < 1 || height < 1) { fprintf(stderr,"Error: invalid dimensions [%d x %d] passed to rgb_image_malloc\n",width,height); return(1); } /*-------------------------------------------------------------------------- ** If the dimensions are the same, then return success, nothing to be done **------------------------------------------------------------------------*/ if(width == image->width && height == image->height) return(0); /*-------------------------------------------------------------------------- ** If the image already contains data, it needs to be destroyed **------------------------------------------------------------------------*/ if(image->data != NULL) rgb_image_destroy_data(image); /*-------------------------------------------------------------------------- ** Begin memory allocation -- allocate memory in columns s.t. it is easy ** to read coordinate values (ie. [x][y]) **------------------------------------------------------------------------*/ image->data = malloc(width * sizeof(rgb*)); if(image->data == NULL) { fprintf(stderr,"Unable to allocate memory for rgb_image struct\n"); return(1); } /*-------------------------------------------------------------------------- ** Allocate memory for each column **------------------------------------------------------------------------*/ for(x = 0; x < width; x++) { image->data[x] = NULL; image->data[x] = malloc(height * sizeof(rgb)); if(image->data[x] == NULL) { /*---------------------------------------------------------------------- ** Unable to allocate memory, make sure to clean-up the memory that has ** already been allocated **--------------------------------------------------------------------*/ image->width = x; rgb_image_destroy(image); fprintf(stderr,"Unable to allocate memory for rgb_image struct\n"); return(1); } } /*-------------------------------------------------------------------------- ** Set the image width and height before returning success **------------------------------------------------------------------------*/ image->width = width; image->height = height; //image->bit_depth = 8; return(0); } /*---------------------------------------------------------------------------- ** Convert an rgb_image to a png file. ** Return values: ** 0 - success ** 1 - bad png file -- not able to open ** 2 - bad memory allocation **--------------------------------------------------------------------------*/ int rgb_image_to_png(rgb_image *image, char *png_file) { FILE *fp; int x, y; int rc = 0; png_structp png_ptr = (png_structp)NULL; png_infop info_ptr = (png_infop)NULL; png_bytepp write_data = (png_bytepp)NULL; /*-------------------------------------------------------------------------- ** Open the png_file for writing **------------------------------------------------------------------------*/ fp = fopen(png_file, "wb"); if (!fp) { rc = ERR_PNG_FILE; goto ERREXIT; } /*-------------------------------------------------------------------------- ** Create the png write structures **------------------------------------------------------------------------*/ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL); if (!png_ptr) { rc = ERR_MALLOC; goto ERREXIT; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { rc = ERR_MALLOC; goto ERREXIT; } /*-------------------------------------------------------------------------- ** Set the callback jump buffer **------------------------------------------------------------------------*/ if (setjmp(png_jmpbuf(png_ptr))) { rc = ERR_MALLOC; goto ERREXIT; } /*-------------------------------------------------------------------------- ** Initialize the io structures **------------------------------------------------------------------------*/ png_init_io(png_ptr, fp); /*-------------------------------------------------------------------------- ** Set the image information **------------------------------------------------------------------------*/ png_set_IHDR(png_ptr, info_ptr, image->width, image->height, image->bit_depth, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /*-------------------------------------------------------------------------- ** Allocate memory for the write buffer **------------------------------------------------------------------------*/ write_data = (png_bytepp)malloc(image->height * sizeof(png_bytep)); if(!write_data) { rc = ERR_MALLOC; goto ERREXIT; } for(y=0; y < image->height; y++) { write_data[y] = (png_bytep)malloc(image->width * 3); if(!write_data[y]) { rc = ERR_MALLOC; goto ERREXIT; } } /*-------------------------------------------------------------------------- ** Move information from the rgb_image structure into the write buffer **------------------------------------------------------------------------*/ for(y=0; y < image->height; y++) { for(x=0; x < image->width; x++) { write_data[y][x*3] = image->data[x][y].r; write_data[y][(x*3)+1] = image->data[x][y].g; write_data[y][(x*3)+2] = image->data[x][y].b; } } /*-------------------------------------------------------------------------- ** Insert data into info_ptr and write the information to the file **------------------------------------------------------------------------*/ png_set_rows(png_ptr, info_ptr, write_data); png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); ERREXIT: for(y=0; y < image->height; y++) if(write_data[y]) free(write_data[y]); if(write_data) free(write_data); if(png_ptr && info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr); else if(png_ptr) png_destroy_write_struct(&png_ptr, (png_infopp)NULL); if(fp) fclose(fp); return(rc); } /*---------------------------------------------------------------------------- ** Combine two png images. attach_image will be to the left of main_image. ** The resultant image will be set to main_image. attach_image will be preserved. ** Return values: ** 0 - success ** 1 - failure **--------------------------------------------------------------------------*/ int rgb_image_attach(rgb_image **main_image, rgb_image **attach_image, int count) { rgb_image *tmp_image = NULL; rgb_image *tmain = *main_image; int width, height; int rc = 0; int i, j, c, separator, x, y; int attach_width = 0, attach_height = 0; tmp_image = rgb_image_init(); if(tmp_image == NULL) { fprintf(stderr,"Unable to allocate memory for rgb_image\n"); rc = 1; goto EXIT; } // set the offset for the main image separator = 2; // figure out the size needed for attachment portion for(i = 0; i < count; i++) { if(attach_height) attach_height += separator; attach_height += attach_image[i]->height; if(!attach_width || attach_image[i]->width > attach_width) attach_width = attach_image[i]->width; } // determine the height of the new image if(tmain->height > attach_height) height = tmain->height; else height = attach_height; height += separator*2; // determine the width of the new image width = attach_width + tmain->width + (separator*3); // allocate the memory for the new image if(rgb_image_malloc(tmp_image, width, height)) { rc = 1; goto EXIT; } // more writing done, but more sensible approach // clear out the image first for(i = 0; i < width; i++) { for(j = 0; j < height; j++) { tmp_image->data[i][j].r = 0; tmp_image->data[i][j].g = 0; tmp_image->data[i][j].b = 0; } } // write out the attached images x = separator; y = separator; for(c = 0; c < count; c++) { for(i = 0; i < attach_image[c]->width; i++) { for(j = 0; j < attach_image[c]->height; j++) { tmp_image->data[i+x][y+j].r = attach_image[c]->data[i][j].r; tmp_image->data[i+x][y+j].g = attach_image[c]->data[i][j].g; tmp_image->data[i+x][y+j].b = attach_image[c]->data[i][j].b; } } y += attach_image[c]->height + separator; } // write out the main image x = attach_width + (2*separator); y = separator; for(i = 0; i < tmain->width; i++) { for(j = 0; j < tmain->height; j++) { tmp_image->data[i+x][j+y].r = tmain->data[i][j].r; tmp_image->data[i+x][j+y].g = tmain->data[i][j].g; tmp_image->data[i+x][j+y].b = tmain->data[i][j].b; } } // draw the border // don't forget to set the bit depth for the new rgb_image // todo: make sure bit depth of two images are compatible tmp_image->bit_depth = 8; EXIT: if(tmp_image) { rgb_image_destroy(*main_image); *main_image = tmp_image; } return(rc); } /*---------------------------------------------------------------------------- ** Convert a png file to an rgb_image structure. ** Return values: ** 0 - success ** 1 - bad png file (either not able to open or bad format) ** 2 - bad memory allocation **--------------------------------------------------------------------------*/ int png_to_rgb_image(char *png_file, rgb_image *image) { FILE *fp; int read_num = 8, rc = SUCCESS; int width, height; int x,y; unsigned char header[read_num]; png_structp png_ptr = (png_structp)NULL; png_infop info_ptr = (png_infop)NULL; png_bytepp row_pointers; /*-------------------------------------------------------------------------- ** Make sure that png_file exists and that it is a png file **------------------------------------------------------------------------*/ fp = fopen(png_file, "rb"); if (!fp) { char *p = getenv("CXTEST_PICTURE_SEARCH_DIR"); if (p && strlen(p)) { char *q = malloc(strlen(p) + strlen(png_file) + 3); strcpy(q, p); if (*(q + strlen(q) - 1) != '/') strcat(q, "/"); strcat(q, png_file); fp = fopen(q, "rb"); free(q); } } if (!fp) { fprintf(stderr,"Error: unable to open file [%s]\n",png_file); rc = ERR_PNG_FILE; goto ERREXIT; } if(read_num != fread(header, 1, read_num, fp)) { fprintf(stderr,"Error: unable to read header from file [%s]\n",png_file); rc = ERR_PNG_FILE; goto ERREXIT; } if(png_sig_cmp(header, 0, read_num) != 0) { fprintf(stderr,"Error: [%s] is not a png formatted imgae file\n",png_file); rc = ERR_PNG_FILE; goto ERREXIT; } /*-------------------------------------------------------------------------- ** Initialize the png structures **------------------------------------------------------------------------*/ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL); if (!png_ptr) { fprintf(stderr,"Error: unable to create png read struct\n"); rc = ERR_MALLOC; goto ERREXIT; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { fprintf(stderr,"Error: unable to create png info struct\n"); rc = ERR_MALLOC; goto ERREXIT; } /*-------------------------------------------------------------------------- ** Initialize the IO structures **------------------------------------------------------------------------*/ png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, read_num); /*-------------------------------------------------------------------------- ** Read the png file and with appropriate transformations -- convert to ** 8 bit color depth and remove alpha component **------------------------------------------------------------------------*/ png_read_png(png_ptr, info_ptr, (PNG_TRANSFORM_STRIP_16|PNG_TRANSFORM_STRIP_ALPHA|PNG_TRANSFORM_PACKING), NULL); /*-------------------------------------------------------------------------- ** Get the height and width of the png image -- allocate appropriate memory ** for the rgb_image **------------------------------------------------------------------------*/ height = png_get_image_height(png_ptr, info_ptr); width = png_get_image_width(png_ptr, info_ptr); if(rgb_image_malloc(image, width, height)) { rc = ERR_MALLOC; goto ERREXIT; } /*-------------------------------------------------------------------------- ** Get the data row pointers and copy image into rgb_image -- png_get_rows ** is a high level function call, png takes care of malloc and free **------------------------------------------------------------------------*/ row_pointers = png_get_rows(png_ptr, info_ptr); for(y=0; y < height; y++) { for(x=0; x < width; x++) { image->data[x][y].r = row_pointers[y][x*3]; image->data[x][y].g = row_pointers[y][(x*3)+1]; image->data[x][y].b = row_pointers[y][(x*3)+2]; } } /*-------------------------------------------------------------------------- ** Set the bit_depth for the image **--------------------------------------------------------------------------*/ image->bit_depth = 8; ERREXIT: if(fp) fclose(fp); if(png_ptr && info_ptr) png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); else if(png_ptr) png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return(rc); } /*---------------------------------------------------------------------------- ** Set the pixel format for ximage ** precondition: win_image_init() has been called for w_image ** and w_image->ximage has been set (no longer null) **--------------------------------------------------------------------------*/ void win_image_set_pixel_format(win_image *w_image) { /*-------------------------------------------------------------------------- ** Initialize temp r, g, and b masks, to be used to determine the ** r, g, and b counts and shifts **------------------------------------------------------------------------*/ unsigned long tmp_rmask = w_image->ximage->red_mask; unsigned long tmp_gmask = w_image->ximage->green_mask; unsigned long tmp_bmask = w_image->ximage->blue_mask; int i; /*-------------------------------------------------------------------------- ** Figure out the shift and count for r, g, and b ** Find the Red shift and count **------------------------------------------------------------------------*/ for(i = 0; i < 32; i++) { if((tmp_rmask & 1) == 1) { if(w_image->pformat.r_shift == -1) w_image->pformat.r_shift = i; w_image->pformat.r_count++; } else if(w_image->pformat.r_shift != -1) break; tmp_rmask = tmp_rmask >> 1; } /*-------------------------------------------------------------------------- ** Find the Green shift and count **------------------------------------------------------------------------*/ for(i = 0; i < 32; i++) { if((tmp_gmask & 1) == 1) { if(w_image->pformat.g_shift == -1) w_image->pformat.g_shift = i; w_image->pformat.g_count++; } else if(w_image->pformat.g_shift != -1) break; tmp_gmask = tmp_gmask >> 1; } /*-------------------------------------------------------------------------- ** Find the Blue shift and count **------------------------------------------------------------------------*/ for(i = 0; i < 32; i++) { if((tmp_bmask & 1) == 1) { if(w_image->pformat.b_shift == -1) w_image->pformat.b_shift = i; w_image->pformat.b_count++; } else if(w_image->pformat.b_shift != -1) break; tmp_bmask = tmp_bmask >> 1; } /*-------------------------------------------------------------------------- ** Assign the r, g, and b masks **------------------------------------------------------------------------*/ w_image->pformat.r_mask = w_image->ximage->red_mask; w_image->pformat.g_mask = w_image->ximage->green_mask; w_image->pformat.b_mask = w_image->ximage->blue_mask; } /*---------------------------------------------------------------------------- ** Set the viewable parameters for an ximage **--------------------------------------------------------------------------*/ void find_viewable_coords(int global_coord, int dpy_dimension, int win_dimension, int *origin_coord, int *adjusted_dimension) { /*-------------------------------------------------------------------------- ** If the dimensions are already set, then adjust them accordingly **------------------------------------------------------------------------*/ if(*adjusted_dimension > 0) { if(*adjusted_dimension + *origin_coord >= dpy_dimension) *adjusted_dimension -= ((*adjusted_dimension + *origin_coord) - dpy_dimension); if(*origin_coord < 0) { *adjusted_dimension += *origin_coord; *origin_coord = 0; } } else { /*------------------------------------------------------------------------ ** Adjust the dimension around the dimension axis origin **----------------------------------------------------------------------*/ *adjusted_dimension = win_dimension; if( global_coord < 0 ) { *origin_coord -= global_coord; *adjusted_dimension += global_coord; } /*------------------------------------------------------------------------ ** Adjust the dimension at the other edge of the window **----------------------------------------------------------------------*/ if( global_coord + *adjusted_dimension >= dpy_dimension ) *adjusted_dimension -= ((*adjusted_dimension + global_coord) - dpy_dimension); } /*------------------------------------------------------------------------ ** Aditional control if we are in broken X, i.e CrossOver Mac 6.1 branch ** with bundled X implemenation **----------------------------------------------------------------------*/ if(*adjusted_dimension > dpy_dimension) *adjusted_dimension = dpy_dimension; } /*---------------------------------------------------------------------------- ** Set the viewable parameters for an ximage **--------------------------------------------------------------------------*/ void win_image_set_viewable_params(win_image *w_image, int global_x, int global_y, int display_width, int display_height, int win_width, int win_height) { /*-------------------------------------------------------------------------- ** Find the viewable origin coord and width for the x axis **------------------------------------------------------------------------*/ find_viewable_coords(global_x, display_width, win_width, &w_image->origin_x, &w_image->width); /*-------------------------------------------------------------------------- ** Find the viewable origin coord and width for the y axis **------------------------------------------------------------------------*/ find_viewable_coords(global_y, display_height, win_height, &w_image->origin_y, &w_image->height); } /*---------------------------------------------------------------------------- ** Get the ximage ** -- might want to think about changing operations for win == root_win ** return 0 on success, 1 on failure **--------------------------------------------------------------------------*/ int win_image_set_ximage(win_image *wimage, Display *display, Window win) { Window root_win = 0, dummy; XWindowAttributes win_attr; int global_x, global_y; int display_width = -1, display_height = -1; /*-------------------------------------------------------------------------- ** Make sure to reset wimage if it already has an XImage **--------------------------------------------------------------------------*/ if(wimage->ximage != (XImage *)NULL) win_image_destroy_ximage(wimage); /*-------------------------------------------------------------------------- ** Get the root window **--------------------------------------------------------------------------*/ root_win = DefaultRootWindow(display); if(!root_win) { fprintf(stderr, "Unable to get default root window\n"); return(1); } /*-------------------------------------------------------------------------- ** Get the window attributes **--------------------------------------------------------------------------*/ if( !XGetWindowAttributes(display, win, &win_attr)) { fprintf(stderr,"Unable to get window attributes\n"); return(1); } /*-------------------------------------------------------------------------- ** Find the global coordinates of the upper left corner of the window **--------------------------------------------------------------------------*/ if( !XTranslateCoordinates(display, win, root_win, 0, 0, &global_x, &global_y, &dummy)) { fprintf(stderr,"Unable to translate coordinates\n"); return(1); } /*-------------------------------------------------------------------------- ** Get the display width and height **--------------------------------------------------------------------------*/ display_width = DisplayWidth(display, DefaultScreen(display)); display_height = DisplayHeight(display, DefaultScreen(display)); if ( display_width == -1 || display_height == -1) { fprintf(stderr,"Unable to retrieve display width and/or height\n"); return(1); } /*-------------------------------------------------------------------------- ** Find and set the viewable window parameters for win and capture the ximage **--------------------------------------------------------------------------*/ win_image_set_viewable_params(wimage, global_x, global_y, display_width, display_height, win_attr.width, win_attr.height); wimage->ximage = XGetImage(display, win, wimage->origin_x, wimage->origin_y, wimage->width, wimage->height, AllPlanes, ZPixmap); if( wimage->ximage == (XImage *)NULL) { fprintf(stderr, "Unable to allocate ximage\n"); return(1); } /*-------------------------------------------------------------------------- ** Get the pixel format for w_image.ximage, but only if it has not previously ** been set... pixel format will not change on fly **--------------------------------------------------------------------------*/ if(wimage->pformat.r_shift == -1) win_image_set_pixel_format(wimage); return(0); } /*---------------------------------------------------------------------------- ** Convert to 8 bit depth **--------------------------------------------------------------------------*/ short convert_to_8bit(short pixel_component, int component_size) { short return_val; switch(component_size) { case 5: return_val = pixel_component << 3 | pixel_component >> 2; break; case 6: return_val = pixel_component << 2 | pixel_component >> 4; break; default: return_val = pixel_component; break; } return(return_val); } /*---------------------------------------------------------------------------- ** Convert a win_image to a rgb_image **--------------------------------------------------------------------------*/ int win_image_to_rgb_image(win_image *w_image, rgb_image *r_image) { int x, y; unsigned long pixel; short r, g, b; /*-------------------------------------------------------------------------- ** Allocate memory for r_image **--------------------------------------------------------------------------*/ if(rgb_image_malloc(r_image, w_image->width, w_image->height)) return(1); /*-------------------------------------------------------------------------- ** Go through the ximage and assign r_image values, x first **--------------------------------------------------------------------------*/ for(x = 0; x < w_image->width; x++) { /*------------------------------------------------------------------------ ** Go through the y values for each x value of ximage **------------------------------------------------------------------------*/ for(y = 0; y < w_image->height; y++) { pixel = XGetPixel(w_image->ximage, x, y); /*---------------------------------------------------------------------- ** Find the r, g, and b values **----------------------------------------------------------------------*/ r = (pixel & w_image->pformat.r_mask) >> w_image->pformat.r_shift; g = (pixel & w_image->pformat.g_mask) >> w_image->pformat.g_shift; b = (pixel & w_image->pformat.b_mask) >> w_image->pformat.b_shift; /*---------------------------------------------------------------------- ** Convert the pixels to 8 bit per r, g, b and assign values **----------------------------------------------------------------------*/ r_image->data[x][y].r = convert_to_8bit(r, w_image->pformat.r_count); r_image->data[x][y].g = convert_to_8bit(g, w_image->pformat.g_count); r_image->data[x][y].b = convert_to_8bit(b, w_image->pformat.b_count); } } /*-------------------------------------------------------------------------- ** Record the bit depth that is being used **--------------------------------------------------------------------------*/ r_image->bit_depth = 8; return(0); } /*---------------------------------------------------------------------------- ** Convert an rgb image to an rgb histogram **--------------------------------------------------------------------------*/ int rgb_image_to_rgb_hist(rgb_image *r_image, rgb_hist *r_hist) { int i=0; int j=0; /*-------------------------------------------------------------------------- ** Allocate memory for r_hist **--------------------------------------------------------------------------*/ // r_hist=rgb_hist_init(); //if( r_hist==NULL ) // return(1); // printf("width: %d, height: %d\n",r_image->width,r_image->height); for(i=0; iwidth; i++) { for(j=0; jheight; j++) { /*----------------------------------------------------------------------- ** At each pixel, get the rgb image's r,g and b values **---------------------------------------------------------------------*/ int r_val=r_image->data[i][j].r; int g_val=r_image->data[i][j].g; int b_val=r_image->data[i][j].b; /*---------------------------------------------------------------------------- ** Increment the spots in the arrays that correspond to the image's rgb values **--------------------------------------------------------------------------*/ r_hist->r[r_val]++; r_hist->g[g_val]++; r_hist->b[b_val]++; /*------------------------------------------------------------------ ** Increment the variable that stores how many pixels there are **----------------------------------------------------------------*/ r_hist->total_count++; } } r_hist->width=r_image->width; r_hist->height=r_image->height; return(0); } /*---------------------------------------------------------------------------- ** Convert a win image to an rgb histogram **--------------------------------------------------------------------------*/ int win_image_to_rgb_hist(win_image *w_image, rgb_hist *r_hist) { rgb_image *r_image=NULL; /*-------------------------------------------------------------------------- ** Convert the win image to an rgb image **--------------------------------------------------------------------------*/ if (!win_image_to_rgb_image(w_image, r_image)) return(1); /*-------------------------------------------------------------------------- ** Call rgb_image_to_rgb_hist on the newly created rgb image **--------------------------------------------------------------------------*/ if (!rgb_image_to_rgb_hist(r_image, r_hist)) return(1); /*-------------------------------------------------------------------------- ** If we are here, both function calls worked; we exit successfully **--------------------------------------------------------------------------*/ return(0); } /*---------------------------------------------------------------------------- ** Compare two pixels ** return 0 if they are within the error margin, 1 if they are not ** -- might want to think about making percentage **--------------------------------------------------------------------------*/ int rgb_pixel_comparison(rgb *p1, rgb *p2, int err_margin) { /*-------------------------------------------------------------------------- ** Compare each component of the pixel separately **--------------------------------------------------------------------------*/ if( err_margin < abs(p1->r - p2->r)) return 1; if( err_margin < abs(p1->g - p2->g)) return 1; if( err_margin < abs(p1->b - p2->b)) return 1; /*-------------------------------------------------------------------------- ** All components w/in error margin... success **--------------------------------------------------------------------------*/ return 0; } /*---------------------------------------------------------------------------- ** Move through the subimage, comparing each pixel with a set location ** from the image **--------------------------------------------------------------------------*/ int rgb_image_subimage_search (rgb_image *image, rgb_image *subimage, int err_margin, int x, int y) { int i, j; for (i = 0; i < subimage->width; i++) { for (j = 0; j < subimage->height; j++) { /*------------------------------------------------------------------------ ** Do a comparison of each pixel **----------------------------------------------------------------------*/ if ( rgb_pixel_comparison( &image->data[i+x][j+y], &subimage->data[i][j], err_margin)) return(1); } } /*-------------------------------------------------------------------------- ** All pixels in the subimage are within the error margin, success **--------------------------------------------------------------------------*/ return(0); } /*---------------------------------------------------------------------------- ** Find one rgb_image inside of another ** --return 0 on success, 1 on image not found, 2 on error **--------------------------------------------------------------------------*/ int rgb_image_find_subimage(rgb_image *image, rgb_image *subimage, int err_margin, int *x, int *y) { int x_diff, y_diff; int i = 0, j = 0; int rc = 1; /*-------------------------------------------------------------------------- ** Make sure that the subimage is smaller than the image & that they have ** the same bit depth **--------------------------------------------------------------------------*/ x_diff = image->width - subimage->width; y_diff = image->height - subimage->height; if (x_diff < 0 || y_diff < 0 || image->bit_depth != subimage->bit_depth) return(2); /*-------------------------------------------------------------------------- ** Loop through the image, sending a search at each potential location of ** the subimage's upper-left corner **--------------------------------------------------------------------------*/ for (i = 0; i <= x_diff && rc; i++) { for (j = 0; j <= y_diff && rc; j++) { rc = rgb_image_subimage_search(image, subimage, err_margin, i, j); } } /*-------------------------------------------------------------------------- ** Adjust the coordinates, x and y, to be coordinates of the image ** -- if no coords are passed in, or if they are not applicable to the ** subimage (ie. too large), then use the middle of the subimage **--------------------------------------------------------------------------*/ if(!rc) { if(*x < 0 || *x > subimage->width || *y < 0 || *y > subimage->height) { *x = subimage->width/2; *y = subimage->height/2; } *x += i; *y += j; } return(rc); }