Fix run length encoding of marked image, bump to version 0.8
[colorize.git] / gui / colorize.c
1 #include <gtk/gtk.h>
2 #include <gdk/gdkkeysyms.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <math.h>
7 #include "main.h"
8 #include "image.h"
9 #include "colorize.h"
10 #include "../src/mark.h"
11 #include "../src/img.h"
12 #include "../src/yuv.h"
13 #include "../src/dir_seperator.h"
14 #include "../lib/darray.h"
15 #include "../lib/colorize.h"
16 #include "../src/process.h"
17 #include "palette.h"
18 #include "timeline.h"
19
20 enum thread_preview {
21         PREVIEW_OFF,
22         PREVIEW_NEW,
23         PREVIEW_ALLOC,
24         PREVIEW_ON,
25         PREVIEW_FREE,
26 };
27
28 static int thread_debug = 0;
29 static int thread_running = 0;
30 static enum thread_preview thread_preview = PREVIEW_OFF;
31
32 struct colorize_priv {
33         GtkWidget *window;
34         GdkPixbuf *pixbuf;
35         int width, height, alpha;
36         char filename[256];
37         char folder[256];
38         unsigned short *img;
39 };
40
41 static void colorize_destroy(GtkWidget *widget, gpointer priv)
42 {
43         struct colorize_priv *cp = (struct colorize_priv *) priv;
44
45         gtk_widget_destroy(cp->window);
46         g_object_unref(cp->pixbuf);
47         free(cp->img);
48         free(cp);
49 }
50
51 static gboolean colorize_key_press(GtkWidget *widget, GdkEventKey *event, gpointer priv)
52 {
53         switch (event->keyval) {
54         case GDK_q:
55         case GDK_w:
56                 if (event->state & GDK_CONTROL_MASK) {
57                         gtk_widget_destroy(widget);
58                         return TRUE;
59                 }
60         default:
61                 ;//printf("%x\n", event->keyval);
62         }
63
64         return FALSE;
65 }
66
67 static void save_event(gpointer *priv)
68 {
69         struct colorize_priv *cp = (struct colorize_priv *) priv;
70         GtkWidget *dialog;
71         char *filename = NULL;
72         FILE *fp;
73
74         dialog = gtk_file_chooser_dialog_new("Select file to save colorized image",
75                 GTK_WINDOW(main_window),
76                 GTK_FILE_CHOOSER_ACTION_SAVE,
77                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
78                 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
79                 NULL);
80
81         gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), cp->folder);
82         gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), cp->filename);
83         if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
84                 filename = strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)));
85         }
86
87         gtk_widget_destroy(dialog);
88
89         if (!filename)
90                 return;
91
92         if ((fp = fopen(filename, "r"))) {
93                 int ret;
94                 fclose(fp);
95                 GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
96                         GTK_DIALOG_DESTROY_WITH_PARENT,
97                         GTK_MESSAGE_ERROR,
98                         GTK_BUTTONS_OK_CANCEL,
99                         "Image already exists, overwrite it?");
100                 ret = gtk_dialog_run(GTK_DIALOG (dialog));
101                 gtk_widget_destroy(dialog);
102                 if (ret != GTK_RESPONSE_OK)
103                         goto exit;
104         }
105
106
107         save_img(cp->img, cp->width, cp->height, cp->alpha, filename, 0);
108
109 exit:
110         free(filename);
111 }
112
113 static void dummy_event(gpointer *priv)
114 {
115 }
116
117 static void close_event(gpointer *priv)
118 {
119         struct colorize_priv *cp = (struct colorize_priv *) priv;
120
121         gtk_widget_destroy(cp->window);
122 }
123
124 void colorize_image(void)
125 {
126         darray_t *gI = NULL, *cI = NULL, *I = NULL, *mI = NULL;
127         double *ptr_gI = NULL, *ptr_cI = NULL, *ptr_y = NULL, *ptr_u = NULL, *ptr_v = NULL, *ptr_a = NULL, *ptr_r = NULL, *ptr_b = NULL, *ptr_c = NULL, *ptr_m = NULL;
128         int dims[4];
129         int width = img_width, height = img_height;
130         int features, change_bc, change_alpha;
131         char *feat_names[20];
132         int i, j;
133         int c;
134         int rc;
135         GdkPixbuf *pixbuf;
136         GtkWidget *image;
137         guchar *data;
138         GtkWidget *colorize_window;
139         GtkWidget *vbox;
140         GtkWidget *menu_bar;
141         GtkWidget *root_menu;
142         GtkWidget *menu;
143         GtkWidget *menu_item;
144         struct colorize_priv *cp;
145         int rs;
146         int zoom_field;
147         char *p, *q;
148
149         if (!img_pixbuf)
150                 return;
151
152         /* generate grey image array */
153         dims[0] = width; dims[1] = height; dims[2] = 3; dims[3] = 1;
154         gI = darrayCreate(4, dims);
155         if (!gI) {
156                 printerror("No memory: failed to create grey image array");
157                 goto error;
158         }
159         ptr_gI = darrayGetPr(gI);
160         img2array_short(img_grey_buffer, width, height, ptr_gI, width, height);
161
162         /* generade marked color image */
163         dims[0] = width; dims[1] = height; dims[2] = 3; dims[3] = 1;
164         cI = darrayCreate(4, dims);
165         if (!cI) {
166                 printerror("No memory: failed to create marked image array");
167                 goto error;
168         }
169         ptr_cI = darrayGetPr(cI);
170         img2array_short(img_grey_buffer, width, height, ptr_cI, width, height);
171         change_bc = change_alpha = 0;
172         for (i = 0; i < height; i++) {
173                 for (j = 0; j < width; j++) {
174                         /* do not apply mask on index 0 */
175                         c = img_mark_buffer[i*width+j];
176                         if (c == 0)
177                                 continue;
178                         /* check for any brightness/contrast change */
179                         if (mark_palette[c-1].bright != 0 || mark_palette[c-1].contrast != 1)
180                                 change_bc = 1;
181                         /* check for any alpha change */
182                         if (mark_palette[c-1].alpha < 1)
183                                 change_alpha = 1;
184                         /* do not apply white pixles, this meas: keep original color */
185                         if (mark_palette[c-1].r == 255 && mark_palette[c-1].g == 255 && mark_palette[c-1].b == 255)
186                                 continue;
187                         ptr_cI[i*width+j] = mark_palette[c-1].r / 255.0F;
188                         ptr_cI[i*width+j + width*height] = mark_palette[c-1].g / 255.0F;
189                         ptr_cI[i*width+j + width*height*2] = mark_palette[c-1].b / 255.0F;
190                 }
191         }
192
193         rc = alloc_I_arrays(&I, &mI, width, height, 1, &features, feat_names, change_alpha, change_bc);
194         if (rc)
195                 goto error;
196
197         set_I_ptr(I, mI, width, height, 0, features, change_alpha, change_bc, &ptr_y, &ptr_u, &ptr_v, &ptr_a, &ptr_r, &ptr_b, &ptr_c, &ptr_m);
198
199         // convert original image into YUV
200         rgb2yuv(ptr_gI, ptr_gI, width, height);
201         // convert maked image into YUV
202         rgb2yuv(ptr_cI, ptr_cI, width, height);
203
204         /* apply mask to mI */
205         for (i = 0; i < height; i++) {
206                 for (j = 0; j < width; j++) {
207                         /* do not apply mask on index 0 */
208                         c = img_mark_buffer[i*width+j];
209                         ptr_m[i*width+j] = (c == 0) ? 0.0F : 1.0F;
210                 }
211         }
212
213         prepare_arrays(width, height, change_alpha, change_bc, img_mark_buffer, ptr_gI, ptr_cI, ptr_y, ptr_u, ptr_v, ptr_a, ptr_r, ptr_b, ptr_c, ptr_m, NO_TEST);
214
215         /* destroy temporary gI and cI */
216         darrayDestroy(gI);
217         gI = NULL;
218         darrayDestroy(cI);
219         cI = NULL;
220
221         /* render u and v change */
222         rc = colorize(I, mI, NULL, NULL, 5, 10, 0.01, 0, 0, feat_names, NULL);
223         if (rc < 0) {
224                 printerror("No memory! Use smaller image or add more memory.");
225                 goto error;
226         }
227
228         postpare_arrays(width, height, change_alpha, change_bc, ptr_y, ptr_u, ptr_v, ptr_a, ptr_r, ptr_b, ptr_c, ptr_m, NO_TEST);
229
230         if (img_scale_y == img_scale_x*2)
231                 zoom_field = 2;
232         else
233                 zoom_field = 1;
234
235         /* convert YUV to RGB */
236         pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, width, height * zoom_field);
237         yuv2rgb(ptr_y, ptr_y, width, height);
238
239         /* private structure */
240         cp = calloc(sizeof(struct colorize_priv), 1);
241         cp->width = width;
242         cp->height = height;
243         cp->alpha = change_alpha;
244
245         /* apply image to be saved later */
246         cp->img = malloc(width*height*(3+change_alpha)*sizeof(unsigned short));
247         array2img_short(ptr_y, width, height, cp->img, width, height, change_alpha);
248
249         /* create image */
250         if (change_alpha) {
251                 /* simulate alpha by pattern */
252                 double pat, a;
253                 for (i = 0; i < height; i++) {
254                         for (j = 0; j < width; j++) {
255                                 pat = (((j>>3)&1) == ((i>>3)&1)) ? 0.5 : 0.75;
256                                 a = ptr_a[i*width+j];
257                                 /* yuv is actually RGB */
258                                 ptr_y[i*width+j] = a * ptr_y[i*width+j] + (1.0 - a) * pat;
259                                 ptr_u[i*width+j] = a * ptr_u[i*width+j] + (1.0 - a) * pat;
260                                 ptr_v[i*width+j] = a * ptr_v[i*width+j] + (1.0 - a) * pat;
261                         }
262                 }
263         }
264         data = gdk_pixbuf_get_pixels(pixbuf);
265         rs = gdk_pixbuf_get_rowstride(pixbuf);
266         for (i = 0; i < height*zoom_field; i++) {
267                 for (j = 0; j < width; j++) {
268                         /* yuv is actually RGB */
269                         c = ptr_y[(i/zoom_field)*width+j] * 255.0F;
270                         if (c < 0)
271                                 c = 0;
272                         else if (c > 255)
273                                 c = 255;
274                         data[i*rs + 3*j + 0] = c;
275                         c = ptr_u[(i/zoom_field)*width+j] * 255.0F;
276                         if (c < 0)
277                                 c = 0;
278                         else if (c > 255)
279                                 c = 255;
280                         data[i*rs + 3*j + 1] = c;
281                         c = ptr_v[(i/zoom_field)*width+j] * 255.0F;
282                         if (c < 0)
283                                 c = 0;
284                         else if (c > 255)
285                                 c = 255;
286                         data[i*rs + 3*j + 2] = c;
287                 }
288         }
289
290         image = gtk_image_new_from_pixbuf(pixbuf);
291         gtk_widget_show(image);
292
293         darrayDestroy(mI);
294         mI = NULL;
295         darrayDestroy(I);
296         I = NULL;
297
298         /* during real time rendering, we cannot check if all arrays are free */
299         if (thread_preview == PREVIEW_OFF)
300                 darrayDone();
301
302         /* create window */
303         colorize_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
304         gtk_window_set_title(GTK_WINDOW(colorize_window), "Colorized");
305         g_signal_connect(colorize_window, "destroy", G_CALLBACK(colorize_destroy), cp);
306         g_signal_connect(colorize_window, "key_press_event", G_CALLBACK(colorize_key_press), cp);
307
308         cp->window = colorize_window;
309         cp->pixbuf = pixbuf;
310         p = frame_list[timeline_selected].filename;
311         while((q = strchr(p, DIR_SEPERATOR)))
312                 p = q + 1;
313         strcpy(cp->folder, frame_list[timeline_selected].filename);
314         cp->folder[p - frame_list[timeline_selected].filename] = '\0';
315         sprintf(cp->filename, "colorized_%s", p);
316
317         /* create menu*/
318         menu_bar = gtk_menu_bar_new();
319         gtk_widget_show(menu_bar);
320         menu = gtk_menu_new();
321         root_menu = gtk_menu_item_new_with_mnemonic("_File");
322         gtk_widget_show(root_menu);
323
324         menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_SAVE_AS, NULL);
325         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
326         g_signal_connect_swapped(menu_item, "activate", G_CALLBACK(save_event), cp);
327         gtk_widget_show(menu_item);
328         menu_item = gtk_separator_menu_item_new();
329         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
330         g_signal_connect_swapped(menu_item, "activate", G_CALLBACK(dummy_event), cp);
331         gtk_widget_show(menu_item);
332         menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CLOSE, NULL);
333         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
334         g_signal_connect_swapped(menu_item, "activate", G_CALLBACK(close_event), cp);
335         gtk_widget_show(menu_item);
336         gtk_menu_item_set_submenu(GTK_MENU_ITEM(root_menu), menu);
337         gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), root_menu);
338
339         /* create vbox (complete window) */
340         vbox = gtk_vbox_new(FALSE, 0);
341         gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 2);
342         gtk_box_pack_start(GTK_BOX(vbox), image, FALSE, FALSE, 2);
343         gtk_widget_show(vbox);
344
345         gtk_container_add(GTK_CONTAINER(colorize_window), vbox);
346         gtk_widget_show(colorize_window);
347
348 error:
349         darrayDestroy(gI);
350         darrayDestroy(cI);
351         darrayDestroy(mI);
352         darrayDestroy(I);
353
354         /* during real time rendering, we cannot check if all arrays are free */
355         if (thread_preview == PREVIEW_OFF)
356                 darrayDone();
357 }
358
359 /* real time thread */
360
361 static void *colorize_thread(void *arg)
362 {
363         struct colorize *col = NULL;
364         darray_t *gI = NULL, *cI = NULL, *I = NULL, *mI = NULL;
365         unsigned char *mark_buffer = NULL;
366         int dims[4];
367         int features, change_bc = 0, change_alpha = 0;
368         char *feat_names[20];
369         int i, j;
370         int c;
371         int rc;
372         if (thread_debug)
373                 printf("%s: thread entered\n", __func__);
374
375 loop:
376         gdk_threads_enter();
377         if (thread_running < 1) {
378                 if (thread_debug)
379                         printf("%s: thread leaving\n", __func__);
380                 thread_running = 0;
381                 goto reset;
382         }
383         if (thread_preview == PREVIEW_NEW) {
384                 thread_preview = PREVIEW_ALLOC;
385                 goto reset;
386         }
387         if (thread_preview == PREVIEW_ALLOC) {
388                 int width, height;
389
390                 if (thread_debug)
391                         printf("%s: new preview\n", __func__);
392                 width = img_width;
393                 height = img_height;
394
395                 /* alloc gI and cI array */
396                 dims[0] = width; dims[1] = height; dims[2] = 3; dims[3] = 1;
397                 gI = darrayCreate(4, dims);
398                 if (!gI) {
399                         printerror("No memory: failed to create grey image array");
400                         thread_preview = PREVIEW_OFF;
401                         goto reset;
402                 }
403                 dims[0] = width; dims[1] = height; dims[2] = 3; dims[3] = 1;
404                 cI = darrayCreate(4, dims);
405                 if (!cI) {
406                         printerror("No memory: failed to create marked image array");
407                         thread_preview = PREVIEW_OFF;
408                         goto reset;
409                 }
410                 mark_buffer = malloc(width*height);
411                 if (!mark_buffer) {
412                         printerror("No memory: failed to create marked index image");
413                         thread_preview = PREVIEW_OFF;
414                         goto reset;
415                 }
416                 thread_preview = PREVIEW_ON;
417         }
418         if (thread_preview == PREVIEW_ON) {
419                 int width, height;
420                 double *ptr_gI = NULL, *ptr_cI = NULL, *ptr_y = NULL, *ptr_u = NULL, *ptr_v = NULL, *ptr_a = NULL, *ptr_r = NULL, *ptr_b = NULL, *ptr_c = NULL, *ptr_m = NULL;
421
422                 if (thread_debug)
423                         printf("%s: prepare gI/cI\n", __func__);
424                 width = img_width;
425                 height = img_height;
426
427                 /* generate grey image array */
428                 ptr_gI = darrayGetPr(gI);
429                 img2array_short(img_grey_buffer, width, height, ptr_gI, width, height);
430                 /* generade marked color image */
431                 ptr_cI = darrayGetPr(cI);
432                 img2array_short(img_grey_buffer, width, height, ptr_cI, width, height);
433                 /* copy mark buffer */
434                 memcpy(mark_buffer, img_mark_buffer, width*height);
435
436                 /* prepare while unlocked */
437                 gdk_threads_leave();
438                 /* apply marked pixles */
439                 change_bc = change_alpha = 0;
440                 for (i = 0; i < height; i++) {
441                         for (j = 0; j < width; j++) {
442                                 /* do not apply mask on index 0 */
443                                 c = mark_buffer[i*width+j];
444                                 if (c == 0)
445                                         continue;
446 #if 0
447 iterative colorization does not work with change_bc and change_alpha, because it alters I image before and after colorization
448                                 /* check for any brightness/contrast change */
449                                 if (mark_palette[c-1].bright != 0 || mark_palette[c-1].contrast != 1)
450                                         change_bc = 1;
451                                 /* check for any alpha change */
452                                 if (mark_palette[c-1].alpha < 1)
453                                         change_alpha = 1;
454 #endif
455                                 /* do not apply white pixles, this meas: keep original color */
456                                 if (mark_palette[c-1].r == 255 && mark_palette[c-1].g == 255 && mark_palette[c-1].b == 255)
457                                         continue;
458                                 ptr_cI[i*width+j] = mark_palette[c-1].r / 255.0F;
459                                 ptr_cI[i*width+j + width*height] = mark_palette[c-1].g / 255.0F;
460                                 ptr_cI[i*width+j + width*height*2] = mark_palette[c-1].b / 255.0F;
461                         }
462                 }
463
464                 rc = alloc_I_arrays(&I, &mI, width, height, 1, &features, feat_names, change_alpha, change_bc);
465                 if (rc) {
466                         printerror("No memory! Use smaller image or add more memory.");
467                         thread_preview = PREVIEW_OFF;
468                         goto reset;
469                 }
470
471                 set_I_ptr(I, mI, width, height, 0, features, change_alpha, change_bc, &ptr_y, &ptr_u, &ptr_v, &ptr_a, &ptr_r, &ptr_b, &ptr_c, &ptr_m);
472
473                 // convert original image into YUV
474                 rgb2yuv(ptr_gI, ptr_gI, width, height);
475                 // convert maked image into YUV
476                 rgb2yuv(ptr_cI, ptr_cI, width, height);
477
478                 /* apply mask to mI */
479                 for (i = 0; i < height; i++) {
480                         for (j = 0; j < width; j++) {
481                                 /* do not apply mask on index 0 */
482                                 c = mark_buffer[i*width+j];
483                                 ptr_m[i*width+j] = (c == 0) ? 0.0F : 1.0F;
484                         }
485                 }
486
487                 prepare_arrays(width, height, change_alpha, change_bc, mark_buffer, ptr_gI, ptr_cI, ptr_y, ptr_u, ptr_v, ptr_a, ptr_r, ptr_b, ptr_c, ptr_m, NO_TEST);
488
489                 /* prepared, so we lock */
490                 gdk_threads_enter();
491         }
492         if (thread_preview == PREVIEW_ON) {
493                 int width, height;
494                 double *ptr_gI = NULL, *ptr_y = NULL, *ptr_u = NULL, *ptr_v = NULL, *ptr_a = NULL, *ptr_r = NULL, *ptr_b = NULL, *ptr_c = NULL, *ptr_m = NULL;
495
496                 if (thread_debug)
497                         printf("%s: render preview\n", __func__);
498                 width = img_width;
499                 height = img_height;
500
501                 /* render while unlocked */
502                 gdk_threads_leave();
503
504                 set_I_ptr(I, mI, width, height, 0, features, change_alpha, change_bc, &ptr_y, &ptr_u, &ptr_v, &ptr_a, &ptr_r, &ptr_b, &ptr_c, &ptr_m);
505
506                 /* render u and v change */
507                 rc = colorize(I, mI, NULL, NULL, 1, 1, 0.0, 1, 0, feat_names, &col);
508                 if (rc < 0) {
509                         printerror("No memory! Use smaller image or add more memory.");
510                         thread_preview = PREVIEW_OFF;
511                         goto reset;
512                 }
513
514                 postpare_arrays(width, height, change_alpha, change_bc, ptr_y, ptr_u, ptr_v, ptr_a, ptr_r, ptr_b, ptr_c, ptr_m, NO_TEST);
515
516                 /* convert YUV to RGB */
517                 ptr_gI = darrayGetPr(gI);
518                 yuv2rgb(ptr_y, ptr_gI, width, height);
519
520                 /* create image */
521                 if (change_alpha) {
522                         /* simulate alpha by pattern */
523                         double pat, a;
524                         for (i = 0; i < height; i++) {
525                                 for (j = 0; j < width; j++) {
526                                         pat = (((j>>3)&1) == ((i>>3)&1)) ? 0.5 : 0.75;
527                                         a = ptr_a[i*width+j];
528                                         ptr_gI[i*width+j] = a * ptr_gI[i*width+j] + (1.0 - a) * pat;
529                                         ptr_gI[i*width+j + width*height] = a * ptr_gI[i*width+j + width*height] + (1.0 - a) * pat;
530                                         ptr_gI[i*width+j + width*height*2] = a * ptr_gI[i*width+j + width*height*2] + (1.0 - a) * pat;
531                                 }
532                         }
533                 }
534
535                 /* rendered, so we lock */
536                 gdk_threads_enter();
537         }
538         if (thread_preview == PREVIEW_ON) {
539                 int width, height;
540                 double *ptr_gI = NULL;
541
542                 width = img_width;
543                 height = img_height;
544                 ptr_gI = darrayGetPr(gI);
545                 array2img_short(ptr_gI, width, height, img_preview_buffer, width, height, 0);
546                 draw_image(0, 0, -1, -1);
547         }
548         gdk_threads_leave();
549
550         if (thread_preview == PREVIEW_OFF)
551                 usleep(100000);
552
553         if (thread_preview == PREVIEW_FREE) {
554                 thread_preview = PREVIEW_OFF;
555                 goto reset;
556         }
557
558         goto loop;
559
560 reset:
561         if (col) {
562                 colorize_free(col);
563                 col = NULL;
564         }
565         if (mark_buffer) {
566                 free(mark_buffer);
567                 mark_buffer = NULL;
568         }
569         darrayDestroy(gI);
570         gI = NULL;
571         darrayDestroy(cI);
572         cI = NULL;
573         darrayDestroy(mI);
574         mI = NULL;
575         darrayDestroy(I);
576         I = NULL;
577         darrayDone();
578         gdk_threads_leave();
579
580         if (thread_running)
581                 goto loop;
582
583         return NULL;
584 }
585
586
587
588 int colorize_preview_init(void)
589 {
590         pthread_t tid;
591
592         if (thread_running) {
593                 /* we want an exit */
594                 thread_running = -1;
595                 if (thread_debug)
596                         printf("%s: thread already running, terminating\n", __func__);
597                 return -1;
598         }
599
600         if (pthread_create(&tid, NULL, colorize_thread, NULL) < 0) {
601                 if (thread_debug)
602                         printf("colorize thread creation failed!");
603                 return -1;
604         }
605
606         if (thread_debug)
607                 printf("%s: thread created\n", __func__);
608         thread_running = 1;
609
610         return 0;
611 }
612
613 void colorize_preview_terminate(void)
614 {
615         colorize_preview_free();
616
617         if (thread_running > 0) {
618                 if (thread_debug)
619                         printf("%s: threaed is running\n", __func__);
620                 thread_running = -1;
621         }
622         if (thread_running)
623                 if (thread_debug)
624                         printf("%s: waiting to terminate thread\n", __func__);
625         gdk_threads_leave();
626         while(thread_running) {
627                 usleep(1000);
628         }
629         gdk_threads_enter();
630         if (thread_debug)
631                 printf("%s: thread is terminated\n", __func__);
632 }
633
634 /* indicate a new preview image */
635 void colorize_preview_alloc(void)
636 {
637         thread_preview = PREVIEW_NEW;
638 }
639
640 /* indicate no preview image */
641 void colorize_preview_free(void)
642 {
643         if (thread_preview != PREVIEW_OFF)
644                 if (thread_debug)
645                         printf("%s: disable preview\n", __func__);
646         thread_preview = PREVIEW_FREE;
647 }
648