kopia lustrzana https://gitlab.com/sane-project/frontends
preview: use GPixBuf and and lib function to do resize
Better to use stock functions to do image preview resizing.preview_fixes
rodzic
b330f79c18
commit
8b7d063442
314
src/preview.c
314
src/preview.c
|
@ -156,14 +156,24 @@ screen_size_get_dimensions (gint *width, gint *height)
|
|||
}
|
||||
|
||||
static void
|
||||
draw_rect(cairo_t *cr, double coord[4])
|
||||
draw_selection (Preview *p, cairo_t *cr)
|
||||
{
|
||||
if (!p->selection.active)
|
||||
return;
|
||||
|
||||
double *coord = p->selection.coord;
|
||||
double x, y, w, h;
|
||||
|
||||
/*
|
||||
* Make sure that we account for a selection dragged in reverse
|
||||
* from what we expect, e.g leftwards or upwards or both.
|
||||
*
|
||||
*/
|
||||
x = coord[0];
|
||||
y = coord[1];
|
||||
w = coord[2] - x;
|
||||
h = coord[3] - y;
|
||||
|
||||
if (w < 0)
|
||||
{
|
||||
x = coord[2];
|
||||
|
@ -174,32 +184,30 @@ draw_rect(cairo_t *cr, double coord[4])
|
|||
y = coord[3];
|
||||
h = -h;
|
||||
}
|
||||
cairo_set_line_width(cr, 1.5);
|
||||
const double dashes1[2] = {4.0, 4.0};
|
||||
|
||||
/*
|
||||
* Draw selection rectangle. One black dash, then another, filling in the
|
||||
* black dash gaps with white. This means that regardless of the picture, the
|
||||
* dash pattern is visible.
|
||||
*
|
||||
*/
|
||||
const double dashes1[2] = { 4.0, 4.0 };
|
||||
const double dashes2[4] = { 0.0, 4.0, 4.0, 0.0 };
|
||||
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_set_line_width (cr, 1.5);
|
||||
|
||||
// Black dashes.
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
cairo_set_dash(cr, dashes1, sizeof(dashes1)/sizeof(dashes1[0]), 0);
|
||||
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
|
||||
cairo_rectangle(cr, x, y, w + 1, h + 1);
|
||||
cairo_stroke(cr);
|
||||
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
|
||||
const double dashes2[4] = {0.0, 4.0, 4.0, 0.0};
|
||||
cairo_set_dash(cr, dashes2, sizeof(dashes2)/sizeof(dashes2[0]), 0);
|
||||
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
|
||||
cairo_rectangle(cr, x, y, w + 1, h + 1);
|
||||
cairo_stroke(cr);
|
||||
}
|
||||
cairo_set_dash (cr, dashes1, sizeof(dashes1) / sizeof(dashes1[0]), 0);
|
||||
cairo_rectangle (cr, x, y, w + 1, h + 1);
|
||||
cairo_stroke (cr);
|
||||
|
||||
static void
|
||||
draw_selection (Preview * p, cairo_t *cr)
|
||||
{
|
||||
if (p->previous_selection.active)
|
||||
draw_rect (cr, p->previous_selection.coord);
|
||||
|
||||
if (p->selection.active)
|
||||
draw_rect (cr, p->selection.coord);
|
||||
|
||||
p->previous_selection = p->selection;
|
||||
// White dashes.
|
||||
cairo_set_dash (cr, dashes2, sizeof(dashes2) / sizeof(dashes2[0]), 0);
|
||||
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
|
||||
cairo_rectangle (cr, x, y, w + 1, h + 1);
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -211,8 +219,6 @@ update_selection (Preview * p)
|
|||
SANE_Word val;
|
||||
int i, optnum;
|
||||
|
||||
p->previous_selection = p->selection;
|
||||
|
||||
memcpy (dev_selection, p->surface, sizeof (dev_selection));
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
|
@ -288,62 +294,62 @@ get_image_scale (Preview * p, float *xscalep, float *yscalep)
|
|||
static void
|
||||
paint_image (Preview * p)
|
||||
{
|
||||
float xscale, yscale, src_x, src_y;
|
||||
int dst_x, dst_y, height, x, y, src_offset;
|
||||
gint gwidth, gheight;
|
||||
|
||||
gwidth = p->preview_width;
|
||||
gheight = p->preview_height;
|
||||
|
||||
get_image_scale (p, &xscale, &yscale);
|
||||
|
||||
if (p->preview_row == NULL)
|
||||
p->preview_row = malloc (3 * gwidth);
|
||||
else
|
||||
p->preview_row = realloc (p->preview_row, 3 * gwidth);
|
||||
memset (p->preview_row, 0xff, 3 * gwidth);
|
||||
if (p->preview_data == NULL)
|
||||
p->preview_data = malloc (3 * gwidth * gheight);
|
||||
else
|
||||
p->preview_data = realloc (p->preview_data, 3 * gwidth * gheight);
|
||||
memset (p->preview_data, 0xff, 3 * gwidth * gheight);
|
||||
gtk_widget_queue_draw (p->window);
|
||||
|
||||
/* don't draw last line unless it's complete: */
|
||||
height = p->image_y;
|
||||
if (p->image_x == 0 && height < p->image_height)
|
||||
++height;
|
||||
|
||||
/* for now, use simple nearest-neighbor interpolation: */
|
||||
src_offset = 0;
|
||||
src_x = src_y = 0.0;
|
||||
for (dst_y = 0; dst_y < gheight; ++dst_y)
|
||||
{
|
||||
y = (int) (src_y + 0.5);
|
||||
if (y >= height)
|
||||
break;
|
||||
src_offset = y * 3 * p->image_width;
|
||||
|
||||
if (p->image_data)
|
||||
for (dst_x = 0; dst_x < gwidth; ++dst_x)
|
||||
{
|
||||
x = (int) (src_x + 0.5);
|
||||
if (x >= p->image_width)
|
||||
break;
|
||||
|
||||
p->preview_row[3 * dst_x + 0] =
|
||||
p->image_data[src_offset + 3 * x + 0];
|
||||
p->preview_row[3 * dst_x + 1] =
|
||||
p->image_data[src_offset + 3 * x + 1];
|
||||
p->preview_row[3 * dst_x + 2] =
|
||||
p->image_data[src_offset + 3 * x + 2];
|
||||
src_x += xscale;
|
||||
}
|
||||
memcpy(p->preview_data + (size_t) dst_y * (size_t) gwidth * 3, p->preview_row, (size_t) gwidth * 3);
|
||||
src_x = 0.0;
|
||||
src_y += yscale;
|
||||
}
|
||||
gtk_widget_queue_draw (p->window);
|
||||
// float xscale, yscale, src_x, src_y;
|
||||
// int dst_x, dst_y, height, x, y, src_offset;
|
||||
// gint gwidth, gheight;
|
||||
//
|
||||
// gwidth = p->preview_width;
|
||||
// gheight = p->preview_height;
|
||||
//
|
||||
// get_image_scale (p, &xscale, &yscale);
|
||||
//
|
||||
// if (p->preview_row == NULL)
|
||||
// p->preview_row = malloc (3 * gwidth);
|
||||
// else
|
||||
// p->preview_row = realloc (p->preview_row, 3 * gwidth);
|
||||
// memset (p->preview_row, 0xff, 3 * gwidth);
|
||||
//// if (p->preview_data == NULL)
|
||||
//// p->preview_data = malloc (3 * gwidth * gheight);
|
||||
//// else
|
||||
//// p->preview_data = realloc (p->preview_data, 3 * gwidth * gheight);
|
||||
//// memset (p->preview_data, 0xff, 3 * gwidth * gheight);
|
||||
// gtk_widget_queue_draw (p->window);
|
||||
//
|
||||
// /* don't draw last line unless it's complete: */
|
||||
// height = p->image_y;
|
||||
// if (p->image_x == 0 && height < p->image_height)
|
||||
// ++height;
|
||||
//
|
||||
// /* for now, use simple nearest-neighbor interpolation: */
|
||||
// src_offset = 0;
|
||||
// src_x = src_y = 0.0;
|
||||
// for (dst_y = 0; dst_y < gheight; ++dst_y)
|
||||
// {
|
||||
// y = (int) (src_y + 0.5);
|
||||
// if (y >= height)
|
||||
// break;
|
||||
// src_offset = y * 3 * p->image_width;
|
||||
//
|
||||
// if (p->image_data)
|
||||
// for (dst_x = 0; dst_x < gwidth; ++dst_x)
|
||||
// {
|
||||
// x = (int) (src_x + 0.5);
|
||||
// if (x >= p->image_width)
|
||||
// break;
|
||||
//
|
||||
// p->preview_row[3 * dst_x + 0] =
|
||||
// p->image_data[src_offset + 3 * x + 0];
|
||||
// p->preview_row[3 * dst_x + 1] =
|
||||
// p->image_data[src_offset + 3 * x + 1];
|
||||
// p->preview_row[3 * dst_x + 2] =
|
||||
// p->image_data[src_offset + 3 * x + 2];
|
||||
// src_x += xscale;
|
||||
// }
|
||||
// memcpy(p->preview_data + (size_t) dst_y * (size_t) gwidth * 3, p->preview_row, (size_t) gwidth * 3);
|
||||
// src_x = 0.0;
|
||||
// src_y += yscale;
|
||||
// }
|
||||
// gtk_widget_queue_draw (p->window);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -376,8 +382,8 @@ display_image (Preview * p)
|
|||
p->image_data = realloc (p->image_data,
|
||||
3 * p->image_width * p->image_height);
|
||||
assert (p->image_data);
|
||||
p->preview_data = realloc (p->preview_data,
|
||||
3 * p->image_width * p->image_height);
|
||||
// p->preview_data = realloc (p->preview_data,
|
||||
// 3 * p->image_width * p->image_height);
|
||||
}
|
||||
display_partial_image (p);
|
||||
scan_done (p);
|
||||
|
@ -608,7 +614,7 @@ increment_image_y (Preview * p)
|
|||
extra_size = 3 * 32 * p->image_width;
|
||||
p->image_height += 32;
|
||||
p->image_data = realloc (p->image_data, offset + extra_size);
|
||||
p->preview_data = realloc (p->preview_data, offset + extra_size);
|
||||
// p->preview_data = realloc (p->preview_data, offset + extra_size);
|
||||
if (!p->image_data)
|
||||
{
|
||||
snprintf (buf, sizeof (buf),
|
||||
|
@ -619,7 +625,10 @@ increment_image_y (Preview * p)
|
|||
return -1;
|
||||
}
|
||||
memset (p->image_data + offset, 0xff, extra_size);
|
||||
memset (p->preview_data + offset, 0xff, extra_size);
|
||||
// memset (p->preview_data + offset, 0xff, extra_size);
|
||||
|
||||
g_object_unref(p->image_pixbuf);
|
||||
p->image_pixbuf = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -949,12 +958,16 @@ scan_start (Preview * p)
|
|||
gsg_set_sensitivity (p->dialog, FALSE);
|
||||
// gtk_widget_set_sensitive (p->dialog->window->parent->parent->parent, FALSE);
|
||||
|
||||
if (p->preview_data == NULL)
|
||||
p->preview_data = malloc (p->image_width * p->image_height * 3);
|
||||
else
|
||||
p->preview_data = realloc (p->preview_data, 3 * p->image_width * p->image_height);
|
||||
// if (p->preview_data == NULL)
|
||||
// p->preview_data = malloc (p->image_width * p->image_height * 3);
|
||||
// else
|
||||
// p->preview_data = realloc (p->preview_data, 3 * p->image_width * p->image_height);
|
||||
/* clear old preview: */
|
||||
memset (p->preview_data, 0xff, 3 * p->image_width * p->image_height);
|
||||
// memset (p->preview_data, 0xff, 3 * p->image_width * p->image_height);
|
||||
|
||||
g_object_unref(p->image_pixbuf);
|
||||
p->image_pixbuf = NULL;
|
||||
|
||||
gtk_widget_queue_draw (p->window);
|
||||
|
||||
if (p->input_tag >= 0)
|
||||
|
@ -1040,6 +1053,12 @@ scan_start (Preview * p)
|
|||
if (!p->image_data || p->params.pixels_per_line != p->image_width
|
||||
|| (p->params.lines >= 0 && p->params.lines != p->image_height))
|
||||
{
|
||||
if (p->image_pixbuf)
|
||||
{
|
||||
g_object_unref(p->image_pixbuf);
|
||||
p->image_pixbuf = NULL;
|
||||
}
|
||||
|
||||
/* image size changed */
|
||||
if (p->image_data)
|
||||
free (p->image_data);
|
||||
|
@ -1050,7 +1069,7 @@ scan_start (Preview * p)
|
|||
p->image_height = 32; /* may have to adjust as we go... */
|
||||
|
||||
p->image_data = malloc (p->image_width * p->image_height * 3);
|
||||
p->preview_data = malloc (p->preview_width * p->image_height * 3);
|
||||
// p->preview_data = malloc (p->preview_width * p->image_height * 3);
|
||||
if (!p->image_data)
|
||||
{
|
||||
snprintf (buf, sizeof (buf),
|
||||
|
@ -1064,7 +1083,7 @@ scan_start (Preview * p)
|
|||
|
||||
if (p->selection.active)
|
||||
{
|
||||
p->previous_selection = p->selection;
|
||||
// p->previous_selection = p->selection;
|
||||
p->selection.active = FALSE;
|
||||
gtk_widget_queue_draw (p->window);
|
||||
}
|
||||
|
@ -1129,23 +1148,22 @@ restore_preview_image (Preview * p)
|
|||
int width, height;
|
||||
float psurface[4];
|
||||
size_t nread;
|
||||
FILE *in;
|
||||
FILE *in = NULL;
|
||||
|
||||
/* See whether there is a saved preview and load it if present: */
|
||||
|
||||
if (make_preview_image_path (p, sizeof (filename), filename) < 0)
|
||||
return;
|
||||
goto finish;
|
||||
|
||||
in = fopen (filename, "r");
|
||||
if (!in)
|
||||
return;
|
||||
goto finish;
|
||||
|
||||
/* Be careful about consuming too many bytes after the final newline
|
||||
(e.g., consider an image whose first image byte is 13 (`\r'). */
|
||||
if (fscanf (in, "P6\n# surface: %g %g %g %g %u %u\n%d %d\n255%*[\n]",
|
||||
psurface + 0, psurface + 1, psurface + 2, psurface + 3,
|
||||
&psurface_type, &psurface_unit, &width, &height) != 8)
|
||||
return;
|
||||
goto finish;
|
||||
|
||||
if (GROSSLY_DIFFERENT (psurface[0], p->surface[0])
|
||||
|| GROSSLY_DIFFERENT (psurface[1], p->surface[1])
|
||||
|
@ -1153,12 +1171,12 @@ restore_preview_image (Preview * p)
|
|||
|| GROSSLY_DIFFERENT (psurface[3], p->surface[3])
|
||||
|| psurface_type != p->surface_type || psurface_unit != p->surface_unit)
|
||||
/* ignore preview image that was acquired for/with a different surface */
|
||||
return;
|
||||
goto finish;
|
||||
|
||||
p->image_width = width;
|
||||
p->image_height = height;
|
||||
if ((width == 0) || (height == 0))
|
||||
return;
|
||||
goto finish;
|
||||
|
||||
int data_size = 3 * width * height;
|
||||
|
||||
|
@ -1166,25 +1184,21 @@ restore_preview_image (Preview * p)
|
|||
if ((data_size / width) / height != 3)
|
||||
{
|
||||
// overflow occurred. Ignore the image. The dimensions are probably corrupted.
|
||||
return;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
p->image_data = malloc (data_size);
|
||||
if (!p->image_data)
|
||||
return;
|
||||
|
||||
p->preview_data = malloc (data_size);
|
||||
if (!p->preview_data)
|
||||
{
|
||||
free(p->image_data);
|
||||
p->image_data = NULL;
|
||||
return;
|
||||
}
|
||||
goto finish;
|
||||
|
||||
nread = fread (p->image_data, 3, width * height, in);
|
||||
|
||||
p->image_y = nread / width;
|
||||
p->image_x = nread % width;
|
||||
|
||||
finish:
|
||||
if (in)
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
/* This is executed _after_ the gtkpreview's expose routine. */
|
||||
|
@ -1193,13 +1207,40 @@ expose_handler (GtkWidget * window, cairo_t *cr, gpointer data)
|
|||
{
|
||||
Preview *p = data;
|
||||
|
||||
if (p->preview_data == NULL) return FALSE;
|
||||
if (p->image_data == NULL)
|
||||
return FALSE;
|
||||
|
||||
GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(p->preview_data, GDK_COLORSPACE_RGB, FALSE, 8, p->preview_width,
|
||||
p->preview_height, p->preview_width * 3, NULL/*preview_pixbuf_data_destroy*/, NULL);
|
||||
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
|
||||
if (p->image_pixbuf == NULL)
|
||||
{
|
||||
p->image_pixbuf = gdk_pixbuf_new_from_data (p->image_data,
|
||||
GDK_COLORSPACE_RGB, FALSE, 8,
|
||||
p->image_width,
|
||||
p->image_height,
|
||||
p->image_width * 3, NULL,
|
||||
NULL);
|
||||
|
||||
}
|
||||
|
||||
gint width = gtk_widget_get_allocated_width (window);
|
||||
gint height = gtk_widget_get_allocated_height (window);
|
||||
|
||||
gint img_width = gdk_pixbuf_get_width (p->image_pixbuf);
|
||||
gint img_height = gdk_pixbuf_get_height (p->image_pixbuf);
|
||||
double scale = MIN((double )width / img_width, (double )height / img_height);
|
||||
gint scaled_width = img_width * scale;
|
||||
gint scaled_height = img_height * scale;
|
||||
|
||||
/*
|
||||
* TODO: we could store this scaled pixbuf in the Preview and only regenerate it
|
||||
* when the scaled image dimensions change. [RL]
|
||||
*/
|
||||
GdkPixbuf *scaled = gdk_pixbuf_scale_simple (p->image_pixbuf, scaled_width,
|
||||
scaled_height,
|
||||
GDK_INTERP_BILINEAR);
|
||||
|
||||
gdk_cairo_set_source_pixbuf (cr, scaled, 0, 0);
|
||||
cairo_paint(cr);
|
||||
g_object_unref(pixbuf);
|
||||
g_object_unref(scaled);
|
||||
|
||||
if (p->selection_drag == FALSE)
|
||||
update_selection (p);
|
||||
|
@ -1317,10 +1358,10 @@ preview_new (GSGDialog * dialog)
|
|||
p->surface_unit = SANE_UNIT_MM;
|
||||
p->input_tag = -1;
|
||||
p->image_data = NULL;
|
||||
p->preview_data = NULL;
|
||||
p->preview_row = NULL;
|
||||
p->top = NULL;
|
||||
p->scanning = FALSE;
|
||||
p->image_pixbuf = NULL;
|
||||
|
||||
if (first_time)
|
||||
{
|
||||
|
@ -1470,9 +1511,11 @@ preview_update (Preview * p)
|
|||
if (surface_changed && p->image_data)
|
||||
{
|
||||
free (p->image_data);
|
||||
free (p->preview_data);
|
||||
|
||||
g_object_unref(p->image_pixbuf);
|
||||
p->image_pixbuf = NULL;
|
||||
|
||||
p->image_data = 0;
|
||||
p->preview_data = 0;
|
||||
p->image_width = 0;
|
||||
p->image_height = 0;
|
||||
}
|
||||
|
@ -1630,6 +1673,11 @@ preview_destroy (Preview * p)
|
|||
char filename[PATH_MAX];
|
||||
FILE *out;
|
||||
|
||||
if (!p)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (p->scanning)
|
||||
scan_done (p); /* don't save partial window */
|
||||
else if (preferences.preserve_preview && p->image_data
|
||||
|
@ -1648,15 +1696,29 @@ preview_destroy (Preview * p)
|
|||
fclose (out);
|
||||
}
|
||||
}
|
||||
|
||||
if (p->image_data)
|
||||
free (p->image_data);
|
||||
p->image_data = NULL;
|
||||
if (p->preview_data)
|
||||
free (p->preview_data);
|
||||
p->preview_data = NULL;
|
||||
{
|
||||
free (p->image_data);
|
||||
p->image_data = NULL;
|
||||
}
|
||||
|
||||
// if (p->preview_data)
|
||||
// free (p->preview_data);
|
||||
// p->preview_data = NULL;
|
||||
|
||||
if (p->image_pixbuf)
|
||||
{
|
||||
g_object_unref(p->image_pixbuf);
|
||||
p->image_pixbuf = NULL;
|
||||
}
|
||||
|
||||
if (p->preview_row)
|
||||
free (p->preview_row);
|
||||
p->preview_row = NULL;
|
||||
{
|
||||
free (p->preview_row);
|
||||
p->preview_row = NULL;
|
||||
}
|
||||
|
||||
if (p->top)
|
||||
gtk_widget_destroy (p->top);
|
||||
free (p);
|
||||
|
|
|
@ -62,7 +62,6 @@ typedef struct
|
|||
int image_width;
|
||||
int image_height;
|
||||
u_char *image_data; /* 3 * image_width * image_height bytes */
|
||||
u_char *preview_data; /* 3 * image_width * image_height bytes */
|
||||
|
||||
int selection_drag;
|
||||
struct
|
||||
|
@ -70,7 +69,7 @@ typedef struct
|
|||
int active;
|
||||
double coord[4];
|
||||
}
|
||||
selection, previous_selection;
|
||||
selection; // coords of selection box in the preview window
|
||||
|
||||
GtkWidget *top; /* top-level widget */
|
||||
GtkWidget *hruler;
|
||||
|
@ -80,8 +79,7 @@ typedef struct
|
|||
GtkWidget *cancel; /* the cancel button */
|
||||
GtkWidget *preview; /* the preview button */
|
||||
|
||||
cairo_surface_t *surface_cairo;
|
||||
gboolean drawable;
|
||||
GdkPixbuf *image_pixbuf;
|
||||
}
|
||||
Preview;
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue