/* hf_management.c - height field creator/destructor, input / output * and memory management * * Copyright (C) 2001, 2003 Patrice St-Gelais * patrstg@users.sourceforge.net * www.oricom.ca/patrice.st-gelais * * 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 "hf.h" #include "camera.h" #include #define CAM_RECORD_LENGTH 41 #define CAM_RECORD_FORMAT "%3d %3d %6.3f %6.3f %6.3f %3d %7.5f" #define CAM_SCAN_FORMAT "%d %d %f %f %f %d %f" static gchar cam1[CAM_RECORD_LENGTH], cam2[CAM_RECORD_LENGTH], cam3[CAM_RECORD_LENGTH], cam4[CAM_RECORD_LENGTH], cam5[CAM_RECORD_LENGTH]; // Ad hoc global structure for holding comments #define NBPNGCOMMENTS 7 // Software ID, Tiling + 5 cameras static png_text *pngcomments= NULL; extern camera_struct camera_def; extern camera_struct cameras[NBCAMERAS]; // This struct is required to write / read comments in the png file // Here iTXt is not supported (size of the struct is 16 bytes) // (important for initialization...) // typedef struct png_text_struct // { // int compression; /* compression value: // -1: tEXt, none // 0: zTXt, deflate // 1: iTXt, none // 2: iTXt, deflate */ // png_charp key; /* keyword, 1-79 character description of "text" */ // png_charp text; /* comment, may be an empty string (ie "") // or a NULL pointer */ // png_size_t text_length; /* length of the text string */ // #ifdef PNG_iTXt_SUPPORTED // png_size_t itxt_length; /* length of the itxt string */ // png_charp lang; /* language code, 0-79 characters // or a NULL pointer */ // png_charp lang_key; /* keyword translated UTF-8 string, 0 or more // chars or a NULL pointer */ // #endif // } png_text; gint sscanf_camera (gchar *text, gint index) { gint nbargs; nbargs = sscanf (text,CAM_SCAN_FORMAT, &cameras[index].rot_x, &cameras[index].rot_y, &cameras[index].distance, &cameras[index].translate_x, &cameras[index].translate_y, &cameras[index].angle_w, &cameras[index].aspect_ratio); /* printf("Arguments lus dans <<%s>>: %d / 7\n",text, nbargs); printf("INDEX: %2d; ROT_X: %3d; ROT_Y: %3d; DIST: %6.3f; TR_X: %6.3f; TR_Y: %6.3f; ANGLE: %3d; RATIO: %5.3f\n", index, cameras[index].rot_x, cameras[index].rot_y, cameras[index].distance, cameras[index].translate_x, cameras[index].translate_y, cameras[index].angle_w, cameras[index].aspect_ratio); */ return nbargs; } gint snprintf_camera (gchar *buf, gint index, camera_struct *cam) { gint nbchars; nbchars = snprintf(buf,CAM_RECORD_LENGTH,CAM_RECORD_FORMAT, cam->rot_x, cam->rot_y, cam->distance, cam->translate_x, cam->translate_y, cam->angle_w, cam->aspect_ratio); pngcomments[index+2].text = buf; // printf("CAM%1d: %s; LNG: %d\n",index, buf, strlen(buf)); return nbchars; } void write_cameras_in_png (camera_struct *cams[]) { // We store the cameras as fixed length strings // At this point, keys in "pngcomments" are supposed to be initialized static gchar *loc; loc = setlocale(LC_NUMERIC,""); // Standardize on "." as a decimal separator // printf("LOCALE: %s\n",loc); setlocale(LC_NUMERIC,"C"); snprintf_camera (cam1, 0, cams[0]); snprintf_camera (cam2, 1, cams[1]); snprintf_camera (cam3, 2, cams[2]); snprintf_camera (cam4, 3, cams[3]); snprintf_camera (cam5, 4, cams[4]); setlocale(LC_NUMERIC,loc); } void init_png_comments () { gint i; static gchar *keys[] = {"CAMERA1","CAMERA2", "CAMERA3","CAMERA4","CAMERA5" }; static gchar *loc; loc = setlocale(LC_NUMERIC,""); // Standardize on "." as a decimal separator // printf("LOCALE: %s\n",loc); setlocale(LC_NUMERIC,"C"); pngcomments = (png_text *) calloc(sizeof(png_text),NBPNGCOMMENTS); pngcomments[0].compression = PNG_TEXT_COMPRESSION_NONE; pngcomments[0].key = "Software"; pngcomments[0].text = VERSION_NAME; pngcomments[1].compression = PNG_TEXT_COMPRESSION_NONE; pngcomments[1].key = "Tiling"; pngcomments[1].text = "Y"; for (i=2; iif_tiles) pngcomments[1].text = "Y"; else pngcomments[1].text = "N"; write_png_with_text(path_n_file, 16, (gpointer) hf->hf_buf, hf->max_x, hf->max_y, pngcomments, NBPNGCOMMENTS); } gboolean test_power_2(gint hf_size) { // Returns 1 if hf_size is a power of 2 between 128 and 4096 included switch (hf_size) { case 128: break; case 256: break; case 512: break; case 1024: break; case 2048: break; case 4096: break; default: return FALSE; } return TRUE; } unsigned char *expand_8_to_16(unsigned char *img_buf, gint width, gint height) { // Simple expansion of a greyscale 8 bits image to 16 bits image // Future improvement: maybe add noise in the lower weight byte?? unsigned char *new_img; gint i; new_img = (unsigned char *) calloc(width*height,2); for (i=0; i Copyright (c) 1998-01-04 Charles Poynton poynton@inforamp.net Y = 0.212671 * R + 0.715160 * G + 0.072169 * B Libpng approximates this with Y = 0.21268 * R + 0.7151 * G + 0.07217 * B which can be expressed with integers as Y = (6969 * R + 23434 * G + 2365 * B)/32768 */ unsigned long int r,g,b,y; pix8_rgb *pix8; pix16_rgb *pix16; gint i; unsigned char *new_img, *new_img8; unsigned short int *new_img16; if (depth==8) { pix8 = (pix8_rgb *) img_buf; new_img8 = (unsigned char *) calloc(width*height,1); for (i=0; ir; g = (unsigned long int) pix8->g; b = (unsigned long int) pix8->b; y = (6969 * r + 23434 * g + 2365 * b)>>15; *(new_img8+i) = y; pix8++; } new_img = (unsigned char *) new_img8; } else if (depth==16) { pix16 = (pix16_rgb *) img_buf; new_img16 = (unsigned short int *) calloc(width*height,sizeof(unsigned short int)); for (i=0; ir; g = (unsigned long int) pix16->g; b = (unsigned long int) pix16->b; y = (6969 * r + 23434 * g + 2365 * b)>>15; *(new_img16+i) = y; pix16++; } new_img = (unsigned char *) new_img16; } else { free(img_buf); return NULL; } free(img_buf); return new_img; } hf_struct_type * hf_read(gchar *path_n_file, gboolean *fname_tochoose, gchar **msg) { // Reads a PNG HF file and transforms it so it becomes a 16 bits power2 x power2 image // path_n_file: the file to read // fname_tochoose: we set this variable to TRUE if the image is transformed and we // want to keep the original file intact - the displayed file // would be called "documentN" // msg: message to return, if something goes wrong - the "methods" of the // current .c file are not supposed to deal with the human interface! gint depth, width, height, color_type, interlace_type, i; unsigned char *img_buf=NULL; png_text *comments=NULL; gint nbkeys; gchar *loc; gboolean tiling = FALSE; if (!read_png_header(path_n_file, &depth, &width, &height, &color_type, &interlace_type) ) { (*msg) = _("PNG file unreadable"); return NULL; } if (!read_png_with_text(path_n_file, &depth, &img_buf, &width, &height, &color_type, &interlace_type, &comments, &nbkeys)) { (*msg) = _("PNG file unreadable"); return NULL; } if (width!=height) { (*msg) = _("Geomorph requires a square image"); free(img_buf); return NULL; } if (!test_power_2(width)) { (*msg) = _("Geomorph requires a square image nwith edges of 128, 256, 512, 1024, 2048 or 4096 pixels"); free(img_buf); return NULL; } if (color_type!=PNG_COLOR_TYPE_GRAY) { (*msg) = _("Color image converted to B&W under a new name"); (*fname_tochoose) = TRUE; img_buf = rgb_to_grey(img_buf, width, height, depth); if (!img_buf) { (*msg) = _("Not able to convert this image to B&W"); return NULL; } } if (depth!=16) { (*msg) = _("8 bits image converted to 16 bits under a new name"); (*fname_tochoose) = TRUE; // We suppose weird depths (1, 2, 4...) are already converted in read_png img_buf = expand_8_to_16(img_buf, width, height); } if (nbkeys && comments) { loc = setlocale(LC_NUMERIC,""); // Standardize on "." as a decimal separator setlocale(LC_NUMERIC,"C"); for (i=0; imax_x = hfsize; hf->max_y = hfsize; if (image_buf) hf->hf_buf = image_buf; else hf->hf_buf = (hf_type *) malloc(hfsize * hfsize *sizeof(hf_type)); hf->tmp_buf = NULL; hf->tmp2_buf = NULL; hf->result_buf = NULL; hf->select_buf = NULL; hf->min = 0; hf->max = 0xFFFF; hf->avrg = 0xFFFF>>1; hf->hf_buf8 = (unsigned char *) malloc((RIGHT_SHIFT(hfsize,display_scale))* (RIGHT_SHIFT(hfsize,display_scale))*sizeof(unsigned char)); hf->if_rgb = FALSE; hf->display_scale = display_scale; hf->if_tiles = tiling; hf->parameters = NULL; // hf_buf8 is the display buffer, recalculated in the draw_hf function hf->hf_buf8 = NULL; return (gpointer) hf; } gpointer hf_new(gint hfsize, gint display_scale) { // Creates and initializes an HF with default values // The image data is not known // We presume we are generating a new (tiling) HF hf_struct_type *hf; hf = (hf_struct_type *) hf_create(NULL, hfsize, display_scale, TRUE); return hf; } hf_struct_type *hf_copy_new(hf_struct_type *hf) { // Copy a hf_struct onto a newly allocated hf_struct, // for instance for undo / redo purpose hf_struct_type *hfcopy; hfcopy = (hf_struct_type *) malloc(sizeof(hf_struct_type)); // printf("HF_COPY, de %d sur MALLOC: %d\n",hf, hfcopy); memcpy(hfcopy, hf, sizeof(hf_struct_type)); hfcopy->hf_buf = (hf_type *)malloc(hf->max_x*hf->max_y*sizeof(hf_type)); memcpy(hfcopy->hf_buf, hf->hf_buf, hf->max_x*hf->max_y*sizeof(hf_type)); if (hf->tmp_buf) { hfcopy->tmp_buf = (hf_type *)malloc(hf->max_x*hf->max_y*sizeof(hf_type)); memcpy(hfcopy->tmp_buf, hf->tmp_buf, hf->max_x*hf->max_y*sizeof(hf_type)); } if (hf->result_buf) { hfcopy->result_buf = (hf_type *)malloc(hf->max_x*hf->max_y*sizeof(hf_type)); memcpy(hfcopy->result_buf, hf->result_buf, hf->max_x*hf->max_y*sizeof(hf_type)); } if (hf->tmp2_buf) { hfcopy->tmp2_buf = (hf_type *)malloc(hf->max_x*hf->max_y*sizeof(hf_type)); memcpy(hfcopy->tmp2_buf, hf->tmp2_buf, hf->max_x*hf->max_y*sizeof(hf_type)); } // select_buf is not required if (hf->select_buf) hfcopy->select_buf = NULL; // hf_buf8 is initialized with an expose_event hfcopy->hf_buf8 = NULL; return hfcopy; } void hf_backup(hf_struct_type *hf) { // Backup the main buffer into a temporary one if (hf->tmp_buf) free(hf->tmp_buf); hf->tmp_buf = (hf_type *)malloc(hf->max_x*hf->max_y*sizeof(hf_type)); // printf("HF_BACKUP de %d sur %d\n",hf->hf_buf,hf->tmp_buf); memcpy(hf->tmp_buf, hf->hf_buf, hf->max_x*hf->max_y*sizeof(hf_type)); hf_min_max_avrg(hf); } void hf_restore(hf_struct_type *hf) { // Opposite of hf_backup... // printf("HF_RESTORE de %d sur %d\n", hf->tmp_buf, hf->hf_buf); if (hf->tmp_buf) memcpy(hf->hf_buf, hf->tmp_buf, hf->max_x*hf->max_y*sizeof(hf_type)); } void hf_free(hf_struct_type *hf) { if (!hf) return; if (hf->hf_buf) { free(hf->hf_buf); } if (hf->tmp_buf) { free(hf->tmp_buf); } if (hf->tmp2_buf) { free(hf->tmp2_buf); } if (hf->result_buf) { free(hf->result_buf); } if (hf->select_buf) { free(hf->select_buf); } if (hf->hf_buf8) { free(hf->hf_buf8); } if (hf->parameters) free(hf->parameters); free(hf); }