Removed trailing whitespaces
[liblqr.git] / lqr / lqr_carver.c
blob044d5b778447ed1ff90f72fa67b32108d0b06543
1 /* LiquidRescaling Library
2 * Copyright (C) 2007-2009 Carlo Baldassi (the "Author") <carlobaldassi@gmail.com>.
3 * All Rights Reserved.
5 * This library implements the algorithm described in the paper
6 * "Seam Carving for Content-Aware Image Resizing"
7 * by Shai Avidan and Ariel Shamir
8 * which can be found at http://www.faculty.idc.ac.il/arik/imret.pdf
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; version 3 dated June, 2007.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, see <http://www.gnu.org/licenses/>
23 #include <math.h>
25 #include <lqr/lqr_all.h>
27 #ifdef __LQR_VERBOSE__
28 #include <stdio.h>
29 #endif /* __LQR_VERBOSE__ */
31 #ifdef __LQR_DEBUG__
32 #include <stdio.h>
33 #include <assert.h>
34 #endif /* __LQR_DEBUG__ */
36 /**** LQR_CARVER CLASS FUNCTIONS ****/
38 /*** constructor & destructor ***/
40 /* constructors */
41 LqrCarver * lqr_carver_new_common (gint width, gint height, gint channels)
43 LqrCarver *r;
45 TRY_N_N (r = g_try_new (LqrCarver, 1));
47 g_atomic_int_set(&r->state, LQR_CARVER_STATE_STD);
48 g_atomic_int_set(&r->state_lock, 0);
49 g_atomic_int_set(&r->state_lock_queue, 0);
51 r->level = 1;
52 r->max_level = 1;
53 r->transposed = 0;
54 r->active = FALSE;
55 r->root = NULL;
56 r->rigidity = 0;
57 r->resize_aux_layers = FALSE;
58 r->dump_vmaps = FALSE;
59 r->resize_order = LQR_RES_ORDER_HOR;
60 r->attached_list = NULL;
61 r->flushed_vs = NULL;
62 r->preserve_in_buffer = FALSE;
63 TRY_N_N (r->progress = lqr_progress_new());
65 r->en = NULL;
66 r->bias = NULL;
67 r->m = NULL;
68 r->least = NULL;
69 r->_raw = NULL;
70 r->raw = NULL;
71 r->vpath = NULL;
72 r->vpath_x = NULL;
73 r->rigidity_map = NULL;
74 r->rigidity_mask = NULL;
75 r->delta_x = 1;
77 r->h = height;
78 r->w = width;
79 r->channels = channels;
81 r->w0 = r->w;
82 r->h0 = r->h;
83 r->w_start = r->w;
84 r->h_start = r->h;
86 r->rcache = NULL;
87 r->use_rcache = TRUE;
89 r->rwindow = NULL;
90 lqr_carver_set_energy_function_builtin(r, LQR_EF_GRAD_XABS);
91 r->nrg_xmin = NULL;
92 r->nrg_xmax = NULL;
94 r->leftright = 0;
95 r->lr_switch_frequency = 0;
97 r->enl_step = 2.0;
99 TRY_N_N (r->vs = g_try_new0 (gint, r->w * r->h));
101 /* initialize cursor */
103 TRY_N_N (r->c = lqr_cursor_create (r));
105 switch (channels)
107 case 1:
108 lqr_carver_set_image_type (r, LQR_GREY_IMAGE);
109 break;
110 case 2:
111 lqr_carver_set_image_type (r, LQR_GREYA_IMAGE);
112 break;
113 case 3:
114 lqr_carver_set_image_type (r, LQR_RGB_IMAGE);
115 break;
116 case 4:
117 lqr_carver_set_image_type (r, LQR_RGBA_IMAGE);
118 break;
119 case 5:
120 lqr_carver_set_image_type (r, LQR_CMYKA_IMAGE);
121 break;
122 default:
123 lqr_carver_set_image_type (r, LQR_CUSTOM_IMAGE);
124 break;
127 return r;
130 LQR_PUBLIC
131 LqrCarver *
132 lqr_carver_new (guchar * buffer, gint width, gint height, gint channels)
134 return lqr_carver_new_ext (buffer, width, height, channels, LQR_COLDEPTH_8I);
137 LQR_PUBLIC
138 LqrCarver *
139 lqr_carver_new_ext (void * buffer, gint width, gint height, gint channels, LqrColDepth colour_depth)
141 LqrCarver *r;
143 TRY_N_N (r = lqr_carver_new_common (width, height, channels));
145 r->rgb = (void*) buffer;
147 BUF_TRY_NEW_RET_POINTER(r->rgb_ro_buffer, r->channels * r->w, colour_depth);
149 r->col_depth = colour_depth;
151 return r;
154 /* destructor */
155 LQR_PUBLIC
156 void
157 lqr_carver_destroy (LqrCarver * r)
159 if (!r->preserve_in_buffer)
161 g_free (r->rgb);
163 if (r->root == NULL)
165 g_free (r->vs);
167 g_free (r->en);
168 g_free (r->bias);
169 g_free (r->m);
170 g_free (r->rcache);
171 g_free (r->least);
172 lqr_cursor_destroy (r->c);
173 g_free (r->vpath);
174 g_free (r->vpath_x);
175 if (r->rigidity_map != NULL)
177 r->rigidity_map -= r->delta_x;
178 g_free (r->rigidity_map);
180 g_free (r->rigidity_mask);
181 lqr_rwindow_destroy (r->rwindow);
182 g_free (r->nrg_xmin);
183 g_free (r->nrg_xmax);
184 lqr_vmap_list_destroy(r->flushed_vs);
185 lqr_carver_list_destroy(r->attached_list);
186 g_free (r->progress);
187 g_free (r->_raw);
188 g_free (r->raw);
189 g_free (r);
192 /*** initialization ***/
194 LQR_PUBLIC
195 LqrRetVal
196 lqr_carver_init (LqrCarver *r, gint delta_x, gfloat rigidity)
198 gint y, x;
200 CATCH_CANC (r);
202 CATCH_F (r->active == FALSE);
204 CATCH_MEM (r->en = g_try_new (gfloat, r->w * r->h));
205 CATCH_MEM (r->bias = g_try_new0 (gfloat, r->w * r->h));
206 CATCH_MEM (r->m = g_try_new (gfloat, r->w * r->h));
207 CATCH_MEM (r->least = g_try_new (gint, r->w * r->h));
209 CATCH_MEM (r->_raw = g_try_new (gint, r->h_start * r->w_start));
210 CATCH_MEM (r->raw = g_try_new (gint *, r->h_start));
212 for (y = 0; y < r->h; y++)
214 r->raw[y] = r->_raw + y * r->w_start;
215 for (x = 0; x < r->w_start; x++)
217 r->raw[y][x] = y * r->w_start + x;
221 CATCH_MEM (r->vpath = g_try_new (gint, r->h));
222 CATCH_MEM (r->vpath_x = g_try_new (gint, r->h));
224 CATCH_MEM (r->nrg_xmin = g_try_new (gint, r->h));
225 CATCH_MEM (r->nrg_xmax = g_try_new (gint, r->h));
227 /* set rigidity map */
228 r->delta_x = delta_x;
229 r->rigidity = rigidity;
231 r->rigidity_map = g_try_new0 (gfloat, 2 * r->delta_x + 1);
232 r->rigidity_map += r->delta_x;
233 for (x = -r->delta_x; x <= r->delta_x; x++)
235 r->rigidity_map[x] =
236 r->rigidity * powf(fabsf(x), 1.5) / r->h;
239 r->active = TRUE;
241 return LQR_OK;
244 /*** set attributes ***/
246 LQR_PUBLIC
247 LqrRetVal
248 lqr_carver_set_image_type (LqrCarver * r, LqrImageType image_type)
250 CATCH_CANC (r);
252 switch (image_type) {
253 case LQR_GREY_IMAGE:
254 if (r->channels != 1) {
255 return LQR_ERROR;
257 r->alpha_channel = -1;
258 r->black_channel = -1;
259 break;
260 case LQR_GREYA_IMAGE:
261 if (r->channels != 2)
263 return LQR_ERROR;
265 r->alpha_channel = 1;
266 r->black_channel = -1;
267 break;
268 case LQR_CMY_IMAGE:
269 case LQR_RGB_IMAGE:
270 if (r->channels != 3)
272 return LQR_ERROR;
274 r->alpha_channel = -1;
275 r->black_channel = -1;
276 break;
277 case LQR_CMYK_IMAGE:
278 if (r->channels != 4)
280 return LQR_ERROR;
282 r->alpha_channel = -1;
283 r->black_channel = 3;
284 break;
285 case LQR_RGBA_IMAGE:
286 if (r->channels != 4)
288 return LQR_ERROR;
290 r->alpha_channel = 3;
291 r->black_channel = -1;
292 break;
293 case LQR_CMYKA_IMAGE:
294 if (r->channels != 5)
296 return LQR_ERROR;
298 r->alpha_channel = 4;
299 r->black_channel = 3;
300 break;
301 case LQR_CUSTOM_IMAGE:
302 r->alpha_channel = r->channels - 1;
303 r->black_channel = -1;
304 break;
305 default:
306 return LQR_ERROR;
308 r->image_type = image_type;
310 return LQR_OK;
313 LQR_PUBLIC
314 LqrRetVal
315 lqr_carver_set_alpha_channel (LqrCarver * r, gint channel_index)
317 CATCH_CANC (r);
319 if (channel_index < 0) {
320 r->alpha_channel = -1;
321 } else if (channel_index < r->channels) {
322 r->alpha_channel = channel_index;
323 } else {
324 return LQR_ERROR;
326 r->image_type = LQR_CUSTOM_IMAGE;
327 return LQR_OK;
330 LQR_PUBLIC
331 LqrRetVal
332 lqr_carver_set_black_channel (LqrCarver * r, gint channel_index)
334 CATCH_CANC (r);
336 if (channel_index < 0) {
337 r->black_channel = -1;
338 } else if (channel_index < r->channels) {
339 r->black_channel = channel_index;
340 } else {
341 return LQR_ERROR;
343 r->image_type = LQR_CUSTOM_IMAGE;
344 return LQR_OK;
347 /* set gradient function */
348 /* WARNING: THIS FUNCTION IS ONLY MAINTAINED FOR BACK-COMPATIBILITY PURPOSES */
349 /* lqr_carver_set_energy_function_builtin() should be used in newly written code instead */
350 LQR_PUBLIC
351 void
352 lqr_carver_set_gradient_function (LqrCarver * r, LqrGradFuncType gf_ind)
354 switch (gf_ind)
356 case LQR_GF_NORM:
357 lqr_carver_set_energy_function_builtin(r, LQR_EF_GRAD_NORM);
358 break;
359 case LQR_GF_SUMABS:
360 lqr_carver_set_energy_function_builtin(r, LQR_EF_GRAD_SUMABS);
361 break;
362 case LQR_GF_XABS:
363 lqr_carver_set_energy_function_builtin(r, LQR_EF_GRAD_XABS);
364 break;
365 case LQR_GF_NULL:
366 lqr_carver_set_energy_function_builtin(r, LQR_EF_NULL);
367 break;
368 case LQR_GF_NORM_BIAS:
369 case LQR_GF_YABS:
370 lqr_carver_set_energy_function_builtin(r, LQR_EF_NULL);
371 break;
372 #ifdef __LQR_DEBUG__
373 default:
374 assert (0);
375 #endif /* __LQR_DEBUG__ */
379 /* attach carvers to be scaled along with the main one */
380 LQR_PUBLIC
381 LqrRetVal
382 lqr_carver_attach (LqrCarver * r, LqrCarver * aux)
384 CATCH_F (r->w0 == aux->w0);
385 CATCH_F (r->h0 == aux->h0);
386 CATCH_F (g_atomic_int_get(&r->state) == LQR_CARVER_STATE_STD);
387 CATCH_F (g_atomic_int_get(&aux->state) == LQR_CARVER_STATE_STD);
388 CATCH_MEM (r->attached_list = lqr_carver_list_append (r->attached_list, aux));
389 g_free(aux->vs);
390 aux->vs = r->vs;
391 aux->root = r;
393 return LQR_OK;
396 /* set the seam output flag */
397 LQR_PUBLIC
398 void
399 lqr_carver_set_dump_vmaps (LqrCarver *r)
401 r->dump_vmaps = TRUE;
404 /* unset the seam output flag */
405 LQR_PUBLIC
406 void
407 lqr_carver_set_no_dump_vmaps (LqrCarver *r)
409 r->dump_vmaps = FALSE;
412 /* set order if rescaling in both directions */
413 LQR_PUBLIC
414 void
415 lqr_carver_set_resize_order (LqrCarver *r, LqrResizeOrder resize_order)
417 r->resize_order = resize_order;
420 /* set leftright switch interval */
421 LQR_PUBLIC
422 void
423 lqr_carver_set_side_switch_frequency (LqrCarver *r, guint switch_frequency)
425 r->lr_switch_frequency = switch_frequency;
428 /* set enlargement step */
429 LQR_PUBLIC
430 LqrRetVal
431 lqr_carver_set_enl_step (LqrCarver *r, gfloat enl_step)
433 CATCH_F ((enl_step > 1) && (enl_step <= 2));
434 CATCH_CANC (r);
435 r->enl_step = enl_step;
436 return LQR_OK;
439 LQR_PUBLIC
440 void
441 lqr_carver_set_use_cache (LqrCarver *r, gboolean use_cache)
443 if (!use_cache)
445 g_free(r->rcache);
446 r->rcache = NULL;
448 r->use_rcache = use_cache;
449 r->rwindow->use_rcache = use_cache;
452 /* set progress reprot */
453 LQR_PUBLIC
454 void
455 lqr_carver_set_progress (LqrCarver *r, LqrProgress *p)
457 g_free(r->progress);
458 r->progress = p;
461 /* flag the input buffer to avoid destruction */
462 LQR_PUBLIC
463 void
464 lqr_carver_set_preserve_input_image(LqrCarver *r)
466 r->preserve_in_buffer = TRUE;
470 /*** compute maps (energy, minpath & visibility) ***/
472 /* build multisize image up to given depth
473 * it is progressive (can be called multilple times) */
474 LqrRetVal
475 lqr_carver_build_maps (LqrCarver * r, gint depth)
477 #ifdef __LQR_DEBUG__
478 assert (depth <= r->w_start);
479 assert (depth >= 1);
480 #endif /* __LQR_DEBUG__ */
482 CATCH_CANC (r);
484 /* only go deeper if needed */
485 if (depth > r->max_level)
487 CATCH_F (r->active);
488 CATCH_F (r->root == NULL);
490 /* set to minimum width reached so far */
491 lqr_carver_set_width (r, r->w_start - r->max_level + 1);
493 /* compute energy & minpath maps */
494 CATCH (lqr_carver_build_emap (r));
495 CATCH (lqr_carver_build_mmap (r));
497 /* compute visibility map */
498 CATCH (lqr_carver_build_vsmap (r, depth));
500 return LQR_OK;
503 /* compute energy map */
504 LqrRetVal
505 lqr_carver_build_emap (LqrCarver * r)
507 gint x, y;
509 CATCH_CANC(r);
511 if (r->use_rcache && r->rcache == NULL)
513 CATCH_MEM (r->rcache = lqr_carver_generate_rcache (r));
516 for (y = 0; y < r->h; y++)
518 CATCH_CANC(r);
519 for (x = 0; x < r->w; x++)
521 CATCH (lqr_carver_compute_e(r, x, y));
525 return LQR_OK;
528 LqrRetVal
529 lqr_carver_compute_e (LqrCarver * r, gint x, gint y)
531 gint data;
533 /* removed CANC check for performance reasons */
534 /* CATCH_CANC (r); */
536 data = r->raw[y][x];
538 CATCH (lqr_rwindow_fill (r->rwindow, r, x, y));
539 r->en[data] = r->nrg(x, y, r->w, r->h, r->rwindow, r->nrg_extra_data) + r->bias[data] / r->w_start;
541 return LQR_OK;
544 /* compute auxiliary minpath map
545 * defined as
546 * y = 1 : m(x,y) = e(x,y)
547 * y > 1 : m(x,y) = min_{x'=-dx,..,dx} ( m(x-x',y-1) + rig(x') ) + e(x,y)
548 * where
549 * e(x,y) is the energy at point (x,y)
550 * dx is the max seam step delta_x
551 * rig(x') is the rigidity for step x'
553 LqrRetVal
554 lqr_carver_build_mmap (LqrCarver * r)
556 gint x, y;
557 gint data;
558 gint data_down;
559 gint x1_min, x1_max, x1;
560 gfloat m, m1, r_fact;
563 CATCH_CANC(r);
565 /* span first row */
566 for (x = 0; x < r->w; x++)
568 data = r->raw[0][x];
569 #ifdef __LQR_DEBUG__
570 assert (r->vs[data] == 0);
571 #endif /* __LQR_DEBUG__ */
572 r->m[data] = r->en[data];
575 /* span all other rows */
576 for (y = 1; y < r->h; y++)
578 for (x = 0; x < r->w; x++)
580 CATCH_CANC(r);
582 data = r->raw[y][x];
583 #ifdef __LQR_DEBUG__
584 assert (r->vs[data] == 0);
585 #endif /* __LQR_DEBUG__ */
586 /* watch for boundaries */
587 x1_min = MAX (-x, -r->delta_x);
588 x1_max = MIN (r->w - 1 - x, r->delta_x);
589 if (r->rigidity_mask) {
590 r_fact = r->rigidity_mask[data];
591 } else {
592 r_fact = 1;
595 /* we use the data_down pointer to be able to
596 * track the seams later (needed for rigidity) */
597 data_down = r->raw[y - 1][x + x1_min];
598 r->least[data] = data_down;
599 if (r->rigidity)
601 m = r->m[data_down] + r_fact * r->rigidity_map[x1_min];
602 for (x1 = x1_min + 1; x1 <= x1_max; x1++)
604 data_down = r->raw[y - 1][x + x1];
605 /* find the min among the neighbors
606 * in the last row */
607 m1 = r->m[data_down] + r_fact * r->rigidity_map[x1];
608 if ((m1 < m) || ((m1 == m) && (r->leftright == 1)))
610 m = m1;
611 r->least[data] = data_down;
613 /* m = MIN(m, r->m[data_down] + r->rigidity_map[x1]); */
616 else
618 m = r->m[data_down];
619 for (x1 = x1_min + 1; x1 <= x1_max; x1++)
621 data_down = r->raw[y - 1][x + x1];
622 /* find the min among the neighbors
623 * in the last row */
624 m1 = r->m[data_down];
625 if ((m1 < m) || ((m1 == m) && (r->leftright == 1)))
627 m = m1;
628 r->least[data] = data_down;
630 m = MIN (m, r->m[data_down]);
634 /* set current m */
635 r->m[data] = r->en[data] + m;
638 return LQR_OK;
641 /* compute (vertical) visibility map up to given depth
642 * (it also calls inflate() to add image enlargment information) */
643 LqrRetVal
644 lqr_carver_build_vsmap (LqrCarver * r, gint depth)
646 gint l;
647 gint update_step;
648 gint lr_switch_interval = 0;
649 LqrDataTok data_tok;
651 #ifdef __LQR_VERBOSE__
652 printf ("[ building visibility map ]\n");
653 fflush (stdout);
654 #endif /* __LQR_VERBOSE__ */
657 #ifdef __LQR_DEBUG__
658 assert (depth <= r->w_start + 1);
659 assert (depth >= 1);
660 #endif /* __LQR_DEBUG__ */
662 /* default behaviour : compute all possible levels
663 * (complete map) */
664 if (depth == 0)
666 depth = r->w_start + 1;
669 /* here we assume that
670 * lqr_carver_set_width(w_start - max_level + 1);
671 * has been given */
673 /* update step for progress reprt*/
674 update_step = (gint) MAX ((depth - r->max_level) * r->progress->update_step, 1);
676 /* left-right switch interval */
677 if (r->lr_switch_frequency)
679 lr_switch_interval = (depth - r->max_level - 1) / r->lr_switch_frequency + 1;
682 /* cycle over levels */
683 for (l = r->max_level; l < depth; l++)
685 CATCH_CANC(r);
687 if ((l - r->max_level) % update_step == 0)
689 lqr_progress_update (r->progress, (gdouble) (l - r->max_level) /
690 (gdouble) (depth - r->max_level));
693 #ifdef __LQR_DEBUG__
694 /* check raw rows */
695 lqr_carver_debug_check_rows (r);
696 #endif /* __LQR_DEBUG__ */
698 /* compute vertical seam */
699 lqr_carver_build_vpath (r);
701 /* update visibility map
702 * (assign level to the seam) */
703 lqr_carver_update_vsmap (r, l + r->max_level - 1);
705 /* increase (in)visibility level
706 * (make the last seam invisible) */
707 r->level++;
708 r->w--;
710 /* update raw data */
711 lqr_carver_carve (r);
713 if (r->w > 1)
715 /* update the energy */
716 /* CATCH (lqr_carver_build_emap (r)); */
717 CATCH (lqr_carver_update_emap (r));
719 if (r->nrg_builtin_flag)
721 /* recalculate the minpath map */
722 if ((r->lr_switch_frequency) && (((l - r->max_level + lr_switch_interval / 2) % lr_switch_interval) == 0))
724 r->leftright ^= 1;
725 CATCH (lqr_carver_build_mmap (r));
727 else
729 /* lqr_carver_build_mmap (r); */
730 CATCH (lqr_carver_update_mmap (r));
732 } else {
733 if ((r->lr_switch_frequency) && (((l - r->max_level + lr_switch_interval / 2) % lr_switch_interval) == 0))
735 r->leftright ^= 1;
737 CATCH (lqr_carver_build_mmap (r));
740 else
742 /* complete the map (last seam) */
743 lqr_carver_finish_vsmap (r);
747 /* insert seams for image enlargement */
748 CATCH (lqr_carver_inflate (r, depth - 1));
750 /* reset image size */
751 lqr_carver_set_width (r, r->w_start);
752 /* repeat for auxiliary layers */
753 data_tok.integer = r->w_start;
754 CATCH (lqr_carver_list_foreach_recursive (r->attached_list, lqr_carver_set_width_attached, data_tok));
756 #ifdef __LQR_VERBOSE__
757 printf ("[ visibility map OK ]\n");
758 fflush (stdout);
759 #endif /* __LQR_VERBOSE__ */
761 return LQR_OK;
764 /* enlarge the image by seam insertion
765 * visibility map is updated and the resulting multisize image
766 * is complete in both directions */
767 LqrRetVal
768 lqr_carver_inflate (LqrCarver * r, gint l)
770 gint w1, z0, vs, k;
771 gint x, y;
772 gint c_left;
773 void *new_rgb = NULL;
774 gint *new_vs = NULL;
775 gdouble tmp_rgb;
776 gfloat *new_bias = NULL;
777 gfloat *new_rigmask = NULL;
778 LqrDataTok data_tok;
779 LqrCarverState prev_state = LQR_CARVER_STATE_STD;
781 #ifdef __LQR_VERBOSE__
782 printf (" [ inflating (active=%i) ]\n", r->active);
783 fflush (stdout);
784 #endif /* __LQR_VERBOSE__ */
786 #ifdef __LQR_DEBUG__
787 assert (l + 1 > r->max_level); /* otherwise is useless */
788 #endif /* __LQR_DEBUG__ */
790 CATCH_CANC (r);
792 if (r->root == NULL)
794 prev_state = g_atomic_int_get(&r->state);
795 CATCH (lqr_carver_set_state(r, LQR_CARVER_STATE_INFLATING, TRUE));
798 /* first iterate on attached carvers */
799 data_tok.integer = l;
800 CATCH (lqr_carver_list_foreach (r->attached_list, lqr_carver_inflate_attached, data_tok));
802 /* scale to current maximum size
803 * (this is the original size the first time) */
804 lqr_carver_set_width (r, r->w0);
806 /* final width */
807 w1 = r->w0 + l - r->max_level + 1;
809 /* allocate room for new maps */
810 BUF_TRY_NEW0_RET_LQR(new_rgb, w1 * r->h0 * r->channels, r->col_depth);
812 if (r->root == NULL)
814 CATCH_MEM (new_vs = g_try_new0 (gint, w1 * r->h0));
816 if (r->active)
818 CATCH_MEM (new_bias = g_try_new0 (gfloat, w1 * r->h0));
819 if (r->rigidity_mask)
821 CATCH_MEM (new_rigmask = g_try_new (gfloat, w1 * r->h0));
825 /* span the image with a cursor
826 * and build the new image */
827 lqr_cursor_reset (r->c);
828 x = 0;
829 y = 0;
830 for (z0 = 0; z0 < w1 * r->h0; z0++, lqr_cursor_next (r->c))
833 CATCH_CANC (r);
835 /* read visibility */
836 vs = r->vs[r->c->now];
837 if ((vs != 0) && (vs <= l + r->max_level - 1)
838 && (vs >= 2 * r->max_level - 1))
840 /* the point belongs to a previously computed seam
841 * and was not inserted during a previous
842 * inflate() call : insert another seam */
844 /* the new pixel value is equal to the average of its
845 * left and right neighbors */
847 if (r->c->x > 0)
849 c_left = lqr_cursor_left (r->c);
851 else
853 c_left = r->c->now;
856 for (k = 0; k < r->channels; k++)
858 switch (r->col_depth)
860 case LQR_COLDEPTH_8I:
861 tmp_rgb = (AS_8I(r->rgb)[c_left * r->channels + k] +
862 AS_8I(r->rgb)[r->c->now * r->channels + k]) / 2;
863 AS_8I(new_rgb)[z0 * r->channels + k] = (lqr_t_8i) (tmp_rgb + 0.499999);
864 break;
865 case LQR_COLDEPTH_16I:
866 tmp_rgb = (AS_16I(r->rgb)[c_left * r->channels + k] +
867 AS_16I(r->rgb)[r->c->now * r->channels + k]) / 2;
868 AS_16I(new_rgb)[z0 * r->channels + k] = (lqr_t_16i) (tmp_rgb + 0.499999);
869 break;
870 case LQR_COLDEPTH_32F:
871 tmp_rgb = (AS_32F(r->rgb)[c_left * r->channels + k] +
872 AS_32F(r->rgb)[r->c->now * r->channels + k]) / 2;
873 AS_32F(new_rgb)[z0 * r->channels + k] = (lqr_t_32f) tmp_rgb;
874 break;
875 case LQR_COLDEPTH_64F:
876 tmp_rgb = (AS_64F(r->rgb)[c_left * r->channels + k] +
877 AS_64F(r->rgb)[r->c->now * r->channels + k]) / 2;
878 AS_64F(new_rgb)[z0 * r->channels + k] = (lqr_t_64f) tmp_rgb;
879 break;
882 if (r->active)
884 new_bias[z0] = (r->bias[c_left] + r->bias[r->c->now]) / 2;
885 if (r->rigidity_mask)
887 new_rigmask[z0] = (r->rigidity_mask[c_left] + r->rigidity_mask[r->c->now]) / 2;
890 /* the first time inflate() is called
891 * the new visibility should be -vs + 1 but we shift it
892 * so that the final minimum visibiliy will be 1 again
893 * and so that vs=0 still means "uninitialized".
894 * Subsequent inflations account for that */
895 if (r->root == NULL)
897 new_vs[z0] = l - vs + r->max_level;
899 z0++;
901 for (k = 0; k < r->channels; k++)
903 PXL_COPY(new_rgb, z0 * r->channels + k, r->rgb, r->c->now * r->channels + k, r->col_depth);
905 if (r->active)
907 new_bias[z0] = r->bias[r->c->now];
908 if (r->rigidity_mask)
910 new_rigmask[z0] = r->rigidity_mask[r->c->now];
913 if (vs != 0)
915 /* visibility has to be shifted up */
916 if (r->root == NULL)
918 new_vs[z0] = vs + l - r->max_level + 1;
921 else if (r->raw != NULL)
923 #ifdef __LQR_DEBUG__
924 assert (y < r->h_start);
925 assert (x < r->w_start - l);
926 #endif /* __LQR_DEBUG__ */
927 r->raw[y][x] = z0;
928 x++;
929 if (x >= r->w_start - l)
931 x = 0;
932 y++;
937 #ifdef __LQR_DEBUG__
938 if (r->raw != NULL)
940 assert (x == 0);
941 if (w1 != 2 * r->w_start - 1)
943 assert ((y == r->h_start)
944 || (printf ("y=%i hst=%i w1=%i\n", y, r->h_start, w1)
945 && fflush (stdout) && 0));
948 #endif /* __LQR_DEBUG__ */
950 /* substitute maps */
951 if (!r->preserve_in_buffer)
953 g_free (r->rgb);
955 /* g_free (r->vs); */
956 g_free (r->en);
957 g_free (r->m);
958 g_free (r->rcache);
959 g_free (r->least);
960 g_free (r->bias);
961 g_free (r->rigidity_mask);
963 r->rcache = NULL;
965 r->rgb = new_rgb;
966 r->preserve_in_buffer = FALSE;
968 if (r->root == NULL)
970 g_free (r->vs);
971 r->vs = new_vs;
972 CATCH (lqr_carver_propagate_vsmap(r));
974 else
976 /* r->vs = NULL; */
978 if (r->active)
980 r->bias = new_bias;
981 r->rigidity_mask = new_rigmask;
982 CATCH_MEM (r->en = g_try_new0 (gfloat, w1 * r->h0));
983 CATCH_MEM (r->m = g_try_new0 (gfloat, w1 * r->h0));
984 CATCH_MEM (r->least = g_try_new0 (gint, w1 * r->h0));
987 /* set new widths & levels (w_start is kept for reference) */
988 r->level = l + 1;
989 r->max_level = l + 1;
990 r->w0 = w1;
991 r->w = r->w_start;
993 /* reset readout buffer */
994 g_free (r->rgb_ro_buffer);
995 BUF_TRY_NEW0_RET_LQR(r->rgb_ro_buffer, r->w0 * r->channels, r->col_depth);
997 #ifdef __LQR_VERBOSE__
998 printf (" [ inflating OK ]\n");
999 fflush (stdout);
1000 #endif /* __LQR_VERBOSE__ */
1002 if (r->root == NULL)
1004 CATCH (lqr_carver_set_state(r, prev_state, TRUE));
1007 return LQR_OK;
1010 LqrRetVal
1011 lqr_carver_inflate_attached (LqrCarver * r, LqrDataTok data)
1013 return lqr_carver_inflate (r, data.integer);
1017 /*** internal functions for maps computations ***/
1019 #if 0
1020 /* read average pixel value at x, y
1021 * for energy computation */
1022 inline gfloat
1023 lqr_carver_read (LqrCarver * r, gint x, gint y)
1025 gdouble sum = 0;
1026 gint k;
1027 gint now = r->raw[y][x];
1028 for (k = 0; k < r->channels; k++)
1030 switch (r->col_depth)
1032 case LQR_COLDEPTH_8I:
1033 sum += AS_8I(r->rgb)[now * r->channels + k];
1034 break;
1035 case LQR_COLDEPTH_16I:
1036 sum += AS_16I(r->rgb)[now * r->channels + k];
1037 break;
1038 case LQR_COLDEPTH_32F:
1039 sum += AS_32F(r->rgb)[now * r->channels + k];
1040 break;
1041 case LQR_COLDEPTH_64F:
1042 sum += AS_64F(r->rgb)[now * r->channels + k];
1043 break;
1046 switch (r->col_depth)
1048 case LQR_COLDEPTH_8I:
1049 sum /= (255 * r->channels);
1050 break;
1051 case LQR_COLDEPTH_16I:
1052 sum /= ((gdouble)(0xFFFF) * r->channels);
1053 break;
1054 case LQR_COLDEPTH_32F:
1055 case LQR_COLDEPTH_64F:
1056 sum /= r->channels;
1057 break;
1060 return sum;
1064 /* compute energy at x, y */
1065 void
1066 lqr_carver_compute_e (LqrCarver * r, gint x, gint y)
1068 gdouble gx, gy;
1069 gint data;
1071 if (y == 0)
1073 gy = lqr_carver_read (r, x, y + 1) - lqr_carver_read (r, x, y);
1075 else if (y < r->h - 1)
1077 gy =
1078 (lqr_carver_read (r, x, y + 1) - lqr_carver_read (r, x, y - 1)) / 2;
1080 else
1082 gy = lqr_carver_read (r, x, y) - lqr_carver_read (r, x, y - 1);
1085 if (x == 0)
1087 gx = lqr_carver_read (r, x + 1, y) - lqr_carver_read (r, x, y);
1089 else if (x < r->w - 1)
1091 gx =
1092 (lqr_carver_read (r, x + 1, y) - lqr_carver_read (r, x - 1, y)) / 2;
1094 else
1096 gx = lqr_carver_read (r, x, y) - lqr_carver_read (r, x - 1, y);
1098 data = r->raw[y][x];
1099 r->en[data] = (*(r->gf)) (gx, gy) + r->bias[data] / r->w_start;
1101 #endif
1103 /* do the carving
1104 * this actually carves the raw array,
1105 * which holds the indices to be used
1106 * in all the other maps */
1107 void
1108 lqr_carver_carve (LqrCarver * r)
1110 gint x, y;
1112 #ifdef __LQR_DEBUG__
1113 assert (r->root == NULL);
1114 #endif /* __LQR_DEBUG__ */
1116 for (y = 0; y < r->h_start; y++)
1118 #ifdef __LQR_DEBUG__
1119 assert (r->vs[r->raw[y][r->vpath_x[y]]] != 0);
1120 for (x = 0; x < r->vpath_x[y]; x++)
1122 assert (r->vs[r->raw[y][x]] == 0);
1124 #endif /* __LQR_DEBUG__ */
1125 for (x = r->vpath_x[y]; x < r->w; x++)
1127 r->raw[y][x] = r->raw[y][x + 1];
1128 #ifdef __LQR_DEBUG__
1129 assert (r->vs[r->raw[y][x]] == 0);
1130 #endif /* __LQR_DEBUG__ */
1136 /* update energy map after seam removal */
1137 LqrRetVal
1138 lqr_carver_update_emap (LqrCarver * r)
1140 gint x, y;
1141 gint x1, y1, y1_min, y1_max;
1143 if (r->use_rcache)
1145 CATCH_F (r->rcache != NULL);
1148 CATCH_CANC (r);
1150 for (y = 0; y < r->h; y++)
1152 /* note: here the vpath has already
1153 * been carved */
1154 x = r->vpath_x[y];
1155 r->nrg_xmin[y] = x;
1156 r->nrg_xmax[y] = x - 1;
1158 for (y = 0; y < r->h; y++)
1160 x = r->vpath_x[y];
1161 y1_min = MAX (y - r->nrg_radius, 0);
1162 y1_max = MIN (y + r->nrg_radius, r->h - 1);
1164 for (y1 = y1_min; y1 <= y1_max; y1++)
1166 r->nrg_xmin[y1] = MIN (r->nrg_xmin[y1], x - r->nrg_radius);
1167 r->nrg_xmin[y1] = MAX (0, r->nrg_xmin[y1]);
1168 /* note: the -1 below is because of the previous carving */
1169 r->nrg_xmax[y1] = MAX (r->nrg_xmax[y1], x + r->nrg_radius - 1);
1170 r->nrg_xmax[y1] = MIN (r->w - 1, r->nrg_xmax[y1]);
1174 for (y = 0; y < r->h; y++)
1176 CATCH_CANC (r);
1178 for (x1 = r->nrg_xmin[y]; x1 <= r->nrg_xmax[y]; x1++)
1180 CATCH (lqr_carver_compute_e (r, x1, y));
1183 return LQR_OK;
1187 /* update the auxiliary minpath map
1188 * this only updates the affected pixels,
1189 * which start form the beginning of the seam
1190 * and expand at most by delta_x (in both
1191 * directions) at each row */
1192 LqrRetVal
1193 lqr_carver_update_mmap (LqrCarver * r)
1195 gint x, y;
1196 gint x_min, x_max;
1197 gint x1;
1198 gint x1_min, x1_max;
1199 gint data, data_down, least;
1200 gfloat m, m1, r_fact;
1201 gint stop;
1202 gint x_stop;
1204 CATCH_CANC(r);
1206 /* span first row */
1207 /* x_min = MAX (r->vpath_x[0] - r->delta_x, 0); */
1208 x_min = MAX (r->vpath_x[0] - 1, 0);
1209 /* x_max = MIN (r->vpath_x[0] + r->delta_x - 1, r->w - 1); */
1210 /* x_max = MIN (r->vpath_x[0] + r->delta_x, r->w - 1); */
1211 x_max = MIN (r->vpath_x[0], r->w - 1);
1213 for (x = x_min; x <= x_max; x++)
1215 data = r->raw[0][x];
1216 r->m[data] = r->en[data];
1219 /* other rows */
1220 for (y = 1; y < r->h; y++)
1222 CATCH_CANC(r);
1224 /* make sure to include the seam */
1225 x_min = MIN (x_min, MAX(r->vpath_x[y] - 1, 0));
1226 x_max = MAX (x_max, MIN(r->vpath_x[y], r->w - 1));
1227 /* x_max = MAX (x_max, r->vpath_x[y] - 1); */
1229 /* expand the affected region by delta_x */
1230 x_min = MAX (x_min - r->delta_x, 0);
1231 x_max = MIN (x_max + r->delta_x, r->w - 1);
1233 /* span the affected region */
1234 stop = 0;
1235 x_stop = 0;
1236 for (x = x_min; x <= x_max; x++)
1238 data = r->raw[y][x];
1239 if (r->rigidity_mask) {
1240 r_fact = r->rigidity_mask[data];
1241 } else {
1242 r_fact = 1;
1245 /* find the minimum in the previous rows
1246 * as in build_mmap() */
1247 x1_min = MAX (-x, -r->delta_x);
1248 x1_max = MIN (r->w - 1 - x, r->delta_x);
1249 data_down = r->raw[y - 1][x + x1_min];
1250 least = data_down;
1251 if (r->rigidity)
1253 m = r->m[data_down] + r_fact * r->rigidity_map[x1_min];
1254 for (x1 = x1_min + 1; x1 <= x1_max; x1++)
1256 data_down = r->raw[y - 1][x + x1];
1257 m1 = r->m[data_down] + r_fact * r->rigidity_map[x1];
1258 if ((m1 < m) || ((m1 == m) && (r->leftright == 1)))
1260 m = m1;
1261 least = data_down;
1265 else
1267 m = r->m[data_down];
1268 for (x1 = x1_min + 1; x1 <= x1_max; x1++)
1270 data_down = r->raw[y - 1][x + x1];
1271 m1 = r->m[data_down];
1272 if ((m1 < m) || ((m1 == m) && (r->leftright == 1)))
1274 m = m1;
1275 least = data_down;
1280 /* reduce the range if there's no difference
1281 * with the previous map */
1282 if (r->least[data] == least)
1284 if ((x == x_min) && (x < r->vpath_x[y] - 1)
1285 && (r->m[data] == r->en[data] + m))
1287 x_min++;
1289 if ((x > r->vpath_x[y]) && (r->m[data] == r->en[data] + m))
1291 if (stop == 0)
1293 x_stop = x;
1295 stop = 1;
1297 else
1299 stop = 0;
1302 else
1304 stop = 0;
1307 /* set current m */
1308 r->m[data] = r->en[data] + m;
1309 r->least[data] = least;
1311 if ((x == x_max) && (stop))
1313 x_max = x_stop;
1318 return LQR_OK;
1322 /* compute seam path from minpath map */
1323 void
1324 lqr_carver_build_vpath (LqrCarver * r)
1326 gint x, y, z0;
1327 gfloat m, m1;
1328 gint last = -1;
1329 gint last_x = 0;
1330 gint x_min, x_max;
1332 /* we start at last row */
1333 y = r->h - 1;
1335 /* span the last row for the minimum mmap value */
1336 m = (1 << 29);
1337 for (x = 0, z0 = y * r->w_start; x < r->w; x++, z0++)
1339 #ifdef __LQR_DEBUG__
1340 assert (r->vs[r->raw[y][x]] == 0);
1341 #endif /* __LQR_DEBUG__ */
1343 m1 = r->m[r->raw[y][x]];
1344 if ((m1 < m) || ((m1 == m) && (r->leftright == 1)))
1346 last = r->raw[y][x];
1347 last_x = x;
1348 m = m1;
1352 #ifdef __LQR_DEBUG__
1353 assert (last >= 0);
1354 #endif /* __LQR_DEBUG__ */
1356 /* follow the track for the other rows */
1357 for (y = r->h0 - 1; y >= 0; y--)
1359 #ifdef __LQR_DEBUG__
1360 assert (r->vs[last] == 0);
1361 assert (last_x < r->w);
1362 #endif /* __LQR_DEBUG__ */
1363 r->vpath[y] = last;
1364 r->vpath_x[y] = last_x;
1365 if (y > 0)
1367 last = r->least[r->raw[y][last_x]];
1368 /* we also need to retrieve the x coordinate */
1369 x_min = MAX (last_x - r->delta_x, 0);
1370 x_max = MIN (last_x + r->delta_x, r->w - 1);
1371 for (x = x_min; x <= x_max; x++)
1373 if (r->raw[y - 1][x] == last)
1375 last_x = x;
1376 break;
1379 #ifdef __LQR_DEBUG__
1380 assert (x < x_max + 1);
1381 #endif /* __LQR_DEBUG__ */
1386 #if 0
1387 /* we backtrack the seam following the min mmap */
1388 for (y = r->h0 - 1; y >= 0; y--)
1390 #ifdef __LQR_DEBUG__
1391 assert (r->vs[last] == 0);
1392 assert (last_x < r->w);
1393 #endif /* __LQR_DEBUG__ */
1395 r->vpath[y] = last;
1396 r->vpath_x[y] = last_x;
1397 if (y > 0)
1399 m = (1 << 29);
1400 x_min = MAX (0, last_x - r->delta_x);
1401 x_max = MIN (r->w - 1, last_x + r->delta_x);
1402 for (x = x_min; x <= x_max; x++)
1404 m1 = r->m[r->raw[y - 1][x]];
1405 if (m1 < m)
1407 last = r->raw[y - 1][x];
1408 last_x = x;
1409 m = m1;
1414 #endif
1417 /* update visibility map after seam computation */
1418 void
1419 lqr_carver_update_vsmap (LqrCarver * r, gint l)
1421 gint y;
1422 #ifdef __LQR_DEBUG__
1423 assert(r->root == NULL);
1424 #endif /* __LQR_DEBUG__ */
1425 for (y = 0; y < r->h; y++)
1427 #ifdef __LQR_DEBUG__
1428 assert (r->vs[r->vpath[y]] == 0);
1429 assert (r->vpath[y] == r->raw[y][r->vpath_x[y]]);
1430 #endif /* __LQR_DEBUG__ */
1431 r->vs[r->vpath[y]] = l;
1435 /* complete visibility map (last seam) */
1436 /* set the last column of pixels to vis. level w0 */
1437 void
1438 lqr_carver_finish_vsmap (LqrCarver * r)
1440 gint y;
1442 #ifdef __LQR_DEBUG__
1443 assert (r->w == 1);
1444 assert (r->root == NULL);
1445 #endif /* __LQR_DEBUG__ */
1446 lqr_cursor_reset (r->c);
1447 for (y = 1; y <= r->h; y++, lqr_cursor_next (r->c))
1449 #ifdef __LQR_DEBUG__
1450 assert (r->vs[r->c->now] == 0);
1451 #endif /* __LQR_DEBUG__ */
1452 r->vs[r->c->now] = r->w0;
1454 lqr_cursor_reset (r->c);
1457 /* propagate the root carver's visibility map */
1458 LqrRetVal
1459 lqr_carver_propagate_vsmap (LqrCarver * r)
1461 LqrDataTok data_tok;
1463 CATCH_CANC (r);
1465 data_tok.data = NULL;
1466 CATCH (lqr_carver_list_foreach_recursive (r->attached_list, lqr_carver_propagate_vsmap_attached, data_tok));
1467 return LQR_OK;
1470 LqrRetVal
1471 lqr_carver_propagate_vsmap_attached (LqrCarver * r, LqrDataTok data)
1473 LqrDataTok data_tok;
1474 data_tok.data = NULL;
1475 r->vs = r->root->vs;
1476 lqr_carver_scan_reset(r);
1477 /* CATCH (lqr_carver_list_foreach (r->attached_list, lqr_carver_propagate_vsmap_attached, data_tok)); */
1478 return LQR_OK;
1481 /*** image manipulations ***/
1483 /* set width of the multisize image
1484 * (maps have to be computed already) */
1485 void
1486 lqr_carver_set_width (LqrCarver * r, gint w1)
1488 #ifdef __LQR_DEBUG__
1489 assert (w1 <= r->w0);
1490 assert (w1 >= r->w_start - r->max_level + 1);
1491 #endif /* __LQR_DEBUG__ */
1492 r->w = w1;
1493 r->level = r->w0 - w1 + 1;
1496 LqrRetVal
1497 lqr_carver_set_width_attached (LqrCarver * r, LqrDataTok data)
1499 lqr_carver_set_width (r, data.integer);
1500 return LQR_OK;
1505 /* flatten the image to its current state
1506 * (all maps are reset, invisible points are lost) */
1507 LQR_PUBLIC
1508 LqrRetVal
1509 lqr_carver_flatten (LqrCarver * r)
1511 void *new_rgb = NULL;
1512 gfloat *new_bias = NULL;
1513 gfloat *new_rigmask = NULL;
1514 gint x, y, k;
1515 gint z0;
1516 LqrDataTok data_tok;
1517 LqrCarverState prev_state = LQR_CARVER_STATE_STD;
1519 #ifdef __LQR_VERBOSE__
1520 printf (" [ flattening (active=%i) ]\n", r->active);
1521 fflush (stdout);
1522 #endif /* __LQR_VERBOSE__ */
1524 CATCH_CANC(r);
1526 if (r->root == NULL)
1528 prev_state = g_atomic_int_get(&r->state);
1529 CATCH (lqr_carver_set_state (r, LQR_CARVER_STATE_FLATTENING, TRUE));
1532 /* first iterate on attached carvers */
1533 CATCH (lqr_carver_list_foreach (r->attached_list, lqr_carver_flatten_attached, data_tok));
1535 /* free non needed maps first */
1536 g_free (r->en);
1537 g_free (r->m);
1538 g_free (r->rcache);
1539 g_free (r->least);
1541 r->rcache = NULL;
1543 /* allocate room for new map */
1544 BUF_TRY_NEW0_RET_LQR(new_rgb, r->w * r->h * r->channels, r->col_depth);
1546 if (r->active)
1548 CATCH_MEM (new_bias = g_try_new0 (gfloat, r->w * r->h));
1549 if (r->rigidity_mask) {
1550 CATCH_MEM (new_rigmask = g_try_new (gfloat, r->w * r->h));
1553 g_free (r->_raw);
1554 g_free (r->raw);
1555 CATCH_MEM (r->_raw = g_try_new (gint, r->w * r->h));
1556 CATCH_MEM (r->raw = g_try_new (gint *, r->h));
1559 /* span the image with the cursor and copy
1560 * it in the new array */
1561 lqr_cursor_reset (r->c);
1562 for (y = 0; y < r->h; y++)
1564 CATCH_CANC (r);
1566 if (r->active)
1568 r->raw[y] = r->_raw + y * r->w;
1570 for (x = 0; x < r->w; x++)
1572 z0 = y * r->w + x;
1573 for (k = 0; k < r->channels; k++)
1575 PXL_COPY(new_rgb, z0 * r->channels + k, r->rgb, r->c->now * r->channels + k, r->col_depth);
1577 if (r->active)
1579 new_bias[z0] = r->bias[r->c->now];
1580 if (r->rigidity_mask) {
1581 new_rigmask[z0] = r->rigidity_mask[r->c->now];
1583 r->raw[y][x] = z0;
1585 lqr_cursor_next (r->c);
1589 /* substitute the old maps */
1590 if (!r->preserve_in_buffer)
1592 g_free (r->rgb);
1594 r->rgb = new_rgb;
1595 r->preserve_in_buffer = FALSE;
1596 if (r->active)
1598 g_free (r->bias);
1599 r->bias = new_bias;
1600 if (r->rigidity_mask) {
1601 g_free (r->rigidity_mask);
1602 r->rigidity_mask = new_rigmask;
1606 /* init the other maps */
1607 if (r->root == NULL)
1609 g_free (r->vs);
1610 CATCH_MEM (r->vs = g_try_new0 (gint, r->w * r->h));
1611 CATCH (lqr_carver_propagate_vsmap(r));
1613 if (r->active)
1615 CATCH_MEM (r->en = g_try_new0 (gfloat, r->w * r->h));
1616 CATCH_MEM (r->m = g_try_new0 (gfloat, r->w * r->h));
1617 CATCH_MEM (r->least = g_try_new (gint, r->w * r->h));
1620 /* reset widths, heights & levels */
1621 r->w0 = r->w;
1622 r->h0 = r->h;
1623 r->w_start = r->w;
1624 r->h_start = r->h;
1625 r->level = 1;
1626 r->max_level = 1;
1628 #ifdef __LQR_VERBOSE__
1629 printf (" [ flattening OK ]\n");
1630 fflush (stdout);
1631 #endif /* __LQR_VERBOSE__ */
1633 if (r->root == NULL)
1635 CATCH (lqr_carver_set_state (r, prev_state, TRUE));
1638 return LQR_OK;
1641 LqrRetVal
1642 lqr_carver_flatten_attached(LqrCarver *r, LqrDataTok data)
1644 return lqr_carver_flatten(r);
1647 /* transpose the image, in its current state
1648 * (all maps and invisible points are lost) */
1649 LqrRetVal
1650 lqr_carver_transpose (LqrCarver * r)
1652 gint x, y, k;
1653 gint z0, z1;
1654 gint d;
1655 void *new_rgb = NULL;
1656 gfloat *new_bias = NULL;
1657 gfloat *new_rigmask = NULL;
1658 LqrDataTok data_tok;
1659 LqrCarverState prev_state = LQR_CARVER_STATE_STD;
1661 #ifdef __LQR_VERBOSE__
1662 printf ("[ transposing (active=%i) ]\n", r->active);
1663 fflush (stdout);
1664 #endif /* __LQR_VERBOSE__ */
1666 CATCH_CANC (r);
1668 if (r->root == NULL)
1670 prev_state = g_atomic_int_get(&r->state);
1671 CATCH (lqr_carver_set_state (r, LQR_CARVER_STATE_TRANSPOSING, TRUE));
1674 if (r->level > 1)
1676 CATCH (lqr_carver_flatten (r));
1679 /* first iterate on attached carvers */
1680 CATCH (lqr_carver_list_foreach (r->attached_list, lqr_carver_transpose_attached, data_tok));
1682 /* free non needed maps first */
1683 if (r->root == NULL)
1685 g_free (r->vs);
1687 g_free (r->en);
1688 g_free (r->m);
1689 g_free (r->rcache);
1690 g_free (r->least);
1691 g_free (r->rgb_ro_buffer);
1693 r->rcache = NULL;
1695 /* allocate room for the new maps */
1696 BUF_TRY_NEW0_RET_LQR(new_rgb, r->w0 * r->h0 * r->channels, r->col_depth);
1698 if (r->active)
1700 CATCH_MEM (new_bias = g_try_new0 (gfloat, r->w0 * r->h0));
1701 if (r->rigidity_mask)
1703 CATCH_MEM (new_rigmask = g_try_new (gfloat, r->w0 * r->h0));
1705 g_free (r->_raw);
1706 g_free (r->raw);
1707 CATCH_MEM (r->_raw = g_try_new0 (gint, r->h0 * r->w0));
1708 CATCH_MEM (r->raw = g_try_new0 (gint *, r->w0));
1711 /* compute trasposed maps */
1712 for (x = 0; x < r->w; x++)
1714 if (r->active)
1716 r->raw[x] = r->_raw + x * r->h0;
1718 for (y = 0; y < r->h; y++)
1720 z0 = y * r->w0 + x;
1721 z1 = x * r->h0 + y;
1722 for (k = 0; k < r->channels; k++)
1724 PXL_COPY(new_rgb, z1 * r->channels + k, r->rgb, z0 * r->channels + k, r->col_depth);
1726 if (r->active)
1728 new_bias[z1] = r->bias[z0];
1729 if (r->rigidity_mask) {
1730 new_rigmask[z1] = r->rigidity_mask[z0];
1732 r->raw[x][y] = z1;
1737 /* substitute the map */
1738 if (!r->preserve_in_buffer)
1740 g_free (r->rgb);
1742 r->rgb = new_rgb;
1743 r->preserve_in_buffer = FALSE;
1745 if (r->active)
1747 g_free (r->bias);
1748 r->bias = new_bias;
1749 if (r->rigidity_mask) {
1750 g_free (r->rigidity_mask);
1751 r->rigidity_mask = new_rigmask;
1755 /* init the other maps */
1756 if (r->root == NULL)
1758 CATCH_MEM (r->vs = g_try_new0 (gint, r->w0 * r->h0));
1759 CATCH (lqr_carver_propagate_vsmap(r));
1761 if (r->active)
1763 CATCH_MEM (r->en = g_try_new0 (gfloat, r->w0 * r->h0));
1764 CATCH_MEM (r->m = g_try_new0 (gfloat, r->w0 * r->h0));
1765 CATCH_MEM (r->least = g_try_new (gint, r->w0 * r->h0));
1768 /* switch widths & heights */
1769 d = r->w0;
1770 r->w0 = r->h0;
1771 r->h0 = d;
1772 r->w = r->w0;
1773 r->h = r->h0;
1775 /* reset w_start, h_start & levels */
1776 r->w_start = r->w0;
1777 r->h_start = r->h0;
1778 r->level = 1;
1779 r->max_level = 1;
1781 /* reset seam path, cursor and readout buffer */
1782 if (r->active)
1784 g_free (r->vpath);
1785 CATCH_MEM (r->vpath = g_try_new (gint, r->h));
1786 g_free (r->vpath_x);
1787 CATCH_MEM (r->vpath_x = g_try_new (gint, r->h));
1788 g_free (r->nrg_xmin);
1789 CATCH_MEM (r->nrg_xmin = g_try_new (gint, r->h));
1790 g_free (r->nrg_xmax);
1791 CATCH_MEM (r->nrg_xmax = g_try_new (gint, r->h));
1794 BUF_TRY_NEW0_RET_LQR(r->rgb_ro_buffer, r->w0 * r->channels, r->col_depth);
1796 /* rescale rigidity */
1798 if (r->active)
1800 for (x = -r->delta_x; x <= r->delta_x; x++)
1802 r->rigidity_map[x] = r->rigidity_map[x] * r->w0 / r->h0;
1806 /* set transposed flag */
1807 r->transposed = (r->transposed ? 0 : 1);
1809 #ifdef __LQR_VERBOSE__
1810 printf ("[ transpose OK ]\n");
1811 fflush (stdout);
1812 #endif /* __LQR_VERBOSE__ */
1814 if (r->root == NULL)
1816 CATCH (lqr_carver_set_state (r, prev_state, TRUE));
1819 return LQR_OK;
1822 LqrRetVal
1823 lqr_carver_transpose_attached (LqrCarver * r, LqrDataTok data)
1825 return lqr_carver_transpose(r);
1828 /* resize w + h: these are the liquid rescale methods.
1829 * They automatically determine the depth of the map
1830 * according to the desired size, can be called multiple
1831 * times, transpose the image as necessasry */
1832 LqrRetVal
1833 lqr_carver_resize_width (LqrCarver * r, gint w1)
1835 LqrDataTok data_tok;
1836 gint delta, gamma;
1837 gint delta_max;
1838 /* delta is used to determine the required depth
1839 * gamma to decide if action is necessary */
1840 if (!r->transposed)
1842 delta = w1 - r->w_start;
1843 gamma = w1 - r->w;
1844 delta_max = (gint) ((r->enl_step - 1) * r->w_start) - 1;
1846 else
1848 delta = w1 - r->h_start;
1849 gamma = w1 - r->h;
1850 delta_max = (gint) ((r->enl_step - 1) * r->h_start) - 1;
1852 if (delta_max < 1)
1854 delta_max = 1;
1856 if (delta < 0)
1858 delta = -delta;
1859 delta_max = delta;
1862 CATCH_CANC (r);
1863 CATCH_F (g_atomic_int_get(&r->state) == LQR_CARVER_STATE_STD);
1864 CATCH (lqr_carver_set_state (r, LQR_CARVER_STATE_RESIZING, TRUE));
1866 while (gamma)
1868 gint delta0 = MIN (delta, delta_max);
1869 gint new_w;
1871 delta -= delta0;
1872 if (r->transposed)
1874 CATCH (lqr_carver_transpose (r));
1876 new_w = MIN (w1, r->w_start + delta_max);
1877 gamma = w1 - new_w;
1878 lqr_progress_init (r->progress, r->progress->init_width_message);
1879 CATCH (lqr_carver_build_maps (r, delta0 + 1));
1880 lqr_carver_set_width (r, new_w);
1882 data_tok.integer = new_w;
1883 lqr_carver_list_foreach_recursive (r->attached_list, lqr_carver_set_width_attached, data_tok);
1885 if (r->dump_vmaps)
1887 CATCH (lqr_vmap_internal_dump (r));
1889 lqr_progress_end (r->progress, r->progress->end_width_message);
1890 if (new_w < w1)
1892 CATCH (lqr_carver_flatten(r));
1893 delta_max = (gint) ((r->enl_step - 1) * r->w_start) - 1;
1894 if (delta_max < 1)
1896 delta_max = 1;
1901 CATCH (lqr_carver_set_state (r, LQR_CARVER_STATE_STD, TRUE));
1903 return LQR_OK;
1906 LqrRetVal
1907 lqr_carver_resize_height (LqrCarver * r, gint h1)
1909 LqrDataTok data_tok;
1910 gint delta, gamma;
1911 gint delta_max;
1912 /* delta is used to determine the required depth
1913 * gamma to decide if action is necessary */
1914 if (!r->transposed)
1916 delta = h1 - r->h_start;
1917 gamma = h1 - r->h;
1918 delta_max = (gint) ((r->enl_step - 1) * r->h_start) - 1;
1920 else
1922 delta = h1 - r->w_start;
1923 gamma = h1 - r->w;
1924 delta_max = (gint) ((r->enl_step - 1) * r->w_start) - 1;
1926 if (delta_max < 1)
1928 delta_max = 1;
1930 if (delta < 0)
1932 delta_max = -delta;
1934 delta = delta > 0 ? delta : -delta;
1936 CATCH_CANC (r);
1937 CATCH_F (g_atomic_int_get(&r->state) == LQR_CARVER_STATE_STD);
1938 CATCH (lqr_carver_set_state (r, LQR_CARVER_STATE_RESIZING, TRUE));
1940 while (gamma)
1942 gint delta0 = MIN (delta, delta_max);
1943 gint new_w;
1944 delta -= delta0;
1945 if (!r->transposed)
1947 CATCH (lqr_carver_transpose (r));
1949 new_w = MIN (h1, r->w_start + delta_max);
1950 gamma = h1 - new_w;
1951 lqr_progress_init (r->progress, r->progress->init_height_message);
1952 CATCH (lqr_carver_build_maps (r, delta0 + 1));
1953 lqr_carver_set_width (r, new_w);
1955 data_tok.integer = new_w;
1956 lqr_carver_list_foreach_recursive (r->attached_list, lqr_carver_set_width_attached, data_tok);
1958 if (r->dump_vmaps)
1960 CATCH (lqr_vmap_internal_dump (r));
1962 lqr_progress_end (r->progress, r->progress->end_height_message);
1963 if (new_w < h1)
1965 CATCH (lqr_carver_flatten(r));
1966 delta_max = (gint) ((r->enl_step - 1) * r->w_start) - 1;
1967 if (delta_max < 1)
1969 delta_max = 1;
1974 CATCH (lqr_carver_set_state (r, LQR_CARVER_STATE_STD, TRUE));
1976 return LQR_OK;
1979 /* liquid rescale public method */
1980 LQR_PUBLIC
1981 LqrRetVal
1982 lqr_carver_resize (LqrCarver * r, gint w1, gint h1)
1984 #ifdef __LQR_VERBOSE__
1985 printf("[ Rescale from %i,%i to %i,%i ]\n", (r->transposed ? r->h : r->w), (r->transposed ? r->w : r->h), w1, h1);
1986 fflush(stdout);
1987 #endif /* __LQR_VERBOSE__ */
1988 CATCH_F ((w1 >= 1) && (h1 >= 1));
1989 CATCH_F (r->root == NULL);
1991 CATCH_CANC (r);
1992 CATCH_F (g_atomic_int_get(&r->state) == LQR_CARVER_STATE_STD);
1994 switch (r->resize_order)
1996 case LQR_RES_ORDER_HOR:
1997 CATCH (lqr_carver_resize_width(r, w1));
1998 CATCH (lqr_carver_resize_height(r, h1));
1999 break;
2000 case LQR_RES_ORDER_VERT:
2001 CATCH (lqr_carver_resize_height(r, h1));
2002 CATCH (lqr_carver_resize_width(r, w1));
2003 break;
2004 #ifdef __LQR_DEBUG__
2005 default:
2006 assert(0);
2007 #endif /* __LQR_DEBUG__ */
2009 lqr_carver_scan_reset_all(r);
2011 #ifdef __LQR_VERBOSE__
2012 printf("[ Rescale OK ]\n");
2013 fflush(stdout);
2014 #endif /* __LQR_VERBOSE__ */
2015 return LQR_OK;
2018 LqrRetVal
2019 lqr_carver_set_state (LqrCarver * r, LqrCarverState state, gboolean skip_canceled)
2021 LqrDataTok data_tok;
2022 gint lock_pos;
2024 CATCH_F(r->root == NULL);
2026 lock_pos = g_atomic_int_exchange_and_add(&r->state_lock_queue, 1);
2028 while (g_atomic_int_get(&r->state_lock) != lock_pos)
2030 g_usleep(10000);
2033 if (skip_canceled && g_atomic_int_get(&r->state) == LQR_CARVER_STATE_CANCELLED) {
2034 g_atomic_int_inc(&r->state_lock);
2035 return LQR_OK;
2038 g_atomic_int_set(&r->state, state);
2040 data_tok.integer = state;
2041 CATCH (lqr_carver_list_foreach_recursive (r->attached_list, lqr_carver_set_state_attached, data_tok));
2043 g_atomic_int_inc(&r->state_lock);
2045 return LQR_OK;
2048 LqrRetVal
2049 lqr_carver_set_state_attached (LqrCarver * r, LqrDataTok data)
2051 g_atomic_int_set (&r->state, data.integer);
2052 return LQR_OK;
2055 /* cancel the current action from a different thread */
2056 LQR_PUBLIC
2057 LqrRetVal
2058 lqr_carver_cancel (LqrCarver * r)
2060 LqrCarverState curr_state;
2062 CATCH_F (r->root == NULL);
2064 curr_state = g_atomic_int_get (&r->state);
2066 if ((curr_state == LQR_CARVER_STATE_RESIZING) ||
2067 (curr_state == LQR_CARVER_STATE_INFLATING) ||
2068 (curr_state == LQR_CARVER_STATE_TRANSPOSING) ||
2069 (curr_state == LQR_CARVER_STATE_FLATTENING))
2071 CATCH (lqr_carver_set_state (r, LQR_CARVER_STATE_CANCELLED, TRUE));
2073 return LQR_OK;
2076 /* get current size */
2077 LQR_PUBLIC
2078 gint
2079 lqr_carver_get_width(LqrCarver* r)
2081 return (r->transposed ? r->h : r->w);
2084 LQR_PUBLIC
2085 gint
2086 lqr_carver_get_height(LqrCarver* r)
2088 return (r->transposed ? r->w : r->h);
2091 /* get reference size */
2092 LQR_PUBLIC
2093 gint
2094 lqr_carver_get_ref_width(LqrCarver* r)
2096 return (r->transposed ? r->h_start : r->w_start);
2099 LQR_PUBLIC
2100 gint
2101 lqr_carver_get_ref_height(LqrCarver* r)
2103 return (r->transposed ? r->w_start : r->h_start);
2106 /* get colour channels */
2107 LQR_PUBLIC
2108 gint
2109 lqr_carver_get_channels (LqrCarver * r)
2111 return r->channels;
2114 LQR_PUBLIC
2115 gint
2116 lqr_carver_get_bpp (LqrCarver * r)
2118 return lqr_carver_get_channels(r);
2121 /* get colour depth */
2122 LQR_PUBLIC
2123 LqrColDepth
2124 lqr_carver_get_col_depth (LqrCarver * r)
2126 return r->col_depth;
2129 /* get enlargement step */
2130 LQR_PUBLIC
2131 gfloat
2132 lqr_carver_get_enl_step (LqrCarver * r)
2134 return r->enl_step;
2137 /* get orientation */
2138 LQR_PUBLIC
2139 gint
2140 lqr_carver_get_orientation (LqrCarver* r)
2142 return (r->transposed ? 1 : 0);
2145 /* get depth */
2146 LQR_PUBLIC
2147 gint
2148 lqr_carver_get_depth (LqrCarver *r)
2150 return r->w0 - r->w_start;
2154 /* readout reset */
2155 LQR_PUBLIC
2156 void
2157 lqr_carver_scan_reset (LqrCarver * r)
2159 lqr_cursor_reset (r->c);
2162 LqrRetVal
2163 lqr_carver_scan_reset_attached (LqrCarver * r, LqrDataTok data)
2165 lqr_carver_scan_reset(r);
2166 return lqr_carver_list_foreach(r->attached_list, lqr_carver_scan_reset_attached, data);
2169 void
2170 lqr_carver_scan_reset_all (LqrCarver *r)
2172 LqrDataTok data;
2173 data.data = NULL;
2174 lqr_carver_scan_reset(r);
2175 lqr_carver_list_foreach(r->attached_list, lqr_carver_scan_reset_attached, data);
2180 /* readout all, pixel by bixel */
2181 LQR_PUBLIC
2182 gboolean
2183 lqr_carver_scan (LqrCarver * r, gint * x, gint * y, guchar ** rgb)
2185 gint k;
2186 if (r->col_depth != LQR_COLDEPTH_8I)
2188 return FALSE;
2190 if (r->c->eoc)
2192 lqr_carver_scan_reset (r);
2193 return FALSE;
2195 (*x) = (r->transposed ? r->c->y : r->c->x);
2196 (*y) = (r->transposed ? r->c->x : r->c->y);
2197 for (k = 0; k < r->channels; k++)
2199 AS_8I(r->rgb_ro_buffer)[k] = AS_8I(r->rgb)[r->c->now * r->channels + k];
2201 (*rgb) = AS_8I(r->rgb_ro_buffer);
2202 lqr_cursor_next(r->c);
2203 return TRUE;
2206 LQR_PUBLIC
2207 gboolean
2208 lqr_carver_scan_ext (LqrCarver * r, gint * x, gint * y, void ** rgb)
2210 gint k;
2211 if (r->c->eoc)
2213 lqr_carver_scan_reset (r);
2214 return FALSE;
2216 (*x) = (r->transposed ? r->c->y : r->c->x);
2217 (*y) = (r->transposed ? r->c->x : r->c->y);
2218 for (k = 0; k < r->channels; k++)
2220 PXL_COPY(r->rgb_ro_buffer, k, r->rgb, r->c->now * r->channels + k, r->col_depth);
2223 BUF_POINTER_COPY(rgb, r->rgb_ro_buffer, r->col_depth);
2225 lqr_cursor_next(r->c);
2226 return TRUE;
2229 /* readout all, by line */
2230 LQR_PUBLIC
2231 gboolean
2232 lqr_carver_scan_by_row (LqrCarver *r)
2234 return r->transposed ? FALSE : TRUE;
2237 LQR_PUBLIC
2238 gboolean
2239 lqr_carver_scan_line (LqrCarver * r, gint * n, guchar ** rgb)
2241 if (r->col_depth != LQR_COLDEPTH_8I)
2243 return FALSE;
2245 return lqr_carver_scan_line_ext (r, n, (void**) rgb);
2248 LQR_PUBLIC
2249 gboolean
2250 lqr_carver_scan_line_ext (LqrCarver * r, gint * n, void ** rgb)
2252 gint k, x;
2253 if (r->c->eoc)
2255 lqr_carver_scan_reset (r);
2256 return FALSE;
2258 x = r->c->x;
2259 (*n) = r->c->y;
2260 while (x > 0)
2262 lqr_cursor_prev(r->c);
2263 x = r->c->x;
2265 for (x = 0; x < r->w; x++)
2267 for (k = 0; k < r->channels; k++)
2269 PXL_COPY(r->rgb_ro_buffer, x * r->channels + k, r->rgb, r->c->now * r->channels + k, r->col_depth);
2271 lqr_cursor_next(r->c);
2275 BUF_POINTER_COPY(rgb, r->rgb_ro_buffer, r->col_depth);
2277 return TRUE;
2280 #ifdef __LQR_DEBUG__
2281 void lqr_carver_debug_check_rows(LqrCarver * r)
2283 int x, y;
2284 int data;
2285 for (y = 0; y < r->h; y++)
2287 for (x = 0; x < r->w; x++)
2289 data = r->raw[y][x];
2290 if (data / r->w0 != y)
2292 fflush(stderr);
2294 assert(data / r->w0 == y);
2298 #endif /* __LQR_DEBUG__ */
2301 /**** END OF LQR_CARVER CLASS FUNCTIONS ****/