GRASS GIS 8 Programmer's Manual 8.2.1(2023)-exported
cairodriver/raster.c
Go to the documentation of this file.
1/*!
2 \file lib/cairodriver/raster.c
3
4 \brief GRASS cairo display driver - draw raster
5
6 (C) 2007-2014 by Lars Ahlzen and the GRASS Development Team
7
8 This program is free software under the GNU General Public License
9 (>=v2). Read the file COPYING that comes with GRASS for details.
10
11 \author Lars Ahlzen <lars ahlzen.com> (original contibutor)
12 \author Glynn Clements
13*/
14
15#include <math.h>
16
17#include "cairodriver.h"
18#include <grass/gis.h>
19#include <grass/glocale.h>
20
21#define MAX_IMAGE_SIZE 32767
22
23static int src_t, src_b, src_l, src_r, src_w, src_h;
24static int dst_t, dst_b, dst_l, dst_r, dst_w, dst_h;
25
26static int *trans;
27
28static cairo_surface_t *src_surf;
29static unsigned char *src_data;
30static int src_stride, ca_row;
31
32static int masked;
33
34static double scale(double k, int src_0, int src_1, int dst_0, int dst_1)
35{
36 return dst_0 + (double) (k - src_0) * (dst_1 - dst_0) / (src_1 - src_0);
37}
38
39static int scale_fwd_y(int sy)
40{
41 return (int)floor(scale(sy, src_t, src_b, dst_t, dst_b) + 0.5);
42}
43
44static int scale_rev_x(int dx)
45{
46 return (int)floor(scale(dx + 0.5, dst_l, dst_r, src_l, src_r));
47}
48
49static int next_row(int sy, int dy)
50{
51 sy++;
52
53 for (;;) {
54 int y = scale_fwd_y(sy);
55
56 if (y > dy)
57 return sy - 1;
58 sy++;
59 }
60}
61
62/*!
63 \brief Start drawing raster
64
65 \todo are top and left swapped?
66
67 \param mask non-zero int for mask
68 \param s source (map) extent (left, right, top, bottom)
69 \param d destination (image) extent (left, right, top, bottom)
70*/
71void Cairo_begin_raster(int mask, int s[2][2], double d[2][2])
72{
73 int i;
74 cairo_status_t status;
75
76 masked = mask;
77
78 src_l = s[0][0];
79 src_r = s[0][1];
80 src_t = s[1][0];
81 src_b = s[1][1];
82
83 src_w = src_r - src_l;
84 src_h = src_b - src_t;
85
86 dst_l = (int) floor(d[0][0] + 0.5);
87 dst_r = (int) floor(d[0][1] + 0.5);
88 dst_t = (int) floor(d[1][0] + 0.5);
89 dst_b = (int) floor(d[1][1] + 0.5);
90
91 dst_w = dst_r - dst_l;
92 dst_h = dst_b - dst_t;
93
94 G_debug(1, "Cairo_begin_raster(): masked=%d, src_lrtb=%d %d %d %d -> w/h=%d %d, "
95 "dst_lrtb=%d %d %d %d -> w/h=%d %d",
96 masked, src_l, src_r, src_t, src_b, src_w, src_h,
97 dst_l, dst_r, dst_t, dst_b, dst_w, dst_h);
98
99 /* create source surface */
100 src_surf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, ca.width, ca.height);
101 status = cairo_surface_status(src_surf);
102 if (status != CAIRO_STATUS_SUCCESS)
103 G_fatal_error("%s - %s - size: %dx%d (cairo limit: %dx%d)",
104 _("Failed to create cairo surface"),
105 cairo_status_to_string (status), ca.width, ca.height,
107
108 src_data = cairo_image_surface_get_data(src_surf);
109 src_stride = cairo_image_surface_get_stride(src_surf);
110 ca_row = 0;
111
112 /* allocate buffer for down-sampling data */
113 trans = G_malloc(dst_w * sizeof(int));
114 for (i = 0; i < dst_w; i++)
115 trans[i] = scale_rev_x(dst_l + i);
116}
117
118/*!
119 \brief Draw raster row
120
121 \param n number of cells
122 \param row raster row (starting at 0)
123 \param red,grn,blu,nul red,green,blue and null value
124
125 \return next row
126*/
127int Cairo_raster(int n, int row,
128 const unsigned char *red, const unsigned char *grn,
129 const unsigned char *blu, const unsigned char *nul)
130{
131 int d_y0 = scale_fwd_y(row + 0);
132 int d_y1 = scale_fwd_y(row + 1);
133 int d_rows = d_y1 - d_y0;
134 int x0 = MAX(0 - dst_l, 0);
135 int x1 = MIN(ca.width - dst_l, dst_w);
136 int y0 = MAX(0 - d_y0, 0);
137 int y1 = MIN(ca.height - d_y0, d_rows);
138 int x, y;
139
140 if (y1 <= y0)
141 return next_row(row, d_y1);
142
143 G_debug(3, "Cairo_raster(): n=%d row=%d", n, row);
144
145 for (x = x0; x < x1; x++) {
146 int xx = dst_l + x;
147 int j = trans[x];
148 unsigned int c;
149
150 if (masked && nul && nul[j])
151 c = 0;
152 else {
153 unsigned int r = red[j];
154 unsigned int g = grn[j];
155 unsigned int b = blu[j];
156 unsigned int a = 0xFF;
157 c = (a << 24) + (r << 16) + (g << 8) + (b << 0);
158 }
159
160 for (y = y0; y < y1; y++) {
161 int yy = d_y0 + y;
162 *(unsigned int *)(src_data + yy * src_stride + xx * 4) = c;
163 }
164 }
165
166 ca.modified = 1;
167 ca_row++;
168
169 return next_row(row, d_y1);
170}
171
172/*!
173 \brief Finish drawing raster
174*/
176{
177 G_debug(1, "Cairo_end_raster()");
178
179 /* paint source surface onto destination (scaled) */
180 cairo_save(cairo);
181 /* cairo_translate(cairo, dst_l, dst_t); */
182 /* cairo_scale(cairo, dst_w / src_w, dst_h / src_h); */
183 cairo_surface_mark_dirty(src_surf);
184 cairo_set_source_surface(cairo, src_surf, 0, 0);
185 cairo_pattern_set_filter(cairo_get_source(cairo), CAIRO_FILTER_NEAREST);
186 cairo_paint(cairo);
187 cairo_restore(cairo);
188
189 /* cleanup */
190 G_free(trans);
191 cairo_surface_destroy(src_surf);
192 ca.modified = 1;
193}
void G_free(void *buf)
Free allocated memory.
Definition: alloc.c:149
void Cairo_begin_raster(int mask, int s[2][2], double d[2][2])
Start drawing raster.
void Cairo_end_raster(void)
Finish drawing raster.
#define MAX_IMAGE_SIZE
int Cairo_raster(int n, int row, const unsigned char *red, const unsigned char *grn, const unsigned char *blu, const unsigned char *nul)
Draw raster row.
GRASS cairo display driver - header file.
struct cairo_state ca
cairo_t * cairo
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition: debug.c:65
double b
double r
void G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
Definition: gis/error.c:160
float g
Definition: named_colr.c:8
#define MIN(a, b)
Definition: shpopen.c:298
#define MAX(a, b)
Definition: shpopen.c:299
#define x