| 1 | /* |
|---|
| 2 | This file is part of the Astrometry.net suite. |
|---|
| 3 | Copyright 2007 Keir Mierle and Dustin Lang. |
|---|
| 4 | Copyright 2009 Dustin Lang. |
|---|
| 5 | |
|---|
| 6 | The Astrometry.net suite is free software; you can redistribute |
|---|
| 7 | it and/or modify it under the terms of the GNU General Public License |
|---|
| 8 | as published by the Free Software Foundation, version 2. |
|---|
| 9 | |
|---|
| 10 | The Astrometry.net suite is distributed in the hope that it will be |
|---|
| 11 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 13 | General Public License for more details. |
|---|
| 14 | |
|---|
| 15 | You should have received a copy of the GNU General Public License |
|---|
| 16 | along with the Astrometry.net suite ; if not, write to the Free Software |
|---|
| 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|---|
| 18 | */ |
|---|
| 19 | #include <stdio.h> |
|---|
| 20 | #include <stdlib.h> |
|---|
| 21 | #include <math.h> |
|---|
| 22 | #include <errno.h> |
|---|
| 23 | #include <string.h> |
|---|
| 24 | #include <limits.h> |
|---|
| 25 | #include <unistd.h> |
|---|
| 26 | #include <sys/param.h> |
|---|
| 27 | #include <assert.h> |
|---|
| 28 | #include <stdarg.h> |
|---|
| 29 | |
|---|
| 30 | #include <zlib.h> |
|---|
| 31 | #include <cairo.h> |
|---|
| 32 | |
|---|
| 33 | #include "an-bool.h" |
|---|
| 34 | #include "tilerender.h" |
|---|
| 35 | #include "starutil.h" |
|---|
| 36 | #include "cairoutils.h" |
|---|
| 37 | #include "ioutils.h" |
|---|
| 38 | #include "fitsioutils.h" |
|---|
| 39 | #include "bl.h" |
|---|
| 40 | #include "log.h" |
|---|
| 41 | #include "errors.h" |
|---|
| 42 | |
|---|
| 43 | #include "render_tycho.h" |
|---|
| 44 | #include "render_gridlines.h" |
|---|
| 45 | #include "render_usnob.h" |
|---|
| 46 | #include "render_rdls.h" |
|---|
| 47 | #include "render_boundary.h" |
|---|
| 48 | #include "render_constellation.h" |
|---|
| 49 | #include "render_messier.h" |
|---|
| 50 | #include "render_solid.h" |
|---|
| 51 | #include "render_images.h" |
|---|
| 52 | #include "render_cairo.h" |
|---|
| 53 | #include "render_skdt.h" |
|---|
| 54 | #include "render_quads.h" |
|---|
| 55 | #include "render_match.h" |
|---|
| 56 | #include "render_healpixes.h" |
|---|
| 57 | |
|---|
| 58 | // Ugh, zlib before 1.2.0 didn't include compressBound()... |
|---|
| 59 | // And ZLIB_VERNUM wasn't defined until 1.2.0.2 |
|---|
| 60 | #if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1200) |
|---|
| 61 | // This was copy-n-pasted directly from the zlib source code version 1.2.3: |
|---|
| 62 | /* compress.c -- compress a memory buffer |
|---|
| 63 | * Copyright (C) 1995-2003 Jean-loup Gailly. |
|---|
| 64 | * For conditions of distribution and use, see copyright notice in zlib.h |
|---|
| 65 | */ |
|---|
| 66 | uLong compressBound (uLong sourceLen) { |
|---|
| 67 | return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; |
|---|
| 68 | } |
|---|
| 69 | #endif |
|---|
| 70 | |
|---|
| 71 | /** |
|---|
| 72 | This program gets called by "tile.php"/django in response to a |
|---|
| 73 | client requesting a Google maps tile. The coordinates of the tile |
|---|
| 74 | are specified as a range of RA and DEC values. |
|---|
| 75 | |
|---|
| 76 | The RA coordinates are passed as -x <lower-RA> -X <upper-RA> |
|---|
| 77 | The DEC coordinates are -y <lower-DEC> -Y <upper-DEC> |
|---|
| 78 | The width and height in pixels are -w <width> -h <height> |
|---|
| 79 | */ |
|---|
| 80 | |
|---|
| 81 | static void print_help(char* prog) { |
|---|
| 82 | printf("Usage: %s\n" |
|---|
| 83 | "\n" |
|---|
| 84 | " These four flags are required: they specify the rectangle in RA,Dec space\n" |
|---|
| 85 | " that this tile will cover.\n" |
|---|
| 86 | " -x <lower-RA>\n" |
|---|
| 87 | " -X <upper-RA>\n" |
|---|
| 88 | " -y <lower-Dec>\n" |
|---|
| 89 | " -Y <upper-Dec>\n" |
|---|
| 90 | "\n" |
|---|
| 91 | " If you use this flag, the coordinates are instead interpreted as Mercator\n" |
|---|
| 92 | " coordinates in the unit square.\n" |
|---|
| 93 | " [-M]: in Mercator coords\n" |
|---|
| 94 | "\n" |
|---|
| 95 | " These two flags are required: they specify the output image size.\n" |
|---|
| 96 | " -w <image-width>\n" |
|---|
| 97 | " -h <image-height>\n" |
|---|
| 98 | "\n" |
|---|
| 99 | " Output options: the default is to write a PNG image to standard out.\n" |
|---|
| 100 | " [-J]: write jpeg\n" |
|---|
| 101 | " [-R]: write a raw floating-point image\n" |
|---|
| 102 | "\n" |
|---|
| 103 | "\n" |
|---|
| 104 | " Argument files: in order to pass a large number of filenames or other arguments,\n" |
|---|
| 105 | " you can pass a file containing:\n" |
|---|
| 106 | " <keyword> <arguments>\n" |
|---|
| 107 | " <keyword> <arguments>\n" |
|---|
| 108 | " ...\n" |
|---|
| 109 | " [-A <argument-file>]\n" |
|---|
| 110 | "\n" |
|---|
| 111 | "\n" |
|---|
| 112 | " Layers: the output image is rendered one layer at a time, in the specified order.\n" |
|---|
| 113 | " Each rendering layer takes its own arguments, listed below.\n" |
|---|
| 114 | " -l <layer-name> [-l <layer-name> ...]\n" |
|---|
| 115 | "\n" |
|---|
| 116 | " -l solid -- Renders a solid, opaque, black background.\n" |
|---|
| 117 | " By default the background is black but transparent.\n" |
|---|
| 118 | "\n" |
|---|
| 119 | " -l tycho -- Renders Tycho-2 stars.\n" |
|---|
| 120 | " -T <tycho-mkdt-file>: path to the Tycho-2 Mercator-kdtree data file.\n" |
|---|
| 121 | " This file can be created with \"make-merctree\".\n" |
|---|
| 122 | " [-c]: apply Hogg's color-correction\n" |
|---|
| 123 | " [-s]: apply arcsinh brightness mapping\n" |
|---|
| 124 | " [-q]: apply sqrt brightness mapping\n" |
|---|
| 125 | " [-e <scale>]: apply nonlinearities at the given scale\n" |
|---|
| 126 | " [-g <gain>]: apply this gain factor to brightnesses (makes the stars brighter)\n" |
|---|
| 127 | "\n" |
|---|
| 128 | " -l images -- Renders images.\n" |
|---|
| 129 | " [-n]: plot pixel density, not the pixels themselves.\n" |
|---|
| 130 | " [-s, -e, -g]: as above.\n" |
|---|
| 131 | " Reads from argument file (-A):\n" |
|---|
| 132 | " wcsfn <wcs-file>\n" |
|---|
| 133 | " jpegfn <jpeg-file>\n" |
|---|
| 134 | "\n" |
|---|
| 135 | " -l quads -- Renders Astrometry.net index qudas\n" |
|---|
| 136 | " Reads from argument file (-A):\n" |
|---|
| 137 | " index <index-filename>\n" |
|---|
| 138 | "\n" |
|---|
| 139 | " -l cairo -- Renders cairo commands.\n" |
|---|
| 140 | " Reads from argument file (-A):\n" |
|---|
| 141 | " cairo color <r> <g> <b> [<a>]\n" |
|---|
| 142 | " cairo moveto <ra> <dec>\n" |
|---|
| 143 | " cairo lineto <ra> <dec>\n" |
|---|
| 144 | " cairo stroke\n" |
|---|
| 145 | "\n" |
|---|
| 146 | " -l healpix -- Renders healpix boundaries.\n" |
|---|
| 147 | " [-f <nside>]: default 1\n" |
|---|
| 148 | "\n" |
|---|
| 149 | "\n", prog); |
|---|
| 150 | } |
|---|
| 151 | |
|---|
| 152 | const char* OPTIONS = "ab:c:de:f:g:h:i:k:l:npqr:svw:x:y:zA:B:C:D:F:I:JK:L:MN:PRS:T:V:W:X:Y:"; |
|---|
| 153 | |
|---|
| 154 | struct renderer { |
|---|
| 155 | char* name; |
|---|
| 156 | render_func_t imgrender; |
|---|
| 157 | render_cairo_func_t cairorender; |
|---|
| 158 | // don't change the order of these fields! |
|---|
| 159 | }; |
|---|
| 160 | typedef struct renderer renderer_t; |
|---|
| 161 | |
|---|
| 162 | /* All render layers must go in here */ |
|---|
| 163 | static renderer_t renderers[] = { |
|---|
| 164 | { "tycho", render_tycho, NULL }, |
|---|
| 165 | { "grid", NULL, render_gridlines }, |
|---|
| 166 | { "healpix", NULL, render_healpixes }, |
|---|
| 167 | { "usnob", render_usnob, NULL }, |
|---|
| 168 | { "rdls", render_rdls, NULL }, |
|---|
| 169 | { "constellation", render_constellation, NULL }, |
|---|
| 170 | { "messier", render_messier, NULL }, |
|---|
| 171 | { "clean", render_usnob, NULL }, |
|---|
| 172 | { "dirty", render_usnob, NULL }, |
|---|
| 173 | { "solid", NULL, render_solid }, |
|---|
| 174 | { "images", render_images, NULL }, |
|---|
| 175 | { "userimage", render_images, NULL }, |
|---|
| 176 | { "boundaries",NULL, render_boundary }, |
|---|
| 177 | { "userboundary", NULL, render_boundary }, |
|---|
| 178 | { "userdot", NULL, render_boundary }, |
|---|
| 179 | { "cairo", NULL, render_cairo }, |
|---|
| 180 | { "skdt", NULL, render_skdt }, |
|---|
| 181 | { "quads", NULL, render_quads }, |
|---|
| 182 | { "match", NULL, render_match }, |
|---|
| 183 | }; |
|---|
| 184 | |
|---|
| 185 | static void default_rdls_args(render_args_t* args) { |
|---|
| 186 | // Set the other RDLS-related args if they haven't been set already. |
|---|
| 187 | if (sl_size(args->rdlscolors) < sl_size(args->rdlsfns)) |
|---|
| 188 | sl_append(args->rdlscolors, NULL); |
|---|
| 189 | if (il_size(args->Nstars) < sl_size(args->rdlsfns)) |
|---|
| 190 | il_append(args->Nstars, 0); |
|---|
| 191 | if (il_size(args->fieldnums) < sl_size(args->rdlsfns)) |
|---|
| 192 | il_append(args->fieldnums, 0); |
|---|
| 193 | } |
|---|
| 194 | |
|---|
| 195 | void get_string_args_of_types(render_args_t* args, const char* prefixes[], int Nprefixes, sl* lst, sl* matched_prefixes) { |
|---|
| 196 | int i, j; |
|---|
| 197 | if (!args->arglist) |
|---|
| 198 | return; |
|---|
| 199 | for (i=0; i<sl_size(args->arglist); i++) { |
|---|
| 200 | char* str = sl_get(args->arglist, i); |
|---|
| 201 | for (j=0; j<Nprefixes; j++) |
|---|
| 202 | if (starts_with(str, prefixes[j])) { |
|---|
| 203 | sl_append(lst, str + strlen(prefixes[j])); |
|---|
| 204 | if (matched_prefixes) |
|---|
| 205 | sl_append(matched_prefixes, prefixes[j]); |
|---|
| 206 | } |
|---|
| 207 | } |
|---|
| 208 | } |
|---|
| 209 | |
|---|
| 210 | void get_string_args_of_type(render_args_t* args, const char* prefix, sl* lst) { |
|---|
| 211 | int i; |
|---|
| 212 | int skip = strlen(prefix); |
|---|
| 213 | if (!args->arglist) |
|---|
| 214 | return; |
|---|
| 215 | for (i=0; i<sl_size(args->arglist); i++) { |
|---|
| 216 | char* str = sl_get(args->arglist, i); |
|---|
| 217 | if (starts_with(str, prefix)) { |
|---|
| 218 | sl_append(lst, str + skip); |
|---|
| 219 | } |
|---|
| 220 | } |
|---|
| 221 | } |
|---|
| 222 | |
|---|
| 223 | int parse_rgba_arg(const char* argstr, double* rgba) { |
|---|
| 224 | dl* dlst; |
|---|
| 225 | dlst = dl_new(4); |
|---|
| 226 | get_double_args(argstr, dlst); |
|---|
| 227 | if (dl_size(dlst) != 4) { |
|---|
| 228 | logmsg("Argument: \"%s\": expected 4 numbers, got %i.\n", argstr, dl_size(dlst)); |
|---|
| 229 | return -1; |
|---|
| 230 | } |
|---|
| 231 | dl_copy(dlst, 0, 4, rgba); |
|---|
| 232 | dl_free(dlst); |
|---|
| 233 | return 0; |
|---|
| 234 | } |
|---|
| 235 | |
|---|
| 236 | int get_first_rgba_arg_of_type(render_args_t* args, const char* prefix, double* rgba) { |
|---|
| 237 | const char* argstr; |
|---|
| 238 | argstr = get_first_arg_of_type(args, prefix); |
|---|
| 239 | if (!argstr) |
|---|
| 240 | return -1; |
|---|
| 241 | return parse_rgba_arg(argstr, rgba); |
|---|
| 242 | } |
|---|
| 243 | |
|---|
| 244 | const char* get_first_arg_of_type(render_args_t* args, const char* prefix) { |
|---|
| 245 | int i; |
|---|
| 246 | if (!args->arglist) |
|---|
| 247 | return NULL; |
|---|
| 248 | for (i=0; i<sl_size(args->arglist); i++) { |
|---|
| 249 | char* str = sl_get(args->arglist, i); |
|---|
| 250 | if (starts_with(str, prefix)) |
|---|
| 251 | return str; |
|---|
| 252 | } |
|---|
| 253 | return NULL; |
|---|
| 254 | } |
|---|
| 255 | |
|---|
| 256 | int get_int_arg(const char* arg, int def) { |
|---|
| 257 | char* c = index(arg, ' '); |
|---|
| 258 | char* endp; |
|---|
| 259 | int val; |
|---|
| 260 | if (!c) return def; |
|---|
| 261 | val = strtol(c+1, &endp, 0); |
|---|
| 262 | if (endp == c) return def; |
|---|
| 263 | return val; |
|---|
| 264 | } |
|---|
| 265 | |
|---|
| 266 | double get_double_arg(const char* arg, double def) { |
|---|
| 267 | char* c = index(arg, ' '); |
|---|
| 268 | char* endp; |
|---|
| 269 | double val; |
|---|
| 270 | if (!c) return def; |
|---|
| 271 | c++; |
|---|
| 272 | val = strtod(c, &endp); |
|---|
| 273 | if (endp == c) return def; |
|---|
| 274 | return val; |
|---|
| 275 | } |
|---|
| 276 | |
|---|
| 277 | void get_double_args(const char* arg, dl* lst) { |
|---|
| 278 | char* c = index(arg, ' '); |
|---|
| 279 | char* endp; |
|---|
| 280 | double val; |
|---|
| 281 | if (!c) return; |
|---|
| 282 | while (c && *c) { |
|---|
| 283 | c++; |
|---|
| 284 | val = strtod(c, &endp); |
|---|
| 285 | if (endp == c) break; |
|---|
| 286 | dl_append(lst, val); |
|---|
| 287 | c = endp; |
|---|
| 288 | } |
|---|
| 289 | } |
|---|
| 290 | |
|---|
| 291 | void get_double_args_of_type(render_args_t* args, const char* prefix, dl* lst) { |
|---|
| 292 | int i; |
|---|
| 293 | int skip = strlen(prefix); |
|---|
| 294 | if (!args->arglist) |
|---|
| 295 | return; |
|---|
| 296 | for (i=0; i<sl_size(args->arglist); i++) { |
|---|
| 297 | double d; |
|---|
| 298 | char* str = sl_get(args->arglist, i); |
|---|
| 299 | if (!starts_with(str, prefix)) |
|---|
| 300 | continue; |
|---|
| 301 | d = atof(str + skip); |
|---|
| 302 | dl_append(lst, d); |
|---|
| 303 | } |
|---|
| 304 | } |
|---|
| 305 | |
|---|
| 306 | double get_double_arg_of_type(render_args_t* args, const char* name, double def) { |
|---|
| 307 | double rtn; |
|---|
| 308 | dl* lst = dl_new(4); |
|---|
| 309 | get_double_args_of_type(args, name, lst); |
|---|
| 310 | if (dl_size(lst) == 0) |
|---|
| 311 | rtn = def; |
|---|
| 312 | else |
|---|
| 313 | rtn = dl_get(lst, 0); |
|---|
| 314 | dl_free(lst); |
|---|
| 315 | return rtn; |
|---|
| 316 | } |
|---|
| 317 | |
|---|
| 318 | extern char *optarg; |
|---|
| 319 | extern int optind, opterr, optopt; |
|---|
| 320 | |
|---|
| 321 | int main(int argc, char *argv[]) { |
|---|
| 322 | int argchar; |
|---|
| 323 | int gotx, goty, gotX, gotY, gotw, goth; |
|---|
| 324 | double xzoom; |
|---|
| 325 | unsigned char* img; |
|---|
| 326 | render_args_t args; |
|---|
| 327 | sl* layers; |
|---|
| 328 | int i; |
|---|
| 329 | bool inmerc = 0; |
|---|
| 330 | bool writejpeg = FALSE; |
|---|
| 331 | int loglvl = LOG_MSG; |
|---|
| 332 | |
|---|
| 333 | if (argc == 1) { |
|---|
| 334 | print_help(argv[0]); |
|---|
| 335 | exit(0); |
|---|
| 336 | } |
|---|
| 337 | |
|---|
| 338 | memset(&args, 0, sizeof(render_args_t)); |
|---|
| 339 | |
|---|
| 340 | // default args: |
|---|
| 341 | args.colorcor = 1.44; |
|---|
| 342 | args.linewidth = 2.0; |
|---|
| 343 | |
|---|
| 344 | args.rdlsfns = sl_new(4); |
|---|
| 345 | args.rdlscolors = sl_new(4); |
|---|
| 346 | args.Nstars = il_new(4); |
|---|
| 347 | args.fieldnums = il_new(4); |
|---|
| 348 | args.imagefns = sl_new(4); |
|---|
| 349 | args.imwcsfns = sl_new(4); |
|---|
| 350 | args.argfilenames = sl_new(4); |
|---|
| 351 | |
|---|
| 352 | layers = sl_new(16); |
|---|
| 353 | gotx = goty = gotX = gotY = gotw = goth = FALSE; |
|---|
| 354 | |
|---|
| 355 | while ((argchar = getopt (argc, argv, OPTIONS)) != -1) |
|---|
| 356 | switch (argchar) { |
|---|
| 357 | case 'f': |
|---|
| 358 | args.nside = atoi(optarg); |
|---|
| 359 | break; |
|---|
| 360 | case 'T': |
|---|
| 361 | args.tycho_mkdt = optarg; |
|---|
| 362 | break; |
|---|
| 363 | case 'v': |
|---|
| 364 | loglvl++; |
|---|
| 365 | break; |
|---|
| 366 | case 'A': |
|---|
| 367 | sl_append(args.argfilenames, optarg); |
|---|
| 368 | break; |
|---|
| 369 | case 'K': |
|---|
| 370 | args.colorlist = optarg; |
|---|
| 371 | break; |
|---|
| 372 | case 'b': |
|---|
| 373 | args.ubstyle = optarg; |
|---|
| 374 | break; |
|---|
| 375 | case 'J': |
|---|
| 376 | writejpeg = TRUE; |
|---|
| 377 | break; |
|---|
| 378 | case 'S': |
|---|
| 379 | args.filelist = strdup(optarg); |
|---|
| 380 | break; |
|---|
| 381 | case 'n': |
|---|
| 382 | args.density = TRUE; |
|---|
| 383 | break; |
|---|
| 384 | case 'D': |
|---|
| 385 | args.cachedir = strdup(optarg); |
|---|
| 386 | break; |
|---|
| 387 | case 'V': |
|---|
| 388 | args.version = optarg; |
|---|
| 389 | break; |
|---|
| 390 | case 'z': |
|---|
| 391 | args.zoomright = TRUE; |
|---|
| 392 | break; |
|---|
| 393 | case 'd': |
|---|
| 394 | args.zoomdown = TRUE; |
|---|
| 395 | break; |
|---|
| 396 | case 'p': |
|---|
| 397 | args.nopre = TRUE; |
|---|
| 398 | break; |
|---|
| 399 | case 'C': |
|---|
| 400 | args.cmap = strdup(optarg); |
|---|
| 401 | break; |
|---|
| 402 | case 'M': |
|---|
| 403 | inmerc = TRUE; |
|---|
| 404 | break; |
|---|
| 405 | case 'R': |
|---|
| 406 | args.makerawfloatimg = 1; |
|---|
| 407 | break; |
|---|
| 408 | case 'B': |
|---|
| 409 | args.dashbox = atof(optarg); |
|---|
| 410 | break; |
|---|
| 411 | case 'F': |
|---|
| 412 | il_append(args.fieldnums, atoi(optarg)); |
|---|
| 413 | break; |
|---|
| 414 | case 'N': |
|---|
| 415 | il_append(args.Nstars, atoi(optarg)); |
|---|
| 416 | break; |
|---|
| 417 | case 'r': |
|---|
| 418 | default_rdls_args(&args); |
|---|
| 419 | sl_append(args.rdlsfns, optarg); |
|---|
| 420 | break; |
|---|
| 421 | case 'k': |
|---|
| 422 | sl_append(args.rdlscolors, optarg); |
|---|
| 423 | break; |
|---|
| 424 | case 'i': |
|---|
| 425 | sl_append(args.imagefns, optarg); |
|---|
| 426 | break; |
|---|
| 427 | case 'W': |
|---|
| 428 | args.wcsfn = strdup(optarg); |
|---|
| 429 | break; |
|---|
| 430 | case 'I': |
|---|
| 431 | sl_append(args.imwcsfns, optarg); |
|---|
| 432 | break; |
|---|
| 433 | case 'c': |
|---|
| 434 | args.colorcor = atof(optarg); |
|---|
| 435 | break; |
|---|
| 436 | case 's': |
|---|
| 437 | args.arc = TRUE; |
|---|
| 438 | break; |
|---|
| 439 | case 'q': |
|---|
| 440 | args.sqrt = TRUE; |
|---|
| 441 | break; |
|---|
| 442 | case 'e': |
|---|
| 443 | args.nlscale = atof(optarg); |
|---|
| 444 | break; |
|---|
| 445 | case 'a': |
|---|
| 446 | args.arith = TRUE; |
|---|
| 447 | break; |
|---|
| 448 | case 'g': |
|---|
| 449 | args.gain = atof(optarg); |
|---|
| 450 | break; |
|---|
| 451 | case 'l': |
|---|
| 452 | sl_append(layers, optarg); |
|---|
| 453 | break; |
|---|
| 454 | case 'L': |
|---|
| 455 | args.linewidth = atof(optarg); |
|---|
| 456 | break; |
|---|
| 457 | case 'x': |
|---|
| 458 | args.ramin = atof(optarg); |
|---|
| 459 | gotx = TRUE; |
|---|
| 460 | break; |
|---|
| 461 | case 'X': |
|---|
| 462 | args.ramax = atof(optarg); |
|---|
| 463 | goty = TRUE; |
|---|
| 464 | break; |
|---|
| 465 | case 'y': |
|---|
| 466 | args.decmin = atof(optarg); |
|---|
| 467 | gotX = TRUE; |
|---|
| 468 | break; |
|---|
| 469 | case 'Y': |
|---|
| 470 | args.decmax = atof(optarg); |
|---|
| 471 | gotY = TRUE; |
|---|
| 472 | break; |
|---|
| 473 | case 'w': |
|---|
| 474 | args.W = atoi(optarg); |
|---|
| 475 | gotw = TRUE; |
|---|
| 476 | break; |
|---|
| 477 | case 'h': |
|---|
| 478 | args.H = atoi(optarg); |
|---|
| 479 | goth = TRUE; |
|---|
| 480 | break; |
|---|
| 481 | } |
|---|
| 482 | log_init(loglvl); |
|---|
| 483 | log_to(stderr); |
|---|
| 484 | |
|---|
| 485 | if (!(gotx && goty && gotX && gotY && gotw && goth)) { |
|---|
| 486 | logmsg("tilecache: Invalid inputs: need "); |
|---|
| 487 | if (!gotx) logmsg("-x "); |
|---|
| 488 | if (!gotX) logmsg("-X "); |
|---|
| 489 | if (!goty) logmsg("-y "); |
|---|
| 490 | if (!gotY) logmsg("-Y "); |
|---|
| 491 | if (!gotw) logmsg("-w "); |
|---|
| 492 | if (!goth) logmsg("-h "); |
|---|
| 493 | logmsg("\n"); |
|---|
| 494 | exit(-1); |
|---|
| 495 | } |
|---|
| 496 | |
|---|
| 497 | default_rdls_args(&args); |
|---|
| 498 | |
|---|
| 499 | if (args.W > 4096 || args.H > 4096) { |
|---|
| 500 | logmsg("tilecache: Width or height too large (limit 1024)\n"); |
|---|
| 501 | exit(-1); |
|---|
| 502 | } |
|---|
| 503 | |
|---|
| 504 | logmsg("tilecache: BEGIN TILECACHE\n"); |
|---|
| 505 | |
|---|
| 506 | fits_use_error_system(); |
|---|
| 507 | |
|---|
| 508 | if (inmerc) { |
|---|
| 509 | // -x -X -y -Y were given in Mercator coordinates - convert to deg. |
|---|
| 510 | // this is for cases where it's more convenient to specify the coords |
|---|
| 511 | // in Merc coords (eg prerendering) |
|---|
| 512 | args.ramin = merc2radeg(args.ramin); |
|---|
| 513 | args.ramax = merc2radeg(args.ramax); |
|---|
| 514 | args.decmin = merc2decdeg(args.decmin); |
|---|
| 515 | args.decmax = merc2decdeg(args.decmax); |
|---|
| 516 | } |
|---|
| 517 | |
|---|
| 518 | // min ra -> max merc. |
|---|
| 519 | args.xmercmax = radeg2merc(args.ramin); |
|---|
| 520 | args.xmercmin = radeg2merc(args.ramax); |
|---|
| 521 | args.ymercmin = decdeg2merc(args.decmin); |
|---|
| 522 | args.ymercmax = decdeg2merc(args.decmax); |
|---|
| 523 | |
|---|
| 524 | // The y mercator position can end up *near* but not exactly |
|---|
| 525 | // equal to the boundary conditions... clamp. |
|---|
| 526 | args.ymercmin = MAX(0.0, args.ymercmin); |
|---|
| 527 | args.ymercmax = MIN(1.0, args.ymercmax); |
|---|
| 528 | |
|---|
| 529 | args.xpixelpermerc = (double)args.W / (args.xmercmax - args.xmercmin); |
|---|
| 530 | args.ypixelpermerc = (double)args.H / (args.ymercmax - args.ymercmin); |
|---|
| 531 | args.xmercperpixel = 1.0 / args.xpixelpermerc; |
|---|
| 532 | args.ymercperpixel = 1.0 / args.ypixelpermerc; |
|---|
| 533 | |
|---|
| 534 | xzoom = args.xpixelpermerc / 256.0; |
|---|
| 535 | args.zoomlevel = (int)rint(log(fabs(xzoom)) / log(2.0)); |
|---|
| 536 | logmsg("tilecache: zoomlevel: %d\n", args.zoomlevel); |
|---|
| 537 | |
|---|
| 538 | // Rescue boneheads. |
|---|
| 539 | if (!sl_size(layers)) { |
|---|
| 540 | logmsg("tilecache: Do you maybe want to try rendering some layers?\n"); |
|---|
| 541 | } |
|---|
| 542 | |
|---|
| 543 | for (i=0; i<sl_size(args.argfilenames); i++) { |
|---|
| 544 | sl* lines; |
|---|
| 545 | char* fn = sl_get(args.argfilenames, i); |
|---|
| 546 | lines = file_get_lines(fn, FALSE); |
|---|
| 547 | if (!lines) { |
|---|
| 548 | ERROR("Failed to read args file: \"%s\"", fn); |
|---|
| 549 | return -1; |
|---|
| 550 | } |
|---|
| 551 | if (!args.arglist) |
|---|
| 552 | args.arglist = lines; |
|---|
| 553 | else { |
|---|
| 554 | sl_merge_lists(args.arglist, lines); |
|---|
| 555 | sl_free2(lines); |
|---|
| 556 | } |
|---|
| 557 | } |
|---|
| 558 | |
|---|
| 559 | // Allocate a black image. |
|---|
| 560 | img = calloc(4 * args.W * args.H, 1); |
|---|
| 561 | |
|---|
| 562 | for (i=0; i<sl_size(layers); i++) { |
|---|
| 563 | int j, k; |
|---|
| 564 | int NR = sizeof(renderers) / sizeof(renderer_t); |
|---|
| 565 | char* layer = sl_get(layers, i); |
|---|
| 566 | bool gotit = FALSE; |
|---|
| 567 | uchar* thisimg = calloc(4 * args.W * args.H, 1); |
|---|
| 568 | |
|---|
| 569 | for (j=0; j<NR; j++) { |
|---|
| 570 | renderer_t* r = renderers + j; |
|---|
| 571 | int res = -1; |
|---|
| 572 | if (!streq(layer, r->name)) |
|---|
| 573 | continue; |
|---|
| 574 | args.currentlayer = r->name; |
|---|
| 575 | if (r->cairorender) { |
|---|
| 576 | // hacky... we really should do the compositing in cairo. |
|---|
| 577 | cairo_t* cairo; |
|---|
| 578 | cairo_surface_t* target; |
|---|
| 579 | target = cairo_image_surface_create_for_data(thisimg, CAIRO_FORMAT_ARGB32, args.W, args.H, args.W*4); |
|---|
| 580 | cairo = cairo_create(target); |
|---|
| 581 | res = r->cairorender(cairo, &args); |
|---|
| 582 | cairoutils_argb32_to_rgba(thisimg, args.W, args.H); |
|---|
| 583 | cairo_surface_destroy(target); |
|---|
| 584 | cairo_destroy(cairo); |
|---|
| 585 | } else if (r->imgrender) { |
|---|
| 586 | res = r->imgrender(thisimg, &args); |
|---|
| 587 | } else { |
|---|
| 588 | logmsg("tilecache: neither 'imgrender' nor 'cairorender' is defined for renderer \"%s\"\n", r->name); |
|---|
| 589 | continue; |
|---|
| 590 | } |
|---|
| 591 | if (res) { |
|---|
| 592 | logmsg("tilecache: Renderer \"%s\" failed.\n", r->name); |
|---|
| 593 | } else { |
|---|
| 594 | logmsg("tilecache: Renderer \"%s\" succeeded.\n", r->name); |
|---|
| 595 | } |
|---|
| 596 | gotit = TRUE; |
|---|
| 597 | break; |
|---|
| 598 | } |
|---|
| 599 | // Save a different kind of bonehead. |
|---|
| 600 | if (!gotit) { |
|---|
| 601 | logmsg("tilecache: No renderer found for layer \"%s\".\n", layer); |
|---|
| 602 | } |
|---|
| 603 | |
|---|
| 604 | // Composite. |
|---|
| 605 | for (j=0; j<args.H; j++) { |
|---|
| 606 | for (k=0; k<args.W; k++) { |
|---|
| 607 | float alpha; |
|---|
| 608 | uchar* newpix = pixel(k, j, thisimg, &args); |
|---|
| 609 | uchar* accpix = pixel(k, j, img, &args); |
|---|
| 610 | alpha = newpix[3] / 255.0; |
|---|
| 611 | |
|---|
| 612 | accpix[0] = accpix[0]*(1.0 - alpha) + newpix[0] * alpha; |
|---|
| 613 | accpix[1] = accpix[1]*(1.0 - alpha) + newpix[1] * alpha; |
|---|
| 614 | accpix[2] = accpix[2]*(1.0 - alpha) + newpix[2] * alpha; |
|---|
| 615 | accpix[3] = MIN(255, accpix[3] + newpix[3]); |
|---|
| 616 | } |
|---|
| 617 | } |
|---|
| 618 | |
|---|
| 619 | free(thisimg); |
|---|
| 620 | } |
|---|
| 621 | |
|---|
| 622 | if (args.makerawfloatimg) { |
|---|
| 623 | fwrite(args.rawfloatimg, sizeof(float), args.W * args.H * 3, stdout); |
|---|
| 624 | free(args.rawfloatimg); |
|---|
| 625 | } else { |
|---|
| 626 | if (writejpeg) |
|---|
| 627 | cairoutils_stream_jpeg(stdout, img, args.W, args.H); |
|---|
| 628 | else |
|---|
| 629 | cairoutils_stream_png(stdout, img, args.W, args.H); |
|---|
| 630 | } |
|---|
| 631 | |
|---|
| 632 | free(img); |
|---|
| 633 | |
|---|
| 634 | sl_free2(args.arglist); |
|---|
| 635 | sl_free2(args.rdlsfns); |
|---|
| 636 | sl_free2(args.rdlscolors); |
|---|
| 637 | sl_free2(args.imagefns); |
|---|
| 638 | sl_free2(args.imwcsfns); |
|---|
| 639 | sl_free2(layers); |
|---|
| 640 | |
|---|
| 641 | il_free(args.Nstars); |
|---|
| 642 | il_free(args.fieldnums); |
|---|
| 643 | |
|---|
| 644 | free(args.wcsfn); |
|---|
| 645 | free(args.cmap); |
|---|
| 646 | |
|---|
| 647 | logmsg("tilecache: END TILECACHE\n"); |
|---|
| 648 | |
|---|
| 649 | return 0; |
|---|
| 650 | } |
|---|
| 651 | |
|---|
| 652 | int parse_color(char c, double* p_r, double* p_g, double* p_b) { |
|---|
| 653 | double r, g, b; |
|---|
| 654 | switch (c) { |
|---|
| 655 | case 'r': // red |
|---|
| 656 | r = 1.0; |
|---|
| 657 | g = b = 0.0; |
|---|
| 658 | break; |
|---|
| 659 | case 'b': // blue |
|---|
| 660 | r = g = 0.0; |
|---|
| 661 | b = 1.0; |
|---|
| 662 | break; |
|---|
| 663 | case 'm': // magenta |
|---|
| 664 | r = b = 1.0; |
|---|
| 665 | g = 0.0; |
|---|
| 666 | break; |
|---|
| 667 | case 'y': // yellow |
|---|
| 668 | r = g = 1.0; |
|---|
| 669 | b = 0.0; |
|---|
| 670 | break; |
|---|
| 671 | case 'g': // green |
|---|
| 672 | r = b = 0.0; |
|---|
| 673 | g = 1.0; |
|---|
| 674 | break; |
|---|
| 675 | case 'c': // cyan |
|---|
| 676 | r = 0.0; |
|---|
| 677 | g = b = 1.0; |
|---|
| 678 | break; |
|---|
| 679 | case 'w': // white |
|---|
| 680 | r = g = b = 1.0; |
|---|
| 681 | break; |
|---|
| 682 | default: |
|---|
| 683 | return -1; |
|---|
| 684 | } |
|---|
| 685 | if (p_r) *p_r = r; |
|---|
| 686 | if (p_g) *p_g = g; |
|---|
| 687 | if (p_b) *p_b = b; |
|---|
| 688 | return 0; |
|---|
| 689 | } |
|---|
| 690 | |
|---|
| 691 | /* |
|---|
| 692 | We need to flip RA somewhere... |
|---|
| 693 | |
|---|
| 694 | We convert Longitude to RA to Mercator to Pixels. |
|---|
| 695 | |
|---|
| 696 | We choose to insert the flip in the conversion from RA to Mercator. |
|---|
| 697 | */ |
|---|
| 698 | |
|---|
| 699 | double xpixel2mercf(double pix, render_args_t* args) { |
|---|
| 700 | return args->xmercmin + pix * args->xmercperpixel; |
|---|
| 701 | } |
|---|
| 702 | |
|---|
| 703 | double ypixel2mercf(double pix, render_args_t* args) { |
|---|
| 704 | return args->ymercmax - pix * args->ymercperpixel; |
|---|
| 705 | } |
|---|
| 706 | |
|---|
| 707 | double xmerc2pixelf(double x, render_args_t* args) { |
|---|
| 708 | return (x - args->xmercmin) * args->xpixelpermerc; |
|---|
| 709 | } |
|---|
| 710 | |
|---|
| 711 | double ymerc2pixelf(double y, render_args_t* args) { |
|---|
| 712 | return (args->ymercmax - y) * args->ypixelpermerc; |
|---|
| 713 | } |
|---|
| 714 | |
|---|
| 715 | ////// The following are just composed of simpler conversions. |
|---|
| 716 | |
|---|
| 717 | // RA in degrees |
|---|
| 718 | int ra2pixel(double ra, render_args_t* args) { |
|---|
| 719 | return xmerc2pixel(radeg2merc(ra), args); |
|---|
| 720 | } |
|---|
| 721 | |
|---|
| 722 | // DEC in degrees |
|---|
| 723 | int dec2pixel(double dec, render_args_t* args) { |
|---|
| 724 | return ymerc2pixel(decdeg2merc(dec), args); |
|---|
| 725 | } |
|---|
| 726 | |
|---|
| 727 | // RA in degrees |
|---|
| 728 | double ra2pixelf(double ra, render_args_t* args) { |
|---|
| 729 | return xmerc2pixelf(radeg2merc(ra), args); |
|---|
| 730 | } |
|---|
| 731 | |
|---|
| 732 | // DEC in degrees |
|---|
| 733 | double dec2pixelf(double dec, render_args_t* args) { |
|---|
| 734 | return ymerc2pixelf(decdeg2merc(dec), args); |
|---|
| 735 | } |
|---|
| 736 | |
|---|
| 737 | // to RA in degrees |
|---|
| 738 | double pixel2ra(double pix, render_args_t* args) { |
|---|
| 739 | return merc2radeg(xpixel2mercf(pix, args)); |
|---|
| 740 | } |
|---|
| 741 | |
|---|
| 742 | // to DEC in degrees |
|---|
| 743 | double pixel2dec(double pix, render_args_t* args) { |
|---|
| 744 | return merc2decdeg(ypixel2mercf(pix, args)); |
|---|
| 745 | } |
|---|
| 746 | |
|---|
| 747 | int xmerc2pixel(double x, render_args_t* args) { |
|---|
| 748 | return (int)floor(xmerc2pixelf(x, args)); |
|---|
| 749 | } |
|---|
| 750 | |
|---|
| 751 | int ymerc2pixel(double y, render_args_t* args) { |
|---|
| 752 | return (int)floor(ymerc2pixelf(y, args)); |
|---|
| 753 | } |
|---|
| 754 | |
|---|
| 755 | int in_image(int x, int y, render_args_t* args) { |
|---|
| 756 | return (x >= 0 && x < args->W && y >=0 && y < args->H); |
|---|
| 757 | } |
|---|
| 758 | |
|---|
| 759 | int in_image_margin(int x, int y, int margin, render_args_t* args) { |
|---|
| 760 | return (x >= -margin && x < (args->W + margin) && y >= -margin && y < (args->H + margin)); |
|---|
| 761 | } |
|---|
| 762 | |
|---|
| 763 | uchar* pixel(int x, int y, uchar* img, render_args_t* args) { |
|---|
| 764 | return img + 4*(y*args->W + x); |
|---|
| 765 | } |
|---|
| 766 | |
|---|
| 767 | // draw a line in Mercator space, handling wrap-around if necessary. |
|---|
| 768 | void draw_line_merc(double mx1, double my1, double mx2, double my2, |
|---|
| 769 | cairo_t* cairo, render_args_t* args) { |
|---|
| 770 | cairo_move_to(cairo, xmerc2pixel(mx1, args), ymerc2pixel(my1, args)); |
|---|
| 771 | cairo_line_to(cairo, xmerc2pixel(mx2, args), ymerc2pixel(my2, args)); |
|---|
| 772 | if (MIN(mx1,mx2) < 0) { |
|---|
| 773 | cairo_move_to(cairo, xmerc2pixel(mx1+1, args), ymerc2pixel(my1, args)); |
|---|
| 774 | cairo_line_to(cairo, xmerc2pixel(mx2+1, args), ymerc2pixel(my2, args)); |
|---|
| 775 | } |
|---|
| 776 | if (MAX(mx1,mx2) > 1) { |
|---|
| 777 | cairo_move_to(cairo, xmerc2pixel(mx1-1, args), ymerc2pixel(my1, args)); |
|---|
| 778 | cairo_line_to(cairo, xmerc2pixel(mx2-1, args), ymerc2pixel(my2, args)); |
|---|
| 779 | } |
|---|
| 780 | } |
|---|
| 781 | |
|---|
| 782 | // ra,dec in degrees. |
|---|
| 783 | void draw_segmented_line(double ra1, double dec1, |
|---|
| 784 | double ra2, double dec2, |
|---|
| 785 | int SEGS, |
|---|
| 786 | cairo_t* cairo, render_args_t* args) { |
|---|
| 787 | int i, s, k; |
|---|
| 788 | double xyz1[3], xyz2[3]; |
|---|
| 789 | bool wrap; |
|---|
| 790 | |
|---|
| 791 | radecdeg2xyzarr(ra1, dec1, xyz1); |
|---|
| 792 | radecdeg2xyzarr(ra2, dec2, xyz2); |
|---|
| 793 | |
|---|
| 794 | wrap = (fabs(ra1 - ra2) >= 180.0) || |
|---|
| 795 | (args->ramin < 0) || (args->ramax > 360.0); |
|---|
| 796 | |
|---|
| 797 | // Draw segmented line. |
|---|
| 798 | for (i=0; i<(1 + (wrap?1:0)); i++) { |
|---|
| 799 | for (s=0; s<SEGS; s++) { |
|---|
| 800 | double xyz[3], frac; |
|---|
| 801 | double ra, dec; |
|---|
| 802 | double mx; |
|---|
| 803 | double px, py; |
|---|
| 804 | frac = (double)s / (double)(SEGS-1); |
|---|
| 805 | for (k=0; k<3; k++) |
|---|
| 806 | xyz[k] = xyz1[k]*(1.0-frac) + xyz2[k]*frac; |
|---|
| 807 | normalize_3(xyz); |
|---|
| 808 | xyzarr2radecdeg(xyz, &ra, &dec); |
|---|
| 809 | mx = radeg2merc(ra); |
|---|
| 810 | |
|---|
| 811 | if (wrap) { |
|---|
| 812 | // in the first pass we draw the left side (mx>0.5) |
|---|
| 813 | if ((i==0) && (mx < 0.5)) mx += 1.0; |
|---|
| 814 | // in the second pass we draw the right side (wx<0.5) |
|---|
| 815 | if ((i==1) && (mx > 0.5)) mx -= 1.0; |
|---|
| 816 | } |
|---|
| 817 | px = xmerc2pixelf(mx, args); |
|---|
| 818 | py = dec2pixelf(dec, args); |
|---|
| 819 | |
|---|
| 820 | if (s==0) |
|---|
| 821 | cairo_move_to(cairo, px, py); |
|---|
| 822 | else |
|---|
| 823 | cairo_line_to(cairo, px, py); |
|---|
| 824 | } |
|---|
| 825 | } |
|---|
| 826 | } |
|---|
| 827 | |
|---|
| 828 | static int cache_get_filename(render_args_t* args, |
|---|
| 829 | const char* cachedomain, const char* key, |
|---|
| 830 | char* fn, int fnlen) { |
|---|
| 831 | if (snprintf(fn, fnlen, "%s/%s/%s", args->cachedir, cachedomain, key) > fnlen) { |
|---|
| 832 | logmsg("Filename truncated in cache_load/cache_save.\n"); |
|---|
| 833 | return -1; |
|---|
| 834 | } |
|---|
| 835 | return 0; |
|---|
| 836 | } |
|---|
| 837 | |
|---|
| 838 | void* cache_load(render_args_t* args, |
|---|
| 839 | const char* cachedomain, const char* key, int* length) { |
|---|
| 840 | char fn[1024]; |
|---|
| 841 | unsigned char* buf; |
|---|
| 842 | size_t len; |
|---|
| 843 | uint32_t typeid; |
|---|
| 844 | unsigned char* orig; |
|---|
| 845 | int rtn; |
|---|
| 846 | uLong origlen; |
|---|
| 847 | uint32_t* ubuf; |
|---|
| 848 | |
|---|
| 849 | if (!args->cachedir) |
|---|
| 850 | return NULL; |
|---|
| 851 | if (cache_get_filename(args, cachedomain, key, fn, sizeof(fn))) { |
|---|
| 852 | return NULL; |
|---|
| 853 | } |
|---|
| 854 | if (!file_exists(fn)) |
|---|
| 855 | return NULL; |
|---|
| 856 | buf = file_get_contents(fn, &len, FALSE); |
|---|
| 857 | if (!buf) { |
|---|
| 858 | logmsg("Failed to read file contents in cache_load.\n"); |
|---|
| 859 | return NULL; |
|---|
| 860 | } |
|---|
| 861 | if (len < 2*sizeof(uint32_t)) { |
|---|
| 862 | logmsg("Cache file too small: \"%s\n", fn); |
|---|
| 863 | free(buf); |
|---|
| 864 | return NULL; |
|---|
| 865 | } |
|---|
| 866 | |
|---|
| 867 | // Pull the two header values off the front... |
|---|
| 868 | ubuf = (uint32_t*)buf; |
|---|
| 869 | // Grab typeid. |
|---|
| 870 | typeid = ubuf[0]; |
|---|
| 871 | // Grab original (uncompressed) length. |
|---|
| 872 | origlen = ubuf[1]; |
|---|
| 873 | |
|---|
| 874 | if (typeid != 1) { |
|---|
| 875 | logmsg("File \"%s\" does not have typeid 1.\n", fn); |
|---|
| 876 | free(buf); |
|---|
| 877 | return NULL; |
|---|
| 878 | } |
|---|
| 879 | orig = malloc(origlen); |
|---|
| 880 | if (!orig) { |
|---|
| 881 | logmsg("Failed to allocate %i bytes for uncompressed cache file \"%s\".\n", (int)origlen, fn); |
|---|
| 882 | free(buf); |
|---|
| 883 | return NULL; |
|---|
| 884 | } |
|---|
| 885 | if (length) |
|---|
| 886 | *length = origlen; |
|---|
| 887 | //logmsg("Origlen as described by the cache file: %d\n", ulen); |
|---|
| 888 | //logmsg("File size as determined by file_get_contents() = %d\n", len); |
|---|
| 889 | rtn = uncompress(orig, &origlen, buf + 2*sizeof(uint32_t), len - 2*sizeof(uint32_t)); |
|---|
| 890 | free(buf); |
|---|
| 891 | if (rtn != Z_OK) { |
|---|
| 892 | logmsg("Failed to uncompress() file \"%s\": %s\n", fn, zError(rtn)); |
|---|
| 893 | free(orig); |
|---|
| 894 | return NULL; |
|---|
| 895 | } |
|---|
| 896 | return orig; |
|---|
| 897 | } |
|---|
| 898 | |
|---|
| 899 | int cache_save(render_args_t* args, |
|---|
| 900 | const char* cachedomain, const char* key, |
|---|
| 901 | const void* data, int length) { |
|---|
| 902 | char fn[1024]; |
|---|
| 903 | FILE* fid; |
|---|
| 904 | uint32_t typeid; |
|---|
| 905 | unsigned char* compressed = NULL; |
|---|
| 906 | uLong complen; |
|---|
| 907 | uint32_t ulen; |
|---|
| 908 | int rtn; |
|---|
| 909 | |
|---|
| 910 | if (!args->cachedir) |
|---|
| 911 | return -1; |
|---|
| 912 | if (cache_get_filename(args, cachedomain, key, fn, sizeof(fn))) { |
|---|
| 913 | return -1; |
|---|
| 914 | } |
|---|
| 915 | fid = fopen(fn, "wb"); |
|---|
| 916 | if (!fid) { |
|---|
| 917 | logmsg("Failed to open cache file \"%s\": %s\n", fn, strerror(errno)); |
|---|
| 918 | goto cleanup; |
|---|
| 919 | } |
|---|
| 920 | |
|---|
| 921 | complen = compressBound(length); |
|---|
| 922 | compressed = malloc(complen + 2*sizeof(uint32_t)); |
|---|
| 923 | if (!compressed) { |
|---|
| 924 | logmsg("Failed to allocate compressed cache buffer\n"); |
|---|
| 925 | goto cleanup; |
|---|
| 926 | } |
|---|
| 927 | |
|---|
| 928 | // first four bytes: type id |
|---|
| 929 | typeid = 1; |
|---|
| 930 | if (fwrite(&typeid, sizeof(uint32_t), 1, fid) != 1) { |
|---|
| 931 | logmsg("Failed to write cache file \"%s\": %s\n", fn, strerror(errno)); |
|---|
| 932 | goto cleanup; |
|---|
| 933 | } |
|---|
| 934 | ulen = length; |
|---|
| 935 | if (fwrite(&ulen, sizeof(uint32_t), 1, fid) != 1) { |
|---|
| 936 | logmsg("Failed to write cache file \"%s\": %s\n", fn, strerror(errno)); |
|---|
| 937 | goto cleanup; |
|---|
| 938 | } |
|---|
| 939 | rtn = compress(compressed, &complen, data, length); |
|---|
| 940 | if (rtn != Z_OK) { |
|---|
| 941 | logmsg("compress() error: %s\n", zError(rtn)); |
|---|
| 942 | goto cleanup; |
|---|
| 943 | } |
|---|
| 944 | if (fwrite(compressed, 1, complen, fid) != complen) { |
|---|
| 945 | logmsg("Failed to write cache file \"%s\": %s\n", fn, strerror(errno)); |
|---|
| 946 | goto cleanup; |
|---|
| 947 | } |
|---|
| 948 | if (fclose(fid)) { |
|---|
| 949 | logmsg("Failed to close cache file \"%s\": %s\n", fn, strerror(errno)); |
|---|
| 950 | goto cleanup; |
|---|
| 951 | } |
|---|
| 952 | |
|---|
| 953 | free(compressed); |
|---|
| 954 | return 0; |
|---|
| 955 | |
|---|
| 956 | cleanup: |
|---|
| 957 | free(compressed); |
|---|
| 958 | if (fid) |
|---|
| 959 | fclose(fid); |
|---|
| 960 | unlink(fn); |
|---|
| 961 | return -1; |
|---|
| 962 | } |
|---|
| 963 | |
|---|
| 964 | |
|---|