~ubuntu-branches/ubuntu/trusty/postgis/trusty-security

« back to all changes in this revision

Viewing changes to doc/html/image_src/generator.c

  • Committer: Bazaar Package Importer
  • Author(s): Francesco Paolo Lovergine
  • Date: 2009-12-11 13:10:34 UTC
  • mfrom: (1.1.9 upstream) (5.2.1 experimental)
  • Revision ID: james.westby@ubuntu.com-20091211131034-wmsz69wxvt95pe5r
Tags: 1.4.0-2
* Upload to unstable.
* Better parameterized debian/rules against postgis $(VERSION).
* Added dblatex and libcunit1-dev among build-deps.
* Added postgis_comments.sql to contrib/ SQL templates.
* Dropping 8.3 support, no more supported for squeeze.
  (closes: #559587)
* Do not stop on error in postrm if the target dir does not exist.
  (closes: #560409)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**********************************************************************
 
2
 * $Id: generator.c 3967 2009-05-04 16:48:11Z kneufeld $
 
3
 *
 
4
 * PostGIS - Spatial Types for PostgreSQL
 
5
 * http://postgis.refractions.net
 
6
 * Copyright 2008 Kevin Neufeld
 
7
 *
 
8
 * This is free software; you can redistribute and/or modify it under
 
9
 * the terms of the GNU General Public Licence. See the COPYING file.
 
10
 *
 
11
 * This program will generate a .png image for every .wkt file specified
 
12
 * in this directory's Makefile.  Every .wkt file may contain several
 
13
 * entries of geometries represented as WKT strings.  Every line in
 
14
 * a wkt file is stylized using a predetermined style (line thinkness,
 
15
 * fill color, etc) currently hard coded in this programs main function.
 
16
 *
 
17
 * In order to generate a png file, ImageMagicK must be installed in the
 
18
 * user's path as system calls are invoked to "convert".  In this manner,
 
19
 * WKT files are converted into SVG syntax and rasterized as png.  (PostGIS's
 
20
 * internal SVG methods could not be used dues to syntax issues with ImageMagick)
 
21
 *
 
22
 * The goal of this application is to dynamically generate all the spatial
 
23
 * pictures used in PostGIS's documentation pages.
 
24
 *
 
25
 * Note: the coordinates of the supplied geometries should be within the x-y range
 
26
 * of 200, otherwise they will appear outside of the generated image.
 
27
 *
 
28
 **********************************************************************/
 
29
 
 
30
#include <stdio.h>
 
31
#include <stdlib.h>
 
32
#include <string.h>
 
33
#include <ctype.h>
 
34
 
 
35
#include "lwalgorithm.h"
 
36
#include "styles.h"
 
37
 
 
38
#define SHOW_DIGS_DOUBLE 15
 
39
#define MAX_DOUBLE_PRECISION 15
 
40
#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 2) /* +2 for dot and sign */
 
41
 
 
42
// Some global styling variables
 
43
char *imageSize = "200x200";
 
44
 
 
45
 
 
46
int getStyleName(char **styleName, char* line);
 
47
 
 
48
/**
 
49
 * Set up liblwgeom to run in stand-alone mode using the
 
50
 * usual system memory handling functions.
 
51
 */
 
52
void lwgeom_init_allocators(void)
 
53
{
 
54
        /* liblwgeom callback - install default handlers */
 
55
        lwgeom_install_default_allocators();
 
56
}
 
57
 
 
58
/**
 
59
 * Writes the coordinates of a POINTARRAY to a char* where ordinates are
 
60
 * separated by a comma and coordinates by a space so that the coordinate
 
61
 * pairs can be interpreted by ImageMagick's SVG draw command.
 
62
 *
 
63
 * @param output a reference to write the POINTARRAY to
 
64
 * @param pa a reference to a POINTARRAY
 
65
 * @return the numbers of character written to *output
 
66
 */
 
67
static size_t
 
68
pointarrayToString(char *output, POINTARRAY *pa)
 
69
{
 
70
        char x[MAX_DIGS_DOUBLE+MAX_DOUBLE_PRECISION+1];
 
71
        char y[MAX_DIGS_DOUBLE+MAX_DOUBLE_PRECISION+1];
 
72
        int i;
 
73
        char *ptr = output;
 
74
 
 
75
        for ( i=0; i < pa->npoints; i++ )
 
76
        {
 
77
                POINT2D pt;
 
78
                getPoint2d_p(pa, i, &pt);
 
79
                sprintf(x, "%f", pt.x);
 
80
                trim_trailing_zeros(x);
 
81
                sprintf(y, "%f", pt.y);
 
82
                trim_trailing_zeros(y);
 
83
                if ( i ) ptr += sprintf(ptr, " ");
 
84
                ptr += sprintf(ptr, "%s,%s", x, y);
 
85
        }
 
86
 
 
87
        return (ptr - output);
 
88
}
 
89
 
 
90
/**
 
91
 * Serializes a LWPOINT to a char*.  This is a helper function that partially
 
92
 * writes the appropriate draw and fill commands used to generate an SVG image
 
93
 * using ImageMagick's "convert" command.
 
94
 
 
95
 * @param output a char reference to write the LWPOINT to
 
96
 * @param lwp a reference to a LWPOINT
 
97
 * @return the numbers of character written to *output
 
98
 */
 
99
static size_t
 
100
drawPoint(char *output, LWPOINT *lwp, LAYERSTYLE *styles)
 
101
{
 
102
        char x[MAX_DIGS_DOUBLE+MAX_DOUBLE_PRECISION+1];
 
103
        char y1[MAX_DIGS_DOUBLE+MAX_DOUBLE_PRECISION+1];
 
104
        char y2[MAX_DIGS_DOUBLE+MAX_DOUBLE_PRECISION+1];
 
105
        char *ptr = output;
 
106
        POINTARRAY *pa = lwp->point;
 
107
        POINT2D p;
 
108
        getPoint2d_p(pa, 0, &p);
 
109
 
 
110
        sprintf(x, "%f", p.x);
 
111
        trim_trailing_zeros(x);
 
112
        sprintf(y1, "%f", p.y);
 
113
        trim_trailing_zeros(y1);
 
114
        sprintf(y2, "%f", p.y + styles->pointSize);
 
115
        trim_trailing_zeros(y2);
 
116
 
 
117
        ptr += sprintf(ptr, "-fill %s -strokewidth 0 ", styles->pointColor);
 
118
        ptr += sprintf(ptr, "-draw \"circle %s,%s %s,%s", x, y1, x, y2);
 
119
        ptr += sprintf(ptr, "'\" ");
 
120
 
 
121
        return (ptr - output);
 
122
}
 
123
 
 
124
/**
 
125
 * Serializes a LWLINE to a char*.  This is a helper function that partially
 
126
 * writes the appropriate draw and stroke commands used to generate an SVG image
 
127
 * using ImageMagick's "convert" command.
 
128
 
 
129
 * @param output a char reference to write the LWLINE to
 
130
 * @param lwl a reference to a LWLINE
 
131
 * @return the numbers of character written to *output
 
132
 */
 
133
static size_t
 
134
drawLineString(char *output, LWLINE *lwl, LAYERSTYLE *style)
 
135
{
 
136
        char *ptr = output;
 
137
 
 
138
        ptr += sprintf(ptr, "-fill none -stroke %s -strokewidth %d ", style->lineColor, style->lineWidth);
 
139
        ptr += sprintf(ptr, "-draw \"stroke-linecap round stroke-linejoin round path 'M ");
 
140
        ptr += pointarrayToString(ptr, lwl->points );
 
141
        ptr += sprintf(ptr, "'\" ");
 
142
 
 
143
        return (ptr - output);
 
144
}
 
145
 
 
146
/**
 
147
 * Serializes a LWPOLY to a char*.  This is a helper function that partially
 
148
 * writes the appropriate draw and fill commands used to generate an SVG image
 
149
 * using ImageMagick's "convert" command.
 
150
 
 
151
 * @param output a char reference to write the LWPOLY to
 
152
 * @param lwp a reference to a LWPOLY
 
153
 * @return the numbers of character written to *output
 
154
 */
 
155
static size_t
 
156
drawPolygon(char *output, LWPOLY *lwp, LAYERSTYLE *style)
 
157
{
 
158
        char *ptr = output;
 
159
        int i;
 
160
 
 
161
        ptr += sprintf(ptr, "-fill %s -stroke %s -strokewidth %d ", style->polygonFillColor, style->polygonStrokeColor, style->polygonStrokeWidth );
 
162
        ptr += sprintf(ptr, "-draw \"path '");
 
163
        for (i=0; i<lwp->nrings; i++)
 
164
        {
 
165
                ptr += sprintf(ptr, "M ");
 
166
                ptr += pointarrayToString(ptr, lwp->rings[i] );
 
167
                ptr += sprintf(ptr, " ");
 
168
        }
 
169
        ptr += sprintf(ptr, "'\" ");
 
170
 
 
171
        return (ptr - output);
 
172
}
 
173
 
 
174
/**
 
175
 * Serializes a LWGEOM to a char*.  This is a helper function that partially
 
176
 * writes the appropriate draw, stroke, and fill commands used to generate an
 
177
 * SVG image using ImageMagick's "convert" command.
 
178
 
 
179
 * @param output a char reference to write the LWGEOM to
 
180
 * @param lwgeom a reference to a LWGEOM
 
181
 * @return the numbers of character written to *output
 
182
 */
 
183
static size_t
 
184
drawGeometry(char *output, LWGEOM *lwgeom, LAYERSTYLE *styles )
 
185
{
 
186
        char *ptr = output;
 
187
        int i;
 
188
        int type = lwgeom_getType(lwgeom->type);
 
189
 
 
190
        switch (type)
 
191
        {
 
192
        case POINTTYPE:
 
193
                ptr += drawPoint(ptr, (LWPOINT*)lwgeom, styles );
 
194
                break;
 
195
        case LINETYPE:
 
196
                ptr += drawLineString(ptr, (LWLINE*)lwgeom, styles );
 
197
                break;
 
198
        case POLYGONTYPE:
 
199
                ptr += drawPolygon(ptr, (LWPOLY*)lwgeom, styles );
 
200
                break;
 
201
        case MULTIPOINTTYPE:
 
202
        case MULTILINETYPE:
 
203
        case MULTIPOLYGONTYPE:
 
204
        case COLLECTIONTYPE:
 
205
                for (i=0; i<((LWCOLLECTION*)lwgeom)->ngeoms; i++)
 
206
                {
 
207
                        ptr += drawGeometry( ptr, lwcollection_getsubgeom ((LWCOLLECTION*)lwgeom, i), styles );
 
208
                }
 
209
                break;
 
210
        }
 
211
 
 
212
        return (ptr - output);
 
213
}
 
214
 
 
215
/**
 
216
 * Invokes a system call to ImageMagick's "convert" command that adds a drop
 
217
 * shadow to the current layer image.
 
218
 *
 
219
 * @param layerNumber the current working layer number.
 
220
 */
 
221
static void
 
222
addDropShadow(int layerNumber)
 
223
{
 
224
        // TODO: change to properly sized string
 
225
        char str[512];
 
226
        sprintf(
 
227
            str,
 
228
            "convert tmp%d.png -gravity center \\( +clone -background navy -shadow 100x3+4+4 \\) +swap -background none -flatten tmp%d.png",
 
229
            layerNumber, layerNumber);
 
230
        system(str);
 
231
        LWDEBUGF(4, "%s", str);
 
232
}
 
233
 
 
234
/**
 
235
 * Invokes a system call to ImageMagick's "convert" command that adds a
 
236
 * highlight to the current layer image.
 
237
 *
 
238
 * @param layerNumber the current working layer number.
 
239
 */
 
240
static void
 
241
addHighlight(int layerNumber)
 
242
{
 
243
        // TODO: change to properly sized string
 
244
        char str[512];
 
245
        sprintf(
 
246
            str,
 
247
            "convert tmp%d.png \\( +clone -channel A -separate +channel -negate -background black -virtual-pixel background -blur 0x3 -shade 120x55 -contrast-stretch 0%% +sigmoidal-contrast 7x50%% -fill grey50 -colorize 10%% +clone +swap -compose overlay -composite \\) -compose In -composite tmp%d.png",
 
248
            layerNumber, layerNumber);
 
249
        system(str);
 
250
        LWDEBUGF(4, "%s", str);
 
251
}
 
252
 
 
253
/**
 
254
 * Invokes a system call to ImageMagick's "convert" command that reduces
 
255
 * the overall filesize
 
256
 *
 
257
 * @param filename the current working image.
 
258
 */
 
259
static void
 
260
optimizeImage(char* filename)
 
261
{
 
262
        char *str;
 
263
        str = malloc( (18 + (2*strlen(filename)) + 1) * sizeof(char) );
 
264
        sprintf(str, "convert %s -depth 8 %s", filename, filename);
 
265
        system(str);
 
266
        LWDEBUGF(4, "%s", str);
 
267
        free(str);
 
268
}
 
269
 
 
270
/**
 
271
 * Flattens all the temporary processing png files into a single image
 
272
 */
 
273
static void
 
274
flattenLayers(char* filename)
 
275
{
 
276
        char *str;
 
277
        str = malloc( (48 + strlen(filename) + 1) * sizeof(char) );
 
278
        sprintf(str, "convert tmp[0-9].png -background none -flatten %s", filename);
 
279
 
 
280
        LWDEBUGF(4, "%s", str);
 
281
        system(str);
 
282
        // TODO: only remove the tmp files if they exist.
 
283
        remove("tmp0.png");
 
284
        remove("tmp1.png");
 
285
        remove("tmp2.png");
 
286
        remove("tmp3.png");
 
287
        remove("tmp4.png");
 
288
        remove("tmp5.png");
 
289
        free(str);
 
290
}
 
291
 
 
292
 
 
293
// TODO: comments
 
294
int
 
295
getStyleName(char **styleName, char* line)
 
296
{
 
297
        char *ptr = strrchr(line, ';');
 
298
        if (ptr == NULL)
 
299
        {
 
300
                *styleName = malloc( 8 );
 
301
                strncpy(*styleName, "Default", 7);
 
302
                (*styleName)[7] = '\0';
 
303
                return 1;
 
304
        }
 
305
        else
 
306
        {
 
307
                *styleName = malloc( ptr - line + 1);
 
308
                strncpy(*styleName, line, ptr - line);
 
309
                (*styleName)[ptr - line] = '\0';
 
310
                LWDEBUGF( 4, "%s", *styleName );
 
311
                return 0;
 
312
        }
 
313
}
 
314
 
 
315
 
 
316
/**
 
317
 * Main Application.  Currently, drawing styles are hardcoded in this method.
 
318
 * Future work may entail reading the styles from a .properties file.
 
319
 */
 
320
int main( int argc, const char* argv[] )
 
321
{
 
322
        FILE *pfile;
 
323
        LWGEOM *lwgeom;
 
324
        char line [2048];
 
325
        char *filename;
 
326
        int layerCount;
 
327
        int styleNumber;
 
328
        LAYERSTYLE *styles;
 
329
 
 
330
        getStyles(&styles);
 
331
 
 
332
        if ( argc != 2 )
 
333
        {
 
334
                lwerror("You must specifiy a wkt filename to convert.\n");
 
335
                return -1;
 
336
        }
 
337
 
 
338
        if ( (pfile = fopen(argv[1], "r")) == NULL)
 
339
        {
 
340
                perror ( argv[1] );
 
341
                return -1;
 
342
        }
 
343
 
 
344
        filename = malloc( strlen(argv[1])+11 );
 
345
        strncpy( filename, "../images/", 10 );
 
346
        strncat( filename, argv[1], strlen(argv[1])-3 );
 
347
        strncat( filename, "png", 3 );
 
348
 
 
349
        printf( "generating %s\n", filename );
 
350
 
 
351
        layerCount = 0;
 
352
        while ( fgets ( line, sizeof line, pfile ) != NULL && !isspace(*line) )
 
353
        {
 
354
 
 
355
                char output[2048];
 
356
                char *ptr = output;
 
357
                char *styleName;
 
358
                int useDefaultStyle;
 
359
 
 
360
                ptr += sprintf( ptr, "convert -size %s xc:none ", imageSize );
 
361
 
 
362
                useDefaultStyle = getStyleName(&styleName, line);
 
363
                LWDEBUGF( 4, "%s", styleName );
 
364
 
 
365
                if (useDefaultStyle)
 
366
                {
 
367
                        printf("   Warning: using Default style for layer %d\n", layerCount);
 
368
                        lwgeom = lwgeom_from_ewkt( line, PARSER_CHECK_NONE );
 
369
                }
 
370
                else
 
371
                        lwgeom = lwgeom_from_ewkt( line+strlen(styleName)+1, PARSER_CHECK_NONE );
 
372
                LWDEBUGF( 4, "geom = %s", lwgeom_to_ewkt((LWGEOM*)lwgeom,0) );
 
373
 
 
374
                styleNumber = layerCount % length(styles);
 
375
                ptr += drawGeometry( ptr, lwgeom, getStyle(styles, styleName) );
 
376
 
 
377
                ptr += sprintf( ptr, "-flip tmp%d.png", layerCount );
 
378
 
 
379
                lwfree( lwgeom );
 
380
 
 
381
                LWDEBUGF( 4, "%s", output );
 
382
                system(output);
 
383
 
 
384
                addHighlight( layerCount );
 
385
                addDropShadow( layerCount );
 
386
                layerCount++;
 
387
                free(styleName);
 
388
        }
 
389
 
 
390
        flattenLayers(filename);
 
391
        optimizeImage(filename);
 
392
 
 
393
        fclose(pfile);
 
394
        free(filename);
 
395
        freeStyles(&styles);
 
396
        return 0;
 
397
}