7 #include "../src/ppm.h"
8 #include "../src/mark.h"
9 #include "../src/yuv.h"
13 #include "../src/dir_seperator.h"
15 /* currently loaded image */
17 GdkPixbuf *img_pixbuf = NULL;
18 int img_width, img_height;
19 int copy_width, copy_height;
21 unsigned char *img_grey_buffer = NULL;
22 unsigned char *img_mark_buffer = NULL, *img_mark_buffer_undo[UNDO_MAX], *img_mark_buffer_copy;
23 int button_down_x_undo[UNDO_MAX], button_down_y_undo[UNDO_MAX];
24 int undo_current, undo_num;
25 int img_scale_x = 16, img_scale_y = 16;
26 int anything_modified;
27 extern int button_down_x, button_down_y;
29 /* load image and create pixbuf */
30 void create_image(const char *filename)
33 static char imgfile[256];
37 anything_modified = 0;
39 strcpy(img_name, filename);
43 while((q = strchr(p, DIR_SEPERATOR)))
45 strcpy(imgfile, filename);
46 imgfile[p - filename] = '\0';
47 strcat(imgfile, "colorized_");
50 strcpy(imgfile, filename);
51 rc = load_img(-1, &img_grey_buffer, &img_width, &img_height, imgfile, 0);
53 img_grey_buffer = NULL;
55 printerror("Failed to load grey image '%s'", imgfile);
63 img_mark_buffer = malloc(img_width*img_height);
64 if (!img_mark_buffer) {
65 free(img_grey_buffer);
66 img_grey_buffer = NULL;
69 memset(img_mark_buffer, 0, img_width*img_height);
70 undo_current = undo_num = 0;
71 memset(img_mark_buffer_undo, 0, sizeof(img_mark_buffer_undo));
73 if (load_marked(img_mark_buffer, img_width, img_height, frame_list[timeline_selected].filename) == 0)
74 frame_list[timeline_selected].marked = 1;
76 frame_list[timeline_selected].marked = 0;
81 create_or_reset_pixbuf(1);
84 void create_or_reset_pixbuf(int resize)
86 int w, h, dw = 0, dh = 0;
87 GdkScreen *screen = gtk_window_get_screen(GTK_WINDOW(main_window));
90 /* calculate the maximum windows size, so that the border will not exceed the screen size */
91 gdk_window_get_frame_extents(gtk_widget_get_window(main_window), &max);
92 max.width -= main_window->allocation.width;
93 max.height -= main_window->allocation.height;
98 max.width = gdk_screen_get_width(screen)-max.width;
99 max.height = gdk_screen_get_height(screen)-max.height;
101 if (resize && screen) {
103 w = img_scroll->allocation.width-20;
104 h = img_scroll->allocation.height-20;
105 if (w < img_width*img_scale_x/16) {
106 w = main_window->allocation.width - w + img_width*img_scale_x/16;
108 if (img_scale_x > 4) {
109 int aspect = img_scale_y / img_scale_x;
111 img_scale_y = img_scale_x * aspect;
116 dw = w - main_window->allocation.width;
118 if (h < img_height*img_scale_y/16) {
119 h = main_window->allocation.height - h + img_height*img_scale_y/16;
120 if (h > max.height) {
121 if (img_scale_x > 4) {
122 int aspect = img_scale_y / img_scale_x;
124 img_scale_y = img_scale_x * aspect;
129 dh = h - main_window->allocation.height;
131 // printf("%d %d\n", gdk_screen_get_width(screen), gdk_screen_get_height(screen));
133 gtk_window_resize(GTK_WINDOW(main_window), main_window->allocation.width+dw, main_window->allocation.height+dh);
137 g_object_unref(img_pixbuf);
140 img_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, img_width*img_scale_x/16, img_height*img_scale_y/16);
142 gtk_drawing_area_size(GTK_DRAWING_AREA(img_drawing_area), img_width*img_scale_x/16, img_height*img_scale_y/16);
145 timeline_show_name(timeline_selected);
149 void destroy_image(void)
156 g_object_unref(img_pixbuf);
159 free(img_grey_buffer);
160 img_grey_buffer = NULL;
161 free(img_mark_buffer);
162 img_mark_buffer = NULL;
163 for (i = 0; i < UNDO_MAX; i++) {
164 if (img_mark_buffer_undo[i]) {
165 free(img_mark_buffer_undo[i]);
166 img_mark_buffer_undo[i] = NULL;
171 /* draw (area) of pixbuf */
172 void draw_image(int x, int y, int w, int h)
174 GdkDrawable *draw = gtk_widget_get_window(img_drawing_area);
175 int window_width, window_height, x_offset, y_offset;
176 gdk_drawable_get_size (draw, &window_width, &window_height);
177 double _r, _g, _b, _y, _u, _v, u_palette, v_palette;
178 int _c, preview_asis = 0;
186 unsigned char compose[w*3];
192 data = gdk_pixbuf_get_pixels(img_pixbuf);
193 rs = gdk_pixbuf_get_rowstride(img_pixbuf);
195 /* this should not happen */
196 if (window_width < img_width*img_scale_x/16)
197 window_width = img_width*img_scale_x/16;
198 if (window_height < img_height*img_scale_y/16)
199 window_height = img_height*img_scale_y/16;
201 /* we need to calculate an offset, since the drawing area is now larger */
202 x_offset = (window_width - img_width*img_scale_x/16) / 2;
203 y_offset = (window_height - img_height*img_scale_y/16) / 2;
205 /* clip to window size */
208 if (x >= window_width)
209 x = window_width - 1;
212 if (y >= window_height)
213 y = window_height - 1;
214 if (x + w > window_width)
215 w = window_width - x;
218 if (y + h > window_height)
219 h = window_height - y;
223 /* draw top border */
225 int temp = (h+y >= y_offset) ? y_offset-y : h; /* height */
226 gdk_draw_rectangle(draw, img_drawing_area->style->bg_gc[GTK_WIDGET_STATE(img_drawing_area)], TRUE, x, y, w, (h+y >= y_offset) ? y_offset-y : h);
233 /* draw bottom border */
234 if (y+h >= y_offset+img_height*img_scale_y/16) {
235 int temp = (y < y_offset+img_height*img_scale_y/16) ? y_offset+img_height*img_scale_y/16 : y; /* y start */
236 gdk_draw_rectangle(draw, img_drawing_area->style->bg_gc[GTK_WIDGET_STATE(img_drawing_area)], TRUE, x, temp, w, h - (temp-y));
242 /* draw left border */
244 int temp = (w+x >= x_offset) ? x_offset-x : w; /* width */
245 gdk_draw_rectangle(draw, img_drawing_area->style->bg_gc[GTK_WIDGET_STATE(img_drawing_area)], TRUE, x, y, (w+x >= x_offset) ? x_offset-x : w, h);
252 /* draw right border */
253 if (x+w >= x_offset+img_width*img_scale_x/16) {
254 int temp = (x < x_offset+img_width*img_scale_x/16) ? x_offset+img_width*img_scale_x/16 : x; /* x start **/
255 gdk_draw_rectangle(draw, img_drawing_area->style->bg_gc[GTK_WIDGET_STATE(img_drawing_area)], TRUE, temp, y, w - (temp-x), h);
264 if (img_grey_buffer) {
266 rgb2yuv_pixle(mark_palette[mark_selected].r / 255.0F, mark_palette[mark_selected].g / 255.0F, mark_palette[mark_selected].b / 255.0F, &_y, &u_palette, &v_palette);
267 /* check for white color (no change) */
268 if (mark_palette[mark_selected].r == 255 && mark_palette[mark_selected].g == 255 && mark_palette[mark_selected].r == 255)
271 /* compose image (segment) line by line */
272 for (i = 0; i < h; i++) {
273 for (j = 0; j < w; j++) {
274 if (preview && !rendered && !flowview) {
275 /* apply selected color from palette to all pixles */
276 _r = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3] / 255.0F;
277 _g = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3+1] / 255.0F;
278 _b = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3+2] / 255.0F;
279 rgb2yuv_pixle(_r, _g, _b, &_y, &_u, &_v);
280 _y = (_y - 0.5) * mark_palette[mark_selected].contrast + 0.5;
281 _y += mark_palette[mark_selected].bright;
287 yuv2rgb_pixle(_y, _u, _v, &_r, &_g, &_b);
289 yuv2rgb_pixle(_y, u_palette, v_palette, &_r, &_g, &_b);
310 compose[j*3] = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3];
311 compose[j*3+1] = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3+1];
312 compose[j*3+2] = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3+2];
314 c = img_mark_buffer[(j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y)];
315 if (c > 0 && !flowview && !(rendered && preview)) {
317 if (c-1 == mark_selected) {
324 compose[j*3+2] = 128;
327 compose[j*3] = mark_palette[c-1].r;
328 compose[j*3+1] = mark_palette[c-1].g;
329 compose[j*3+2] = mark_palette[c-1].b;
333 memcpy(data + rs*(i+y) + x*3, compose, w*3);
336 for (i = 0; i < h; i++)
337 memset(data + rs*(i+y) + x*3, 0, w*3);
340 gdk_draw_pixbuf(draw, NULL, img_pixbuf, x, y, x+x_offset, y+y_offset, w, h, GDK_RGB_DITHER_NONE, 0, 0);
344 /* plot brush on mark buffer */
345 void paint_brush(int x, int y, int size, int paint)
347 GdkDrawable *draw = gtk_widget_get_window(img_drawing_area);
348 int window_width, window_height;
349 gdk_drawable_get_size (draw, &window_width, &window_height);
351 /* we need to calculate an offset, since the drawing area is now larger */
352 x -= (window_width - img_width*img_scale_x/16) / 2;
353 y -= (window_height - img_height*img_scale_y/16) / 2;
355 x = x*16/img_scale_x;
356 y = y*16/img_scale_y;
358 if (!img_mark_buffer || flowview)
361 int x1 = x - size + 1;
362 int x2 = x + size - 1;
363 int y1 = y - size + 1;
364 int y2 = y + size - 1;
375 if (y1 >= img_height)
379 if (y2 >= img_height)
384 /* only paint color, if paint is set */
386 paint = mark_selected + 1;
388 for (i = y1; i <= y2; i++) {
389 for (j = x1; j <= x2; j++) {
390 img_mark_buffer[j+img_width*i] = paint;
395 void erase_mark(int index)
399 if (!img_mark_buffer)
402 /* no index, erase all */
404 memset(img_mark_buffer, 0, img_width * img_height);
408 /* only erase indexed color */
409 for (i = 0; i < img_width * img_height; i++) {
410 if (img_mark_buffer[i] == index)
411 img_mark_buffer[i] = 0;
415 void move_mark(int x, int y)
420 if (!img_mark_buffer || undo_current == 0)
423 src = img_mark_buffer_undo[undo_current-1];
427 if (y < 0 || (y == 0 && x < 0)) {
428 /* move up in memory */
429 for (j = 0; j < img_height; j++) {
430 for (i = 0; i < img_width; i++) {
431 if (i < x || i >= img_width+x || j < y || j >= img_height+y)
432 img_mark_buffer[j*img_width+i] = 0;
434 img_mark_buffer[j*img_width+i] = src[(j-y)*img_width+(i-x)];
438 /* move down in memory */
439 for (j = img_height-1; j >= 0; j--) {
440 for (i = img_width-1; i >= 0; i--) {
441 if (i < x || i >= img_width+x || j < y || j >= img_height+y)
442 img_mark_buffer[j*img_width+i] = 0;
444 img_mark_buffer[j*img_width+i] = src[(j-y)*img_width+(i-x)];
450 void copy_mark_to_undo(void)
452 anything_modified = 1;
454 if (!img_mark_buffer)
457 if (undo_current < UNDO_MAX) {
458 /* allocate new undobuffer and append */
459 if (!img_mark_buffer_undo[undo_current])
460 img_mark_buffer_undo[undo_current] = malloc(img_width*img_height);
461 if (!img_mark_buffer_undo[undo_current])
465 /* shift and use oldest undobuffer */
466 unsigned char *temp = img_mark_buffer_undo[0];
468 for (i = 0; i < UNDO_MAX - 1; i++)
469 img_mark_buffer_undo[i] = img_mark_buffer_undo[i+1];
470 img_mark_buffer_undo[UNDO_MAX - 1] = temp;
472 undo_num = undo_current;
473 //printf("storing undo #%d\n", undo_current-1);
474 memcpy(img_mark_buffer_undo[undo_current-1], img_mark_buffer, img_width*img_height);
475 button_down_x_undo[undo_current-1] = button_down_x;
476 button_down_y_undo[undo_current-1] = button_down_y;
479 void copy_undo_to_mark(int redo)
481 if (!img_mark_buffer)
484 //printf("num is %d\n", undo_num);
486 /* nothing to undo */
487 if (undo_current == 0)
490 /* if we are at the end of the history, we need to add the current image to undo history */
491 if (undo_current == undo_num) {
496 //printf("restore undo #%d\n", undo_current);
498 /* nothing to redo */
499 if (undo_current >= undo_num-1)
502 //printf("restore undo #%d\n", undo_current);
504 memcpy(img_mark_buffer, img_mark_buffer_undo[undo_current], img_width*img_height);
505 button_down_x = button_down_x_undo[undo_current];
506 button_down_y = button_down_y_undo[undo_current];
509 void copy_color(int index)
513 if (img_mark_buffer_copy)
514 free(img_mark_buffer_copy);
515 img_mark_buffer_copy = malloc(img_width*img_height);
516 if (!img_mark_buffer_copy)
519 memcpy(img_mark_buffer_copy, img_mark_buffer, img_width*img_height);
520 copy_width = img_width;
521 copy_height = img_height;
523 /* erase indexed color except given index */
524 for (i = 0; i < img_width * img_height; i++) {
525 if (index && img_mark_buffer_copy[i] != index)
526 img_mark_buffer_copy[i] = 0;
530 void paste_color(void)
534 if (!img_mark_buffer_copy)
537 if (copy_width != img_width || copy_height != img_height) {
538 printerror("Image in copy buffer has different dimenstions.");
542 /* paste indexed pixles */
543 for (i = 0; i < img_width * img_height; i++) {
544 if (img_mark_buffer_copy[i])
545 img_mark_buffer[i] = img_mark_buffer_copy[i];