Overall progress for sessions
[liblqr.git] / lqr / lqr_carver.c
blob94550b4e971bcec401d0794da33af9c8127d436a
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->nrg_active = FALSE;
56 r->root = NULL;
57 r->rigidity = 0;
58 r->resize_aux_layers = FALSE;
59 r->dump_vmaps = FALSE;
60 r->resize_order = LQR_RES_ORDER_HOR;
61 r->attached_list = NULL;
62 r->flushed_vs = NULL;
63 r->preserve_in_buffer = FALSE;
64 TRY_N_N (r->progress = lqr_progress_new());
65 r->session_update_step = 1;
66 r->session_rescale_total = 0;
67 r->session_rescale_current = 0;
69 r->en = NULL;
70 r->bias = NULL;
71 r->m = NULL;
72 r->least = NULL;
73 r->_raw = NULL;
74 r->raw = NULL;
75 r->vpath = NULL;
76 r->vpath_x = NULL;
77 r->rigidity_map = NULL;
78 r->rigidity_mask = NULL;
79 r->delta_x = 1;
81 r->h = height;
82 r->w = width;
83 r->channels = channels;
85 r->w0 = r->w;
86 r->h0 = r->h;
87 r->w_start = r->w;
88 r->h_start = r->h;
90 r->rcache = NULL;
91 r->use_rcache = TRUE;
93 r->rwindow = NULL;
94 lqr_carver_set_energy_function_builtin(r, LQR_EF_GRAD_XABS);
95 r->nrg_xmin = NULL;
96 r->nrg_xmax = NULL;
97 r->nrg_uptodate = FALSE;
99 r->leftright = 0;
100 r->lr_switch_frequency = 0;
102 r->enl_step = 2.0;
104 TRY_N_N (r->vs = g_try_new0 (gint, r->w * r->h));
106 /* initialize cursor */
108 TRY_N_N (r->c = lqr_cursor_create (r));
110 switch (channels)
112 case 1:
113 lqr_carver_set_image_type (r, LQR_GREY_IMAGE);
114 break;
115 case 2:
116 lqr_carver_set_image_type (r, LQR_GREYA_IMAGE);
117 break;
118 case 3:
119 lqr_carver_set_image_type (r, LQR_RGB_IMAGE);
120 break;
121 case 4:
122 lqr_carver_set_image_type (r, LQR_RGBA_IMAGE);
123 break;
124 case 5:
125 lqr_carver_set_image_type (r, LQR_CMYKA_IMAGE);
126 break;
127 default:
128 lqr_carver_set_image_type (r, LQR_CUSTOM_IMAGE);
129 break;
132 return r;
135 /* LQR_PUBLIC */
136 LqrCarver *
137 lqr_carver_new (guchar * buffer, gint width, gint height, gint channels)
139 return lqr_carver_new_ext (buffer, width, height, channels, LQR_COLDEPTH_8I);
142 /* LQR_PUBLIC */
143 LqrCarver *
144 lqr_carver_new_ext (void * buffer, gint width, gint height, gint channels, LqrColDepth colour_depth)
146 LqrCarver *r;
148 TRY_N_N (r = lqr_carver_new_common (width, height, channels));
150 r->rgb = (void*) buffer;
152 BUF_TRY_NEW_RET_POINTER(r->rgb_ro_buffer, r->channels * r->w, colour_depth);
154 r->col_depth = colour_depth;
156 return r;
159 /* destructor */
160 /* LQR_PUBLIC */
161 void
162 lqr_carver_destroy (LqrCarver * r)
164 if (!r->preserve_in_buffer)
166 g_free (r->rgb);
168 if (r->root == NULL)
170 g_free (r->vs);
172 g_free (r->en);
173 g_free (r->bias);
174 g_free (r->m);
175 g_free (r->rcache);
176 g_free (r->least);
177 lqr_cursor_destroy (r->c);
178 g_free (r->vpath);
179 g_free (r->vpath_x);
180 if (r->rigidity_map != NULL)
182 r->rigidity_map -= r->delta_x;
183 g_free (r->rigidity_map);
185 g_free (r->rigidity_mask);
186 lqr_rwindow_destroy (r->rwindow);
187 g_free (r->nrg_xmin);
188 g_free (r->nrg_xmax);
189 lqr_vmap_list_destroy(r->flushed_vs);
190 lqr_carver_list_destroy(r->attached_list);
191 g_free (r->progress);
192 g_free (r->_raw);
193 g_free (r->raw);
194 g_free (r);
197 /*** initialization ***/
199 LqrRetVal
200 lqr_carver_init_energy_related (LqrCarver *r)
202 gint y, x;
204 CATCH_F (r->active == FALSE);
205 CATCH_F (r->nrg_active == FALSE);
207 CATCH_MEM (r->en = g_try_new (gfloat, r->w * r->h));
208 CATCH_MEM (r->_raw = g_try_new (gint, r->h_start * r->w_start));
209 CATCH_MEM (r->raw = g_try_new (gint *, r->h_start));
211 for (y = 0; y < r->h; y++)
213 r->raw[y] = r->_raw + y * r->w_start;
214 for (x = 0; x < r->w_start; x++)
216 r->raw[y][x] = y * r->w_start + x;
220 r->nrg_active = TRUE;
222 return LQR_OK;
226 /* LQR_PUBLIC */
227 LqrRetVal
228 lqr_carver_init (LqrCarver *r, gint delta_x, gfloat rigidity)
230 gint x;
232 CATCH_CANC (r);
234 CATCH_F (r->active == FALSE);
236 if (r->nrg_active == FALSE)
238 CATCH (lqr_carver_init_energy_related (r));
241 /* CATCH_MEM (r->bias = g_try_new0 (gfloat, r->w * r->h)); */
242 CATCH_MEM (r->m = g_try_new (gfloat, r->w * r->h));
243 CATCH_MEM (r->least = g_try_new (gint, r->w * r->h));
245 CATCH_MEM (r->vpath = g_try_new (gint, r->h));
246 CATCH_MEM (r->vpath_x = g_try_new (gint, r->h));
248 CATCH_MEM (r->nrg_xmin = g_try_new (gint, r->h));
249 CATCH_MEM (r->nrg_xmax = g_try_new (gint, r->h));
251 /* set rigidity map */
252 r->delta_x = delta_x;
253 r->rigidity = rigidity;
255 r->rigidity_map = g_try_new0 (gfloat, 2 * r->delta_x + 1);
256 r->rigidity_map += r->delta_x;
257 for (x = -r->delta_x; x <= r->delta_x; x++)
259 r->rigidity_map[x] =
260 r->rigidity * powf(fabsf(x), 1.5) / r->h;
263 r->active = TRUE;
265 return LQR_OK;
268 /*** set attributes ***/
270 /* LQR_PUBLIC */
271 LqrRetVal
272 lqr_carver_set_image_type (LqrCarver * r, LqrImageType image_type)
274 CATCH_CANC (r);
276 switch (image_type) {
277 case LQR_GREY_IMAGE:
278 if (r->channels != 1) {
279 return LQR_ERROR;
281 r->alpha_channel = -1;
282 r->black_channel = -1;
283 break;
284 case LQR_GREYA_IMAGE:
285 if (r->channels != 2)
287 return LQR_ERROR;
289 r->alpha_channel = 1;
290 r->black_channel = -1;
291 break;
292 case LQR_CMY_IMAGE:
293 case LQR_RGB_IMAGE:
294 if (r->channels != 3)
296 return LQR_ERROR;
298 r->alpha_channel = -1;
299 r->black_channel = -1;
300 break;
301 case LQR_CMYK_IMAGE:
302 if (r->channels != 4)
304 return LQR_ERROR;
306 r->alpha_channel = -1;
307 r->black_channel = 3;
308 break;
309 case LQR_RGBA_IMAGE:
310 if (r->channels != 4)
312 return LQR_ERROR;
314 r->alpha_channel = 3;
315 r->black_channel = -1;
316 break;
317 case LQR_CMYKA_IMAGE:
318 if (r->channels != 5)
320 return LQR_ERROR;
322 r->alpha_channel = 4;
323 r->black_channel = 3;
324 break;
325 case LQR_CUSTOM_IMAGE:
326 r->alpha_channel = r->channels - 1;
327 r->black_channel = -1;
328 break;
329 default:
330 return LQR_ERROR;
332 r->image_type = image_type;
334 g_free(r->rcache);
335 r->rcache = NULL;
336 r->nrg_uptodate = FALSE;
338 return LQR_OK;
341 /* LQR_PUBLIC */
342 LqrRetVal
343 lqr_carver_set_alpha_channel (LqrCarver * r, gint channel_index)
345 CATCH_CANC (r);
347 if (channel_index < 0) {
348 r->alpha_channel = -1;
349 } else if (channel_index < r->channels) {
350 r->alpha_channel = channel_index;
351 } else {
352 return LQR_ERROR;
354 r->image_type = LQR_CUSTOM_IMAGE;
356 g_free(r->rcache);
357 r->rcache = NULL;
358 r->nrg_uptodate = FALSE;
360 return LQR_OK;
363 /* LQR_PUBLIC */
364 LqrRetVal
365 lqr_carver_set_black_channel (LqrCarver * r, gint channel_index)
367 CATCH_CANC (r);
369 if (channel_index < 0) {
370 r->black_channel = -1;
371 } else if (channel_index < r->channels) {
372 r->black_channel = channel_index;
373 } else {
374 return LQR_ERROR;
376 r->image_type = LQR_CUSTOM_IMAGE;
378 g_free(r->rcache);
379 r->rcache = NULL;
380 r->nrg_uptodate = FALSE;
382 return LQR_OK;
385 /* set gradient function */
386 /* WARNING: THIS FUNCTION IS ONLY MAINTAINED FOR BACK-COMPATIBILITY PURPOSES */
387 /* lqr_carver_set_energy_function_builtin() should be used in newly written code instead */
388 /* LQR_PUBLIC */
389 void
390 lqr_carver_set_gradient_function (LqrCarver * r, LqrGradFuncType gf_ind)
392 switch (gf_ind)
394 case LQR_GF_NORM:
395 lqr_carver_set_energy_function_builtin(r, LQR_EF_GRAD_NORM);
396 break;
397 case LQR_GF_SUMABS:
398 lqr_carver_set_energy_function_builtin(r, LQR_EF_GRAD_SUMABS);
399 break;
400 case LQR_GF_XABS:
401 lqr_carver_set_energy_function_builtin(r, LQR_EF_GRAD_XABS);
402 break;
403 case LQR_GF_NULL:
404 lqr_carver_set_energy_function_builtin(r, LQR_EF_NULL);
405 break;
406 case LQR_GF_NORM_BIAS:
407 case LQR_GF_YABS:
408 lqr_carver_set_energy_function_builtin(r, LQR_EF_NULL);
409 break;
410 #ifdef __LQR_DEBUG__
411 default:
412 assert (0);
413 #endif /* __LQR_DEBUG__ */
417 /* attach carvers to be scaled along with the main one */
418 /* LQR_PUBLIC */
419 LqrRetVal
420 lqr_carver_attach (LqrCarver * r, LqrCarver * aux)
422 CATCH_F (r->w0 == aux->w0);
423 CATCH_F (r->h0 == aux->h0);
424 CATCH_F (g_atomic_int_get(&r->state) == LQR_CARVER_STATE_STD);
425 CATCH_F (g_atomic_int_get(&aux->state) == LQR_CARVER_STATE_STD);
426 CATCH_MEM (r->attached_list = lqr_carver_list_append (r->attached_list, aux));
427 g_free(aux->vs);
428 aux->vs = r->vs;
429 aux->root = r;
431 return LQR_OK;
434 /* set the seam output flag */
435 /* LQR_PUBLIC */
436 void
437 lqr_carver_set_dump_vmaps (LqrCarver *r)
439 r->dump_vmaps = TRUE;
442 /* unset the seam output flag */
443 /* LQR_PUBLIC */
444 void
445 lqr_carver_set_no_dump_vmaps (LqrCarver *r)
447 r->dump_vmaps = FALSE;
450 /* set order if rescaling in both directions */
451 /* LQR_PUBLIC */
452 void
453 lqr_carver_set_resize_order (LqrCarver *r, LqrResizeOrder resize_order)
455 r->resize_order = resize_order;
458 /* set leftright switch interval */
459 /* LQR_PUBLIC */
460 void
461 lqr_carver_set_side_switch_frequency (LqrCarver *r, guint switch_frequency)
463 r->lr_switch_frequency = switch_frequency;
466 /* set enlargement step */
467 /* LQR_PUBLIC */
468 LqrRetVal
469 lqr_carver_set_enl_step (LqrCarver *r, gfloat enl_step)
471 CATCH_F ((enl_step > 1) && (enl_step <= 2));
472 CATCH_CANC (r);
473 r->enl_step = enl_step;
474 return LQR_OK;
477 /* LQR_PUBLIC */
478 void
479 lqr_carver_set_use_cache (LqrCarver *r, gboolean use_cache)
481 if (!use_cache)
483 g_free(r->rcache);
484 r->rcache = NULL;
486 r->use_rcache = use_cache;
487 r->rwindow->use_rcache = use_cache;
490 /* set progress reprot */
491 /* LQR_PUBLIC */
492 void
493 lqr_carver_set_progress (LqrCarver *r, LqrProgress *p)
495 g_free(r->progress);
496 r->progress = p;
499 /* flag the input buffer to avoid destruction */
500 /* LQR_PUBLIC */
501 void
502 lqr_carver_set_preserve_input_image(LqrCarver *r)
504 r->preserve_in_buffer = TRUE;
508 /*** compute maps (energy, minpath & visibility) ***/
510 /* build multisize image up to given depth
511 * it is progressive (can be called multilple times) */
512 LqrRetVal
513 lqr_carver_build_maps (LqrCarver * r, gint depth)
515 #ifdef __LQR_DEBUG__
516 assert (depth <= r->w_start);
517 assert (depth >= 1);
518 #endif /* __LQR_DEBUG__ */
520 CATCH_CANC (r);
522 /* only go deeper if needed */
523 if (depth > r->max_level)
525 CATCH_F (r->active);
526 CATCH_F (r->root == NULL);
528 /* set to minimum width reached so far */
529 lqr_carver_set_width (r, r->w_start - r->max_level + 1);
531 /* compute energy & minpath maps */
532 CATCH (lqr_carver_build_emap (r));
533 CATCH (lqr_carver_build_mmap (r));
535 /* compute visibility map */
536 CATCH (lqr_carver_build_vsmap (r, depth));
538 return LQR_OK;
541 /* compute energy map */
542 LqrRetVal
543 lqr_carver_build_emap (LqrCarver * r)
545 gint x, y;
547 CATCH_CANC(r);
549 if (r->nrg_uptodate)
551 return LQR_OK;
554 if (r->use_rcache && r->rcache == NULL)
556 CATCH_MEM (r->rcache = lqr_carver_generate_rcache (r));
559 for (y = 0; y < r->h; y++)
561 CATCH_CANC(r);
562 /* r->nrg_xmin[y] = 0; */
563 /* r->nrg_xmax[y] = r->w - 1; */
564 for (x = 0; x < r->w; x++)
566 CATCH (lqr_carver_compute_e(r, x, y));
570 r->nrg_uptodate = TRUE;
572 return LQR_OK;
575 LqrRetVal
576 lqr_carver_compute_e (LqrCarver * r, gint x, gint y)
578 gint data;
579 gfloat b_add = 0;
581 /* removed CANC check for performance reasons */
582 /* CATCH_CANC (r); */
584 data = r->raw[y][x];
586 CATCH (lqr_rwindow_fill (r->rwindow, r, x, y));
587 if (r->bias != NULL)
589 b_add = r->bias[data] / r->w_start;
591 r->en[data] = r->nrg(x, y, r->w, r->h, r->rwindow, r->nrg_extra_data) + b_add;
593 return LQR_OK;
596 /* compute auxiliary minpath map
597 * defined as
598 * y = 1 : m(x,y) = e(x,y)
599 * y > 1 : m(x,y) = min_{x'=-dx,..,dx} ( m(x-x',y-1) + rig(x') ) + e(x,y)
600 * where
601 * e(x,y) is the energy at point (x,y)
602 * dx is the max seam step delta_x
603 * rig(x') is the rigidity for step x'
605 LqrRetVal
606 lqr_carver_build_mmap (LqrCarver * r)
608 gint x, y;
609 gint data;
610 gint data_down;
611 gint x1_min, x1_max, x1;
612 gfloat m, m1, r_fact;
615 CATCH_CANC(r);
617 /* span first row */
618 for (x = 0; x < r->w; x++)
620 data = r->raw[0][x];
621 #ifdef __LQR_DEBUG__
622 assert (r->vs[data] == 0);
623 #endif /* __LQR_DEBUG__ */
624 r->m[data] = r->en[data];
627 /* span all other rows */
628 for (y = 1; y < r->h; y++)
630 for (x = 0; x < r->w; x++)
632 CATCH_CANC(r);
634 data = r->raw[y][x];
635 #ifdef __LQR_DEBUG__
636 assert (r->vs[data] == 0);
637 #endif /* __LQR_DEBUG__ */
638 /* watch for boundaries */
639 x1_min = MAX (-x, -r->delta_x);
640 x1_max = MIN (r->w - 1 - x, r->delta_x);
641 if (r->rigidity_mask) {
642 r_fact = r->rigidity_mask[data];
643 } else {
644 r_fact = 1;
647 /* we use the data_down pointer to be able to
648 * track the seams later (needed for rigidity) */
649 data_down = r->raw[y - 1][x + x1_min];
650 r->least[data] = data_down;
651 if (r->rigidity)
653 m = r->m[data_down] + r_fact * r->rigidity_map[x1_min];
654 for (x1 = x1_min + 1; x1 <= x1_max; x1++)
656 data_down = r->raw[y - 1][x + x1];
657 /* find the min among the neighbors
658 * in the last row */
659 m1 = r->m[data_down] + r_fact * r->rigidity_map[x1];
660 if ((m1 < m) || ((m1 == m) && (r->leftright == 1)))
662 m = m1;
663 r->least[data] = data_down;
665 /* m = MIN(m, r->m[data_down] + r->rigidity_map[x1]); */
668 else
670 m = r->m[data_down];
671 for (x1 = x1_min + 1; x1 <= x1_max; x1++)
673 data_down = r->raw[y - 1][x + x1];
674 /* find the min among the neighbors
675 * in the last row */
676 m1 = r->m[data_down];
677 if ((m1 < m) || ((m1 == m) && (r->leftright == 1)))
679 m = m1;
680 r->least[data] = data_down;
682 m = MIN (m, r->m[data_down]);
686 /* set current m */
687 r->m[data] = r->en[data] + m;
690 return LQR_OK;
693 /* compute (vertical) visibility map up to given depth
694 * (it also calls inflate() to add image enlargment information) */
695 LqrRetVal
696 lqr_carver_build_vsmap (LqrCarver * r, gint depth)
698 gint l;
699 gint lr_switch_interval = 0;
700 LqrDataTok data_tok;
702 #ifdef __LQR_VERBOSE__
703 printf ("[ building visibility map ]\n");
704 fflush (stdout);
705 #endif /* __LQR_VERBOSE__ */
708 #ifdef __LQR_DEBUG__
709 assert (depth <= r->w_start + 1);
710 assert (depth >= 1);
711 #endif /* __LQR_DEBUG__ */
713 /* default behaviour : compute all possible levels
714 * (complete map) */
715 if (depth == 0)
717 depth = r->w_start + 1;
720 /* here we assume that
721 * lqr_carver_set_width(w_start - max_level + 1);
722 * has been given */
724 /* left-right switch interval */
725 if (r->lr_switch_frequency)
727 lr_switch_interval = (depth - r->max_level - 1) / r->lr_switch_frequency + 1;
730 /* cycle over levels */
731 for (l = r->max_level; l < depth; l++)
733 CATCH_CANC(r);
735 if ((l - r->max_level + r->session_rescale_current) % r->session_update_step == 0)
737 lqr_progress_update (r->progress, (gdouble) (l - r->max_level + r->session_rescale_current) /
738 (gdouble) (r->session_rescale_total));
741 #ifdef __LQR_DEBUG__
742 /* check raw rows */
743 lqr_carver_debug_check_rows (r);
744 #endif /* __LQR_DEBUG__ */
746 /* compute vertical seam */
747 lqr_carver_build_vpath (r);
749 /* update visibility map
750 * (assign level to the seam) */
751 lqr_carver_update_vsmap (r, l + r->max_level - 1);
753 /* increase (in)visibility level
754 * (make the last seam invisible) */
755 r->level++;
756 r->w--;
758 /* update raw data */
759 lqr_carver_carve (r);
761 if (r->w > 1)
763 /* update the energy */
764 /* CATCH (lqr_carver_build_emap (r)); */
765 CATCH (lqr_carver_update_emap (r));
767 /* recalculate the minpath map */
768 if ((r->lr_switch_frequency) && (((l - r->max_level + lr_switch_interval / 2) % lr_switch_interval) == 0))
770 r->leftright ^= 1;
771 CATCH (lqr_carver_build_mmap (r));
773 else
775 /* lqr_carver_build_mmap (r); */
776 CATCH (lqr_carver_update_mmap (r));
779 else
781 /* complete the map (last seam) */
782 lqr_carver_finish_vsmap (r);
786 /* insert seams for image enlargement */
787 CATCH (lqr_carver_inflate (r, depth - 1));
789 /* reset image size */
790 lqr_carver_set_width (r, r->w_start);
791 /* repeat for auxiliary layers */
792 data_tok.integer = r->w_start;
793 CATCH (lqr_carver_list_foreach_recursive (r->attached_list, lqr_carver_set_width_attached, data_tok));
795 #ifdef __LQR_VERBOSE__
796 printf ("[ visibility map OK ]\n");
797 fflush (stdout);
798 #endif /* __LQR_VERBOSE__ */
800 return LQR_OK;
803 /* enlarge the image by seam insertion
804 * visibility map is updated and the resulting multisize image
805 * is complete in both directions */
806 LqrRetVal
807 lqr_carver_inflate (LqrCarver * r, gint l)
809 gint w1, z0, vs, k;
810 gint x, y;
811 gint c_left;
812 void *new_rgb = NULL;
813 gint *new_vs = NULL;
814 gdouble tmp_rgb;
815 gfloat *new_bias = NULL;
816 gfloat *new_rigmask = NULL;
817 LqrDataTok data_tok;
818 LqrCarverState prev_state = LQR_CARVER_STATE_STD;
820 #ifdef __LQR_VERBOSE__
821 printf (" [ inflating (active=%i) ]\n", r->active);
822 fflush (stdout);
823 #endif /* __LQR_VERBOSE__ */
825 #ifdef __LQR_DEBUG__
826 assert (l + 1 > r->max_level); /* otherwise is useless */
827 #endif /* __LQR_DEBUG__ */
829 CATCH_CANC (r);
831 if (r->root == NULL)
833 prev_state = g_atomic_int_get(&r->state);
834 CATCH (lqr_carver_set_state(r, LQR_CARVER_STATE_INFLATING, TRUE));
837 /* first iterate on attached carvers */
838 data_tok.integer = l;
839 CATCH (lqr_carver_list_foreach (r->attached_list, lqr_carver_inflate_attached, data_tok));
841 /* scale to current maximum size
842 * (this is the original size the first time) */
843 lqr_carver_set_width (r, r->w0);
845 /* final width */
846 w1 = r->w0 + l - r->max_level + 1;
848 /* allocate room for new maps */
849 BUF_TRY_NEW0_RET_LQR(new_rgb, w1 * r->h0 * r->channels, r->col_depth);
851 if (r->root == NULL)
853 CATCH_MEM (new_vs = g_try_new0 (gint, w1 * r->h0));
855 if (r->active)
857 if (r->bias)
859 CATCH_MEM (new_bias = g_try_new0 (gfloat, w1 * r->h0));
861 if (r->rigidity_mask)
863 CATCH_MEM (new_rigmask = g_try_new (gfloat, w1 * r->h0));
867 /* span the image with a cursor
868 * and build the new image */
869 lqr_cursor_reset (r->c);
870 x = 0;
871 y = 0;
872 for (z0 = 0; z0 < w1 * r->h0; z0++, lqr_cursor_next (r->c))
875 CATCH_CANC (r);
877 /* read visibility */
878 vs = r->vs[r->c->now];
879 if ((vs != 0) && (vs <= l + r->max_level - 1)
880 && (vs >= 2 * r->max_level - 1))
882 /* the point belongs to a previously computed seam
883 * and was not inserted during a previous
884 * inflate() call : insert another seam */
886 /* the new pixel value is equal to the average of its
887 * left and right neighbors */
889 if (r->c->x > 0)
891 c_left = lqr_cursor_left (r->c);
893 else
895 c_left = r->c->now;
898 for (k = 0; k < r->channels; k++)
900 switch (r->col_depth)
902 case LQR_COLDEPTH_8I:
903 tmp_rgb = (AS_8I(r->rgb)[c_left * r->channels + k] +
904 AS_8I(r->rgb)[r->c->now * r->channels + k]) / 2;
905 AS_8I(new_rgb)[z0 * r->channels + k] = (lqr_t_8i) (tmp_rgb + 0.499999);
906 break;
907 case LQR_COLDEPTH_16I:
908 tmp_rgb = (AS_16I(r->rgb)[c_left * r->channels + k] +
909 AS_16I(r->rgb)[r->c->now * r->channels + k]) / 2;
910 AS_16I(new_rgb)[z0 * r->channels + k] = (lqr_t_16i) (tmp_rgb + 0.499999);
911 break;
912 case LQR_COLDEPTH_32F:
913 tmp_rgb = (AS_32F(r->rgb)[c_left * r->channels + k] +
914 AS_32F(r->rgb)[r->c->now * r->channels + k]) / 2;
915 AS_32F(new_rgb)[z0 * r->channels + k] = (lqr_t_32f) tmp_rgb;
916 break;
917 case LQR_COLDEPTH_64F:
918 tmp_rgb = (AS_64F(r->rgb)[c_left * r->channels + k] +
919 AS_64F(r->rgb)[r->c->now * r->channels + k]) / 2;
920 AS_64F(new_rgb)[z0 * r->channels + k] = (lqr_t_64f) tmp_rgb;
921 break;
924 if (r->active)
926 if (r->bias)
928 new_bias[z0] = (r->bias[c_left] + r->bias[r->c->now]) / 2;
930 if (r->rigidity_mask)
932 new_rigmask[z0] = (r->rigidity_mask[c_left] + r->rigidity_mask[r->c->now]) / 2;
935 /* the first time inflate() is called
936 * the new visibility should be -vs + 1 but we shift it
937 * so that the final minimum visibiliy will be 1 again
938 * and so that vs=0 still means "uninitialized".
939 * Subsequent inflations account for that */
940 if (r->root == NULL)
942 new_vs[z0] = l - vs + r->max_level;
944 z0++;
946 for (k = 0; k < r->channels; k++)
948 PXL_COPY(new_rgb, z0 * r->channels + k, r->rgb, r->c->now * r->channels + k, r->col_depth);
950 if (r->active)
952 if (r->bias)
954 new_bias[z0] = r->bias[r->c->now];
956 if (r->rigidity_mask)
958 new_rigmask[z0] = r->rigidity_mask[r->c->now];
961 if (vs != 0)
963 /* visibility has to be shifted up */
964 if (r->root == NULL)
966 new_vs[z0] = vs + l - r->max_level + 1;
969 else if (r->raw != NULL)
971 #ifdef __LQR_DEBUG__
972 assert (y < r->h_start);
973 assert (x < r->w_start - l);
974 #endif /* __LQR_DEBUG__ */
975 r->raw[y][x] = z0;
976 x++;
977 if (x >= r->w_start - l)
979 x = 0;
980 y++;
985 #ifdef __LQR_DEBUG__
986 if (r->raw != NULL)
988 assert (x == 0);
989 if (w1 != 2 * r->w_start - 1)
991 assert ((y == r->h_start)
992 || (printf ("y=%i hst=%i w1=%i\n", y, r->h_start, w1)
993 && fflush (stdout) && 0));
996 #endif /* __LQR_DEBUG__ */
998 /* substitute maps */
999 if (!r->preserve_in_buffer)
1001 g_free (r->rgb);
1003 /* g_free (r->vs); */
1004 g_free (r->en);
1005 g_free (r->m);
1006 g_free (r->rcache);
1007 g_free (r->least);
1008 g_free (r->bias);
1009 g_free (r->rigidity_mask);
1011 r->bias = NULL;
1012 r->rcache = NULL;
1013 r->nrg_uptodate = FALSE;
1015 r->rgb = new_rgb;
1016 r->preserve_in_buffer = FALSE;
1018 if (r->root == NULL)
1020 g_free (r->vs);
1021 r->vs = new_vs;
1022 CATCH (lqr_carver_propagate_vsmap(r));
1024 else
1026 /* r->vs = NULL; */
1028 if (r->nrg_active)
1030 CATCH_MEM (r->en = g_try_new0 (gfloat, w1 * r->h0));
1032 if (r->active)
1034 r->bias = new_bias;
1035 r->rigidity_mask = new_rigmask;
1036 CATCH_MEM (r->m = g_try_new0 (gfloat, w1 * r->h0));
1037 CATCH_MEM (r->least = g_try_new0 (gint, w1 * r->h0));
1040 /* set new widths & levels (w_start is kept for reference) */
1041 r->level = l + 1;
1042 r->max_level = l + 1;
1043 r->w0 = w1;
1044 r->w = r->w_start;
1046 /* reset readout buffer */
1047 g_free (r->rgb_ro_buffer);
1048 BUF_TRY_NEW0_RET_LQR(r->rgb_ro_buffer, r->w0 * r->channels, r->col_depth);
1050 #ifdef __LQR_VERBOSE__
1051 printf (" [ inflating OK ]\n");
1052 fflush (stdout);
1053 #endif /* __LQR_VERBOSE__ */
1055 if (r->root == NULL)
1057 CATCH (lqr_carver_set_state(r, prev_state, TRUE));
1060 return LQR_OK;
1063 LqrRetVal
1064 lqr_carver_inflate_attached (LqrCarver * r, LqrDataTok data)
1066 return lqr_carver_inflate (r, data.integer);
1070 /*** internal functions for maps computations ***/
1072 /* do the carving
1073 * this actually carves the raw array,
1074 * which holds the indices to be used
1075 * in all the other maps */
1076 void
1077 lqr_carver_carve (LqrCarver * r)
1079 gint x, y;
1081 #ifdef __LQR_DEBUG__
1082 assert (r->root == NULL);
1083 #endif /* __LQR_DEBUG__ */
1085 for (y = 0; y < r->h_start; y++)
1087 #ifdef __LQR_DEBUG__
1088 assert (r->vs[r->raw[y][r->vpath_x[y]]] != 0);
1089 for (x = 0; x < r->vpath_x[y]; x++)
1091 assert (r->vs[r->raw[y][x]] == 0);
1093 #endif /* __LQR_DEBUG__ */
1094 for (x = r->vpath_x[y]; x < r->w; x++)
1096 r->raw[y][x] = r->raw[y][x + 1];
1097 #ifdef __LQR_DEBUG__
1098 assert (r->vs[r->raw[y][x]] == 0);
1099 #endif /* __LQR_DEBUG__ */
1103 r->nrg_uptodate = FALSE;
1107 /* update energy map after seam removal */
1108 LqrRetVal
1109 lqr_carver_update_emap (LqrCarver * r)
1111 gint x, y;
1112 gint y1, y1_min, y1_max;
1114 CATCH_CANC (r);
1116 if (r->nrg_uptodate)
1118 return LQR_OK;
1120 if (r->use_rcache)
1122 CATCH_F (r->rcache != NULL);
1125 for (y = 0; y < r->h; y++)
1127 /* note: here the vpath has already
1128 * been carved */
1129 x = r->vpath_x[y];
1130 r->nrg_xmin[y] = x;
1131 r->nrg_xmax[y] = x - 1;
1133 for (y = 0; y < r->h; y++)
1135 x = r->vpath_x[y];
1136 y1_min = MAX (y - r->nrg_radius, 0);
1137 y1_max = MIN (y + r->nrg_radius, r->h - 1);
1139 for (y1 = y1_min; y1 <= y1_max; y1++)
1141 r->nrg_xmin[y1] = MIN (r->nrg_xmin[y1], x - r->nrg_radius);
1142 r->nrg_xmin[y1] = MAX (0, r->nrg_xmin[y1]);
1143 /* note: the -1 below is because of the previous carving */
1144 r->nrg_xmax[y1] = MAX (r->nrg_xmax[y1], x + r->nrg_radius - 1);
1145 r->nrg_xmax[y1] = MIN (r->w - 1, r->nrg_xmax[y1]);
1149 for (y = 0; y < r->h; y++)
1151 CATCH_CANC (r);
1153 for (x = r->nrg_xmin[y]; x <= r->nrg_xmax[y]; x++)
1155 CATCH (lqr_carver_compute_e (r, x, y));
1159 r->nrg_uptodate = TRUE;
1161 return LQR_OK;
1164 /* update the auxiliary minpath map
1165 * this only updates the affected pixels,
1166 * which start form the beginning of the changed
1167 * energy region around the seam and expand
1168 * at most by delta_x (in both directions)
1169 * at each row */
1170 LqrRetVal
1171 lqr_carver_update_mmap (LqrCarver * r)
1173 gint x, y;
1174 gint x_min, x_max;
1175 gint x1, dx;
1176 gint x1_min, x1_max;
1177 gint data, data_down, least;
1178 gfloat m, m1, r_fact;
1179 gfloat new_m;
1180 gfloat * mc = NULL;
1181 gint stop;
1182 gint x_stop;
1184 CATCH_CANC(r);
1185 CATCH_F (r->nrg_uptodate);
1187 if (r->rigidity)
1189 CATCH_MEM (mc = g_try_new(gfloat, 2 * r->delta_x + 1));
1190 mc += r->delta_x;
1193 /* span first row */
1194 /* x_min = MAX (r->vpath_x[0] - r->delta_x, 0); */
1195 x_min = MAX (r->nrg_xmin[0], 0);
1196 /* x_max = MIN (r->vpath_x[0] + r->delta_x - 1, r->w - 1); */
1197 /* x_max = MIN (r->vpath_x[0] + r->delta_x, r->w - 1); */
1198 x_max = MIN (r->nrg_xmax[0], r->w - 1);
1200 for (x = x_min; x <= x_max; x++)
1202 data = r->raw[0][x];
1203 r->m[data] = r->en[data];
1207 /* other rows */
1208 for (y = 1; y < r->h; y++)
1210 CATCH_CANC(r);
1212 /* make sure to include the changed energy region */
1213 x_min = MIN (x_min, r->nrg_xmin[y]);
1214 x_max = MAX (x_max, r->nrg_xmax[y]);
1216 /* expand the affected region by delta_x */
1217 x_min = MAX (x_min - r->delta_x, 0);
1218 x_max = MIN (x_max + r->delta_x, r->w - 1);
1220 /* span the affected region */
1221 stop = 0;
1222 x_stop = 0;
1223 for (x = x_min; x <= x_max; x++)
1225 data = r->raw[y][x];
1226 if (r->rigidity_mask) {
1227 r_fact = r->rigidity_mask[data];
1228 } else {
1229 r_fact = 1;
1232 /* find the minimum in the previous rows
1233 * as in build_mmap() */
1234 x1_min = MAX (0, x - r->delta_x);
1235 x1_max = MIN (r->w - 1, x + r->delta_x);
1237 if (r->rigidity)
1239 dx = x1_min - x;
1240 switch (x1_max - x1_min + 1)
1242 case 1:
1243 MRSET1(y, x1_min, dx);
1244 m = r->leftright ? MRMINR1(y, x1_min, dx) : MRMINL1(y, x1_min, dx);
1245 break;
1246 case 2:
1247 MRSET2(y, x1_min, dx);
1248 m = r->leftright ? MRMINR2(y, x1_min, dx) : MRMINL2(y, x1_min, dx);
1249 break;
1250 case 3:
1251 MRSET3(y, x1_min, dx);
1252 m = r->leftright ? MRMINR3(y, x1_min, dx) : MRMINL3(y, x1_min, dx);
1253 break;
1254 case 4:
1255 MRSET4(y, x1_min, dx);
1256 m = r->leftright ? MRMINR4(y, x1_min, dx) : MRMINL4(y, x1_min, dx);
1257 break;
1258 case 5:
1259 MRSET5(y, x1_min, dx);
1260 m = r->leftright ? MRMINR5(y, x1_min, dx) : MRMINL5(y, x1_min, dx);
1261 break;
1262 default:
1263 data_down = r->raw[y - 1][x1_min];
1264 least = data_down;
1265 m = r->m[data_down] + r_fact * r->rigidity_map[dx++];
1266 /* fprintf(stderr, "y,x=%i,%i x1=%i dx=%i mr=%g MR=%g m=%g M=%g\n", y, x, x1_min, dx, m, MRDOWN(y, x1_min, dx), r->m[data_down], MDOWN(y, x1_min)); fflush(stderr); */
1267 for (x1 = x1_min + 1; x1 <= x1_max; x1++, dx++)
1269 data_down = r->raw[y - 1][x1];
1270 m1 = r->m[data_down] + r_fact * r->rigidity_map[dx];
1271 /* fprintf(stderr, "y,x=%i,%i x1=%i dx=%i mr=%g MR=%g m=%g M=%g\n", y, x, x1, dx, m1, MRDOWN(y, x1, dx), r->m[data_down], MDOWN(y, x1)); fflush(stderr); */
1272 if ((m1 < m) || ((m1 == m) && (r->leftright == 1)))
1274 m = m1;
1275 least = data_down;
1279 /* fprintf(stderr, "y,x=%i,%i x1_min,max=%i,%i least=%i m=%g\n", y, x, x1_min, x1_max, least, m); fflush(stderr); */
1281 else
1283 switch (x1_max - x1_min + 1)
1285 case 1:
1286 m = r->leftright ? MMINR1(y, x1_min) : MMINL1(y, x1_min);
1287 break;
1288 case 2:
1289 m = r->leftright ? MMINR2(y, x1_min) : MMINL2(y, x1_min);
1290 break;
1291 case 3:
1292 m = r->leftright ? MMINR3(y, x1_min) : MMINL3(y, x1_min);
1293 break;
1294 case 4:
1295 m = r->leftright ? MMINR4(y, x1_min) : MMINL4(y, x1_min);
1296 break;
1297 case 5:
1298 m = r->leftright ? MMINR5(y, x1_min) : MMINL5(y, x1_min);
1299 break;
1300 default:
1301 data_down = r->raw[y - 1][x1_min];
1302 least = data_down;
1303 m = r->m[data_down];
1304 for (x1 = x1_min + 1; x1 <= x1_max; x1++)
1306 data_down = r->raw[y - 1][x1];
1307 m1 = r->m[data_down];
1308 if ((m1 < m) || ((m1 == m) && (r->leftright == 1)))
1310 m = m1;
1311 least = data_down;
1315 /* fprintf(stderr, "y,x=%i,%i x1_min,max=%i,%i least=%i m=%g\n", y, x, x1_min, x1_max, least, m); fflush(stderr); */
1318 new_m = r->en[data] + m;
1320 /* reduce the range if there's no (relevant) difference
1321 * with the previous map */
1322 if (r->least[data] == least)
1324 if (fabsf(r->m[data] - new_m) < UPDATE_TOLERANCE)
1326 if (stop == 0)
1328 x_stop = x;
1330 stop = 1;
1331 new_m = r->m[data];
1333 else
1335 stop = 0;
1336 r->m[data] = new_m;
1338 if ((x == x_min) && stop)
1340 x_min++;
1343 else
1345 stop = 0;
1346 r->m[data] = new_m;
1349 r->least[data] = least;
1351 if ((x == x_max) && (stop))
1353 x_max = x_stop;
1359 if (r->rigidity)
1361 mc -= r->delta_x;
1362 g_free(mc);
1365 return LQR_OK;
1370 /* compute seam path from minpath map */
1371 void
1372 lqr_carver_build_vpath (LqrCarver * r)
1374 gint x, y, z0;
1375 gfloat m, m1;
1376 gint last = -1;
1377 gint last_x = 0;
1378 gint x_min, x_max;
1380 /* we start at last row */
1381 y = r->h - 1;
1383 /* span the last row for the minimum mmap value */
1384 m = (1 << 29);
1385 for (x = 0, z0 = y * r->w_start; x < r->w; x++, z0++)
1387 #ifdef __LQR_DEBUG__
1388 assert (r->vs[r->raw[y][x]] == 0);
1389 #endif /* __LQR_DEBUG__ */
1391 m1 = r->m[r->raw[y][x]];
1392 if ((m1 < m) || ((m1 == m) && (r->leftright == 1)))
1394 last = r->raw[y][x];
1395 last_x = x;
1396 m = m1;
1400 #ifdef __LQR_DEBUG__
1401 assert (last >= 0);
1402 #endif /* __LQR_DEBUG__ */
1404 /* follow the track for the other rows */
1405 for (y = r->h0 - 1; y >= 0; y--)
1407 #ifdef __LQR_DEBUG__
1408 assert (r->vs[last] == 0);
1409 assert (last_x < r->w);
1410 #endif /* __LQR_DEBUG__ */
1411 r->vpath[y] = last;
1412 r->vpath_x[y] = last_x;
1413 if (y > 0)
1415 last = r->least[r->raw[y][last_x]];
1416 /* we also need to retrieve the x coordinate */
1417 x_min = MAX (last_x - r->delta_x, 0);
1418 x_max = MIN (last_x + r->delta_x, r->w - 1);
1419 for (x = x_min; x <= x_max; x++)
1421 if (r->raw[y - 1][x] == last)
1423 last_x = x;
1424 break;
1427 #ifdef __LQR_DEBUG__
1428 assert (x < x_max + 1);
1429 #endif /* __LQR_DEBUG__ */
1434 #if 0
1435 /* we backtrack the seam following the min mmap */
1436 for (y = r->h0 - 1; y >= 0; y--)
1438 #ifdef __LQR_DEBUG__
1439 assert (r->vs[last] == 0);
1440 assert (last_x < r->w);
1441 #endif /* __LQR_DEBUG__ */
1443 r->vpath[y] = last;
1444 r->vpath_x[y] = last_x;
1445 if (y > 0)
1447 m = (1 << 29);
1448 x_min = MAX (0, last_x - r->delta_x);
1449 x_max = MIN (r->w - 1, last_x + r->delta_x);
1450 for (x = x_min; x <= x_max; x++)
1452 m1 = r->m[r->raw[y - 1][x]];
1453 if (m1 < m)
1455 last = r->raw[y - 1][x];
1456 last_x = x;
1457 m = m1;
1462 #endif
1465 /* update visibility map after seam computation */
1466 void
1467 lqr_carver_update_vsmap (LqrCarver * r, gint l)
1469 gint y;
1470 #ifdef __LQR_DEBUG__
1471 assert(r->root == NULL);
1472 #endif /* __LQR_DEBUG__ */
1473 for (y = 0; y < r->h; y++)
1475 #ifdef __LQR_DEBUG__
1476 assert (r->vs[r->vpath[y]] == 0);
1477 assert (r->vpath[y] == r->raw[y][r->vpath_x[y]]);
1478 #endif /* __LQR_DEBUG__ */
1479 r->vs[r->vpath[y]] = l;
1483 /* complete visibility map (last seam) */
1484 /* set the last column of pixels to vis. level w0 */
1485 void
1486 lqr_carver_finish_vsmap (LqrCarver * r)
1488 gint y;
1490 #ifdef __LQR_DEBUG__
1491 assert (r->w == 1);
1492 assert (r->root == NULL);
1493 #endif /* __LQR_DEBUG__ */
1494 lqr_cursor_reset (r->c);
1495 for (y = 1; y <= r->h; y++, lqr_cursor_next (r->c))
1497 #ifdef __LQR_DEBUG__
1498 assert (r->vs[r->c->now] == 0);
1499 #endif /* __LQR_DEBUG__ */
1500 r->vs[r->c->now] = r->w0;
1502 lqr_cursor_reset (r->c);
1505 /* propagate the root carver's visibility map */
1506 LqrRetVal
1507 lqr_carver_propagate_vsmap (LqrCarver * r)
1509 LqrDataTok data_tok;
1511 CATCH_CANC (r);
1513 data_tok.data = NULL;
1514 CATCH (lqr_carver_list_foreach_recursive (r->attached_list, lqr_carver_propagate_vsmap_attached, data_tok));
1515 return LQR_OK;
1518 LqrRetVal
1519 lqr_carver_propagate_vsmap_attached (LqrCarver * r, LqrDataTok data)
1521 LqrDataTok data_tok;
1522 data_tok.data = NULL;
1523 r->vs = r->root->vs;
1524 lqr_carver_scan_reset(r);
1525 /* CATCH (lqr_carver_list_foreach (r->attached_list, lqr_carver_propagate_vsmap_attached, data_tok)); */
1526 return LQR_OK;
1529 /*** image manipulations ***/
1531 /* set width of the multisize image
1532 * (maps have to be computed already) */
1533 void
1534 lqr_carver_set_width (LqrCarver * r, gint w1)
1536 #ifdef __LQR_DEBUG__
1537 assert (w1 <= r->w0);
1538 assert (w1 >= r->w_start - r->max_level + 1);
1539 #endif /* __LQR_DEBUG__ */
1540 r->w = w1;
1541 r->level = r->w0 - w1 + 1;
1544 LqrRetVal
1545 lqr_carver_set_width_attached (LqrCarver * r, LqrDataTok data)
1547 lqr_carver_set_width (r, data.integer);
1548 return LQR_OK;
1553 /* flatten the image to its current state
1554 * (all maps are reset, invisible points are lost) */
1555 /* LQR_PUBLIC */
1556 LqrRetVal
1557 lqr_carver_flatten (LqrCarver * r)
1559 void *new_rgb = NULL;
1560 gfloat *new_bias = NULL;
1561 gfloat *new_rigmask = NULL;
1562 gint x, y, k;
1563 gint z0;
1564 LqrDataTok data_tok;
1565 LqrCarverState prev_state = LQR_CARVER_STATE_STD;
1567 #ifdef __LQR_VERBOSE__
1568 printf (" [ flattening (active=%i) ]\n", r->active);
1569 fflush (stdout);
1570 #endif /* __LQR_VERBOSE__ */
1572 CATCH_CANC(r);
1574 if (r->root == NULL)
1576 prev_state = g_atomic_int_get(&r->state);
1577 CATCH (lqr_carver_set_state (r, LQR_CARVER_STATE_FLATTENING, TRUE));
1580 /* first iterate on attached carvers */
1581 CATCH (lqr_carver_list_foreach (r->attached_list, lqr_carver_flatten_attached, data_tok));
1583 /* free non needed maps first */
1584 g_free (r->en);
1585 g_free (r->m);
1586 g_free (r->rcache);
1587 g_free (r->least);
1589 r->rcache = NULL;
1590 r->nrg_uptodate = FALSE;
1592 /* allocate room for new map */
1593 BUF_TRY_NEW0_RET_LQR(new_rgb, r->w * r->h * r->channels, r->col_depth);
1595 if (r->active)
1597 if (r->rigidity_mask)
1599 CATCH_MEM (new_rigmask = g_try_new (gfloat, r->w * r->h));
1602 if (r->nrg_active)
1604 if (r->bias)
1606 CATCH_MEM (new_bias = g_try_new0 (gfloat, r->w * r->h));
1608 g_free (r->_raw);
1609 g_free (r->raw);
1610 CATCH_MEM (r->_raw = g_try_new (gint, r->w * r->h));
1611 CATCH_MEM (r->raw = g_try_new (gint *, r->h));
1614 /* span the image with the cursor and copy
1615 * it in the new array */
1616 lqr_cursor_reset (r->c);
1617 for (y = 0; y < r->h; y++)
1619 CATCH_CANC (r);
1621 if (r->nrg_active)
1623 r->raw[y] = r->_raw + y * r->w;
1625 for (x = 0; x < r->w; x++)
1627 z0 = y * r->w + x;
1628 for (k = 0; k < r->channels; k++)
1630 PXL_COPY(new_rgb, z0 * r->channels + k, r->rgb, r->c->now * r->channels + k, r->col_depth);
1632 if (r->active)
1634 if (r->rigidity_mask)
1636 new_rigmask[z0] = r->rigidity_mask[r->c->now];
1639 if (r->nrg_active)
1641 if (r->bias)
1643 new_bias[z0] = r->bias[r->c->now];
1645 r->raw[y][x] = z0;
1647 lqr_cursor_next (r->c);
1651 /* substitute the old maps */
1652 if (!r->preserve_in_buffer)
1654 g_free (r->rgb);
1656 r->rgb = new_rgb;
1657 r->preserve_in_buffer = FALSE;
1658 if (r->nrg_active)
1660 g_free (r->bias);
1661 r->bias = new_bias;
1663 if (r->active)
1665 g_free (r->rigidity_mask);
1666 r->rigidity_mask = new_rigmask;
1669 /* init the other maps */
1670 if (r->root == NULL)
1672 g_free (r->vs);
1673 CATCH_MEM (r->vs = g_try_new0 (gint, r->w * r->h));
1674 CATCH (lqr_carver_propagate_vsmap(r));
1676 if (r->nrg_active)
1678 CATCH_MEM (r->en = g_try_new0 (gfloat, r->w * r->h));
1680 if (r->active)
1682 CATCH_MEM (r->m = g_try_new0 (gfloat, r->w * r->h));
1683 CATCH_MEM (r->least = g_try_new (gint, r->w * r->h));
1686 /* reset widths, heights & levels */
1687 r->w0 = r->w;
1688 r->h0 = r->h;
1689 r->w_start = r->w;
1690 r->h_start = r->h;
1691 r->level = 1;
1692 r->max_level = 1;
1694 #ifdef __LQR_VERBOSE__
1695 printf (" [ flattening OK ]\n");
1696 fflush (stdout);
1697 #endif /* __LQR_VERBOSE__ */
1699 if (r->root == NULL)
1701 CATCH (lqr_carver_set_state (r, prev_state, TRUE));
1704 return LQR_OK;
1707 LqrRetVal
1708 lqr_carver_flatten_attached(LqrCarver *r, LqrDataTok data)
1710 return lqr_carver_flatten(r);
1713 /* transpose the image, in its current state
1714 * (all maps and invisible points are lost) */
1715 LqrRetVal
1716 lqr_carver_transpose (LqrCarver * r)
1718 gint x, y, k;
1719 gint z0, z1;
1720 gint d;
1721 void *new_rgb = NULL;
1722 gfloat *new_bias = NULL;
1723 gfloat *new_rigmask = NULL;
1724 LqrDataTok data_tok;
1725 LqrCarverState prev_state = LQR_CARVER_STATE_STD;
1727 #ifdef __LQR_VERBOSE__
1728 printf ("[ transposing (active=%i) ]\n", r->active);
1729 fflush (stdout);
1730 #endif /* __LQR_VERBOSE__ */
1732 CATCH_CANC (r);
1734 if (r->root == NULL)
1736 prev_state = g_atomic_int_get(&r->state);
1737 CATCH (lqr_carver_set_state (r, LQR_CARVER_STATE_TRANSPOSING, TRUE));
1740 if (r->level > 1)
1742 CATCH (lqr_carver_flatten (r));
1745 /* first iterate on attached carvers */
1746 CATCH (lqr_carver_list_foreach (r->attached_list, lqr_carver_transpose_attached, data_tok));
1748 /* free non needed maps first */
1749 if (r->root == NULL)
1751 g_free (r->vs);
1753 g_free (r->en);
1754 g_free (r->m);
1755 g_free (r->rcache);
1756 g_free (r->least);
1757 g_free (r->rgb_ro_buffer);
1759 r->rcache = NULL;
1760 r->nrg_uptodate = FALSE;
1762 /* allocate room for the new maps */
1763 BUF_TRY_NEW0_RET_LQR(new_rgb, r->w0 * r->h0 * r->channels, r->col_depth);
1765 if (r->active)
1767 if (r->rigidity_mask)
1769 CATCH_MEM (new_rigmask = g_try_new (gfloat, r->w0 * r->h0));
1772 if (r->nrg_active)
1774 if (r->bias)
1776 CATCH_MEM (new_bias = g_try_new0 (gfloat, r->w0 * r->h0));
1778 g_free (r->_raw);
1779 g_free (r->raw);
1780 CATCH_MEM (r->_raw = g_try_new0 (gint, r->h0 * r->w0));
1781 CATCH_MEM (r->raw = g_try_new0 (gint *, r->w0));
1784 /* compute trasposed maps */
1785 for (x = 0; x < r->w; x++)
1787 if (r->nrg_active)
1789 r->raw[x] = r->_raw + x * r->h0;
1791 for (y = 0; y < r->h; y++)
1793 z0 = y * r->w0 + x;
1794 z1 = x * r->h0 + y;
1795 for (k = 0; k < r->channels; k++)
1797 PXL_COPY(new_rgb, z1 * r->channels + k, r->rgb, z0 * r->channels + k, r->col_depth);
1799 if (r->active)
1801 if (r->rigidity_mask)
1803 new_rigmask[z1] = r->rigidity_mask[z0];
1806 if (r->nrg_active)
1808 if (r->bias)
1810 new_bias[z1] = r->bias[z0];
1812 r->raw[x][y] = z1;
1817 /* substitute the map */
1818 if (!r->preserve_in_buffer)
1820 g_free (r->rgb);
1822 r->rgb = new_rgb;
1823 r->preserve_in_buffer = FALSE;
1825 if (r->nrg_active)
1827 g_free (r->bias);
1828 r->bias = new_bias;
1830 if (r->active)
1832 g_free (r->rigidity_mask);
1833 r->rigidity_mask = new_rigmask;
1836 /* init the other maps */
1837 if (r->root == NULL)
1839 CATCH_MEM (r->vs = g_try_new0 (gint, r->w0 * r->h0));
1840 CATCH (lqr_carver_propagate_vsmap(r));
1842 if (r->nrg_active)
1844 CATCH_MEM (r->en = g_try_new0 (gfloat, r->w0 * r->h0));
1846 if (r->active)
1848 CATCH_MEM (r->m = g_try_new0 (gfloat, r->w0 * r->h0));
1849 CATCH_MEM (r->least = g_try_new (gint, r->w0 * r->h0));
1852 /* switch widths & heights */
1853 d = r->w0;
1854 r->w0 = r->h0;
1855 r->h0 = d;
1856 r->w = r->w0;
1857 r->h = r->h0;
1859 /* reset w_start, h_start & levels */
1860 r->w_start = r->w0;
1861 r->h_start = r->h0;
1862 r->level = 1;
1863 r->max_level = 1;
1865 /* reset seam path, cursor and readout buffer */
1866 if (r->active)
1868 g_free (r->vpath);
1869 CATCH_MEM (r->vpath = g_try_new (gint, r->h));
1870 g_free (r->vpath_x);
1871 CATCH_MEM (r->vpath_x = g_try_new (gint, r->h));
1872 g_free (r->nrg_xmin);
1873 CATCH_MEM (r->nrg_xmin = g_try_new (gint, r->h));
1874 g_free (r->nrg_xmax);
1875 CATCH_MEM (r->nrg_xmax = g_try_new (gint, r->h));
1878 BUF_TRY_NEW0_RET_LQR(r->rgb_ro_buffer, r->w0 * r->channels, r->col_depth);
1880 /* rescale rigidity */
1882 if (r->active)
1884 for (x = -r->delta_x; x <= r->delta_x; x++)
1886 r->rigidity_map[x] = r->rigidity_map[x] * r->w0 / r->h0;
1890 /* set transposed flag */
1891 r->transposed = (r->transposed ? 0 : 1);
1893 #ifdef __LQR_VERBOSE__
1894 printf ("[ transpose OK ]\n");
1895 fflush (stdout);
1896 #endif /* __LQR_VERBOSE__ */
1898 if (r->root == NULL)
1900 CATCH (lqr_carver_set_state (r, prev_state, TRUE));
1903 return LQR_OK;
1906 LqrRetVal
1907 lqr_carver_transpose_attached (LqrCarver * r, LqrDataTok data)
1909 return lqr_carver_transpose(r);
1912 /* resize w + h: these are the liquid rescale methods.
1913 * They automatically determine the depth of the map
1914 * according to the desired size, can be called multiple
1915 * times, transpose the image as necessasry */
1916 LqrRetVal
1917 lqr_carver_resize_width (LqrCarver * r, gint w1)
1919 LqrDataTok data_tok;
1920 gint delta, gamma;
1921 gint delta_max;
1922 /* delta is used to determine the required depth
1923 * gamma to decide if action is necessary */
1924 if (!r->transposed)
1926 delta = w1 - r->w_start;
1927 gamma = w1 - r->w;
1928 delta_max = (gint) ((r->enl_step - 1) * r->w_start) - 1;
1930 else
1932 delta = w1 - r->h_start;
1933 gamma = w1 - r->h;
1934 delta_max = (gint) ((r->enl_step - 1) * r->h_start) - 1;
1936 if (delta_max < 1)
1938 delta_max = 1;
1940 if (delta < 0)
1942 delta = -delta;
1943 delta_max = delta;
1946 CATCH_CANC (r);
1947 CATCH_F (g_atomic_int_get(&r->state) == LQR_CARVER_STATE_STD);
1948 CATCH (lqr_carver_set_state (r, LQR_CARVER_STATE_RESIZING, TRUE));
1950 /* update step for progress reprt*/
1951 r->session_rescale_total = gamma > 0 ? gamma : -gamma;
1952 r->session_rescale_current = 0;
1953 r->session_update_step = (gint) MAX (r->session_rescale_total * r->progress->update_step, 1);
1955 if (r->session_rescale_total)
1957 lqr_progress_init (r->progress, r->progress->init_width_message);
1960 while (gamma)
1962 gint delta0 = MIN (delta, delta_max);
1963 gint new_w;
1965 delta -= delta0;
1966 if (r->transposed)
1968 CATCH (lqr_carver_transpose (r));
1970 new_w = MIN (w1, r->w_start + delta_max);
1971 gamma = w1 - new_w;
1972 CATCH (lqr_carver_build_maps (r, delta0 + 1));
1973 lqr_carver_set_width (r, new_w);
1975 data_tok.integer = new_w;
1976 lqr_carver_list_foreach_recursive (r->attached_list, lqr_carver_set_width_attached, data_tok);
1978 r->session_rescale_current = r->session_rescale_total - (gamma > 0 ? gamma : -gamma);
1980 if (r->dump_vmaps)
1982 CATCH (lqr_vmap_internal_dump (r));
1984 if (new_w < w1)
1986 CATCH (lqr_carver_flatten(r));
1987 delta_max = (gint) ((r->enl_step - 1) * r->w_start) - 1;
1988 if (delta_max < 1)
1990 delta_max = 1;
1995 if (r->session_rescale_total)
1997 lqr_progress_end (r->progress, r->progress->end_width_message);
2000 CATCH (lqr_carver_set_state (r, LQR_CARVER_STATE_STD, TRUE));
2002 return LQR_OK;
2005 LqrRetVal
2006 lqr_carver_resize_height (LqrCarver * r, gint h1)
2008 LqrDataTok data_tok;
2009 gint delta, gamma;
2010 gint delta_max;
2011 /* delta is used to determine the required depth
2012 * gamma to decide if action is necessary */
2013 if (!r->transposed)
2015 delta = h1 - r->h_start;
2016 gamma = h1 - r->h;
2017 delta_max = (gint) ((r->enl_step - 1) * r->h_start) - 1;
2019 else
2021 delta = h1 - r->w_start;
2022 gamma = h1 - r->w;
2023 delta_max = (gint) ((r->enl_step - 1) * r->w_start) - 1;
2025 if (delta_max < 1)
2027 delta_max = 1;
2029 if (delta < 0)
2031 delta_max = -delta;
2033 delta = delta > 0 ? delta : -delta;
2035 CATCH_CANC (r);
2036 CATCH_F (g_atomic_int_get(&r->state) == LQR_CARVER_STATE_STD);
2037 CATCH (lqr_carver_set_state (r, LQR_CARVER_STATE_RESIZING, TRUE));
2039 /* update step for progress reprt*/
2040 r->session_rescale_total = gamma > 0 ? gamma : -gamma;
2041 r->session_rescale_current = 0;
2042 r->session_update_step = (gint) MAX (r->session_rescale_total * r->progress->update_step, 1);
2044 if (r->session_rescale_total)
2046 lqr_progress_init (r->progress, r->progress->init_height_message);
2049 while (gamma)
2051 gint delta0 = MIN (delta, delta_max);
2052 gint new_w;
2053 delta -= delta0;
2054 if (!r->transposed)
2056 CATCH (lqr_carver_transpose (r));
2058 new_w = MIN (h1, r->w_start + delta_max);
2059 gamma = h1 - new_w;
2060 CATCH (lqr_carver_build_maps (r, delta0 + 1));
2061 lqr_carver_set_width (r, new_w);
2063 data_tok.integer = new_w;
2064 lqr_carver_list_foreach_recursive (r->attached_list, lqr_carver_set_width_attached, data_tok);
2066 r->session_rescale_current = r->session_rescale_total - (gamma > 0 ? gamma : - gamma);
2068 if (r->dump_vmaps)
2070 CATCH (lqr_vmap_internal_dump (r));
2072 if (new_w < h1)
2074 CATCH (lqr_carver_flatten(r));
2075 delta_max = (gint) ((r->enl_step - 1) * r->w_start) - 1;
2076 if (delta_max < 1)
2078 delta_max = 1;
2083 if (r->session_rescale_total)
2085 lqr_progress_end (r->progress, r->progress->end_height_message);
2088 CATCH (lqr_carver_set_state (r, LQR_CARVER_STATE_STD, TRUE));
2090 return LQR_OK;
2093 /* liquid rescale public method */
2094 /* LQR_PUBLIC */
2095 LqrRetVal
2096 lqr_carver_resize (LqrCarver * r, gint w1, gint h1)
2098 #ifdef __LQR_VERBOSE__
2099 printf("[ Rescale from %i,%i to %i,%i ]\n", (r->transposed ? r->h : r->w), (r->transposed ? r->w : r->h), w1, h1);
2100 fflush(stdout);
2101 #endif /* __LQR_VERBOSE__ */
2102 CATCH_F ((w1 >= 1) && (h1 >= 1));
2103 CATCH_F (r->root == NULL);
2105 CATCH_CANC (r);
2106 CATCH_F (g_atomic_int_get(&r->state) == LQR_CARVER_STATE_STD);
2108 switch (r->resize_order)
2110 case LQR_RES_ORDER_HOR:
2111 CATCH (lqr_carver_resize_width(r, w1));
2112 CATCH (lqr_carver_resize_height(r, h1));
2113 break;
2114 case LQR_RES_ORDER_VERT:
2115 CATCH (lqr_carver_resize_height(r, h1));
2116 CATCH (lqr_carver_resize_width(r, w1));
2117 break;
2118 #ifdef __LQR_DEBUG__
2119 default:
2120 assert(0);
2121 #endif /* __LQR_DEBUG__ */
2123 lqr_carver_scan_reset_all(r);
2125 #ifdef __LQR_VERBOSE__
2126 printf("[ Rescale OK ]\n");
2127 fflush(stdout);
2128 #endif /* __LQR_VERBOSE__ */
2129 return LQR_OK;
2132 LqrRetVal
2133 lqr_carver_set_state (LqrCarver * r, LqrCarverState state, gboolean skip_canceled)
2135 LqrDataTok data_tok;
2136 gint lock_pos;
2138 CATCH_F(r->root == NULL);
2140 lock_pos = g_atomic_int_exchange_and_add(&r->state_lock_queue, 1);
2142 while (g_atomic_int_get(&r->state_lock) != lock_pos)
2144 g_usleep(10000);
2147 if (skip_canceled && g_atomic_int_get(&r->state) == LQR_CARVER_STATE_CANCELLED) {
2148 g_atomic_int_inc(&r->state_lock);
2149 return LQR_OK;
2152 g_atomic_int_set(&r->state, state);
2154 data_tok.integer = state;
2155 CATCH (lqr_carver_list_foreach_recursive (r->attached_list, lqr_carver_set_state_attached, data_tok));
2157 g_atomic_int_inc(&r->state_lock);
2159 return LQR_OK;
2162 LqrRetVal
2163 lqr_carver_set_state_attached (LqrCarver * r, LqrDataTok data)
2165 g_atomic_int_set (&r->state, data.integer);
2166 return LQR_OK;
2169 /* cancel the current action from a different thread */
2170 /* LQR_PUBLIC */
2171 LqrRetVal
2172 lqr_carver_cancel (LqrCarver * r)
2174 LqrCarverState curr_state;
2176 CATCH_F (r->root == NULL);
2178 curr_state = g_atomic_int_get (&r->state);
2180 if ((curr_state == LQR_CARVER_STATE_RESIZING) ||
2181 (curr_state == LQR_CARVER_STATE_INFLATING) ||
2182 (curr_state == LQR_CARVER_STATE_TRANSPOSING) ||
2183 (curr_state == LQR_CARVER_STATE_FLATTENING))
2185 CATCH (lqr_carver_set_state (r, LQR_CARVER_STATE_CANCELLED, TRUE));
2187 return LQR_OK;
2190 /* get current size */
2191 /* LQR_PUBLIC */
2192 gint
2193 lqr_carver_get_width(LqrCarver* r)
2195 return (r->transposed ? r->h : r->w);
2198 /* LQR_PUBLIC */
2199 gint
2200 lqr_carver_get_height(LqrCarver* r)
2202 return (r->transposed ? r->w : r->h);
2205 /* get reference size */
2206 /* LQR_PUBLIC */
2207 gint
2208 lqr_carver_get_ref_width(LqrCarver* r)
2210 return (r->transposed ? r->h_start : r->w_start);
2213 /* LQR_PUBLIC */
2214 gint
2215 lqr_carver_get_ref_height(LqrCarver* r)
2217 return (r->transposed ? r->w_start : r->h_start);
2220 /* get colour channels */
2221 /* LQR_PUBLIC */
2222 gint
2223 lqr_carver_get_channels (LqrCarver * r)
2225 return r->channels;
2228 /* LQR_PUBLIC */
2229 gint
2230 lqr_carver_get_bpp (LqrCarver * r)
2232 return lqr_carver_get_channels(r);
2235 /* get colour depth */
2236 /* LQR_PUBLIC */
2237 LqrColDepth
2238 lqr_carver_get_col_depth (LqrCarver * r)
2240 return r->col_depth;
2243 /* get enlargement step */
2244 /* LQR_PUBLIC */
2245 gfloat
2246 lqr_carver_get_enl_step (LqrCarver * r)
2248 return r->enl_step;
2251 /* get orientation */
2252 /* LQR_PUBLIC */
2253 gint
2254 lqr_carver_get_orientation (LqrCarver* r)
2256 return (r->transposed ? 1 : 0);
2259 /* get depth */
2260 /* LQR_PUBLIC */
2261 gint
2262 lqr_carver_get_depth (LqrCarver *r)
2264 return r->w0 - r->w_start;
2268 /* readout reset */
2269 /* LQR_PUBLIC */
2270 void
2271 lqr_carver_scan_reset (LqrCarver * r)
2273 lqr_cursor_reset (r->c);
2276 LqrRetVal
2277 lqr_carver_scan_reset_attached (LqrCarver * r, LqrDataTok data)
2279 lqr_carver_scan_reset(r);
2280 return lqr_carver_list_foreach(r->attached_list, lqr_carver_scan_reset_attached, data);
2283 void
2284 lqr_carver_scan_reset_all (LqrCarver *r)
2286 LqrDataTok data;
2287 data.data = NULL;
2288 lqr_carver_scan_reset(r);
2289 lqr_carver_list_foreach(r->attached_list, lqr_carver_scan_reset_attached, data);
2294 /* readout all, pixel by bixel */
2295 /* LQR_PUBLIC */
2296 gboolean
2297 lqr_carver_scan (LqrCarver * r, gint * x, gint * y, guchar ** rgb)
2299 gint k;
2300 if (r->col_depth != LQR_COLDEPTH_8I)
2302 return FALSE;
2304 if (r->c->eoc)
2306 lqr_carver_scan_reset (r);
2307 return FALSE;
2309 (*x) = (r->transposed ? r->c->y : r->c->x);
2310 (*y) = (r->transposed ? r->c->x : r->c->y);
2311 for (k = 0; k < r->channels; k++)
2313 AS_8I(r->rgb_ro_buffer)[k] = AS_8I(r->rgb)[r->c->now * r->channels + k];
2315 (*rgb) = AS_8I(r->rgb_ro_buffer);
2316 lqr_cursor_next(r->c);
2317 return TRUE;
2320 /* LQR_PUBLIC */
2321 gboolean
2322 lqr_carver_scan_ext (LqrCarver * r, gint * x, gint * y, void ** rgb)
2324 gint k;
2325 if (r->c->eoc)
2327 lqr_carver_scan_reset (r);
2328 return FALSE;
2330 (*x) = (r->transposed ? r->c->y : r->c->x);
2331 (*y) = (r->transposed ? r->c->x : r->c->y);
2332 for (k = 0; k < r->channels; k++)
2334 PXL_COPY(r->rgb_ro_buffer, k, r->rgb, r->c->now * r->channels + k, r->col_depth);
2337 BUF_POINTER_COPY(rgb, r->rgb_ro_buffer, r->col_depth);
2339 lqr_cursor_next(r->c);
2340 return TRUE;
2343 /* readout all, by line */
2344 /* LQR_PUBLIC */
2345 gboolean
2346 lqr_carver_scan_by_row (LqrCarver *r)
2348 return r->transposed ? FALSE : TRUE;
2351 /* LQR_PUBLIC */
2352 gboolean
2353 lqr_carver_scan_line (LqrCarver * r, gint * n, guchar ** rgb)
2355 if (r->col_depth != LQR_COLDEPTH_8I)
2357 return FALSE;
2359 return lqr_carver_scan_line_ext (r, n, (void**) rgb);
2362 /* LQR_PUBLIC */
2363 gboolean
2364 lqr_carver_scan_line_ext (LqrCarver * r, gint * n, void ** rgb)
2366 gint k, x;
2367 if (r->c->eoc)
2369 lqr_carver_scan_reset (r);
2370 return FALSE;
2372 x = r->c->x;
2373 (*n) = r->c->y;
2374 while (x > 0)
2376 lqr_cursor_prev(r->c);
2377 x = r->c->x;
2379 for (x = 0; x < r->w; x++)
2381 for (k = 0; k < r->channels; k++)
2383 PXL_COPY(r->rgb_ro_buffer, x * r->channels + k, r->rgb, r->c->now * r->channels + k, r->col_depth);
2385 lqr_cursor_next(r->c);
2389 BUF_POINTER_COPY(rgb, r->rgb_ro_buffer, r->col_depth);
2391 return TRUE;
2394 #ifdef __LQR_DEBUG__
2395 void lqr_carver_debug_check_rows(LqrCarver * r)
2397 int x, y;
2398 int data;
2399 for (y = 0; y < r->h; y++)
2401 for (x = 0; x < r->w; x++)
2403 data = r->raw[y][x];
2404 if (data / r->w0 != y)
2406 fflush(stderr);
2408 assert(data / r->w0 == y);
2412 #endif /* __LQR_DEBUG__ */
2415 /**** END OF LQR_CARVER CLASS FUNCTIONS ****/