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;
183 int _c, preview_asis = 0;
191 unsigned char compose[w*3];
197 data = gdk_pixbuf_get_pixels(img_pixbuf);
198 rs = gdk_pixbuf_get_rowstride(img_pixbuf);
200 /* this should not happen */
201 if (window_width < img_width*img_scale_x/16)
202 window_width = img_width*img_scale_x/16;
203 if (window_height < img_height*img_scale_y/16)
204 window_height = img_height*img_scale_y/16;
206 /* we need to calculate an offset, since the drawing area is now larger */
207 x_offset = (window_width - img_width*img_scale_x/16) / 2;
208 y_offset = (window_height - img_height*img_scale_y/16) / 2;
210 /* clip to window size */
213 if (x >= window_width)
214 x = window_width - 1;
217 if (y >= window_height)
218 y = window_height - 1;
219 if (x + w > window_width)
220 w = window_width - x;
223 if (y + h > window_height)
224 h = window_height - y;
228 /* draw top border */
230 int temp = (h+y >= y_offset) ? y_offset-y : h; /* height */
231 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);
238 /* draw bottom border */
239 if (y+h >= y_offset+img_height*img_scale_y/16) {
240 int temp = (y < y_offset+img_height*img_scale_y/16) ? y_offset+img_height*img_scale_y/16 : y; /* y start */
241 gdk_draw_rectangle(draw, img_drawing_area->style->bg_gc[GTK_WIDGET_STATE(img_drawing_area)], TRUE, x, temp, w, h - (temp-y));
247 /* draw left border */
249 int temp = (w+x >= x_offset) ? x_offset-x : w; /* width */
250 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);
257 /* draw right border */
258 if (x+w >= x_offset+img_width*img_scale_x/16) {
259 int temp = (x < x_offset+img_width*img_scale_x/16) ? x_offset+img_width*img_scale_x/16 : x; /* x start **/
260 gdk_draw_rectangle(draw, img_drawing_area->style->bg_gc[GTK_WIDGET_STATE(img_drawing_area)], TRUE, temp, y, w - (temp-x), h);
269 if (img_grey_buffer) {
271 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);
272 /* check for white color (no change) */
273 if (mark_palette[mark_selected].r == 255 && mark_palette[mark_selected].g == 255 && mark_palette[mark_selected].r == 255)
276 /* compose image (segment) line by line */
277 for (i = 0; i < h; i++) {
278 for (j = 0; j < w; j++) {
279 if (preview && !rendered && !flowview) {
280 /* apply selected color from palette to all pixles */
281 _r = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3] / 65535.0F;
282 _g = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3+1] / 65535.0F;
283 _b = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3+2] / 65535.0F;
284 rgb2yuv_pixle(_r, _g, _b, &_y, &_u, &_v);
285 _y = (_y - 0.5) * mark_palette[mark_selected].contrast + 0.5;
286 _y += mark_palette[mark_selected].bright;
292 yuv2rgb_pixle(_y, _u, _v, &_r, &_g, &_b);
294 yuv2rgb_pixle(_y, u_palette, v_palette, &_r, &_g, &_b);
315 compose[j*3] = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3] >> 8;
316 compose[j*3+1] = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3+1] >> 8;
317 compose[j*3+2] = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3+2] >> 8;
319 c = img_mark_buffer[(j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y)];
320 if (c > 0 && !flowview && !(rendered && preview)) {
322 if (c-1 == mark_selected) {
329 compose[j*3+2] = 128;
332 cr = mark_palette[c-1].r;
333 cg = mark_palette[c-1].g;
334 cb = mark_palette[c-1].b;
335 if (cr == 255 && cg == 255 && cb == 255) {
336 compose[j*3] = compose[j*3+1] = compose[j*3+2] = ((((i+y)>>3)&1) == (((j+x)>>3)&1)) ? 255 : 192;
346 memcpy(data + rs*(i+y) + x*3, compose, w*3);
349 for (i = 0; i < h; i++)
350 memset(data + rs*(i+y) + x*3, 0, w*3);
353 gdk_draw_pixbuf(draw, NULL, img_pixbuf, x, y, x+x_offset, y+y_offset, w, h, GDK_RGB_DITHER_NONE, 0, 0);
357 /* plot brush on mark buffer */
358 void paint_brush(int x, int y, int size, int paint)
360 GdkDrawable *draw = gtk_widget_get_window(img_drawing_area);
361 int window_width, window_height;
362 gdk_drawable_get_size (draw, &window_width, &window_height);
364 /* we need to calculate an offset, since the drawing area is now larger */
365 x -= (window_width - img_width*img_scale_x/16) / 2;
366 y -= (window_height - img_height*img_scale_y/16) / 2;
368 x = x*16/img_scale_x;
369 y = y*16/img_scale_y;
371 if (!img_mark_buffer || flowview)
374 int x1 = x - size + 1;
375 int x2 = x + size - 1;
376 int y1 = y - size + 1;
377 int y2 = y + size - 1;
388 if (y1 >= img_height)
392 if (y2 >= img_height)
397 /* only paint color, if paint is set */
399 paint = mark_selected + 1;
401 for (i = y1; i <= y2; i++) {
402 for (j = x1; j <= x2; j++) {
403 img_mark_buffer[j+img_width*i] = paint;
408 void erase_mark(int index)
412 if (!img_mark_buffer)
415 /* no index, erase all */
417 memset(img_mark_buffer, 0, img_width * img_height);
421 /* only erase indexed color */
422 for (i = 0; i < img_width * img_height; i++) {
423 if (img_mark_buffer[i] == index)
424 img_mark_buffer[i] = 0;
428 void move_mark(int x, int y)
433 if (!img_mark_buffer || undo_current == 0)
436 src = img_mark_buffer_undo[undo_current-1];
440 if (y < 0 || (y == 0 && x < 0)) {
441 /* move up in memory */
442 for (j = 0; j < img_height; j++) {
443 for (i = 0; i < img_width; i++) {
444 if (i < x || i >= img_width+x || j < y || j >= img_height+y)
445 img_mark_buffer[j*img_width+i] = 0;
447 img_mark_buffer[j*img_width+i] = src[(j-y)*img_width+(i-x)];
451 /* move down in memory */
452 for (j = img_height-1; j >= 0; j--) {
453 for (i = img_width-1; i >= 0; i--) {
454 if (i < x || i >= img_width+x || j < y || j >= img_height+y)
455 img_mark_buffer[j*img_width+i] = 0;
457 img_mark_buffer[j*img_width+i] = src[(j-y)*img_width+(i-x)];
463 void copy_mark_to_undo(void)
465 anything_modified = 1;
467 if (!img_mark_buffer)
470 if (undo_current < UNDO_MAX) {
471 /* allocate new undobuffer and append */
472 if (!img_mark_buffer_undo[undo_current])
473 img_mark_buffer_undo[undo_current] = malloc(img_width*img_height);
474 if (!img_mark_buffer_undo[undo_current])
478 /* shift and use oldest undobuffer */
479 unsigned char *temp = img_mark_buffer_undo[0];
481 for (i = 0; i < UNDO_MAX - 1; i++)
482 img_mark_buffer_undo[i] = img_mark_buffer_undo[i+1];
483 img_mark_buffer_undo[UNDO_MAX - 1] = temp;
485 undo_num = undo_current;
486 //printf("storing undo #%d\n", undo_current-1);
487 memcpy(img_mark_buffer_undo[undo_current-1], img_mark_buffer, img_width*img_height);
488 button_down_x_undo[undo_current-1] = button_down_x;
489 button_down_y_undo[undo_current-1] = button_down_y;
492 void copy_undo_to_mark(int redo)
494 if (!img_mark_buffer)
497 //printf("num is %d\n", undo_num);
499 /* nothing to undo */
500 if (undo_current == 0)
503 /* if we are at the end of the history, we need to add the current image to undo history */
504 if (undo_current == undo_num) {
509 //printf("restore undo #%d\n", undo_current);
511 /* nothing to redo */
512 if (undo_current >= undo_num-1)
515 //printf("restore undo #%d\n", undo_current);
517 memcpy(img_mark_buffer, img_mark_buffer_undo[undo_current], img_width*img_height);
518 button_down_x = button_down_x_undo[undo_current];
519 button_down_y = button_down_y_undo[undo_current];
522 void copy_color(int index)
526 if (img_mark_buffer_copy)
527 free(img_mark_buffer_copy);
528 img_mark_buffer_copy = malloc(img_width*img_height);
529 if (!img_mark_buffer_copy)
532 memcpy(img_mark_buffer_copy, img_mark_buffer, img_width*img_height);
533 copy_width = img_width;
534 copy_height = img_height;
536 /* erase indexed color except given index */
537 for (i = 0; i < img_width * img_height; i++) {
538 if (index && img_mark_buffer_copy[i] != index)
539 img_mark_buffer_copy[i] = 0;
543 void paste_color(void)
547 if (!img_mark_buffer_copy)
550 if (copy_width != img_width || copy_height != img_height) {
551 printerror("Image in copy buffer has different dimenstions.");
555 /* paste indexed pixles */
556 for (i = 0; i < img_width * img_height; i++) {
557 if (img_mark_buffer_copy[i])
558 img_mark_buffer[i] = img_mark_buffer_copy[i];