diff options
author | Alessio Treglia <alessio@debian.org> | 2010-08-16 14:20:18 +0200 |
---|---|---|
committer | Alessio Treglia <alessio@debian.org> | 2010-08-16 14:20:18 +0200 |
commit | 37152f58469b7595694f7c42555d21d5198e3672 (patch) | |
tree | 5f23e309f8923a417fcc7e177a95bef584362fa7 /src/page-view.c | |
parent | 2a72bdeb81030847462135698e1cbff1c685ee18 (diff) | |
parent | bbf22aaaa2fd5fe725a979f801472d52a1323242 (diff) |
Merge commit 'upstream/2.31.90.1'
Diffstat (limited to 'src/page-view.c')
-rw-r--r-- | src/page-view.c | 209 |
1 files changed, 149 insertions, 60 deletions
diff --git a/src/page-view.c b/src/page-view.c index 2c37fc2..40823f6 100644 --- a/src/page-view.c +++ b/src/page-view.c @@ -43,7 +43,7 @@ struct PageViewPrivate { /* Page being rendered */ Page *page; - + /* Image to render at current resolution */ GdkPixbuf *image; @@ -53,6 +53,9 @@ struct PageViewPrivate /* True if image needs to be regenerated */ gboolean update_image; + + /* Direction of currently scanned image */ + ScanDirection scan_direction; /* Next scan line to render */ gint scan_line; @@ -104,7 +107,8 @@ page_view_set_selected (PageView *view, gboolean selected) } -gboolean page_view_get_selected (PageView *view) +gboolean +page_view_get_selected (PageView *view) { g_return_val_if_fail (view != NULL, FALSE); return view->priv->selected; @@ -143,19 +147,92 @@ page_view_get_y_offset (PageView *view) } -static guchar * -get_pixel (guchar *input, gint rowstride, gint n_channels, gint x, gint y) +static guchar +get_sample (const guchar *line, gint x, gint depth, gint sample) +{ + // FIXME + return 0xFF; +} + + +static void +get_pixel (Page *page, gint x, gint y, guchar *pixel) { - return input + rowstride * y + x * n_channels; + gint t, depth, n_channels; + const guchar *p, *line; + + switch (page_get_scan_direction (page)) + { + case TOP_TO_BOTTOM: + break; + case BOTTOM_TO_TOP: + x = page_get_scan_width (page) - x; + y = page_get_scan_height (page) - y; + break; + case LEFT_TO_RIGHT: + t = x; + x = page_get_scan_width (page) - y; + y = t; + break; + case RIGHT_TO_LEFT: + t = x; + x = y; + y = page_get_scan_height (page) - t; + break; + } + + depth = page_get_depth (page); + n_channels = page_get_n_channels (page); + line = page_get_pixels (page) + page_get_rowstride (page) * y; + + /* Optimise for 8 bit images */ + if (depth == 8 && n_channels == 3) { + p = line + x * n_channels; + pixel[0] = p[0]; + pixel[1] = p[1]; + pixel[2] = p[2]; + return; + } + else if (depth == 8 && n_channels == 1) { + p = line + x; + pixel[0] = pixel[1] = pixel[2] = p[0]; + return; + } + + /* Optimise for bitmaps */ + else if (depth == 1 && n_channels == 1) { + p = line + (x / 8); + pixel[0] = pixel[1] = pixel[2] = p[0] & (0x80 >> (x % 8)) ? 0x00 : 0xFF; + return; + } + + /* Optimise for 2 bit images */ + else if (depth == 2 && n_channels == 1) { + gint sample; + gint block_shift[4] = { 6, 4, 2, 0 }; + + p = line + (x / 4); + sample = (p[0] >> block_shift[x % 4]) & 0x3; + sample = sample * 255 / 3; + + pixel[0] = pixel[1] = pixel[2] = sample; + return; + } + + /* Use slow method */ + pixel[0] = get_sample (line, x, depth, x * n_channels); + pixel[0] = get_sample (line, x, depth, x * n_channels + 1); + pixel[0] = get_sample (line, x, depth, x * n_channels + 2); } static void -set_pixel (guchar *input, gint rowstride, gint n_channels, +set_pixel (Page *page, double l, double r, double t, double b, guchar *pixel) { gint x, y; gint L, R, T, B; + guchar p[3]; double scale, red, green, blue; /* Decimation: @@ -225,7 +302,7 @@ set_pixel (guchar *input, gint rowstride, gint n_channels, if ((r - l <= 1.0 && (gint)r == (gint)l) || (b - t <= 1.0 && (gint)b == (gint)t)) { /* Inside */ if ((gint)l == (gint)r || (gint)t == (gint)b) { - guchar *p = get_pixel (input, rowstride, n_channels, (gint)l, (gint)t); + get_pixel (page, (gint)l, (gint)t, p); pixel[0] = p[0]; pixel[1] = p[1]; pixel[2] = p[2]; @@ -234,34 +311,34 @@ set_pixel (guchar *input, gint rowstride, gint n_channels, /* Stradling horizontal edge */ if (L > R) { - guchar *p = get_pixel (input, rowstride, n_channels, R, T-1); + get_pixel (page, R, T-1, p); red += p[0] * (r-l)*(T-t); green += p[1] * (r-l)*(T-t); blue += p[2] * (r-l)*(T-t); for (y = T; y < B; y++) { - guchar *p = get_pixel (input, rowstride, n_channels, R, y); + get_pixel (page, R, y, p); red += p[0] * (r-l); green += p[1] * (r-l); blue += p[2] * (r-l); } - p = get_pixel (input, rowstride, n_channels, R, B); + get_pixel (page, R, B, p); red += p[0] * (r-l)*(b-B); green += p[1] * (r-l)*(b-B); blue += p[2] * (r-l)*(b-B); } /* Stradling vertical edge */ else { - guchar *p = get_pixel (input, rowstride, n_channels, L - 1, B); + get_pixel (page, L - 1, B, p); red += p[0] * (b-t)*(L-l); green += p[1] * (b-t)*(L-l); blue += p[2] * (b-t)*(L-l); for (x = L; x < R; x++) { - guchar *p = get_pixel (input, rowstride, n_channels, x, B); + get_pixel (page, x, B, p); red += p[0] * (b-t); green += p[1] * (b-t); blue += p[2] * (b-t); } - p = get_pixel (input, rowstride, n_channels, R, B); + get_pixel (page, R, B, p); red += p[0] * (b-t)*(r-R); green += p[1] * (b-t)*(r-R); blue += p[2] * (b-t)*(r-R); @@ -277,7 +354,7 @@ set_pixel (guchar *input, gint rowstride, gint n_channels, /* Add the middle pixels */ for (x = L; x < R; x++) { for (y = T; y < B; y++) { - guchar *p = get_pixel (input, rowstride, n_channels, x, y); + get_pixel (page, x, y, p); red += p[0]; green += p[1]; blue += p[2]; @@ -287,14 +364,14 @@ set_pixel (guchar *input, gint rowstride, gint n_channels, /* Add the weighted top and bottom pixels */ for (x = L; x < R; x++) { if (t != T) { - guchar *p = get_pixel (input, rowstride, n_channels, x, T - 1); + get_pixel (page, x, T - 1, p); red += p[0] * (T - t); green += p[1] * (T - t); blue += p[2] * (T - t); } if (b != B) { - guchar *p = get_pixel (input, rowstride, n_channels, x, B); + get_pixel (page, x, B, p); red += p[0] * (b - B); green += p[1] * (b - B); blue += p[2] * (b - B); @@ -304,14 +381,14 @@ set_pixel (guchar *input, gint rowstride, gint n_channels, /* Add the left and right pixels */ for (y = T; y < B; y++) { if (l != L) { - guchar *p = get_pixel (input, rowstride, n_channels, L - 1, y); + get_pixel (page, L - 1, y, p); red += p[0] * (L - l); green += p[1] * (L - l); blue += p[2] * (L - l); } if (r != R) { - guchar *p = get_pixel (input, rowstride, n_channels, R, y); + get_pixel (page, R, y, p); red += p[0] * (r - R); green += p[1] * (r - R); blue += p[2] * (r - R); @@ -320,25 +397,25 @@ set_pixel (guchar *input, gint rowstride, gint n_channels, /* Add the corner pixels */ if (l != L && t != T) { - guchar *p = get_pixel (input, rowstride, n_channels, L - 1, T - 1); + get_pixel (page, L - 1, T - 1, p); red += p[0] * (L - l)*(T - t); green += p[1] * (L - l)*(T - t); blue += p[2] * (L - l)*(T - t); } if (r != R && t != T) { - guchar *p = get_pixel (input, rowstride, n_channels, R, T - 1); + get_pixel (page, R, T - 1, p); red += p[0] * (r - R)*(T - t); green += p[1] * (r - R)*(T - t); blue += p[2] * (r - R)*(T - t); } if (r != R && b != B) { - guchar *p = get_pixel (input, rowstride, n_channels, R, B); + get_pixel (page, R, B, p); red += p[0] * (r - R)*(b - B); green += p[1] * (r - R)*(b - B); blue += p[2] * (r - R)*(b - B); } if (l != L && b != B) { - guchar *p = get_pixel (input, rowstride, n_channels, L - 1, B); + get_pixel (page, L - 1, B, p); red += p[0] * (L - l)*(b - B); green += p[1] * (L - l)*(b - B); blue += p[2] * (L - l)*(b - B); @@ -353,23 +430,19 @@ set_pixel (guchar *input, gint rowstride, gint n_channels, static void -update_preview (GdkPixbuf *image, +update_preview (Page *page, GdkPixbuf **output_image, gint output_width, gint output_height, - Orientation orientation, gint old_scan_line, gint scan_line) + ScanDirection scan_direction, gint old_scan_line, gint scan_line) { - guchar *input, *output; + guchar *output; gint input_width, input_height; - gint input_rowstride, input_n_channels; gint output_rowstride, output_n_channels; gint x, y; gint L, R, T, B; - input = gdk_pixbuf_get_pixels (image); - input_width = gdk_pixbuf_get_width (image); - input_height = gdk_pixbuf_get_height (image); - input_rowstride = gdk_pixbuf_get_rowstride (image); - input_n_channels = gdk_pixbuf_get_n_channels (image); - + input_width = page_get_width (page); + input_height = page_get_height (page); + /* Create new image if one does not exist or has changed size */ if (!*output_image || gdk_pixbuf_get_width (*output_image) != output_width || @@ -381,7 +454,7 @@ update_preview (GdkPixbuf *image, 8, output_width, output_height); - + /* Update entire image */ L = 0; R = output_width - 1; @@ -390,7 +463,7 @@ update_preview (GdkPixbuf *image, } /* Otherwise only update changed area */ else { - switch (orientation) { + switch (scan_direction) { case TOP_TO_BOTTOM: L = 0; R = output_width - 1; @@ -432,15 +505,25 @@ update_preview (GdkPixbuf *image, g_return_if_fail (T >= 0); g_return_if_fail (B < output_height); g_return_if_fail (*output_image != NULL); - + output = gdk_pixbuf_get_pixels (*output_image); output_rowstride = gdk_pixbuf_get_rowstride (*output_image); output_n_channels = gdk_pixbuf_get_n_channels (*output_image); + + if (!page_has_data (page)) { + for (x = L; x <= R; x++) + for (y = T; y <= B; y++) { + guchar *pixel; + pixel = output + output_rowstride * y + x * output_n_channels; + pixel[0] = pixel[1] = pixel[2] = 0xFF; + } + return; + } /* Update changed area */ for (x = L; x <= R; x++) { double l, r; - + l = (double)x * input_width / output_width; r = (double)(x + 1) * input_width / output_width; @@ -450,9 +533,9 @@ update_preview (GdkPixbuf *image, t = (double)y * input_height / output_height; b = (double)(y + 1) * input_height / output_height; - set_pixel (input, input_rowstride, input_n_channels, + set_pixel (page, l, r, t, b, - get_pixel (output, output_rowstride, output_n_channels, x, y)); + output + output_rowstride * y + x * output_n_channels); } } } @@ -475,22 +558,27 @@ get_preview_height (PageView *view) static void update_page_view (PageView *view) { - GdkPixbuf *image; - gint old_scan_line, scan_line; + gint old_scan_line, scan_line, left_steps; if (!view->priv->update_image) return; - image = page_get_image (view->priv->page); old_scan_line = view->priv->scan_line; scan_line = page_get_scan_line (view->priv->page); - update_preview (image, + /* Delete old image if scan direction changed */ + left_steps = view->priv->scan_direction - page_get_scan_direction (view->priv->page); + if (left_steps && view->priv->image) { + g_object_unref (view->priv->image); + view->priv->image = NULL; + } + view->priv->scan_direction = page_get_scan_direction (view->priv->page); + + update_preview (view->priv->page, &view->priv->image, get_preview_width (view), get_preview_height (view), - page_get_orientation (view->priv->page), old_scan_line, scan_line); - g_object_unref (image); + page_get_scan_direction (view->priv->page), old_scan_line, scan_line); view->priv->update_image = FALSE; view->priv->scan_line = scan_line; @@ -844,18 +932,8 @@ page_view_render (PageView *view, cairo_t *context) /* Draw image */ cairo_translate (context, view->priv->border_width, view->priv->border_width); - if (view->priv->image) { - gdk_cairo_set_source_pixbuf (context, view->priv->image, 0, 0); - cairo_paint (context); - } - else { - cairo_scale (context, - (double) get_preview_width (view) / page_get_width (view->priv->page), - (double) get_preview_height (view) / page_get_height (view->priv->page)); - gdk_cairo_set_source_pixbuf (context, page_get_image (view->priv->page), 0, 0); - - cairo_paint (context); - } + gdk_cairo_set_source_pixbuf (context, view->priv->image, 0, 0); + cairo_paint (context); /* Draw throbber */ if (page_is_scanning (view->priv->page) && !page_has_data (view->priv->page)) { @@ -895,8 +973,8 @@ page_view_render (PageView *view, cairo_t *context) double x1, y1, x2, y2; scan_line = page_get_scan_line (view->priv->page); - - switch (page_get_orientation (view->priv->page)) { + + switch (page_get_scan_direction (view->priv->page)) { case TOP_TO_BOTTOM: s = page_to_screen_y (view, scan_line); x1 = 0; y1 = s + 0.5; @@ -1024,7 +1102,7 @@ page_view_get_height (PageView *view) static void -page_image_changed_cb (Page *p, PageView *view) +page_pixels_changed_cb (Page *p, PageView *view) { /* Regenerate image */ view->priv->update_image = TRUE; @@ -1050,16 +1128,27 @@ page_overlay_changed_cb (Page *p, PageView *view) static void +scan_direction_changed_cb (Page *p, PageView *view) +{ + /* Regenerate image */ + view->priv->update_image = TRUE; + g_signal_emit (view, signals[SIZE_CHANGED], 0); + g_signal_emit (view, signals[CHANGED], 0); +} + + +static void page_view_set_page (PageView *view, Page *page) { g_return_if_fail (view != NULL); g_return_if_fail (view->priv->page == NULL); view->priv->page = g_object_ref (page); - g_signal_connect (view->priv->page, "image-changed", G_CALLBACK (page_image_changed_cb), view); + g_signal_connect (view->priv->page, "pixels-changed", G_CALLBACK (page_pixels_changed_cb), view); g_signal_connect (view->priv->page, "size-changed", G_CALLBACK (page_size_changed_cb), view); g_signal_connect (view->priv->page, "crop-changed", G_CALLBACK (page_overlay_changed_cb), view); g_signal_connect (view->priv->page, "scan-line-changed", G_CALLBACK (page_overlay_changed_cb), view); + g_signal_connect (view->priv->page, "scan-direction-changed", G_CALLBACK (scan_direction_changed_cb), view); } |