7 #include "../src/img.h"
8 #include "../src/mark.h"
9 #include "../src/yuv.h"
14 #include "../src/dir_seperator.h"
16 /* currently loaded image */
18 GdkPixbuf *img_pixbuf = NULL;
19 int img_width, img_height;
20 int copy_width, copy_height;
22 unsigned short *img_grey_buffer = NULL, *img_preview_buffer = NULL;
23 unsigned char *img_mark_buffer = NULL, *img_mark_buffer_undo[UNDO_MAX], *img_mark_buffer_copy;
24 int button_down_x_undo[UNDO_MAX], button_down_y_undo[UNDO_MAX];
25 int undo_current, undo_num;
26 int img_scale_x = 16, img_scale_y = 16;
27 int anything_modified;
28 extern int button_down_x, button_down_y;
30 /* load image and create pixbuf */
31 void create_image(const char *filename, int resize)
35 anything_modified = 0;
37 strcpy(img_name, filename);
38 img_grey_buffer = load_img(&img_width, &img_height, filename, 0);
39 if (!img_grey_buffer) {
40 printerror("Failed to load grey image '%s'", filename);
46 create_rendered(filename);
47 img_mark_buffer = malloc(img_width*img_height);
48 if (!img_mark_buffer) {
49 free(img_grey_buffer);
50 img_grey_buffer = NULL;
54 memset(img_mark_buffer, 0, img_width*img_height);
55 undo_current = undo_num = 0;
56 memset(img_mark_buffer_undo, 0, sizeof(img_mark_buffer_undo));
58 if (load_marked(img_mark_buffer, img_width, img_height, frame_list[timeline_selected].filename) == 0)
59 frame_list[timeline_selected].marked = 1;
61 frame_list[timeline_selected].marked = 0;
65 create_or_reset_pixbuf(resize);
70 size_t size = img_width*img_height*3*sizeof(*img_preview_buffer);
74 /* no grey image, so no preview */
75 if (!img_grey_buffer) {
79 img_preview_buffer = malloc(size);
80 if (!img_preview_buffer) {
84 memcpy(img_preview_buffer, img_grey_buffer, size);
86 colorize_preview_alloc();
89 void create_rendered(const char *filename)
91 static char imgfile[256];
97 /* no grey image, so no preview */
98 if (!img_grey_buffer) {
103 while((q = strchr(p, DIR_SEPERATOR)))
105 if (output_prefix[0] == '\0') {
106 strcpy(imgfile, filename);
107 imgfile[p - filename] = '\0';
108 strcat(imgfile, "colorized_");
110 strcpy(imgfile, output_prefix);
114 img_preview_buffer = load_img(&width, &height, imgfile, 0);
115 if (!img_preview_buffer) {
116 printerror("Failed to load rendered image '%s'", imgfile);
119 if (width != img_width || height != img_height) {
120 printerror("Failed to load: Rendered image '%s' has different size", imgfile);
126 void create_or_reset_pixbuf(int resize)
128 int w, h, dw = 0, dh = 0;
129 GdkScreen *screen = gtk_window_get_screen(GTK_WINDOW(main_window));
132 if (resize && screen) {
133 /* process GTK window event to have correct size */
134 while (gtk_events_pending())
135 gtk_main_iteration();
137 /* calculate the maximum windows size, so that the border will not exceed the screen size */
138 gdk_window_get_frame_extents(gtk_widget_get_window(main_window), &max);
139 max.width -= main_window->allocation.width;
140 max.height -= main_window->allocation.height;
145 max.width = gdk_screen_get_width(screen)-max.width;
146 max.height = gdk_screen_get_height(screen)-max.height;
149 w = img_scroll->allocation.width-25;
150 h = img_scroll->allocation.height-25;
151 if (w < img_width*img_scale_x/16) {
152 w = main_window->allocation.width - w + img_width*img_scale_x/16;
154 if (img_scale_x > 4) {
155 int aspect = img_scale_y / img_scale_x;
157 img_scale_y = img_scale_x * aspect;
162 dw = w - main_window->allocation.width;
164 if (h < img_height*img_scale_y/16) {
165 h = main_window->allocation.height - h + img_height*img_scale_y/16;
166 if (h > max.height) {
167 if (img_scale_x > 4) {
168 int aspect = img_scale_y / img_scale_x;
170 img_scale_y = img_scale_x * aspect;
175 dh = h - main_window->allocation.height;
177 // printf("%d %d\n", gdk_screen_get_width(screen), gdk_screen_get_height(screen));
179 gtk_window_resize(GTK_WINDOW(main_window), main_window->allocation.width+dw, main_window->allocation.height+dh);
183 g_object_unref(img_pixbuf);
186 img_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, img_width*img_scale_x/16, img_height*img_scale_y/16);
188 gtk_drawing_area_size(GTK_DRAWING_AREA(img_drawing_area), img_width*img_scale_x/16, img_height*img_scale_y/16);
191 timeline_show_name(timeline_selected);
195 void destroy_image(void)
202 g_object_unref(img_pixbuf);
205 free(img_grey_buffer);
206 img_grey_buffer = NULL;
208 free(img_mark_buffer);
209 img_mark_buffer = NULL;
210 for (i = 0; i < UNDO_MAX; i++) {
211 if (img_mark_buffer_undo[i]) {
212 free(img_mark_buffer_undo[i]);
213 img_mark_buffer_undo[i] = NULL;
218 void destroy_preview(void)
220 colorize_preview_free();
221 free(img_preview_buffer);
222 img_preview_buffer = NULL;
225 /* draw (area) of pixbuf */
226 void draw_image(int x, int y, int w, int h)
228 GdkDrawable *draw = gtk_widget_get_window(img_drawing_area);
229 int window_width, window_height, x_offset, y_offset;
230 gdk_drawable_get_size (draw, &window_width, &window_height);
231 double _r, _g, _b, pat, alpha;
240 unsigned char compose[w*3];
246 data = gdk_pixbuf_get_pixels(img_pixbuf);
247 rs = gdk_pixbuf_get_rowstride(img_pixbuf);
249 /* this should not happen */
250 if (window_width < img_width*img_scale_x/16)
251 window_width = img_width*img_scale_x/16;
252 if (window_height < img_height*img_scale_y/16)
253 window_height = img_height*img_scale_y/16;
255 /* we need to calculate an offset, since the drawing area is now larger */
256 x_offset = (window_width - img_width*img_scale_x/16) / 2;
257 y_offset = (window_height - img_height*img_scale_y/16) / 2;
259 /* clip to window size */
262 if (x >= window_width)
263 x = window_width - 1;
266 if (y >= window_height)
267 y = window_height - 1;
268 if (x + w > window_width)
269 w = window_width - x;
272 if (y + h > window_height)
273 h = window_height - y;
277 /* draw top border */
279 int temp = (h+y >= y_offset) ? y_offset-y : h; /* height */
280 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);
287 /* draw bottom border */
288 if (y+h >= y_offset+img_height*img_scale_y/16) {
289 int temp = (y < y_offset+img_height*img_scale_y/16) ? y_offset+img_height*img_scale_y/16 : y; /* y start */
290 gdk_draw_rectangle(draw, img_drawing_area->style->bg_gc[GTK_WIDGET_STATE(img_drawing_area)], TRUE, x, temp, w, h - (temp-y));
296 /* draw left border */
298 int temp = (w+x >= x_offset) ? x_offset-x : w; /* width */
299 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);
306 /* draw right border */
307 if (x+w >= x_offset+img_width*img_scale_x/16) {
308 int temp = (x < x_offset+img_width*img_scale_x/16) ? x_offset+img_width*img_scale_x/16 : x; /* x start **/
309 gdk_draw_rectangle(draw, img_drawing_area->style->bg_gc[GTK_WIDGET_STATE(img_drawing_area)], TRUE, temp, y, w - (temp-x), h);
318 if (img_grey_buffer) {
319 /* compose image (segment) line by line */
320 for (i = 0; i < h; i++) {
321 for (j = 0; j < w; j++) {
322 if (img_preview_buffer) {
323 /* show preview buffer */
324 compose[j*3] = img_preview_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3] >> 8;
325 compose[j*3+1] = img_preview_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3+1] >> 8;
326 compose[j*3+2] = img_preview_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3+2] >> 8;
328 /* show grey buffer */
329 compose[j*3] = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3] >> 8;
330 compose[j*3+1] = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3+1] >> 8;
331 compose[j*3+2] = img_grey_buffer[((j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y))*3+2] >> 8;
333 c = img_mark_buffer[(j+x)*16/img_scale_x+img_width*((i+y)*16/img_scale_y)];
334 if (c > 0 && !flowview) {
336 cr = mark_palette[c-1].r;
337 cg = mark_palette[c-1].g;
338 cb = mark_palette[c-1].b;
339 alpha = mark_palette[c-1].alpha;
341 pat = ((((i+y)>>3)&1) == (((j+x)>>3)&1)) ? 192.0 : 128.0;
342 _r = (double)cr * alpha + pat * (1-alpha);
343 _g = (double)cg * alpha + pat * (1-alpha);
344 _b = (double)cb * alpha + pat * (1-alpha);
354 if (c-1 == mark_selected) {
361 compose[j*3+2] = 128;
366 memcpy(data + rs*(i+y) + x*3, compose, w*3);
369 for (i = 0; i < h; i++)
370 memset(data + rs*(i+y) + x*3, 0, w*3);
373 gdk_draw_pixbuf(draw, NULL, img_pixbuf, x, y, x+x_offset, y+y_offset, w, h, GDK_RGB_DITHER_NONE, 0, 0);
377 static const char *brushs[] = {
416 " ################# "
417 " ################# "
418 "###################"
419 "###################"
420 "###################"
421 "###################"
422 "###################"
423 "###################"
424 "###################"
425 " ################# "
426 " ################# "
433 /* plot brush on mark buffer */
434 void paint_brush(int x, int y, int size, int paint)
436 GdkDrawable *draw = gtk_widget_get_window(img_drawing_area);
437 int window_width, window_height;
438 gdk_drawable_get_size (draw, &window_width, &window_height);
441 /* we need to calculate an offset, since the drawing area is now larger */
442 x -= (window_width - img_width*img_scale_x/16) / 2;
443 y -= (window_height - img_height*img_scale_y/16) / 2;
445 x = x*16/img_scale_x;
446 y = y*16/img_scale_y;
448 if (!img_mark_buffer || flowview)
451 int x1 = x - size + 1;
452 int x2 = x + size - 1;
453 int y1 = y - size + 1;
454 int y2 = y + size - 1;
455 int clipx = 0, clipy = 0, stride;
468 if (y1 >= img_height)
474 if (y2 >= img_height)
479 /* only paint color, if paint is set */
481 paint = mark_selected + 1;
483 stride = size + size - 1;
484 mask = brushs[size] + stride * clipy + clipx;
485 for (i = y1; i <= y2; i++) {
486 for (j = x1, jj = 0; j <= x2; j++, jj++) {
488 img_mark_buffer[j+img_width*i] = paint;
494 void erase_mark(int index)
498 if (!img_mark_buffer)
501 /* no index, erase all */
503 memset(img_mark_buffer, 0, img_width * img_height);
507 /* only erase indexed color */
508 for (i = 0; i < img_width * img_height; i++) {
509 if (img_mark_buffer[i] == index)
510 img_mark_buffer[i] = 0;
514 void move_mark(int x, int y)
519 if (!img_mark_buffer || undo_current == 0)
522 src = img_mark_buffer_undo[undo_current-1];
526 if (y < 0 || (y == 0 && x < 0)) {
527 /* move up in memory */
528 for (j = 0; j < img_height; j++) {
529 for (i = 0; i < img_width; i++) {
530 if (i < x || i >= img_width+x || j < y || j >= img_height+y)
531 img_mark_buffer[j*img_width+i] = 0;
533 img_mark_buffer[j*img_width+i] = src[(j-y)*img_width+(i-x)];
537 /* move down in memory */
538 for (j = img_height-1; j >= 0; j--) {
539 for (i = img_width-1; i >= 0; i--) {
540 if (i < x || i >= img_width+x || j < y || j >= img_height+y)
541 img_mark_buffer[j*img_width+i] = 0;
543 img_mark_buffer[j*img_width+i] = src[(j-y)*img_width+(i-x)];
549 void copy_mark_to_undo(void)
551 anything_modified = 1;
553 if (!img_mark_buffer)
556 if (undo_current < UNDO_MAX) {
557 /* allocate new undobuffer and append */
558 if (!img_mark_buffer_undo[undo_current])
559 img_mark_buffer_undo[undo_current] = malloc(img_width*img_height);
560 if (!img_mark_buffer_undo[undo_current])
564 /* shift and use oldest undobuffer */
565 unsigned char *temp = img_mark_buffer_undo[0];
567 for (i = 0; i < UNDO_MAX - 1; i++)
568 img_mark_buffer_undo[i] = img_mark_buffer_undo[i+1];
569 img_mark_buffer_undo[UNDO_MAX - 1] = temp;
571 undo_num = undo_current;
572 //printf("storing undo #%d\n", undo_current-1);
573 memcpy(img_mark_buffer_undo[undo_current-1], img_mark_buffer, img_width*img_height);
574 button_down_x_undo[undo_current-1] = button_down_x;
575 button_down_y_undo[undo_current-1] = button_down_y;
578 void copy_undo_to_mark(int redo)
580 if (!img_mark_buffer)
583 //printf("num is %d\n", undo_num);
585 /* nothing to undo */
586 if (undo_current == 0)
589 /* if we are at the end of the history, we need to add the current image to undo history */
590 if (undo_current == undo_num) {
595 //printf("restore undo #%d\n", undo_current);
597 /* nothing to redo */
598 if (undo_current >= undo_num-1)
601 //printf("restore undo #%d\n", undo_current);
603 memcpy(img_mark_buffer, img_mark_buffer_undo[undo_current], img_width*img_height);
604 button_down_x = button_down_x_undo[undo_current];
605 button_down_y = button_down_y_undo[undo_current];
608 void copy_color(int index)
612 if (img_mark_buffer_copy)
613 free(img_mark_buffer_copy);
614 img_mark_buffer_copy = malloc(img_width*img_height);
615 if (!img_mark_buffer_copy)
618 memcpy(img_mark_buffer_copy, img_mark_buffer, img_width*img_height);
619 copy_width = img_width;
620 copy_height = img_height;
622 /* erase indexed color except given index */
623 for (i = 0; i < img_width * img_height; i++) {
624 if (index && img_mark_buffer_copy[i] != index)
625 img_mark_buffer_copy[i] = 0;
629 void paste_color(void)
633 if (!img_mark_buffer_copy)
636 if (copy_width != img_width || copy_height != img_height) {
637 printerror("Image in copy buffer has different dimenstions.");
641 /* paste indexed pixles */
642 for (i = 0; i < img_width * img_height; i++) {
643 if (img_mark_buffer_copy[i])
644 img_mark_buffer[i] = img_mark_buffer_copy[i];