summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/book.c76
-rw-r--r--src/book.h2
-rw-r--r--src/page-view.c209
-rw-r--r--src/page.c575
-rw-r--r--src/page.h37
-rw-r--r--src/scanner.c70
-rw-r--r--src/scanner.h14
-rw-r--r--src/simple-scan.c8
-rw-r--r--src/ui.c41
9 files changed, 579 insertions, 453 deletions
diff --git a/src/book.c b/src/book.c
index 387c7f0..081cbd3 100644
--- a/src/book.c
+++ b/src/book.c
@@ -73,14 +73,13 @@ page_changed_cb (Page *page, Book *book)
Page *
-book_append_page (Book *book, gint width, gint height, gint dpi, Orientation orientation)
+book_append_page (Book *book, gint width, gint height, gint dpi, ScanDirection scan_direction)
{
Page *page;
- page = page_new ();
- g_signal_connect (page, "image-changed", G_CALLBACK (page_changed_cb), book);
+ page = page_new (width, height, dpi, scan_direction);
+ g_signal_connect (page, "pixels-changed", G_CALLBACK (page_changed_cb), book);
g_signal_connect (page, "crop-changed", G_CALLBACK (page_changed_cb), book);
- page_setup (page, width, height, dpi, orientation);
book->priv->pages = g_list_append (book->priv->pages, page);
@@ -222,7 +221,7 @@ book_save_ps (Book *book, GFile *file, GError **error)
double width, height;
GdkPixbuf *image;
- image = page_get_cropped_image (page);
+ image = page_get_image (page, TRUE);
width = gdk_pixbuf_get_width (image) * 72.0 / page_get_dpi (page);
height = gdk_pixbuf_get_height (image) * 72.0 / page_get_dpi (page);
@@ -444,7 +443,7 @@ book_save_pdf (Book *book, GFile *file, GError **error)
height = page_get_height (page);
page_width = width * 72. / page_get_dpi (page);
page_height = height * 72. / page_get_dpi (page);
- image = page_get_cropped_image (page);
+ image = page_get_image (page, TRUE);
pixels = gdk_pixbuf_get_pixels (image);
if (page_is_color (page)) {
@@ -470,13 +469,53 @@ book_save_pdf (Book *book, GFile *file, GError **error)
}
}
}
+ else if (page_get_depth (page) == 2) {
+ int row, shift_count = 6;
+ guchar *write_ptr;
+
+ depth = 2;
+ color_space = "DeviceGray";
+ data_length = height * ((width * 2 + 7) / 8);
+ data = g_malloc (sizeof (guchar) * data_length);
+ write_ptr = data;
+ write_ptr[0] = 0;
+ for (row = 0; row < height; row++) {
+ int x;
+ guchar *in_line;
+
+ /* Pad to the next line */
+ if (shift_count != 6) {
+ write_ptr++;
+ write_ptr[0] = 0;
+ shift_count = 6;
+ }
+
+ in_line = pixels + row * gdk_pixbuf_get_rowstride (image);
+ for (x = 0; x < width; x++) {
+ guchar *in_p = in_line + x*3;
+ if (in_p[0] >= 192)
+ write_ptr[0] |= 3 << shift_count;
+ else if (in_p[0] >= 128)
+ write_ptr[0] |= 2 << shift_count;
+ else if (in_p[0] >= 64)
+ write_ptr[0] |= 1 << shift_count;
+ if (shift_count == 0) {
+ write_ptr++;
+ write_ptr[0] = 0;
+ shift_count = 6;
+ }
+ else
+ shift_count -= 2;
+ }
+ }
+ }
else if (page_get_depth (page) == 1) {
- int row, offset = 7;
+ int row, mask = 0x80;
guchar *write_ptr;
depth = 1;
color_space = "DeviceGray";
- data_length = (height * width + 7) / 8;
+ data_length = height * ((width + 7) / 8);
data = g_malloc (sizeof (guchar) * data_length);
write_ptr = data;
write_ptr[0] = 0;
@@ -484,16 +523,23 @@ book_save_pdf (Book *book, GFile *file, GError **error)
int x;
guchar *in_line;
+ /* Pad to the next line */
+ if (mask != 0x80) {
+ write_ptr++;
+ write_ptr[0] = 0;
+ mask = 0x80;
+ }
+
in_line = pixels + row * gdk_pixbuf_get_rowstride (image);
for (x = 0; x < width; x++) {
guchar *in_p = in_line + x*3;
- if (in_p[0])
- write_ptr[0] |= 1 << offset;
- offset--;
- if (offset < 0) {
+ if (in_p[0] != 0)
+ write_ptr[0] |= mask;
+ mask >>= 1;
+ if (mask == 0) {
write_ptr++;
write_ptr[0] = 0;
- offset = 7;
+ mask = 0x80;
}
}
}
@@ -583,9 +629,9 @@ book_save_pdf (Book *book, GFile *file, GError **error)
/* Page contents */
command = g_strdup_printf ("q\n"
- "%d 0 0 %d 0 0 cm\n"
+ "%f 0 0 %f 0 0 cm\n"
"/Im%d Do\n"
- "Q", width, height, i);
+ "Q", page_width, page_height, i);
pdf_printf (writer, "\n");
number = pdf_start_object (writer);
pdf_printf (writer, "%d 0 obj\n", number);
diff --git a/src/book.h b/src/book.h
index f8fc747..7a336ef 100644
--- a/src/book.h
+++ b/src/book.h
@@ -47,7 +47,7 @@ Book *book_new (void);
void book_clear (Book *book);
-Page *book_append_page (Book *book, gint width, gint height, gint dpi, Orientation orientation);
+Page *book_append_page (Book *book, gint width, gint height, gint dpi, ScanDirection orientation);
void book_delete_page (Book *book, Page *page);
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);
}
diff --git a/src/page.c b/src/page.c
index 655b43b..e70f103 100644
--- a/src/page.c
+++ b/src/page.c
@@ -12,12 +12,11 @@
#include <string.h>
#include "page.h"
-
enum {
- IMAGE_CHANGED,
+ PIXELS_CHANGED,
SIZE_CHANGED,
SCAN_LINE_CHANGED,
- ORIENTATION_CHANGED,
+ SCAN_DIRECTION_CHANGED,
CROP_CHANGED,
LAST_SIGNAL
};
@@ -29,7 +28,7 @@ struct PagePrivate
gint dpi;
/* Number of rows in this page or -1 if currently unknown */
- gint rows;
+ gint expected_rows;
/* Bit depth */
gint depth;
@@ -38,7 +37,8 @@ struct PagePrivate
gchar *color_profile;
/* Scanned image data */
- GdkPixbuf *image;
+ gint width, n_rows, rowstride, n_channels;
+ guchar *pixels;
/* Page is getting data */
gboolean scanning;
@@ -46,14 +46,11 @@ struct PagePrivate
/* TRUE if have some page data */
gboolean has_data;
- /* TRUE if have color data */
- gboolean is_color;
-
/* Expected next scan row */
gint scan_line;
/* Rotation of scanned data */
- Orientation orientation;
+ ScanDirection scan_direction;
/* Crop */
gboolean has_crop;
@@ -65,67 +62,54 @@ G_DEFINE_TYPE (Page, page, G_TYPE_OBJECT);
Page *
-page_new ()
+page_new (gint width, gint height, gint dpi, ScanDirection scan_direction)
{
- return g_object_new (PAGE_TYPE, NULL);
-}
-
-
-void
-page_setup (Page *page, gint width, gint height, gint dpi, Orientation orientation)
-{
- page->priv->orientation = orientation;
+ Page *page;
+
+ page = g_object_new (PAGE_TYPE, NULL);
+ if (scan_direction == TOP_TO_BOTTOM || scan_direction == BOTTOM_TO_TOP) {
+ page->priv->width = width;
+ page->priv->n_rows = height;
+ }
+ else {
+ page->priv->width = height;
+ page->priv->n_rows = width;
+ }
page->priv->dpi = dpi;
- if (orientation == LEFT_TO_RIGHT || orientation == RIGHT_TO_LEFT)
- page->priv->rows = width;
- else
- page->priv->rows = height;
- page->priv->image = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE,
- 8,
- width,
- height);
- g_return_if_fail (page->priv->image != NULL);
- gdk_pixbuf_fill (page->priv->image, 0xFFFFFFFF);
+ page->priv->scan_direction = scan_direction;
+
+ return page;
}
void
-page_set_scan_area (Page *page, gint width, gint rows, gint dpi)
+page_set_page_info (Page *page, ScanPageInfo *info)
{
- gint height;
-
g_return_if_fail (page != NULL);
+ page->priv->expected_rows = info->height;
+ page->priv->dpi = info->dpi;
+
+ /* Create a white page */
+ page->priv->width = info->width;
+ page->priv->n_rows = info->height;
/* Variable height, try 50% of the width for now */
- if (rows < 0)
- height = width / 2;
+ if (page->priv->n_rows < 0)
+ page->priv->n_rows = page->priv->width / 2;
+ page->priv->depth = info->depth;
+ page->priv->n_channels = info->n_channels;
+ page->priv->rowstride = (page->priv->width * page->priv->depth * page->priv->n_channels + 7) / 8;
+ page->priv->pixels = g_realloc (page->priv->pixels, page->priv->n_rows * page->priv->rowstride);
+ g_return_if_fail (page->priv->pixels != NULL);
+
+ /* Fill with white */
+ if (page->priv->depth == 1)
+ memset (page->priv->pixels, 0x00, page->priv->n_rows * page->priv->rowstride);
else
- height = rows;
+ memset (page->priv->pixels, 0xFF, page->priv->n_rows * page->priv->rowstride);
- /* Rotate page */
- if (page->priv->orientation == LEFT_TO_RIGHT || page->priv->orientation == RIGHT_TO_LEFT) {
- gint t;
- t = width;
- width = height;
- height = t;
- }
-
- page->priv->rows = rows;
- page->priv->dpi = dpi;
-
- /* Create a white page */
- /* NOTE: Pixbuf only supports 8 bit RGB images */
- if (page->priv->image)
- g_object_unref (page->priv->image);
- page->priv->image = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE,
- 8,
- width,
- height);
- g_return_if_fail (page->priv->image != NULL);
-
- gdk_pixbuf_fill (page->priv->image, 0xFFFFFFFF);
g_signal_emit (page, signals[SIZE_CHANGED], 0);
- g_signal_emit (page, signals[IMAGE_CHANGED], 0);
+ g_signal_emit (page, signals[PIXELS_CHANGED], 0);
}
@@ -139,7 +123,8 @@ page_start (Page *page)
}
-gboolean page_is_scanning (Page *page)
+gboolean
+page_is_scanning (Page *page)
{
g_return_val_if_fail (page != NULL, FALSE);
@@ -147,60 +132,24 @@ gboolean page_is_scanning (Page *page)
}
-static gint
-get_sample (guchar *data, gint depth, gint index)
-{
- gint i, offset, value, n_bits;
-
- /* Optimise if using 8 bit samples */
- if (depth == 8)
- return data[index];
-
- /* Bit offset for this sample */
- offset = depth * index;
-
- /* Get the remaining bits in the octet this sample starts in */
- i = offset / 8;
- n_bits = 8 - offset % 8;
- value = data[i] & (0xFF >> (8 - n_bits));
-
- /* Add additional octets until get enough bits */
- while (n_bits < depth) {
- value = value << 8 | data[i++];
- n_bits += 8;
- }
-
- /* Trim remaining bits off */
- if (n_bits > depth)
- value >>= n_bits - depth;
-
- return value;
-}
-
-
-gboolean page_has_data (Page *page)
+gboolean
+page_has_data (Page *page)
{
g_return_val_if_fail (page != NULL, FALSE);
return page->priv->has_data;
}
-gboolean page_is_color (Page *page)
+gboolean
+page_is_color (Page *page)
{
g_return_val_if_fail (page != NULL, FALSE);
- return page->priv->is_color;
+ return page->priv->n_channels > 1;
}
gint
-page_get_depth (Page *page)
-{
- g_return_val_if_fail (page != NULL, 0);
- return page->priv->depth;
-}
-
-
-gint page_get_scan_line (Page *page)
+page_get_scan_line (Page *page)
{
g_return_val_if_fail (page != NULL, -1);
return page->priv->scan_line;
@@ -208,126 +157,27 @@ gint page_get_scan_line (Page *page)
static void
-set_pixel (ScanLine *line, gint n, gint x, guchar *pixel)
-{
- gint sample;
- guchar *data;
-
- data = line->data + line->data_length * n;
-
- switch (line->format) {
- case LINE_RGB:
- pixel[0] = get_sample (data, line->depth, x*3) * 0xFF / ((1 << line->depth) - 1);
- pixel[1] = get_sample (data, line->depth, x*3+1) * 0xFF / ((1 << line->depth) - 1);
- pixel[2] = get_sample (data, line->depth, x*3+2) * 0xFF / ((1 << line->depth) - 1);
- break;
- case LINE_GRAY:
- /* Bitmap, 0 = white, 1 = black */
- sample = get_sample (data, line->depth, x) * 0xFF / ((1 << line->depth) - 1);
- if (line->depth == 1)
- sample = sample ? 0x00 : 0xFF;
-
- pixel[0] = pixel[1] = pixel[2] = sample;
- break;
- case LINE_RED:
- pixel[0] = get_sample (data, line->depth, x) * 0xFF / ((1 << line->depth) - 1);
- break;
- case LINE_GREEN:
- pixel[1] = get_sample (data, line->depth, x) * 0xFF / ((1 << line->depth) - 1);
- break;
- case LINE_BLUE:
- pixel[2] = get_sample (data, line->depth, x) * 0xFF / ((1 << line->depth) - 1);
- break;
- }
-}
-
-
-static void
parse_line (Page *page, ScanLine *line, gint n, gboolean *size_changed)
{
- guchar *pixels;
gint line_number;
- gint i, x = 0, y = 0, x_step = 0, y_step = 0;
- gint rowstride, n_channels;
line_number = line->number + n;
- if (line->format != LINE_GRAY)
- page->priv->is_color = TRUE;
- if (line->depth > page->priv->depth)
- page->priv->depth = line->depth;
-
/* Extend image if necessary */
while (line_number >= page_get_scan_height (page)) {
- GdkPixbuf *image;
- gint height, width, new_width, new_height;
+ gint rows;
/* Extend image */
- new_width = width = gdk_pixbuf_get_width (page->priv->image);
- new_height = height = gdk_pixbuf_get_height (page->priv->image);
- if (page->priv->orientation == TOP_TO_BOTTOM || page->priv->orientation == BOTTOM_TO_TOP) {
- new_height = height + width / 2;
- g_debug("Extending image height from %d pixels to %d pixels", height, new_height);
- }
- else {
- new_width = width + height / 2;
- g_debug("Extending image width from %d pixels to %d pixels", width, new_width);
- }
- image = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE,
- 8, new_width, new_height);
-
- /* Copy old data */
- gdk_pixbuf_fill (page->priv->image, 0xFFFFFFFF);
- if (page->priv->orientation == TOP_TO_BOTTOM || page->priv->orientation == LEFT_TO_RIGHT)
- gdk_pixbuf_copy_area (page->priv->image, 0, 0, width, height,
- image, 0, 0);
- else
- gdk_pixbuf_copy_area (page->priv->image, 0, 0, width, height,
- image, new_width - width, new_height - height);
-
- g_object_unref (page->priv->image);
- page->priv->image = image;
+ rows = page->priv->n_rows;
+ page->priv->n_rows = rows + page->priv->width / 2;
+ g_debug("Extending image from %d lines to %d lines", rows, page->priv->n_rows);
+ page->priv->pixels = g_realloc (page->priv->pixels, page->priv->n_rows * page->priv->rowstride);
*size_changed = TRUE;
}
-
- switch (page->priv->orientation) {
- case TOP_TO_BOTTOM:
- x = 0;
- y = line_number;
- x_step = 1;
- y_step = 0;
- break;
- case BOTTOM_TO_TOP:
- x = page_get_width (page) - 1;
- y = page_get_height (page) - line_number - 1;
- x_step = -1;
- y_step = 0;
- break;
- case LEFT_TO_RIGHT:
- x = line_number;
- y = page_get_height (page) - 1;
- x_step = 0;
- y_step = -1;
- break;
- case RIGHT_TO_LEFT:
- x = page_get_width (page) - line_number - 1;
- y = 0;
- x_step = 0;
- y_step = 1;
- break;
- }
- pixels = gdk_pixbuf_get_pixels (page->priv->image);
- rowstride = gdk_pixbuf_get_rowstride (page->priv->image);
- n_channels = gdk_pixbuf_get_n_channels (page->priv->image);
- for (i = 0; i < line->width; i++) {
- guchar *pixel;
-
- pixel = pixels + y * rowstride + x * n_channels;
- set_pixel (line, n, i, pixel);
- x += x_step;
- y += y_step;
- }
+
+ /* Copy in new row */
+ memcpy (page->priv->pixels + line_number * page->priv->rowstride, line->data + n * line->data_length, line->data_length);
page->priv->scan_line = line_number;
}
@@ -349,7 +199,7 @@ page_parse_scan_line (Page *page, ScanLine *line)
if (size_changed)
g_signal_emit (page, signals[SIZE_CHANGED], 0);
g_signal_emit (page, signals[SCAN_LINE_CHANGED], 0);
- g_signal_emit (page, signals[IMAGE_CHANGED], 0);
+ g_signal_emit (page, signals[PIXELS_CHANGED], 0);
}
@@ -361,35 +211,15 @@ page_finish (Page *page)
g_return_if_fail (page != NULL);
/* Trim page */
- if (page->priv->rows < 0 &&
- page->priv->scan_line != gdk_pixbuf_get_height (page->priv->image)) {
- GdkPixbuf *image;
- gint width, height, new_width, new_height;
-
- new_width = width = gdk_pixbuf_get_width (page->priv->image);
- new_height = height = gdk_pixbuf_get_height (page->priv->image);
- if (page->priv->orientation == TOP_TO_BOTTOM || page->priv->orientation == BOTTOM_TO_TOP) {
- new_height = page->priv->scan_line;
- g_debug("Trimming image height from %d pixels to %d pixels", height, new_height);
- }
- else {
- new_width = page->priv->scan_line;
- g_debug("Trimming image width from %d pixels to %d pixels", width, new_width);
- }
- image = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE,
- 8,
- new_width, new_height);
-
- /* Copy old data */
- if (page->priv->orientation == TOP_TO_BOTTOM || page->priv->orientation == LEFT_TO_RIGHT)
- gdk_pixbuf_copy_area (page->priv->image, 0, 0, width, height,
- image, 0, 0);
- else
- gdk_pixbuf_copy_area (page->priv->image, width - new_width, height - new_height, width, height,
- image, 0, 0);
-
- g_object_unref (page->priv->image);
- page->priv->image = image;
+ if (page->priv->expected_rows < 0 &&
+ page->priv->scan_line != page_get_scan_height (page)) {
+ gint rows;
+
+ rows = page->priv->n_rows;
+ page->priv->n_rows = page->priv->scan_line;
+ page->priv->pixels = g_realloc (page->priv->pixels, page->priv->n_rows * page->priv->rowstride);
+ g_debug("Trimming page from %d lines to %d lines", rows, page->priv->n_rows);
+
size_changed = TRUE;
}
page->priv->scanning = FALSE;
@@ -400,47 +230,36 @@ page_finish (Page *page)
}
-Orientation
-page_get_orientation (Page *page)
+ScanDirection
+page_get_scan_direction (Page *page)
{
g_return_val_if_fail (page != NULL, TOP_TO_BOTTOM);
- return page->priv->orientation;
+ return page->priv->scan_direction;
}
-void
-page_set_orientation (Page *page, Orientation orientation)
+static void
+page_set_scan_direction (Page *page, ScanDirection scan_direction)
{
gint left_steps, t;
- GdkPixbuf *image;
gboolean size_changed = FALSE;
gint width, height;
g_return_if_fail (page != NULL);
- if (page->priv->orientation == orientation)
+ if (page->priv->scan_direction == scan_direction)
return;
/* Work out how many times it has been rotated to the left */
- left_steps = orientation - page->priv->orientation;
+ left_steps = scan_direction - page->priv->scan_direction;
if (left_steps < 0)
left_steps += 4;
+ if (left_steps != 2)
+ size_changed = TRUE;
width = page_get_width (page);
height = page_get_height (page);
-
- /* Rotate image */
- if (left_steps == 1)
- image = gdk_pixbuf_rotate_simple (page->priv->image, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE);
- else if (left_steps == 2)
- image = gdk_pixbuf_rotate_simple (page->priv->image, GDK_PIXBUF_ROTATE_UPSIDEDOWN);
- else
- image = gdk_pixbuf_rotate_simple (page->priv->image, GDK_PIXBUF_ROTATE_CLOCKWISE);
- g_object_unref (page->priv->image);
- page->priv->image = image;
- if (left_steps != 2)
- size_changed = TRUE;
/* Rotate crop */
if (page->priv->has_crop) {
@@ -471,42 +290,42 @@ page_set_orientation (Page *page, Orientation orientation)
}
}
- page->priv->orientation = orientation;
+ page->priv->scan_direction = scan_direction;
if (size_changed)
g_signal_emit (page, signals[SIZE_CHANGED], 0);
- g_signal_emit (page, signals[IMAGE_CHANGED], 0);
- g_signal_emit (page, signals[ORIENTATION_CHANGED], 0);
- g_signal_emit (page, signals[CROP_CHANGED], 0);
+ g_signal_emit (page, signals[SCAN_DIRECTION_CHANGED], 0);
+ if (page->priv->has_crop)
+ g_signal_emit (page, signals[CROP_CHANGED], 0);
}
void
page_rotate_left (Page *page)
{
- Orientation orientation;
+ ScanDirection scan_direction;
g_return_if_fail (page != NULL);
- orientation = page_get_orientation (page);
- if (orientation == RIGHT_TO_LEFT)
- orientation = TOP_TO_BOTTOM;
+ scan_direction = page_get_scan_direction (page);
+ if (scan_direction == RIGHT_TO_LEFT)
+ scan_direction = TOP_TO_BOTTOM;
else
- orientation++;
- page_set_orientation (page, orientation);
+ scan_direction++;
+ page_set_scan_direction (page, scan_direction);
}
void
page_rotate_right (Page *page)
{
- Orientation orientation;
+ ScanDirection scan_direction;
- orientation = page_get_orientation (page);
- if (orientation == TOP_TO_BOTTOM)
- orientation = RIGHT_TO_LEFT;
+ scan_direction = page_get_scan_direction (page);
+ if (scan_direction == TOP_TO_BOTTOM)
+ scan_direction = RIGHT_TO_LEFT;
else
- orientation--;
- page_set_orientation (page, orientation);
+ scan_direction--;
+ page_set_scan_direction (page, scan_direction);
}
@@ -530,7 +349,11 @@ gint
page_get_width (Page *page)
{
g_return_val_if_fail (page != NULL, 0);
- return gdk_pixbuf_get_width (page->priv->image);
+
+ if (page->priv->scan_direction == TOP_TO_BOTTOM || page->priv->scan_direction == BOTTOM_TO_TOP)
+ return page->priv->width;
+ else
+ return page->priv->n_rows;
}
@@ -538,7 +361,33 @@ gint
page_get_height (Page *page)
{
g_return_val_if_fail (page != NULL, 0);
- return gdk_pixbuf_get_height (page->priv->image);
+
+ if (page->priv->scan_direction == TOP_TO_BOTTOM || page->priv->scan_direction == BOTTOM_TO_TOP)
+ return page->priv->n_rows;
+ else
+ return page->priv->width;
+}
+
+
+gint
+page_get_depth (Page *page)
+{
+ g_return_val_if_fail (page != NULL, 0);
+ return page->priv->depth;
+}
+
+
+gint page_get_n_channels (Page *page)
+{
+ g_return_val_if_fail (page != NULL, 0);
+ return page->priv->n_channels;
+}
+
+
+gint page_get_rowstride (Page *page)
+{
+ g_return_val_if_fail (page != NULL, 0);
+ return page->priv->rowstride;
}
@@ -547,10 +396,7 @@ page_get_scan_width (Page *page)
{
g_return_val_if_fail (page != NULL, 0);
- if (page->priv->orientation == TOP_TO_BOTTOM || page->priv->orientation == BOTTOM_TO_TOP)
- return gdk_pixbuf_get_width (page->priv->image);
- else
- return gdk_pixbuf_get_height (page->priv->image);
+ return page->priv->width;
}
@@ -559,10 +405,7 @@ page_get_scan_height (Page *page)
{
g_return_val_if_fail (page != NULL, 0);
- if (page->priv->orientation == TOP_TO_BOTTOM || page->priv->orientation == BOTTOM_TO_TOP)
- return gdk_pixbuf_get_height (page->priv->image);
- else
- return gdk_pixbuf_get_width (page->priv->image);
+ return page->priv->n_rows;
}
@@ -779,44 +622,136 @@ page_get_named_crop (Page *page)
}
-GdkPixbuf *
-page_get_image (Page *page)
+const guchar *
+page_get_pixels (Page *page)
{
g_return_val_if_fail (page != NULL, NULL);
- return g_object_ref (page->priv->image);
+ return page->priv->pixels;
+}
+
+
+// FIXME: Copied from page-view, should be shared code
+static guchar
+get_sample (const guchar *line, gint x, gint depth, gint n_channels, gint channel)
+{
+ // FIXME
+ return 0xFF;
+}
+
+
+// FIXME: Copied from page-view, should be shared code
+static void
+get_pixel (Page *page, gint x, gint y, guchar *pixel)
+{
+ 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, n_channels, 0);
+ pixel[0] = get_sample (line, x, depth, n_channels, 1);
+ pixel[0] = get_sample (line, x, depth, n_channels, 2);
}
GdkPixbuf *
-page_get_cropped_image (Page *page)
+page_get_image (Page *page, gboolean apply_crop)
{
- GdkPixbuf *image, *cropped_image;
- gint x, y, w, h, pw, ph;
+ GdkPixbuf *image;
+ gint x, y, l, r, t, b;
+
+ if (apply_crop && page->priv->has_crop) {
+ l = page->priv->crop_x;
+ r = l + page->priv->crop_width;
+ t = page->priv->crop_y;
+ b = l + page->priv->crop_height;
+
+ if (l < 0)
+ l = 0;
+ if (r > page_get_width (page))
+ r = page_get_width (page);
+ if (t < 0)
+ t = 0;
+ if (b > page_get_height (page))
+ b = page_get_height (page);
+ }
+ else {
+ l = 0;
+ r = page_get_width (page);
+ t = 0;
+ b = page_get_height (page);
+ }
- g_return_val_if_fail (page != NULL, NULL);
+ image = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, r - l, b - t);
- image = page_get_image (page);
+ for (y = t; y < b; y++) {
+ guchar *line = gdk_pixbuf_get_pixels (image) + gdk_pixbuf_get_rowstride (image) * (y - t);
+ for (x = l; x < r; x++) {
+ guchar *pixel;
- if (!page->priv->has_crop)
- return image;
-
- x = page->priv->crop_x;
- y = page->priv->crop_y;
- w = page->priv->crop_width;
- h = page->priv->crop_height;
- pw = gdk_pixbuf_get_width (image);
- ph = gdk_pixbuf_get_height (image);
-
- /* Trim crop */
- if (x + w >= pw)
- w = pw - x;
- if (y + h >= ph)
- h = ph - y;
-
- cropped_image = gdk_pixbuf_new_subpixbuf (image, x, y, w, h);
- g_object_unref (image);
+ pixel = line + (x - l) * 3;
+ get_pixel (page, x, y, pixel);
+ }
+ }
- return cropped_image;
+ return image;
}
@@ -864,7 +799,7 @@ page_save (Page *page, const gchar *type, GFile *file, GError **error)
if (!stream)
return FALSE;
- image = page_get_cropped_image (page);
+ image = page_get_image (page, TRUE);
if (page->priv->color_profile != NULL)
icc_profile_data = get_icc_data_encoded (page->priv->color_profile);
@@ -910,9 +845,7 @@ static void
page_finalize (GObject *object)
{
Page *page = PAGE (object);
- if (page->priv->image)
- g_object_unref (page->priv->image);
- page->priv->image = NULL;
+ g_free (page->priv->pixels);
G_OBJECT_CLASS (page_parent_class)->finalize (object);
}
@@ -924,11 +857,11 @@ page_class_init (PageClass *klass)
object_class->finalize = page_finalize;
- signals[IMAGE_CHANGED] =
- g_signal_new ("image-changed",
+ signals[PIXELS_CHANGED] =
+ g_signal_new ("pixels-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PageClass, image_changed),
+ G_STRUCT_OFFSET (PageClass, pixels_changed),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
@@ -948,11 +881,11 @@ page_class_init (PageClass *klass)
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
- signals[ORIENTATION_CHANGED] =
- g_signal_new ("orientation-changed",
+ signals[SCAN_DIRECTION_CHANGED] =
+ g_signal_new ("scan-direction-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PageClass, orientation_changed),
+ G_STRUCT_OFFSET (PageClass, scan_direction_changed),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
@@ -973,5 +906,5 @@ static void
page_init (Page *page)
{
page->priv = G_TYPE_INSTANCE_GET_PRIVATE (page, PAGE_TYPE, PagePrivate);
- page->priv->orientation = TOP_TO_BOTTOM;
+ page->priv->scan_direction = TOP_TO_BOTTOM;
}
diff --git a/src/page.h b/src/page.h
index 25e3018..993029f 100644
--- a/src/page.h
+++ b/src/page.h
@@ -28,7 +28,7 @@ typedef enum
LEFT_TO_RIGHT,
BOTTOM_TO_TOP,
RIGHT_TO_LEFT
-} Orientation;
+} ScanDirection;
typedef struct PagePrivate PagePrivate;
@@ -43,31 +43,38 @@ typedef struct
{
GObjectClass parent_class;
- void (*image_changed) (Page *page);
+ void (*pixels_changed) (Page *page);
void (*size_changed) (Page *page);
void (*scan_line_changed) (Page *page);
- void (*orientation_changed) (Page *page);
+ void (*scan_direction_changed) (Page *page);
void (*crop_changed) (Page *page);
} PageClass;
GType page_get_type (void);
-Page *page_new (void);
+Page *page_new (gint width, gint height, gint dpi, ScanDirection scan_direction);
-// FIXME: Should be part of page_new
-void page_setup (Page *page, gint width, gint height, gint dpi, Orientation orientation);
-
-void page_set_scan_area (Page *page, gint width, gint rows, gint dpi);
+void page_set_page_info (Page *page, ScanPageInfo *info);
gint page_get_dpi (Page *page);
-gboolean page_is_landscape (Page *page);
-
gint page_get_width (Page *page);
gint page_get_height (Page *page);
+gint page_get_depth (Page *page);
+
+gint page_get_n_channels (Page *page);
+
+gint page_get_rowstride (Page *page);
+
+const guchar *page_get_pixels (Page *page);
+
+guchar *page_get_pixel (Page *page, gint x, gint y);
+
+gboolean page_is_landscape (Page *page);
+
gint page_get_scan_width (Page *page);
gint page_get_scan_height (Page *page);
@@ -84,17 +91,13 @@ gboolean page_has_data (Page *page);
gboolean page_is_color (Page *page);
-gint page_get_depth (Page *page);
-
gint page_get_scan_line (Page *page);
void page_parse_scan_line (Page *page, ScanLine *line);
void page_finish (Page *page);
-Orientation page_get_orientation (Page *page);
-
-void page_set_orientation (Page *page, Orientation orientation);
+ScanDirection page_get_scan_direction (Page *page);
void page_rotate_left (Page *page);
@@ -116,9 +119,7 @@ void page_get_crop (Page *page, gint *x, gint *y, gint *width, gint *height);
gchar *page_get_named_crop (Page *page);
-GdkPixbuf *page_get_image (Page *page);
-
-GdkPixbuf *page_get_cropped_image (Page *page);
+GdkPixbuf *page_get_image (Page *page, gboolean apply_crop);
gboolean page_save (Page *page, const gchar *type, GFile *file, GError **error);
diff --git a/src/scanner.c b/src/scanner.c
index 8383f9f..f4eb08f 100644
--- a/src/scanner.c
+++ b/src/scanner.c
@@ -1160,7 +1160,7 @@ do_get_option (Scanner *scanner)
}
else if (strcmp (option->name, "three-pass") == 0) {
set_bool_option (scanner->priv->handle, option, option_index, FALSE, NULL);
- }
+ }
else if (strcmp (option->name, "test-picture") == 0) {
set_string_option (scanner->priv->handle, option, option_index, "Color pattern", NULL);
}
@@ -1255,6 +1255,11 @@ do_get_parameters (Scanner *scanner)
info->width = scanner->priv->parameters.pixels_per_line;
info->height = scanner->priv->parameters.lines;
info->depth = scanner->priv->parameters.depth;
+ /* Reduce bit depth if requested lower than received */
+ // FIXME: This a hack and only works on 8 bit gray to 2 bit gray
+ if (scanner->priv->parameters.depth == 8 && scanner->priv->parameters.format == SANE_FRAME_GRAY && job->depth == 2 && job->scan_mode == SCAN_MODE_GRAY)
+ info->depth = job->depth;
+ info->n_channels = scanner->priv->parameters.format == SANE_FRAME_GRAY ? 1 : 3;
info->dpi = job->dpi; // FIXME: This is the requested DPI, not the actual DPI
info->device = g_strdup (scanner->priv->current_device);
@@ -1308,10 +1313,13 @@ do_complete_page (Scanner *scanner)
static void
do_read (Scanner *scanner)
{
+ ScanJob *job;
SANE_Status status;
SANE_Int n_to_read, n_read;
gboolean full_read = FALSE;
+ job = (ScanJob *) scanner->priv->job_queue->data;
+
/* Read as many bytes as we expect */
n_to_read = scanner->priv->buffer_size - scanner->priv->n_used;
@@ -1351,19 +1359,19 @@ do_read (Scanner *scanner)
line = g_malloc(sizeof(ScanLine));
switch (scanner->priv->parameters.format) {
case SANE_FRAME_GRAY:
- line->format = LINE_GRAY;
+ line->channel = 0;
break;
case SANE_FRAME_RGB:
- line->format = LINE_RGB;
+ line->channel = -1;
break;
case SANE_FRAME_RED:
- line->format = LINE_RED;
+ line->channel = 0;
break;
case SANE_FRAME_GREEN:
- line->format = LINE_GREEN;
+ line->channel = 1;
break;
case SANE_FRAME_BLUE:
- line->format = LINE_BLUE;
+ line->channel = 2;
break;
}
line->width = scanner->priv->parameters.pixels_per_line;
@@ -1387,6 +1395,56 @@ do_read (Scanner *scanner)
scanner->priv->buffer[i] = line->data[i + (line->n_lines * line->data_length)];
scanner->priv->n_used++;
}
+
+ /* Reduce bit depth if requested lower than received */
+ // FIXME: This a hack and only works on 8 bit gray to 2 bit gray
+ if (scanner->priv->parameters.depth == 8 && scanner->priv->parameters.format == SANE_FRAME_GRAY &&
+ job->depth == 2 && job->scan_mode == SCAN_MODE_GRAY) {
+ gint block_shift = 6;
+ guchar block = 0;
+ guchar *write_ptr = line->data;
+
+ for (i = 0; i < line->n_lines; i++) {
+ guchar *in_line = line->data + i * line->data_length;
+ gint x;
+
+ for (x = 0; x < line->width; x++) {
+ guchar *p = in_line + x;
+ guchar sample;
+
+ if (p[0] >= 192)
+ sample = 3;
+ else if (p[0] >= 128)
+ sample = 2;
+ else if (p[0] >= 64)
+ sample = 1;
+ else
+ sample = 0;
+
+ block |= sample << block_shift;
+ if (block_shift == 0) {
+ *write_ptr = block;
+ write_ptr++;
+ block = 0;
+ block_shift = 6;
+ }
+ else {
+ block_shift -= 2;
+ }
+ }
+
+ /* Finish each line on a byte boundary */
+ if (block_shift != 6) {
+ *write_ptr = block;
+ write_ptr++;
+ block = 0;
+ block_shift = 6;
+ }
+ }
+
+ line->data_length = (line->width * 2 + 7) / 8;
+ }
+
emit_signal (scanner, GOT_LINE, line);
}
}
diff --git a/src/scanner.h b/src/scanner.h
index 5acdc84..72a4ffd 100644
--- a/src/scanner.h
+++ b/src/scanner.h
@@ -33,6 +33,9 @@ typedef struct
/* Bit depth */
gint depth;
+ /* Number of colour channels */
+ gint n_channels;
+
/* Resolution */
gdouble dpi;
@@ -50,14 +53,9 @@ typedef struct
/* Width in pixels and format */
gint width, depth;
- enum
- {
- LINE_GRAY,
- LINE_RGB,
- LINE_RED,
- LINE_GREEN,
- LINE_BLUE
- } format;
+
+ /* Channel for this line or -1 for all channels */
+ gint channel;
/* Raw line data */
guchar *data;
diff --git a/src/simple-scan.c b/src/simple-scan.c
index 54236ae..bb7e036 100644
--- a/src/simple-scan.c
+++ b/src/simple-scan.c
@@ -86,7 +86,7 @@ static Page *
append_page ()
{
Page *page;
- Orientation orientation = TOP_TO_BOTTOM;
+ ScanDirection scan_direction = TOP_TO_BOTTOM;
gboolean do_crop = FALSE;
gchar *named_crop = NULL;
gint width = 100, height = 100, dpi = 100, cx, cy, cw, ch;
@@ -101,7 +101,7 @@ append_page ()
/* Copy info from previous page */
if (page) {
- orientation = page_get_orientation (page);
+ scan_direction = page_get_scan_direction (page);
width = page_get_width (page);
height = page_get_height (page);
dpi = page_get_dpi (page);
@@ -113,7 +113,7 @@ append_page ()
}
}
- page = book_append_page (book, width, height, dpi, orientation);
+ page = book_append_page (book, width, height, dpi, scan_direction);
if (do_crop) {
if (named_crop) {
page_set_named_crop (page, named_crop);
@@ -205,7 +205,7 @@ scanner_page_info_cb (Scanner *scanner, ScanPageInfo *info)
/* Add a new page */
page = append_page ();
- page_set_scan_area (page, info->width, info->height, info->dpi);
+ page_set_page_info (page, info);
/* Get ICC color profile */
/* FIXME: The ICC profile could change */
diff --git a/src/ui.c b/src/ui.c
index 0d23d25..2bea246 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -70,7 +70,7 @@ struct SimpleScanPrivate
BookView *book_view;
gboolean updating_page_menu;
gint default_page_width, default_page_height, default_page_dpi;
- Orientation default_page_orientation;
+ ScanDirection default_page_scan_direction;
gchar *document_hint;
@@ -86,8 +86,8 @@ G_DEFINE_TYPE (SimpleScan, ui, G_TYPE_OBJECT);
static struct
{
const gchar *key;
- Orientation orientation;
-} orientation_keys[] =
+ ScanDirection scan_direction;
+} scan_direction_keys[] =
{
{ "top-to-bottom", TOP_TO_BOTTOM },
{ "bottom-to-top", BOTTOM_TO_TOP },
@@ -326,7 +326,7 @@ add_default_page (SimpleScan *ui)
ui->priv->default_page_width,
ui->priv->default_page_height,
ui->priv->default_page_dpi,
- ui->priv->default_page_orientation);
+ ui->priv->default_page_scan_direction);
book_view_select_page (ui->priv->book_view, page);
}
@@ -742,11 +742,12 @@ get_scan_options (SimpleScan *ui)
struct {
const gchar *name;
ScanMode mode;
+ gint depth;
} profiles[] =
{
- { "text", SCAN_MODE_LINEART },
- { "photo", SCAN_MODE_COLOR },
- { NULL, SCAN_MODE_COLOR }
+ { "text", SCAN_MODE_GRAY, 2 },
+ { "photo", SCAN_MODE_COLOR, 8 },
+ { NULL, SCAN_MODE_COLOR, 8 }
};
gint i;
ScanOptions *options;
@@ -757,7 +758,7 @@ get_scan_options (SimpleScan *ui)
options = g_malloc0 (sizeof (ScanOptions));
options->scan_mode = profiles[i].mode;
- options->depth = 8;
+ options->depth = profiles[i].depth;
if (options->scan_mode == SCAN_MODE_COLOR)
options->dpi = get_photo_dpi (ui);
else
@@ -1190,7 +1191,7 @@ draw_page (GtkPrintOperation *operation,
gtk_print_context_get_dpi_x (print_context) / page_get_dpi (page),
gtk_print_context_get_dpi_y (print_context) / page_get_dpi (page));
- image = page_get_cropped_image (page);
+ image = page_get_image (page, TRUE);
gdk_cairo_set_source_pixbuf (context, image, 0, 0);
cairo_paint (context);
@@ -1324,9 +1325,9 @@ quit (SimpleScan *ui)
gconf_client_set_int(ui->priv->client, GCONF_DIR "/window_height", ui->priv->window_height, NULL);
gconf_client_set_bool(ui->priv->client, GCONF_DIR "/window_is_maximized", ui->priv->window_is_maximized, NULL);
- for (i = 0; orientation_keys[i].key != NULL && orientation_keys[i].orientation != ui->priv->default_page_orientation; i++);
- if (orientation_keys[i].key != NULL)
- gconf_client_set_string(ui->priv->client, GCONF_DIR "/scan_direction", orientation_keys[i].key, NULL);
+ for (i = 0; scan_direction_keys[i].key != NULL && scan_direction_keys[i].scan_direction != ui->priv->default_page_scan_direction; i++);
+ if (scan_direction_keys[i].key != NULL)
+ gconf_client_set_string(ui->priv->client, GCONF_DIR "/scan_direction", scan_direction_keys[i].key, NULL);
gconf_client_set_int (ui->priv->client, GCONF_DIR "/page_width", ui->priv->default_page_width, NULL);
gconf_client_set_int (ui->priv->client, GCONF_DIR "/page_height", ui->priv->default_page_height, NULL);
gconf_client_set_int (ui->priv->client, GCONF_DIR "/page_dpi", ui->priv->default_page_dpi, NULL);
@@ -1408,9 +1409,9 @@ page_size_changed_cb (Page *page, SimpleScan *ui)
static void
-page_orientation_changed_cb (Page *page, SimpleScan *ui)
+page_scan_direction_changed_cb (Page *page, SimpleScan *ui)
{
- ui->priv->default_page_orientation = page_get_orientation (page);
+ ui->priv->default_page_scan_direction = page_get_scan_direction (page);
}
@@ -1420,9 +1421,9 @@ page_added_cb (Book *book, Page *page, SimpleScan *ui)
ui->priv->default_page_width = page_get_width (page);
ui->priv->default_page_height = page_get_height (page);
ui->priv->default_page_dpi = page_get_dpi (page);
- ui->priv->default_page_orientation = page_get_orientation (page);
+ ui->priv->default_page_scan_direction = page_get_scan_direction (page);
g_signal_connect (page, "size-changed", G_CALLBACK (page_size_changed_cb), ui);
- g_signal_connect (page, "orientation-changed", G_CALLBACK (page_orientation_changed_cb), ui);
+ g_signal_connect (page, "scan-direction-changed", G_CALLBACK (page_scan_direction_changed_cb), ui);
}
@@ -1651,12 +1652,12 @@ ui_load (SimpleScan *ui)
/* Find default page details */
scan_direction = gconf_client_get_string(ui->priv->client, GCONF_DIR "/scan_direction", NULL);
- ui->priv->default_page_orientation = TOP_TO_BOTTOM;
+ ui->priv->default_page_scan_direction = TOP_TO_BOTTOM;
if (scan_direction) {
gint i;
- for (i = 0; orientation_keys[i].key != NULL && strcmp (orientation_keys[i].key, scan_direction) != 0; i++);
- if (orientation_keys[i].key != NULL)
- ui->priv->default_page_orientation = orientation_keys[i].orientation;
+ for (i = 0; scan_direction_keys[i].key != NULL && strcmp (scan_direction_keys[i].key, scan_direction) != 0; i++);
+ if (scan_direction_keys[i].key != NULL)
+ ui->priv->default_page_scan_direction = scan_direction_keys[i].scan_direction;
g_free (scan_direction);
}
ui->priv->default_page_width = gconf_client_get_int (ui->priv->client, GCONF_DIR "/page_width", NULL);