Add option to keep I and mI arrays and "neighbor pixle weights" structure
[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 struct colorize_priv {
21         GtkWidget *window;
22         GdkPixbuf *pixbuf;
23         int width, height, alpha;
24         char filename[256];
25         char folder[256];
26         unsigned short *img;
27 };
28
29 static void colorize_destroy(GtkWidget *widget, gpointer priv)
30 {
31         struct colorize_priv *cp = (struct colorize_priv *) priv;
32
33         gtk_widget_destroy(cp->window);
34         g_object_unref(cp->pixbuf);
35         free(cp->img);
36         free(cp);
37 }
38
39 static gboolean colorize_key_press(GtkWidget *widget, GdkEventKey *event, gpointer priv)
40 {
41         switch (event->keyval) {
42         case GDK_q:
43         case GDK_w:
44                 if (event->state & GDK_CONTROL_MASK) {
45                         gtk_widget_destroy(widget);
46                         return TRUE;
47                 }
48         default:
49                 ;//printf("%x\n", event->keyval);
50         }
51
52         return FALSE;
53 }
54
55 static void save_event(gpointer *priv)
56 {
57         struct colorize_priv *cp = (struct colorize_priv *) priv;
58         GtkWidget *dialog;
59         char *filename = NULL;
60         FILE *fp;
61
62         dialog = gtk_file_chooser_dialog_new("Select file to save colorized image",
63                 GTK_WINDOW(main_window),
64                 GTK_FILE_CHOOSER_ACTION_SAVE,
65                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
66                 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
67                 NULL);
68
69         gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), cp->folder);
70         gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), cp->filename);
71         if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
72                 filename = strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)));
73         }
74
75         gtk_widget_destroy(dialog);
76
77         if (!filename)
78                 return;
79
80         if ((fp = fopen(filename, "r"))) {
81                 int ret;
82                 fclose(fp);
83                 GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
84                         GTK_DIALOG_DESTROY_WITH_PARENT,
85                         GTK_MESSAGE_ERROR,
86                         GTK_BUTTONS_OK_CANCEL,
87                         "Image already exists, overwrite it?");
88                 ret = gtk_dialog_run(GTK_DIALOG (dialog));
89                 gtk_widget_destroy(dialog);
90                 if (ret != GTK_RESPONSE_OK)
91                         goto exit;
92         }
93
94
95         save_img(cp->img, cp->width, cp->height, cp->alpha, filename, 0);
96
97 exit:
98         free(filename);
99 }
100
101 static void dummy_event(gpointer *priv)
102 {
103 }
104
105 static void close_event(gpointer *priv)
106 {
107         struct colorize_priv *cp = (struct colorize_priv *) priv;
108
109         gtk_widget_destroy(cp->window);
110 }
111
112 void colorize_image(void)
113 {
114         darray_t *gI = NULL, *cI = NULL, *I = NULL, *mI = NULL;
115         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;
116         int dims[4];
117         int width = img_width, height = img_height;
118         int features, change_bc, change_alpha;
119         char *feat_names[20];
120         int i, j;
121         int c;
122         int rc;
123         GdkPixbuf *pixbuf;
124         GtkWidget *image;
125         guchar *data;
126         GtkWidget *colorize_window;
127         GtkWidget *vbox;
128         GtkWidget *menu_bar;
129         GtkWidget *root_menu;
130         GtkWidget *menu;
131         GtkWidget *menu_item;
132         struct colorize_priv *cp;
133         int rs;
134         int zoom_field;
135         char *p, *q;
136
137         if (!img_pixbuf)
138                 return;
139
140         /* generate grey image array */
141         dims[0] = width; dims[1] = height; dims[2] = 3; dims[3] = 1;
142         gI = darrayCreate(4, dims);
143         if (!gI) {
144                 printerror("No memory: failed to create grey image array");
145                 goto error;
146         }
147         ptr_gI = darrayGetPr(gI);
148         img2array_short(img_grey_buffer, width, height, ptr_gI, width, height);
149
150         /* generade marked color image */
151         dims[0] = width; dims[1] = height; dims[2] = 3; dims[3] = 1;
152         cI = darrayCreate(4, dims);
153         if (!cI) {
154                 printerror("No memory: failed to create marked image array");
155                 goto error;
156         }
157         ptr_cI = darrayGetPr(cI);
158         img2array_short(img_grey_buffer, width, height, ptr_cI, width, height);
159         change_bc = change_alpha = 0;
160         for (i = 0; i < height; i++) {
161                 for (j = 0; j < width; j++) {
162                         /* do not apply mask on index 0 */
163                         c = img_mark_buffer[i*width+j];
164                         if (c == 0)
165                                 continue;
166                         /* check for any brightness/contrast change */
167                         if (mark_palette[c-1].bright != 0 || mark_palette[c-1].contrast != 1)
168                                 change_bc = 1;
169                         /* check for any alpha change */
170                         if (mark_palette[c-1].alpha < 1)
171                                 change_alpha = 1;
172                         /* do not apply white pixles, this meas: keep original color */
173                         if (mark_palette[c-1].r == 255 && mark_palette[c-1].g == 255 && mark_palette[c-1].b == 255)
174                                 continue;
175                         ptr_cI[i*width+j] = mark_palette[c-1].r / 255.0F;
176                         ptr_cI[i*width+j + width*height] = mark_palette[c-1].g / 255.0F;
177                         ptr_cI[i*width+j + width*height*2] = mark_palette[c-1].b / 255.0F;
178                 }
179         }
180
181         rc = alloc_I_arrays(&I, &mI, width, height, 1, &features, feat_names, change_alpha, change_bc);
182         if (rc)
183                 goto error;
184
185         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);
186
187         // convert original image into YUV
188         rgb2yuv(ptr_gI, ptr_gI, width, height);
189         // convert maked image into YUV
190         rgb2yuv(ptr_cI, ptr_cI, width, height);
191
192         /* apply mask to mI */
193         for (i = 0; i < height; i++) {
194                 for (j = 0; j < width; j++) {
195                         /* do not apply mask on index 0 */
196                         c = img_mark_buffer[i*width+j];
197                         ptr_m[i*width+j] = (c == 0) ? 0.0F : 1.0F;
198                 }
199         }
200
201         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);
202
203         /* destroy temporary gI and cI */
204         darrayDestroy(gI);
205         gI = NULL;
206         darrayDestroy(cI);
207         cI = NULL;
208
209         /* render u and v change */
210         rc = colorize(I, mI, NULL, NULL, 5, 1, 0, 0, feat_names, NULL);
211         if (rc < 0) {
212                 printerror("No memory! Use smaller image or add more memory.");
213                 goto error;
214         }
215
216         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);
217
218         if (img_scale_y == img_scale_x*2)
219                 zoom_field = 2;
220         else
221                 zoom_field = 1;
222
223         /* convert YUV to RGB */
224         pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, width, height * zoom_field);
225         yuv2rgb(ptr_y, ptr_y, width, height);
226
227         /* private structure */
228         cp = calloc(sizeof(struct colorize_priv), 1);
229         cp->width = width;
230         cp->height = height;
231         cp->alpha = change_alpha;
232
233         /* apply image to be saved later */
234         cp->img = malloc(width*height*(3+change_alpha)*sizeof(unsigned short));
235         array2img_short(ptr_y, width, height, cp->img, width, height, change_alpha);
236
237         /* create image */
238         if (change_alpha) {
239                 /* simulate alpha by pattern */
240                 double pat, a;
241                 for (i = 0; i < height; i++) {
242                         for (j = 0; j < width; j++) {
243                                 pat = (((j>>3)&1) == ((i>>3)&1)) ? 0.5 : 0.75;
244                                 a = ptr_a[i*width+j];
245                                 /* yuv is actually RGB */
246                                 ptr_y[i*width+j] = a * ptr_y[i*width+j] + (1.0 - a) * pat;
247                                 ptr_u[i*width+j] = a * ptr_u[i*width+j] + (1.0 - a) * pat;
248                                 ptr_v[i*width+j] = a * ptr_v[i*width+j] + (1.0 - a) * pat;
249                         }
250                 }
251         }
252         data = gdk_pixbuf_get_pixels(pixbuf);
253         rs = gdk_pixbuf_get_rowstride(pixbuf);
254         for (i = 0; i < height*zoom_field; i++) {
255                 for (j = 0; j < width; j++) {
256                         /* yuv is actually RGB */
257                         c = ptr_y[(i/zoom_field)*width+j] * 255.0F;
258                         if (c < 0)
259                                 c = 0;
260                         else if (c > 255)
261                                 c = 255;
262                         data[i*rs + 3*j + 0] = c;
263                         c = ptr_u[(i/zoom_field)*width+j] * 255.0F;
264                         if (c < 0)
265                                 c = 0;
266                         else if (c > 255)
267                                 c = 255;
268                         data[i*rs + 3*j + 1] = c;
269                         c = ptr_v[(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 + 2] = c;
275                 }
276         }
277
278         image = gtk_image_new_from_pixbuf(pixbuf);
279         gtk_widget_show(image);
280
281         darrayDestroy(mI);
282         mI = NULL;
283         darrayDestroy(I);
284         I = NULL;
285
286         darrayDone();
287
288         /* create window */
289         colorize_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
290         gtk_window_set_title(GTK_WINDOW(colorize_window), "Colorized");
291         g_signal_connect(colorize_window, "destroy", G_CALLBACK(colorize_destroy), cp);
292         g_signal_connect(colorize_window, "key_press_event", G_CALLBACK(colorize_key_press), cp);
293
294         cp->window = colorize_window;
295         cp->pixbuf = pixbuf;
296         p = frame_list[timeline_selected].filename;
297         while((q = strchr(p, DIR_SEPERATOR)))
298                 p = q + 1;
299         strcpy(cp->folder, frame_list[timeline_selected].filename);
300         cp->folder[p - frame_list[timeline_selected].filename] = '\0';
301         sprintf(cp->filename, "colorized_%s", p);
302
303         /* create menu*/
304         menu_bar = gtk_menu_bar_new();
305         gtk_widget_show(menu_bar);
306         menu = gtk_menu_new();
307         root_menu = gtk_menu_item_new_with_mnemonic("_File");
308         gtk_widget_show(root_menu);
309
310         menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_SAVE_AS, NULL);
311         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
312         g_signal_connect_swapped(menu_item, "activate", G_CALLBACK(save_event), cp);
313         gtk_widget_show(menu_item);
314         menu_item = gtk_separator_menu_item_new();
315         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
316         g_signal_connect_swapped(menu_item, "activate", G_CALLBACK(dummy_event), cp);
317         gtk_widget_show(menu_item);
318         menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CLOSE, NULL);
319         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
320         g_signal_connect_swapped(menu_item, "activate", G_CALLBACK(close_event), cp);
321         gtk_widget_show(menu_item);
322         gtk_menu_item_set_submenu(GTK_MENU_ITEM(root_menu), menu);
323         gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), root_menu);
324
325         /* create vbox (complete window) */
326         vbox = gtk_vbox_new(FALSE, 0);
327         gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 2);
328         gtk_box_pack_start(GTK_BOX(vbox), image, FALSE, FALSE, 2);
329         gtk_widget_show(vbox);
330
331         gtk_container_add(GTK_CONTAINER(colorize_window), vbox);
332         gtk_widget_show(colorize_window);
333
334 error:
335         darrayDestroy(gI);
336         darrayDestroy(cI);
337         darrayDestroy(mI);
338         darrayDestroy(I);
339
340         darrayDone();
341 }