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 short *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, int resize)
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(resize);
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 if (resize && screen) {
91 /* process GTK window event to have correct size */
92 while (gtk_events_pending())
95 /* calculate the maximum windows size, so that the border will not exceed the screen size */
96 gdk_window_get_frame_extents(gtk_widget_get_window(main_window), &max);
97 max.width -= main_window->allocation.width;
98 max.height -= main_window->allocation.height;
103 max.width = gdk_screen_get_width(screen)-max.width;
104 max.height = gdk_screen_get_height(screen)-max.height;
107 w = img_scroll->allocation.width-25;
108 h = img_scroll->allocation.height-25;
109 if (w < img_width*img_scale_x/16) {
110 w = main_window->allocation.width - w + img_width*img_scale_x/16;
112 if (img_scale_x > 4) {
113 int aspect = img_scale_y / img_scale_x;
115 img_scale_y = img_scale_x * aspect;
120 dw = w - main_window->allocation.width;
122 if (h < img_height*img_scale_y/16) {
123 h = main_window->allocation.height - h + img_height*img_scale_y/16;
124 if (h > max.height) {
125 if (img_scale_x > 4) {
126 int aspect = img_scale_y / img_scale_x;
128 img_scale_y = img_scale_x * aspect;
133 dh = h - main_window->allocation.height;
135 // printf("%d %d\n", gdk_screen_get_width(screen), gdk_screen_get_height(screen));
137 gtk_window_resize(GTK_WINDOW(main_window), main_window->allocation.width+dw, main_window->allocation.height+dh);
141 g_object_unref(img_pixbuf);
144 img_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, img_width*img_scale_x/16, img_height*img_scale_y/16);
146 gtk_drawing_area_size(GTK_DRAWING_AREA(img_drawing_area), img_width*img_scale_x/16, img_height*img_scale_y/16);
149 timeline_show_name(timeline_selected);
153 void destroy_image(void)
160 g_object_unref(img_pixbuf);
163 free(img_grey_buffer);
164 img_grey_buffer = NULL;
165 free(img_mark_buffer);
166 img_mark_buffer = NULL;
167 for (i = 0; i < UNDO_MAX; i++) {
168 if (img_mark_buffer_undo[i]) {
169 free(img_mark_buffer_undo[i]);
170 img_mark_buffer_undo[i] = NULL;
175 /* draw (area) of pixbuf */
176 void draw_image(int x, int y, int w, int h)
178 GdkDrawable *draw = gtk_widget_get_window(img_drawing_area);
179 int window_width, window_height, x_offset, y_offset;
180 gdk_drawable_get_size (draw, &window_width, &window_height);
181 double _r, _g, _b, _y, _u, _v, u_palette, v_palette;
182 int _c, preview_asis = 0;
190 unsigned char compose[w*3];
196 data = gdk_pixbuf_get_pixels(img_pixbuf);
197 rs = gdk_pixbuf_get_rowstride(img_pixbuf);
199 /* this should not happen */
200 if (window_width < img_width*img_scale_x/16)
201 window_width = img_width*img_scale_x/16;
202 if (window_height < img_height*img_scale_y/16)
203 window_height = img_height*img_scale_y/16;
205 /* we need to calculate an offset, since the drawing area is now larger */
206 x_offset = (window_width - img_width*img_scale_x/16) / 2;
207 y_offset = (window_height - img_height*img_scale_y/16) / 2;
209 /* clip to window size */
212 if (x >= window_width)
213 x = window_width - 1;
216 if (y >= window_height)
217 y = window_height - 1;
218 if (x + w > window_width)
219 w = window_width - x;
222 if (y + h > window_height)
223 h = window_height - y;
227 /* draw top border */
229 int temp = (h+y >= y_offset) ? y_offset-y : h; /* height */
230 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);
237 /* draw bottom border */
238 if (y+h >= y_offset+img_height*img_scale_y/16) {
239 int temp = (y < y_offset+img_height*img_scale_y/16) ? y_offset+img_height*img_scale_y/16 : y; /* y start */
240 gdk_draw_rectangle(draw, img_drawing_area->style->bg_gc[GTK_WIDGET_STATE(img_drawing_area)], TRUE, x, temp, w, h - (temp-y));
246 /* draw left border */
248 int temp = (w+x >= x_offset) ? x_offset-x : w; /* width */
249 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);
256 /* draw right border */
257 if (x+w >= x_offset+img_width*img_scale_x/16) {
258 int temp = (x < x_offset+img_width*img_scale_x/16) ? x_offset+img_width*img_scale_x/16 : x; /* x start **/
259 gdk_draw_rectangle(draw, img_drawing_area->style->bg_gc[GTK_WIDGET_STATE(img_drawing_area)], TRUE, temp, y, w - (temp-x), h);
268 if (img_grey_buffer) {
270 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);
271 /* check for white color (no change) */
272 if (mark_palette[mark_selected].r == 255 && mark_palette[mark_selected].g == 255 && mark_palette[mark_selected].r == 255)
275 /* compose image (segment) line by line */
276 for (i = 0; i < h; i++) {
277 for (j = 0; j < w; j++) {
278 if (preview && !rendered && !flowview) {
279 /* apply selected color from palette to all pixles */
280 _r = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3] / 65535.0F;
281 _g = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3+1] / 65535.0F;
282 _b = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3+2] / 65535.0F;
283 rgb2yuv_pixle(_r, _g, _b, &_y, &_u, &_v);
284 _y = (_y - 0.5) * mark_palette[mark_selected].contrast + 0.5;
285 _y += mark_palette[mark_selected].bright;
291 yuv2rgb_pixle(_y, _u, _v, &_r, &_g, &_b);
293 yuv2rgb_pixle(_y, u_palette, v_palette, &_r, &_g, &_b);
314 compose[j*3] = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3] >> 8;
315 compose[j*3+1] = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3+1] >> 8;
316 compose[j*3+2] = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3+2] >> 8;
318 c = img_mark_buffer[(j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y)];
319 if (c > 0 && !flowview && !(rendered && preview)) {
321 if (c-1 == mark_selected) {
328 compose[j*3+2] = 128;
331 compose[j*3] = mark_palette[c-1].r;
332 compose[j*3+1] = mark_palette[c-1].g;
333 compose[j*3+2] = mark_palette[c-1].b;
337 memcpy(data + rs*(i+y) + x*3, compose, w*3);
340 for (i = 0; i < h; i++)
341 memset(data + rs*(i+y) + x*3, 0, w*3);
344 gdk_draw_pixbuf(draw, NULL, img_pixbuf, x, y, x+x_offset, y+y_offset, w, h, GDK_RGB_DITHER_NONE, 0, 0);
348 /* plot brush on mark buffer */
349 void paint_brush(int x, int y, int size, int paint)
351 GdkDrawable *draw = gtk_widget_get_window(img_drawing_area);
352 int window_width, window_height;
353 gdk_drawable_get_size (draw, &window_width, &window_height);
355 /* we need to calculate an offset, since the drawing area is now larger */
356 x -= (window_width - img_width*img_scale_x/16) / 2;
357 y -= (window_height - img_height*img_scale_y/16) / 2;
359 x = x*16/img_scale_x;
360 y = y*16/img_scale_y;
362 if (!img_mark_buffer || flowview)
365 int x1 = x - size + 1;
366 int x2 = x + size - 1;
367 int y1 = y - size + 1;
368 int y2 = y + size - 1;
379 if (y1 >= img_height)
383 if (y2 >= img_height)
388 /* only paint color, if paint is set */
390 paint = mark_selected + 1;
392 for (i = y1; i <= y2; i++) {
393 for (j = x1; j <= x2; j++) {
394 img_mark_buffer[j+img_width*i] = paint;
399 void erase_mark(int index)
403 if (!img_mark_buffer)
406 /* no index, erase all */
408 memset(img_mark_buffer, 0, img_width * img_height);
412 /* only erase indexed color */
413 for (i = 0; i < img_width * img_height; i++) {
414 if (img_mark_buffer[i] == index)
415 img_mark_buffer[i] = 0;
419 void move_mark(int x, int y)
424 if (!img_mark_buffer || undo_current == 0)
427 src = img_mark_buffer_undo[undo_current-1];
431 if (y < 0 || (y == 0 && x < 0)) {
432 /* move up in memory */
433 for (j = 0; j < img_height; j++) {
434 for (i = 0; i < img_width; i++) {
435 if (i < x || i >= img_width+x || j < y || j >= img_height+y)
436 img_mark_buffer[j*img_width+i] = 0;
438 img_mark_buffer[j*img_width+i] = src[(j-y)*img_width+(i-x)];
442 /* move down in memory */
443 for (j = img_height-1; j >= 0; j--) {
444 for (i = img_width-1; i >= 0; i--) {
445 if (i < x || i >= img_width+x || j < y || j >= img_height+y)
446 img_mark_buffer[j*img_width+i] = 0;
448 img_mark_buffer[j*img_width+i] = src[(j-y)*img_width+(i-x)];
454 void copy_mark_to_undo(void)
456 anything_modified = 1;
458 if (!img_mark_buffer)
461 if (undo_current < UNDO_MAX) {
462 /* allocate new undobuffer and append */
463 if (!img_mark_buffer_undo[undo_current])
464 img_mark_buffer_undo[undo_current] = malloc(img_width*img_height);
465 if (!img_mark_buffer_undo[undo_current])
469 /* shift and use oldest undobuffer */
470 unsigned char *temp = img_mark_buffer_undo[0];
472 for (i = 0; i < UNDO_MAX - 1; i++)
473 img_mark_buffer_undo[i] = img_mark_buffer_undo[i+1];
474 img_mark_buffer_undo[UNDO_MAX - 1] = temp;
476 undo_num = undo_current;
477 //printf("storing undo #%d\n", undo_current-1);
478 memcpy(img_mark_buffer_undo[undo_current-1], img_mark_buffer, img_width*img_height);
479 button_down_x_undo[undo_current-1] = button_down_x;
480 button_down_y_undo[undo_current-1] = button_down_y;
483 void copy_undo_to_mark(int redo)
485 if (!img_mark_buffer)
488 //printf("num is %d\n", undo_num);
490 /* nothing to undo */
491 if (undo_current == 0)
494 /* if we are at the end of the history, we need to add the current image to undo history */
495 if (undo_current == undo_num) {
500 //printf("restore undo #%d\n", undo_current);
502 /* nothing to redo */
503 if (undo_current >= undo_num-1)
506 //printf("restore undo #%d\n", undo_current);
508 memcpy(img_mark_buffer, img_mark_buffer_undo[undo_current], img_width*img_height);
509 button_down_x = button_down_x_undo[undo_current];
510 button_down_y = button_down_y_undo[undo_current];
513 void copy_color(int index)
517 if (img_mark_buffer_copy)
518 free(img_mark_buffer_copy);
519 img_mark_buffer_copy = malloc(img_width*img_height);
520 if (!img_mark_buffer_copy)
523 memcpy(img_mark_buffer_copy, img_mark_buffer, img_width*img_height);
524 copy_width = img_width;
525 copy_height = img_height;
527 /* erase indexed color except given index */
528 for (i = 0; i < img_width * img_height; i++) {
529 if (index && img_mark_buffer_copy[i] != index)
530 img_mark_buffer_copy[i] = 0;
534 void paste_color(void)
538 if (!img_mark_buffer_copy)
541 if (copy_width != img_width || copy_height != img_height) {
542 printerror("Image in copy buffer has different dimenstions.");
546 /* paste indexed pixles */
547 for (i = 0; i < img_width * img_height; i++) {
548 if (img_mark_buffer_copy[i])
549 img_mark_buffer[i] = img_mark_buffer_copy[i];