[GRASS-SVN] r63582 - grass/trunk/lib/cairodriver
svn_grass at osgeo.org
svn_grass at osgeo.org
Thu Dec 18 04:27:09 PST 2014
Author: glynn
Date: 2014-12-18 04:27:09 -0800 (Thu, 18 Dec 2014)
New Revision: 63582
Modified:
grass/trunk/lib/cairodriver/raster.c
Log:
Make cairo driver rescale rasters rather than having cairo do it (ticket #2403)
Modified: grass/trunk/lib/cairodriver/raster.c
===================================================================
--- grass/trunk/lib/cairodriver/raster.c 2014-12-18 08:28:20 UTC (rev 63581)
+++ grass/trunk/lib/cairodriver/raster.c 2014-12-18 12:27:09 UTC (rev 63582)
@@ -12,21 +12,58 @@
\author Glynn Clements
*/
+#include <math.h>
#include "cairodriver.h"
#include <grass/glocale.h>
#define MAX_IMAGE_SIZE 32767
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
static int src_t, src_b, src_l, src_r, src_w, src_h;
-static double dst_t, dst_b, dst_l, dst_r, dst_w, dst_h;
+static int dst_t, dst_b, dst_l, dst_r, dst_w, dst_h;
+static int *trans;
+
static cairo_surface_t *src_surf;
static unsigned char *src_data;
-static int src_stride;
+static int src_stride, ca_row;
static int masked;
+static double scale(double k, int src_0, int src_1, int dst_0, int dst_1)
+{
+ return dst_0 + (double) (k - src_0) * (dst_1 - dst_0) / (src_1 - src_0);
+}
+
+static int scale_fwd_y(int sy)
+{
+ return (int)floor(scale(sy, src_t, src_b, dst_t, dst_b) + 0.5);
+}
+
+static int scale_rev_x(int dx)
+{
+ return (int)floor(scale(dx + 0.5, dst_l, dst_r, src_l, src_r));
+}
+
+static int next_row(int sy, int dy)
+{
+ sy++;
+
+ for (;;) {
+ int y = scale_fwd_y(sy);
+
+ if (y > dy)
+ return sy - 1;
+ sy++;
+ }
+}
+
/*!
\brief Start drawing raster
@@ -38,6 +75,7 @@
*/
void Cairo_begin_raster(int mask, int s[2][2], double d[2][2])
{
+ int i;
cairo_status_t status;
masked = mask;
@@ -50,36 +88,42 @@
src_w = src_r - src_l;
src_h = src_b - src_t;
- dst_l = d[0][0];
- dst_r = d[0][1];
- dst_t = d[1][0];
- dst_b = d[1][1];
+ dst_l = (int) floor(d[0][0] + 0.5);
+ dst_r = (int) floor(d[0][1] + 0.5);
+ dst_t = (int) floor(d[1][0] + 0.5);
+ dst_b = (int) floor(d[1][1] + 0.5);
dst_w = dst_r - dst_l;
dst_h = dst_b - dst_t;
G_debug(1, "Cairo_begin_raster(): masked=%d, src_lrtb=%d %d %d %d -> w/h=%d/%d, "
- "dst_lrtb=%f %f %f %f -> w/h=%f %f",
+ "dst_lrtb=%d %d %d %d -> w/h=%d %d",
masked, src_l, src_r, src_t, src_b, src_w, src_h,
dst_l, dst_r, dst_t, dst_b, dst_w, dst_h);
/* create source surface */
- src_surf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, src_w, src_h);
+ src_surf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, ca.width, ca.height);
status = cairo_surface_status(src_surf);
if (status != CAIRO_STATUS_SUCCESS)
G_fatal_error("%s - %s - size: %dx%d (cairo limit: %dx%d)",
_("Failed to create cairo surface"),
- cairo_status_to_string (status), src_w, src_h,
+ cairo_status_to_string (status), ca.width, ca.height,
MAX_IMAGE_SIZE, MAX_IMAGE_SIZE);
-
+
src_data = cairo_image_surface_get_data(src_surf);
src_stride = cairo_image_surface_get_stride(src_surf);
+ ca_row = 0;
+
+ /* allocate buffer for down-sampling data */
+ trans = G_malloc(dst_w * sizeof(int));
+ for (i = 0; i < dst_w; i++)
+ trans[i] = scale_rev_x(dst_l + i);
}
/*!
\brief Draw raster row
- \param n number of cell
+ \param n number of cells
\param row raster row (starting at 0)
\param red,grn,blu,nul red,green,blue and null value
@@ -89,27 +133,45 @@
const unsigned char *red, const unsigned char *grn,
const unsigned char *blu, const unsigned char *nul)
{
- int i;
- unsigned int *dst;
+ int d_y0 = scale_fwd_y(row + 0);
+ int d_y1 = scale_fwd_y(row + 1);
+ int d_rows = d_y1 - d_y0;
+ int x0 = MAX(0 - dst_l, 0);
+ int x1 = MIN(ca.width - dst_l, dst_w);
+ int y0 = MAX(0 - d_y0, 0);
+ int y1 = MIN(ca.height - d_y0, d_rows);
+ int x, y;
- dst = (unsigned int *)(src_data + (row - src_t) * src_stride);
+ if (y1 <= y0)
+ return next_row(row, d_y1);
- G_debug(3, "Cairo_raster(): n=%d row=%d", n, row);
+ G_debug(3, "Cairo_raster(): row=%d", row);
- for (i = 0; i < n; i++) {
- if (masked && nul && nul[i])
- *dst++ = 0;
+ for (x = x0; x < x1; x++) {
+ int xx = dst_l + x;
+ int j = trans[x];
+ unsigned int c;
+
+ if (masked && nul && nul[j])
+ c = 0;
else {
- unsigned int r = red[i];
- unsigned int g = grn[i];
- unsigned int b = blu[i];
+ unsigned int r = red[j];
+ unsigned int g = grn[j];
+ unsigned int b = blu[j];
unsigned int a = 0xFF;
+ c = (a << 24) + (r << 16) + (g << 8) + (b << 0);
+ }
- *dst++ = (a << 24) + (r << 16) + (g << 8) + (b << 0);
- }
+ for (y = y0; y < y1; y++) {
+ int yy = d_y0 + y;
+ *(unsigned int *)(src_data + yy * src_stride + xx * 4) = c;
+ }
}
- return row + 1;
+ ca.modified = 1;
+ ca_row++;
+
+ return next_row(row, d_y1);
}
/*!
@@ -121,8 +183,8 @@
/* paint source surface onto destination (scaled) */
cairo_save(cairo);
- cairo_translate(cairo, dst_l, dst_t);
- cairo_scale(cairo, dst_w / src_w, dst_h / src_h);
+ /* cairo_translate(cairo, dst_l, dst_t); */
+ /* cairo_scale(cairo, dst_w / src_w, dst_h / src_h); */
cairo_surface_mark_dirty(src_surf);
cairo_set_source_surface(cairo, src_surf, 0, 0);
cairo_pattern_set_filter(cairo_get_source(cairo), CAIRO_FILTER_NEAREST);
@@ -130,6 +192,7 @@
cairo_restore(cairo);
/* cleanup */
+ G_free(trans);
cairo_surface_destroy(src_surf);
ca.modified = 1;
}
More information about the grass-commit
mailing list