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