1 /* hf.c - 	height field creator/destructor, input / output
2  *			 	and memory management
3  *
4  * Copyright (C) 2001, 2003, 2010 Patrice St-Gelais
5  *         patrstg@users.sourceforge.net
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22 #include "hf.h"
23 #include "hf_calc.h"
24 #include "camera.h"
25 #include "merge.h"
26 
27 #include <png.h>
28 #include <locale.h>
29 
30 #define CAM_RECORD_LENGTH 41
31 #define CAM_RECORD_FORMAT "%3d %3d %6.3f %6.3f %6.3f %3d %7.5f"
32 #define CAM_SCAN_FORMAT "%d %d %f %f %f %d %f"
33 #define WATER_LEVEL_LENGTH 10
34 #define WATER_LEVEL_FORMAT "%6.3f"
35 
36 #ifndef DEFAULT_WATER_LEVEL
37 #define DEFAULT_WATER_LEVEL 0.2
38 #endif
39 
40 static merge_struct mrg = {ADD, NULL, NULL, 0, 0, 0, 0, FALSE, 0.0};
41 
42 static gchar cam1[CAM_RECORD_LENGTH],
43 		cam2[CAM_RECORD_LENGTH],
44 		cam3[CAM_RECORD_LENGTH],
45 		cam4[CAM_RECORD_LENGTH],
46 		cam5[CAM_RECORD_LENGTH],
47 		global_water_level[WATER_LEVEL_LENGTH];
48 
49 //	Ad hoc global structure for holding comments
50 
51 #define NBPNGCOMMENTS 9 // Software ID, Tiling, use water, water level + 5 cameras
52 #define NBKEYS_BEFORE_CAMERAS 4
53 static png_text *pngcomments= NULL;
54 
55 extern camera_struct camera_def;
56 extern camera_struct cameras[NBCAMERAS];
57 
58 // This struct is required to write / read comments in the png file
59 // Here iTXt is not supported (size of the struct is 16 bytes)
60 // (important for initialization...)
61 
62 // typedef struct png_text_struct
63 // {
64 //   int  compression;       /* compression value:
65 //                             -1: tEXt, none
66 //                              0: zTXt, deflate
67 //                              1: iTXt, none
68 //                              2: iTXt, deflate  */
69 //   png_charp key;          /* keyword, 1-79 character description of "text" */
70 //   png_charp text;         /* comment, may be an empty string (ie "")
71 //                              or a NULL pointer */
72 //   png_size_t text_length; /* length of the text string */
73 // #ifdef PNG_iTXt_SUPPORTED
74 //   png_size_t itxt_length; /* length of the itxt string */
75 //   png_charp lang;         /* language code, 0-79 characters
76 //                              or a NULL pointer */
77 //   png_charp lang_key;     /* keyword translated UTF-8 string, 0 or more
78 //                              chars or a NULL pointer */
79 // #endif
80 // } png_text;
81 
82 
sscanf_camera(gchar * text,gint index)83 gint sscanf_camera (gchar *text, gint index) {
84 	gint nbargs;
85 	nbargs = sscanf (text,CAM_SCAN_FORMAT,
86 		&cameras[index].rot_x, &cameras[index].rot_y, &cameras[index].distance,
87 		&cameras[index].translate_x, &cameras[index].translate_y,
88 		&cameras[index].angle_w, &cameras[index].aspect_ratio);
89 
90 /* printf("Arguments lus dans <<%s>>: %d / 7\n",text, nbargs);
91 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",
92 		index, cameras[index].rot_x, cameras[index].rot_y, cameras[index].distance,
93 		cameras[index].translate_x, cameras[index].translate_y,
94 		cameras[index].angle_w, cameras[index].aspect_ratio);
95 */
96 	return nbargs;
97 }
98 
snprintf_camera(gchar * buf,gint index,camera_struct * cam)99 gint snprintf_camera (gchar *buf, gint index, camera_struct *cam) {
100 	gint nbchars;
101 	nbchars = snprintf(buf,CAM_RECORD_LENGTH,CAM_RECORD_FORMAT,
102 		cam->rot_x, cam->rot_y, cam->distance,
103 		cam->translate_x, cam->translate_y, cam->angle_w, cam->aspect_ratio);
104 	pngcomments[index+NBKEYS_BEFORE_CAMERAS].text = buf;
105 // printf("CAM%1d: %s; LNG: %d\n",index, buf, strlen(buf));
106 	return nbchars;
107 }
108 
write_cameras_in_png(camera_struct * cams[])109 void write_cameras_in_png (camera_struct *cams[]) {
110 	// We store the cameras as fixed length strings
111 	// At this point, keys in "pngcomments" are supposed to be initialized
112 
113 	snprintf_camera (cam1, 0, cams[0]);
114 	snprintf_camera (cam2, 1, cams[1]);
115 	snprintf_camera (cam3, 2, cams[2]);
116 	snprintf_camera (cam4, 3, cams[3]);
117 	snprintf_camera (cam5, 4, cams[4]);
118 }
119 
init_png_comments()120 void init_png_comments () {
121 	gint i;
122 	static gchar *keys[] = {"CAMERA1","CAMERA2",
123 		"CAMERA3","CAMERA4","CAMERA5" };
124 
125 	static gchar *tmp,*loc;
126 	tmp = setlocale(LC_NUMERIC,NULL); // Standardize on "." as a decimal separator
127 	loc = (gchar *) malloc(strlen(tmp)+1);
128 	strcpy(loc,tmp);
129 //	printf("LOCALE: %s\n",loc);
130 	setlocale(LC_NUMERIC,"C");
131 
132 	pngcomments = (png_text *) x_calloc(sizeof(png_text),NBPNGCOMMENTS, "png_text");
133 	pngcomments[0].compression =  PNG_TEXT_COMPRESSION_NONE;
134 	pngcomments[0].key =  "Software";
135 	pngcomments[0].text =  VERSION_NAME;
136 	pngcomments[1].compression =  PNG_TEXT_COMPRESSION_NONE;
137 	pngcomments[1].key = "Tiling";
138 	pngcomments[1].text = "Y";
139 	pngcomments[2].compression =  PNG_TEXT_COMPRESSION_NONE;
140 	pngcomments[2].key = "Use water";
141 	pngcomments[2].text = "N";
142 	pngcomments[3].compression =  PNG_TEXT_COMPRESSION_NONE;
143 	pngcomments[3].key = "Water level";
144 	pngcomments[3].text = (gchar *) malloc(WATER_LEVEL_LENGTH);
145 	snprintf(pngcomments[3].text, WATER_LEVEL_LENGTH, WATER_LEVEL_FORMAT, DEFAULT_WATER_LEVEL);
146 
147 	for (i=NBKEYS_BEFORE_CAMERAS; i<NBPNGCOMMENTS; i++) {
148 		pngcomments[i].key = keys[i-NBKEYS_BEFORE_CAMERAS];
149 		pngcomments[i].compression = PNG_TEXT_COMPRESSION_NONE;
150 	}
151 
152 	snprintf_camera (cam1, 0, &cameras[0]);
153 	snprintf_camera (cam2, 1, &cameras[1]);
154 	snprintf_camera (cam3, 2, &cameras[2]);
155 	snprintf_camera (cam4, 3, &cameras[3]);
156 	snprintf_camera (cam5, 4, &cameras[4]);
157 
158 //	printf("LOCALE: %s\n",loc);
159 	setlocale(LC_NUMERIC,loc);
160 	free(loc);
161 #ifdef PNG_iTXt_SUPPORTED
162 	for (i=0; i<NBPNGCOMMENTS; i++)
163 		pngcomments[i].lang = NULL;
164 #endif
165 
166 }
167 
hf_write(hf_struct_type * hf,gchar * path_n_file,camera_struct * cameras[])168 void hf_write( hf_struct_type *hf, gchar *path_n_file, camera_struct *cameras[]) {
169 	gboolean tiling;
170 	static gchar *tmp,*loc;
171 	tmp = setlocale(LC_NUMERIC,NULL); // Standardize on "." as a decimal separator
172 //	printf("LOCALE: %s\n",loc);
173 	loc = (gchar *) malloc(strlen(tmp)+1);
174 	strcpy(loc,tmp);
175 	setlocale(LC_NUMERIC,"C");
176 	if (hf->if_tiles)
177 		tiling = *hf->if_tiles;
178 	else
179 		tiling = TRUE;
180 	if (!pngcomments)
181 		init_png_comments();
182 	write_cameras_in_png (cameras);
183 	if (tiling)
184 		pngcomments[1].text = "Y";
185 	else
186 		pngcomments[1].text = "N";
187 	if (hf->use_water)
188 		pngcomments[2].text = "Y";
189 	else
190 		pngcomments[2].text = "N";
191 //	Added 2010-10-08
192 	snprintf (pngcomments[3].text, WATER_LEVEL_LENGTH, WATER_LEVEL_FORMAT, hf->water_level);
193 	setlocale(LC_NUMERIC,loc);
194 	free(loc);
195 	write_png_with_text(path_n_file, 16, (gpointer) hf->hf_buf, hf->max_x, hf->max_y,
196 		pngcomments, NBPNGCOMMENTS);
197 }
198 
test_power_2(gint hf_size)199 gboolean test_power_2(gint hf_size) {
200 //	Returns 1 if hf_size is a power of 2 between 128 and 4096 included
201 	switch (hf_size) {
202 		case 128:	break;
203 		case 256:	break;
204 		case 512:	break;
205 		case 1024:	break;
206 		case 2048:	break;
207 		case 4096:	break;
208 		default:
209 			return FALSE;
210 	}
211 	return TRUE;
212 }
213 
expand_8_to_16(unsigned char * img_buf,gint width,gint height)214 static unsigned char *expand_8_to_16(unsigned char *img_buf, gint width, gint height) {
215 //	Simple expansion of a greyscale 8 bits image to 16 bits image
216 //	Future improvement:  maybe add noise in the lower weight byte??
217 	unsigned char *new_img;
218 	gint i;
219 	new_img = (unsigned char *) x_calloc(width*height,2, "unsigned char (new_img)");
220 	for (i=0; i<width*height; i++) {
221 	//	Lower byte must appear 1st ... (I'm missing something here...)
222 		*(new_img+i*2+1) = *(img_buf+i);
223 	}
224 	x_free(img_buf);
225 	return new_img;
226 }
227 
rgb_to_grey(unsigned char * img_buf,gint width,gint height,gint depth,gboolean alpha)228 static unsigned char *rgb_to_grey(unsigned char *img_buf, gint width, gint height, gint depth, gboolean alpha) {
229 /*	Extract from libpng, explaining the method
230 The default values approximate those recommended in the Charles
231 Poynton's Color FAQ, <http://www.inforamp.net/~poynton/>
232 Copyright (c) 1998-01-04 Charles Poynton poynton@inforamp.net
233 
234     Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
235 
236 Libpng approximates this with
237 
238     Y = 0.21268 * R    + 0.7151 * G    + 0.07217 * B
239 
240 which can be expressed with integers as
241 
242     Y = (6969 * R + 23434 * G + 2365 * B)/32768
243 */
244 	unsigned long int r,g,b,y;
245 	pix8_rgb *pix8;
246 	pix16_rgb *pix16;
247 	pix8_rgba *pix8a;
248 	pix16_rgba *pix16a;
249 	gint i;
250 	unsigned char *new_img, *new_img8;
251 	unsigned short int *new_img16;
252 	if (depth==8) {
253 		if (alpha)
254 			pix8a = (pix8_rgba *) img_buf;
255 		else
256 			pix8 = (pix8_rgb *) img_buf;
257 		new_img8 = (unsigned char *) x_calloc(width*height,1, "unsigned char (new_img8)");
258 		for (i=0; i<width*height; i++) {
259 			if (alpha) {
260 				r = (unsigned long int) pix8a->r;
261 				g = (unsigned long int) pix8a->g;
262 				b = (unsigned long int) pix8a->b;
263 				pix8a++;
264 			}
265 			else {
266 				r = (unsigned long int) pix8->r;
267 				g = (unsigned long int) pix8->g;
268 				b = (unsigned long int) pix8->b;
269 				pix8++;
270 			}
271 			y = (6969 * r + 23434 * g + 2365 * b)>>15;
272 			*(new_img8+i) = y;
273 		}
274 		new_img = (unsigned char *) new_img8;
275 	}
276 	else
277 		if (depth==16) {
278 			if (alpha)
279 				pix16a = (pix16_rgba *) img_buf;
280 			else
281 				pix16 = (pix16_rgb *) img_buf;
282 			new_img16 = (unsigned short int *) x_calloc(width*height, sizeof(unsigned short int), "unsigned short int (new_img16)");
283 			for (i=0; i<width*height; i++) {
284 				if (alpha) {
285 					r = (unsigned long int) pix16a->r;
286 					g = (unsigned long int) pix16a->g;
287 					b = (unsigned long int) pix16a->b;
288 					pix16a++;
289 				}
290 				else {
291 					r = (unsigned long int) pix16->r;
292 					g = (unsigned long int) pix16->g;
293 					b = (unsigned long int) pix16->b;
294 					pix16++;
295 				}
296 				y = (6969 * r + 23434 * g + 2365 * b)>>15;
297 				*(new_img16+i) = y;
298 			}
299 			new_img = (unsigned char *) new_img16;
300 		}
301 		else {
302 			x_free(img_buf);
303 			return NULL;
304 		}
305 	x_free(img_buf);
306 	return new_img;
307 }
308 
remove_alpha_from_grey(unsigned char * img_buf,gint width,gint height,gint depth)309 static unsigned char *remove_alpha_from_grey (unsigned char *img_buf, gint width, gint height, gint depth) {
310 
311 	gint i;
312 	unsigned char *new_img, *new_img8;
313 	unsigned short int *new_img16, *img_buf16;
314 
315 	if (depth==8) {
316 		new_img8 = (unsigned char *) x_calloc(width*height,1, "unsigned char (new_img8)");
317 		for (i=0; i<width*height; i++) {
318 			*(new_img8+i) = *(img_buf+2*i);
319 		}
320 		new_img = (unsigned char *) new_img8;
321 	}
322 	else 	if (depth==16) {
323 			new_img16 = (unsigned short int *) x_calloc(width*height, sizeof(unsigned short int), "unsigned short int (new_img16)");
324 			img_buf16 = (unsigned short int *) img_buf;
325 			for (i=0; i<width*height; i++) {
326 				*(new_img16+i) = *(img_buf16+2*i);
327 			}
328 			new_img = (unsigned char *) new_img16;
329 		}
330 		else {
331 			x_free(img_buf);
332 			return NULL;
333 		}
334 	x_free(img_buf);
335 	return new_img;
336 }
337 
hf_create(hf_type * image_buf,gint hfsize,gboolean tiling,gboolean * tiling_ptr,gboolean use_water,gfloat water_level)338 static gpointer hf_create(hf_type *image_buf, gint hfsize, gboolean tiling, gboolean *tiling_ptr, gboolean use_water, gfloat water_level ) {
339 //	Create a new HF with the image data given,
340 //	typically after a file read
341 
342 	hf_struct_type *hf;
343 	hf = (hf_struct_type *) x_malloc(sizeof(hf_struct_type), "hf_struct_type");
344 	hf->max_x = hfsize;
345 	hf->max_y = hfsize;
346 	if (image_buf)
347 		hf->hf_buf = image_buf;
348 	else
349 		hf->hf_buf = (hf_type *) x_malloc(hfsize * hfsize *sizeof(hf_type), "hf_type (hf->hf_buf)");
350 	hf->tmp_buf = NULL;
351 	hf->tmp2_buf = NULL;
352 	hf->result_buf = NULL;
353 	hf->select_buf = NULL;
354 	hf->layer_buf = NULL;
355 	hf->if_layer = FALSE;
356 	hf->min = 0;
357 	hf->max = MAX_HF_VALUE;
358 	hf->avrg = MAX_HF_VALUE>>1;
359 
360 	hf->if_tiles = tiling_ptr;
361 	// If no tiling_ptr, tiling is assumed to be TRUE
362 	if (tiling_ptr)
363 		*hf->if_tiles = tiling;
364 	hf->use_water = use_water;
365 	hf->water_level = water_level;
366 	return (gpointer) hf;
367 }
368 
hf_read(gchar * path_n_file,gboolean * fname_tochoose,gchar ** msg,gboolean * tiling_ptr)369 hf_struct_type * hf_read(gchar *path_n_file, gboolean *fname_tochoose, gchar **msg, gboolean *tiling_ptr) {
370 
371 //	Reads a PNG HF file and transforms it so it becomes a 16 bits power2 x power2 image
372 //	path_n_file:  the file to read
373 //	fname_tochoose:  we set this variable to TRUE if the image is transformed and we
374 //			want to keep the original file intact - the displayed file
375 //			would be called "documentN"
376 //	msg:  	message to return, if something goes wrong - the "methods" of the
377 //		current .c file are not supposed to deal with the human interface!
378 	gint depth, width, height, color_type, interlace_type, i;
379 	unsigned char *img_buf=NULL;
380 	png_text *comments=NULL;
381 	gint nbkeys;
382 	gchar *tmp,*loc;
383 	gboolean tiling = FALSE, use_water = FALSE, alpha = FALSE;
384 	gfloat water_level;
385 
386 	if (!read_png_header(path_n_file,  &depth, &width, &height,
387 			&color_type, &interlace_type) )  {
388 		(*msg) = _("PNG file unreadable");
389 		return NULL;
390 	}
391 
392 	if (!read_png_with_text(path_n_file, &depth, &img_buf, &width, &height,
393 			&color_type, &interlace_type, &comments, &nbkeys)) {
394 		(*msg) = _("PNG file unreadable");
395 		return NULL;
396 	}
397 	if (width!=height)  {
398 		(*msg) = _("Geomorph requires a square image");
399 		x_free(img_buf);
400 		return NULL;
401 	}
402 	if (!test_power_2(width)) {
403 		(*msg) = _("Geomorph requires a square image nwith edges of 128, 256, 512, 1024, 2048 or 4096 pixels");
404 		x_free(img_buf);
405 		return NULL;
406 	}
407 
408 	if ((color_type!=PNG_COLOR_TYPE_GRAY) &&
409 		(color_type!=PNG_COLOR_TYPE_GRAY_ALPHA) &&
410 		(color_type!=PNG_COLOR_TYPE_RGB_ALPHA) &&
411 		(color_type!=PNG_COLOR_TYPE_RGB) ) {
412 			(*msg) = _("PNG file unreadable");
413 			return NULL;
414 	}
415 
416 	if ((color_type==PNG_COLOR_TYPE_GRAY_ALPHA) || (color_type==PNG_COLOR_TYPE_RGB_ALPHA))
417 		alpha = TRUE;
418 
419 	if ( (color_type == PNG_COLOR_TYPE_RGB) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) {
420 		(*msg) = _("Color image converted to B&W under a new name");
421 		(*fname_tochoose) = TRUE;
422 		img_buf = rgb_to_grey(img_buf, width, height, depth, alpha);
423 		if (!img_buf) {
424 			(*msg) = _("Not able to convert this image to B&W");
425 			return NULL;
426 		}
427 	}
428 	else if (color_type==PNG_COLOR_TYPE_GRAY_ALPHA) {
429 	// Remove alpha channel if 8 bits or 16 bits grayscale
430 		(*msg) = _("Image converted to 16 bits B&W without alpha under a new name");
431 		(*fname_tochoose) = TRUE;
432 		img_buf = remove_alpha_from_grey (img_buf, width, height, depth);
433 		if (!img_buf) {
434 			(*msg) = _("Not able to convert this image to B&W");
435 			return NULL;
436 		}
437 	}
438 	if (depth!=16) {
439 		(*msg) = _("8 bits image converted to 16 bits under a new name");
440 		(*fname_tochoose) = TRUE;
441 //		We suppose weird depths (1, 2, 4...) are already converted in read_png
442 		img_buf = expand_8_to_16(img_buf, width, height);
443 	}
444 	if (nbkeys && comments) {
445 		tmp = setlocale(LC_NUMERIC,NULL); // Standardize on "." as a decimal separator
446 		loc = (gchar *) malloc(strlen(tmp)+1);
447 		strcpy(loc,tmp);
448 		setlocale(LC_NUMERIC,"C");
449 		for (i=0; i<nbkeys; i++) {
450  // printf("KEY: %s; TEXT: %s\n",comments[i].key, comments[i].text);
451 			if (!strcmp(comments[i].key,"Tiling")) {
452 				if (!strcmp(comments[i].text,"Y"))
453 					tiling = TRUE;
454 			}
455 			if (!strcmp(comments[i].key,"Use water")) {
456 				if (!strcmp(comments[i].text,"Y"))
457 					use_water = TRUE;
458 			}
459 			if (!strcmp(comments[i].key,"Water level")) {
460 //				printf("sscanf (comments[i].text, , water_level)");
461 				sscanf (comments[i].text, "%f", &water_level);
462 // 				printf("Water level in HF_READ: %6.3f\n",water_level);
463 			}
464 			else if (!strcmp(comments[i].key,"CAMERA1"))
465 				sscanf_camera (comments[i].text,0);
466 			else if (!strcmp(comments[i].key,"CAMERA2"))
467 				sscanf_camera (comments[i].text,1);
468 			else if (!strcmp(comments[i].key,"CAMERA3"))
469 				sscanf_camera (comments[i].text,2);
470 			else if (!strcmp(comments[i].key,"CAMERA4"))
471 				sscanf_camera (comments[i].text,3);
472 			else if (!strcmp(comments[i].key,"CAMERA5"))
473 				sscanf_camera (comments[i].text,4);
474 		} // enf for
475 		setlocale(LC_NUMERIC,loc);
476 		free(loc);
477 		free_png_text(&comments,nbkeys);
478 	} // end if (nbkeys...)
479 	return hf_create((hf_type *) img_buf, width, tiling, tiling_ptr, use_water, water_level);
480 }
481 
hf_new(gint hfsize)482 gpointer hf_new(gint hfsize) {
483 //	Creates and initializes an HF with default values
484 //	The image data is not known
485 // 	We presume we are generating a new (tiling) HF
486 	hf_struct_type *hf;
487 	hf = (hf_struct_type *) hf_create(NULL, hfsize, TRUE, NULL, TRUE, DEFAULT_WATER_LEVEL);
488 	return hf;
489 }
490 
hf_set_tiling_ptr(hf_struct_type * hf,gboolean * tiling_ptr)491 void hf_set_tiling_ptr (hf_struct_type *hf, gboolean *tiling_ptr) {
492 	hf->if_tiles = tiling_ptr;
493 }
494 
hf_init_layer(hf_struct_type * hf)495 void hf_init_layer (hf_struct_type *hf) {
496 	if (hf->layer_buf)
497 		x_free (hf->layer_buf);
498 	hf->layer_buf = (hf_type *) x_calloc(hf->max_x*hf->max_y, sizeof(hf_type), "hf_type (hf->layer_buf)");
499 	hf->if_layer = TRUE;
500 }
501 
hf_cancel_layer(hf_struct_type * hf)502 void hf_cancel_layer (hf_struct_type *hf) {
503 	hf->if_layer = FALSE;
504 	if (hf->layer_buf)
505 		x_free (hf->layer_buf);
506 	hf->layer_buf = NULL;
507 }
508 
hf_init_result_buf_from_hf(hf_struct_type * hf)509 void hf_init_result_buf_from_hf (hf_struct_type *hf) {
510 	if (!hf->result_buf)
511 		hf->result_buf =
512 			(hf_type *) x_malloc(sizeof(hf_type) * hf->max_x  * hf->max_y, "hf_type (hf->result_buf)");
513 	memcpy(hf->result_buf, hf->hf_buf, sizeof(hf_type) * hf->max_x  * hf->max_y);
514 }
515 
hf_init_tmp2_buf_from_hf(hf_struct_type * hf)516 void hf_init_tmp2_buf_from_hf (hf_struct_type *hf) {
517 	if (!hf->tmp2_buf)
518 		hf->tmp2_buf =
519 			(hf_type *) x_malloc(sizeof(hf_type) * hf->max_x  * hf->max_y, "hf_type (hf->tmp2_buf)");
520 	memcpy(hf->tmp2_buf, hf->hf_buf, sizeof(hf_type) * hf->max_x  * hf->max_y);
521 }
522 
hf_update_hf_with_layer(hf_struct_type * hf,gint merge_op)523 void hf_update_hf_with_layer (hf_struct_type *hf, gint merge_op) {
524 	gint i;
525 	if (!hf->layer_buf)
526 		return;
527 	if (!hf->tmp2_buf)
528 		return;
529 	if (!hf->hf_buf)
530 		return;
531 	mrg.merge_op = merge_op;
532 	mrg.mix = 0;
533 	mrg.source_offset = 100;
534 	mrg.result_offset = 100;
535 	set_merge_buffers (&mrg, hf->tmp2_buf, hf->layer_buf, hf->hf_buf, hf->max_x, hf->max_y);
536 	simple_merge (&mrg);
537 }
538 
hf_copy_new(hf_struct_type * hf,gboolean flag_swap)539 hf_struct_type *hf_copy_new(hf_struct_type *hf, gboolean flag_swap) {
540 //	Copy a hf_struct onto a newly allocated hf_struct,
541 //	for instance for undo / redo purpose
542 	hf_struct_type *hfcopy;
543 	hfcopy = (hf_struct_type *) x_malloc(sizeof(hf_struct_type), "hf_struct_type (hfcopy)");
544 //	printf("HF_COPY, de %p sur MALLOC: %p; flag_swap: %d\n",hf, hfcopy, flag_swap);
545 	memcpy(hfcopy, hf, sizeof(hf_struct_type));
546 	hfcopy->hf_buf = (hf_type *) x_malloc(hf->max_x*hf->max_y*sizeof(hf_type), "hf_type (hfcopy->hf_buf)");
547 	memcpy(hfcopy->hf_buf, hf->hf_buf, hf->max_x*hf->max_y*sizeof(hf_type));
548 	//	We swap buffers when the copy is intended for use for UNDO
549 	// 	because the data pointers are usually in use in some dialog - they should not vary
550 	//	When the copy does not replace an existing HF, usually flag_swap
551 	//	should be FALSE, or for the REDO operation
552 	//	See hf_wrapper_copy in hf_wrapper.c
553 //	printf("De hf->hf_buf: %p sur hfcopy->hf_buf: %p; flag_swap: %d\n",hf->hf_buf, hfcopy->hf_buf, flag_swap );
554 	if (flag_swap)
555 		swap_buffers((gpointer *)&hfcopy->hf_buf, (gpointer *)&hf->hf_buf);
556 //	printf("De hf->hf_buf: %p sur hfcopy->hf_buf: %p; flag_swap: %d\n",hf->hf_buf, hfcopy->hf_buf, flag_swap );
557 	if (hf->tmp_buf) {
558 		hfcopy->tmp_buf = (hf_type *)x_malloc(hf->max_x*hf->max_y*sizeof(hf_type), "hf_type (hfcopy->tmp_buf)");
559 		memcpy(hfcopy->tmp_buf, hf->tmp_buf, hf->max_x*hf->max_y*sizeof(hf_type));
560 		if (flag_swap)
561 			swap_buffers((gpointer *)&hfcopy->tmp_buf, (gpointer *)&hf->tmp_buf);
562 	}
563 	if (hf->result_buf) {
564 		hfcopy->result_buf = (hf_type *)x_malloc(hf->max_x*hf->max_y*sizeof(hf_type), "hf_type (hfcopy->result_buf)");
565 		memcpy(hfcopy->result_buf, hf->result_buf, hf->max_x*hf->max_y*sizeof(hf_type));
566 		if (flag_swap)
567 			swap_buffers((gpointer *)&hfcopy->result_buf, (gpointer *)&hf->result_buf);
568 	}
569 	if (hf->tmp2_buf) {
570 		hfcopy->tmp2_buf = (hf_type *)x_malloc(hf->max_x*hf->max_y*sizeof(hf_type), "hf_type (hfcopy->tmp2_buf)");
571 		memcpy(hfcopy->tmp2_buf, hf->tmp2_buf, hf->max_x*hf->max_y*sizeof(hf_type));
572 		if (flag_swap)
573 			swap_buffers((gpointer *)&hfcopy->tmp2_buf, (gpointer *)&hf->tmp2_buf);
574 	}
575 	// select_buf is not required
576 	hfcopy->select_buf = NULL;
577 	// layer_buf is not required as well
578 	hfcopy->layer_buf = NULL;
579 	hfcopy->if_layer = FALSE;
580 	return hfcopy;
581 }
582 
hf_backup(hf_struct_type * hf)583 void hf_backup(hf_struct_type *hf) {
584 //	Backup the main buffer into a temporary one
585 	if (!hf->tmp_buf)
586 		hf->tmp_buf = (hf_type *)x_malloc(hf->max_x*hf->max_y*sizeof(hf_type), "hf_type (hf->tmp_buf in hf_backup)");
587 // printf("HF_BACKUP de %p sur %p\n",hf->hf_buf,hf->tmp_buf);
588 	memcpy(hf->tmp_buf, hf->hf_buf, hf->max_x*hf->max_y*sizeof(hf_type));
589 	// For consistency, between computations, hf_buf should == result_buf
590 	if (hf->result_buf)
591 		memcpy(hf->result_buf, hf->hf_buf, hf->max_x*hf->max_y*sizeof(hf_type));
592 	hf_min_max (hf);
593 }
594 
hf_restore(hf_struct_type * hf)595 void hf_restore(hf_struct_type *hf) {
596 	// Opposite of hf_backup...
597 // printf("HF_RESTORE de %d sur %d\n", hf->tmp_buf, hf->hf_buf);
598 	if (hf->tmp_buf)
599 		memcpy(hf->hf_buf, hf->tmp_buf, hf->max_x*hf->max_y*sizeof(hf_type));
600 	// Here result_buf should be the same as hf_buf - restore also cancel the last computation
601 	if (hf->result_buf)
602 		memcpy(hf->result_buf, hf->hf_buf, hf->max_x*hf->max_y*sizeof(hf_type));
603 }
604 
hf_free(hf_struct_type * hf)605 void hf_free(hf_struct_type *hf) {
606 //	printf("HF_FREE de %p\n",hf);
607 	if (!hf) return;
608 	if (hf->hf_buf) {
609 		x_free(hf->hf_buf);
610 	}
611 	if (hf->tmp_buf) {
612 		x_free(hf->tmp_buf);
613 	}
614 	if (hf->tmp2_buf) {
615 		x_free(hf->tmp2_buf);
616 	}
617 	if (hf->result_buf) {
618 		x_free(hf->result_buf);
619 	}
620 	if (hf->select_buf) {
621 		x_free(hf->select_buf);
622 	}
623 	if (hf->layer_buf) {
624 		x_free(hf->layer_buf);
625 	}
626 	x_free(hf);
627 }
628 
hf_reset_buffer(hf_type * hf,gint maxx,gint maxy)629 void hf_reset_buffer (hf_type *hf, gint maxx, gint maxy) {
630 	// Resets HF to 0
631 	gint x,y;
632 	if (!hf)
633 		return;
634 	for (x=0; x<maxx; x++) {
635 		for (y=0; y<maxy; y++)
636 			*(hf+x+y*maxx) = 0;
637 	}
638 }
639 
hf_min_max(hf_struct_type * hf)640 void hf_min_max (hf_struct_type *hf) {
641 //	Refreshes the MIN, MAX. AVRG values of  the 16 bit greyscale buffer
642 	gint i;
643 	gfloat counter = 0.0;
644 	hf->min = *hf->hf_buf;
645 	hf->max = hf->min;
646 //	printf("HF_MIN_MAX_AVRG\n");
647 	for (i=0; i<hf->max_x*hf->max_y; i++) {
648 		if (hf->min>*(hf->hf_buf+i) )
649 			hf->min = *(hf->hf_buf+i);
650 		else
651 			if (hf->max<*(hf->hf_buf+i))
652 				hf->max = *(hf->hf_buf+i);
653 		counter += (gfloat) *(hf->hf_buf+i);
654 	}
655 	hf->avrg = (hf_type) (counter / i);
656 //	printf("Min: %d; Max: %d\n",hf->min,hf->max);
657 }
658 
659