src/pngtile/main.c
changeset 101 578d90d0cf92
parent 98 f195b8195b5a
child 102 a4d1e046ed3e
equal deleted inserted replaced
100:aee9d0b12fe9 101:578d90d0cf92
     5 #include <getopt.h>
     5 #include <getopt.h>
     6 #include <string.h>
     6 #include <string.h>
     7 #include <stdio.h>
     7 #include <stdio.h>
     8 #include <unistd.h>
     8 #include <unistd.h>
     9 #include <stdbool.h>
     9 #include <stdbool.h>
       
    10 
       
    11 enum option_names {
       
    12 
       
    13     _OPT_LONGONLY       = 255,
       
    14 
       
    15     OPT_BENCHMARK,
       
    16     OPT_RANDOMIZE,
       
    17 };
    10 
    18 
    11 /**
    19 /**
    12  * Command-line options
    20  * Command-line options
    13  */
    21  */
    14 static const struct option options[] = {
    22 static const struct option options[] = {
    24     { "x",              true,   NULL,   'x' },
    32     { "x",              true,   NULL,   'x' },
    25     { "y",              true,   NULL,   'y' },
    33     { "y",              true,   NULL,   'y' },
    26     { "zoom",           true,   NULL,   'z' },
    34     { "zoom",           true,   NULL,   'z' },
    27     { "out",            true,   NULL,   'o' },
    35     { "out",            true,   NULL,   'o' },
    28     { "threads",        true,   NULL,   'j' },
    36     { "threads",        true,   NULL,   'j' },
    29     { 0,                0,      0,      0   }
    37     
       
    38     // --long-only options
       
    39     { "benchmark",      true,   NULL,   OPT_BENCHMARK   },
       
    40     { "randomize",      false,  NULL,   OPT_RANDOMIZE   },
       
    41     { 0,                0,      0,      0               }
    30 };
    42 };
    31 
    43 
    32 /**
    44 /**
    33  * Print usage/help info on stderr
    45  * Print usage/help info on stderr
    34  */
    46  */
    37     fprintf(stderr, "Usage: %s [options] <image> [...]\n", argv0);
    49     fprintf(stderr, "Usage: %s [options] <image> [...]\n", argv0);
    38     fprintf(stderr,
    50     fprintf(stderr,
    39         "Open each of the given image files, check cache status, optionally update their cache, display image info, and\n"
    51         "Open each of the given image files, check cache status, optionally update their cache, display image info, and\n"
    40         "optionally render a tile of each.\n"
    52         "optionally render a tile of each.\n"
    41         "\n"
    53         "\n"
    42         "\t-h, --help           show this help and exit\n"
    54         "\t-h, --help               show this help and exit\n"
    43         "\t-q, --quiet          supress informational output\n"
    55         "\t-q, --quiet              supress informational output\n"
    44         "\t-v, --verbose        display more informational output\n"
    56         "\t-v, --verbose            display more informational output\n"
    45         "\t-D, --debug          equivalent to -v\n"
    57         "\t-D, --debug              equivalent to -v\n"
    46         "\t-U, --force-update   unconditionally update image caches\n"
    58         "\t-U, --force-update       unconditionally update image caches\n"
    47         "\t-N, --no-update      do not update the image cache\n"
    59         "\t-N, --no-update          do not update the image cache\n"
    48         "\t-B, --background     set background pattern for sparse cache file: 0xHH..\n"
    60         "\t-B, --background         set background pattern for sparse cache file: 0xHH..\n"
    49         "\t-W, --width          set tile width\n"
    61         "\t-W, --width      PX      set tile width\n"
    50         "\t-H, --height         set tile height\n"
    62         "\t-H, --height     PX      set tile height\n"
    51         "\t-x, --x              set tile x offset\n"
    63         "\t-x, --x          PX      set tile x offset\n"
    52         "\t-y, --y              set tile y offset\n"
    64         "\t-y, --y          PX      set tile y offset\n"
    53         "\t-z, --zoom           set zoom factor (<0)\n"
    65         "\t-z, --zoom       ZL      set zoom factor (<0)\n"
    54         "\t-o, --out            set tile output file\n"
    66         "\t-o, --out        FILE    set tile output file\n"
    55         "\t-j, --threads        number of threads\n"
    67         "\t-j, --threads    N       number of threads\n"
       
    68         "\t--benchmark      N       do N tile renders\n"
       
    69         "\t--randomize              randomize tile x/y coords\n"
    56     );
    70     );
    57 }
    71 }
    58 
    72 
       
    73 unsigned long parse_uint (const char *val, const char *name)
       
    74 {
       
    75     char *endptr;
       
    76     long int out;
       
    77 
       
    78     // decode
       
    79     out = strtol(val, &endptr, 0);
       
    80 
       
    81     // validate
       
    82     if (*endptr || out < 0)
       
    83         EXIT_ERROR(EXIT_FAILURE, "Invalid value for %s: %s", name, val);
       
    84 
       
    85     // ok
       
    86     return out;
       
    87 }
       
    88 
       
    89 signed long parse_sint (const char *val, const char *name)
       
    90 {
       
    91     char *endptr;
       
    92     long int out;
       
    93 
       
    94     // decode
       
    95     out = strtol(val, &endptr, 0);
       
    96 
       
    97     // validate
       
    98     if (*endptr)
       
    99         EXIT_ERROR(EXIT_FAILURE, "Invalid value for %s: %s", name, val);
       
   100 
       
   101     // ok
       
   102     return out;
       
   103 }
       
   104 
       
   105 long randrange (long start, long end)
       
   106 {
       
   107     return start + (rand() * (end - start) / RAND_MAX);
       
   108 }
       
   109 
       
   110 /**
       
   111  * Randomize tile x/y with given image info
       
   112  */
       
   113 void randomize_tile (struct pt_tile_info *ti, const struct pt_image_info *info)
       
   114 {
       
   115     ti->x = randrange(0, info->img_width - ti->width);
       
   116     ti->y = randrange(0, info->img_height - ti->height);
       
   117 }
       
   118 
       
   119 /**
       
   120  * Render a tile
       
   121  */
       
   122 int do_tile (struct pt_ctx *ctx, struct pt_image *image, const struct pt_tile_info *ti, const char *out_path)
       
   123 {
       
   124     FILE *out_file = NULL;
       
   125     char tmp_name[] = "pt-tile-XXXXXX";
       
   126     int err = 0;
       
   127     
       
   128     if (!out_path) {
       
   129         int fd;
       
   130         
       
   131         // temporary file for output
       
   132         if ((fd = mkstemp(tmp_name)) < 0) {
       
   133             log_errno("mkstemp");
       
   134             goto error;
       
   135         }
       
   136 
       
   137         out_path = tmp_name;
       
   138 
       
   139         // open out
       
   140         if ((out_file = fdopen(fd, "wb")) == NULL) {
       
   141             log_errno("fdopen");
       
   142             goto error;
       
   143         }
       
   144 
       
   145     } else if (strcmp(out_path, "-") == 0) {
       
   146         // use stdout
       
   147         if ((out_file = fdopen(STDOUT_FILENO, "wb")) == NULL) {
       
   148             log_errno("fdopen: STDOUT_FILENO");
       
   149             goto error;
       
   150         }
       
   151 
       
   152     } else {
       
   153         // use file
       
   154         if ((out_file = fopen(out_path, "wb")) == NULL) {
       
   155             log_errno("fopen: %s", out_path);
       
   156             goto error;
       
   157         }
       
   158 
       
   159     }
       
   160 
       
   161     
       
   162     if (ctx) {
       
   163         // render
       
   164         log_info("\tAsync render tile %zux%zu@(%zu,%zu) -> %s", ti->width, ti->height, ti->x, ti->y, out_path);
       
   165 
       
   166         if ((err = pt_image_tile_async(image, ti, out_file))) {
       
   167             log_errno("pt_image_tile_async: %s", pt_strerror(err));
       
   168             goto error;
       
   169         }
       
   170 
       
   171         // will close it itself
       
   172         out_file = NULL;
       
   173 
       
   174     } else {
       
   175         // render
       
   176         log_info("\tRender tile %zux%zu@(%zu,%zu) -> %s", ti->width, ti->height, ti->x, ti->y, out_path);
       
   177 
       
   178         if ((err = pt_image_tile_file(image, ti, out_file))) {
       
   179             log_errno("pt_image_tile_file: %s", pt_strerror(err));
       
   180             goto error;
       
   181         }
       
   182     }
       
   183 
       
   184 error:
       
   185     // cleanup
       
   186     if (out_file && fclose(out_file))
       
   187         log_warn_errno("fclose: out_file");
       
   188 
       
   189     return err;
       
   190 }
       
   191 
    59 int main (int argc, char **argv)
   192 int main (int argc, char **argv)
    60 {
   193 {
    61     int opt;
   194     int opt;
    62     bool force_update = false, no_update = false;
   195     bool force_update = false, no_update = false, randomize = false;
    63     struct pt_tile_info ti = {
   196     struct pt_tile_info ti = {
    64         .width  = 800,
   197         .width  = 800,
    65         .height = 600,
   198         .height = 600,
    66         .x      = 0,
   199         .x      = 0,
    67         .y      = 0,
   200         .y      = 0,
    68         .zoom   = 0
   201         .zoom   = 0
    69     };
   202     };
    70     struct pt_image_params update_params = { };
   203     struct pt_image_params update_params = { };
    71     const char *out_path = NULL;
   204     const char *out_path = NULL;
    72     int threads = 0;
   205     int threads = 0, benchmark = 0;
    73     int tmp, err;
   206     int err;
    74     
   207     
    75     // parse arguments
   208     // parse arguments
    76     while ((opt = getopt_long(argc, argv, "hqvDUNB:W:H:x:y:z:o:j:", options, NULL)) != -1) {
   209     while ((opt = getopt_long(argc, argv, "hqvDUNB:W:H:x:y:z:o:j:", options, NULL)) != -1) {
    77         switch (opt) {
   210         switch (opt) {
    78             case 'h':
   211             case 'h':
    81                 
   214                 
    82                 return EXIT_SUCCESS;
   215                 return EXIT_SUCCESS;
    83 
   216 
    84             case 'q':
   217             case 'q':
    85                 // supress excess log output
   218                 // supress excess log output
    86                 set_log_level(LOG_WARN);
   219                 set_log_level(LOG_WARN); break;
    87 
       
    88                 break;
       
    89 
   220 
    90             case 'v':
   221             case 'v':
    91             case 'D':
   222             case 'D':
    92                 // display additional output
   223                 // display additional output
    93                 set_log_level(LOG_DEBUG);
   224                 set_log_level(LOG_DEBUG); break;
    94 
       
    95                 break;
       
    96             
   225             
    97             case 'U':
   226             case 'U':
    98                 // force update of image caches
   227                 // force update of image caches
    99                 force_update = true;
   228                 force_update = true; break;
   100                 
       
   101                 break;
       
   102             
   229             
   103             case 'N':
   230             case 'N':
   104                 // supress update of image caches
   231                 // supress update of image caches
   105                 no_update = true;
   232                 no_update = true; break;
   106 
       
   107                 break;
       
   108 
   233 
   109             case 'B':
   234             case 'B':
   110                 // background pattern
   235                 // background pattern
   111                 {
   236                 {
   112                     unsigned int b1 = 0, b2 = 0, b3 = 0, b4 = 0;
   237                     unsigned int b1 = 0, b2 = 0, b3 = 0, b4 = 0;
   122                     update_params.background_color[3] = b4;
   247                     update_params.background_color[3] = b4;
   123 
   248 
   124                 } break;
   249                 } break;
   125 
   250 
   126             case 'W':
   251             case 'W':
   127                 ti.width = strtol(optarg, NULL, 0); break;
   252                 ti.width = parse_uint(optarg, "--width"); break;
   128 
   253 
   129             case 'H':
   254             case 'H':
   130                 ti.height = strtol(optarg, NULL, 0); break;
   255                 ti.height = parse_uint(optarg, "--height"); break;
   131 
   256 
   132             case 'x':
   257             case 'x':
   133                 ti.x = strtol(optarg, NULL, 0); break;
   258                 ti.x = parse_uint(optarg, "--x"); break;
   134 
   259 
   135             case 'y':
   260             case 'y':
   136                 ti.y = strtol(optarg, NULL, 0); break;
   261                 ti.y = parse_uint(optarg, "--y"); break;
   137 
   262 
   138             case 'z':
   263             case 'z':
   139                 ti.zoom = strtol(optarg, NULL, 0); break;
   264                 ti.zoom = parse_sint(optarg, "--zoom"); break;
   140 
   265 
   141             case 'o':
   266             case 'o':
   142                 // output file
   267                 // output file
   143                 out_path = optarg;
   268                 out_path = optarg; break;
   144 
       
   145                 break;
       
   146 
   269 
   147             case 'j':
   270             case 'j':
   148                 if ((tmp = strtol(optarg, NULL, 0)) < 1)
   271                 threads = parse_uint(optarg, "--threads"); break;
   149                     FATAL("Invalid value for -j/--threads: %s", optarg);
   272 
   150 
   273             case OPT_BENCHMARK:
   151                 threads = tmp; break;
   274                 benchmark = parse_uint(optarg, "--benchmark"); break;
       
   275             
       
   276             case OPT_RANDOMIZE:
       
   277                 randomize = true; break;
   152 
   278 
   153             case '?':
   279             case '?':
   154                 // useage error
   280                 // useage error
   155                 help(argv[0]);
   281                 help(argv[0]);
   156 
   282 
   256                     (long) info->cache_mtime, info->cache_bytes, info->cache_blocks, info->cache_blocks * 512, info->cache_version
   382                     (long) info->cache_mtime, info->cache_bytes, info->cache_blocks, info->cache_blocks * 512, info->cache_version
   257             );
   383             );
   258         }
   384         }
   259 
   385 
   260         // render tile?
   386         // render tile?
   261         if (out_path) {
   387         if (benchmark) {
   262             FILE *out_file;
   388             log_info("\tRunning %d %stile renders...", benchmark, randomize ? "randomized " : "");
   263             char tmp_name[] = "pt-tile-XXXXXX";
   389 
   264 
   390             // n times
   265             if (strcmp(out_path, "-") == 0) {
   391             for (int i = 0; i < benchmark; i++) {
   266                 // use stdout
   392                 // randomize x, y
   267                 if ((out_file = fdopen(STDOUT_FILENO, "wb")) == NULL) {
   393                 if (randomize)
   268                     log_errno("fdopen: STDOUT_FILENO");
   394                     randomize_tile(&ti, info);
       
   395 
       
   396                 if (do_tile(ctx, image, &ti, out_path))
   269                     goto error;
   397                     goto error;
   270                 }
       
   271             
       
   272             } else if (false /* tmp */) {
       
   273                 int fd;
       
   274                 
       
   275                 // temporary file for output
       
   276                 if ((fd = mkstemp(tmp_name)) < 0) {
       
   277                     log_errno("mkstemp");
       
   278                     goto error;
       
   279                 }
       
   280 
       
   281                 out_path = tmp_name;
       
   282 
       
   283                 // open out
       
   284                 if ((out_file = fdopen(fd, "wb")) == NULL) {
       
   285                     log_errno("fdopen");
       
   286                     goto error;
       
   287                 }
       
   288 
       
   289             } else {
       
   290                 // use file
       
   291                 if ((out_file = fopen(out_path, "wb")) == NULL) {
       
   292                     log_errno("fopen: %s", out_path);
       
   293                     goto error;
       
   294                 }
       
   295 
       
   296             }
   398             }
   297 
   399 
   298             
   400         } else if (out_path) {
   299             if (ctx) {
   401             // randomize x, y
   300                 // render
   402             if (randomize)
   301                 log_info("\tAsync render tile %zux%zu@(%zu,%zu) -> %s", ti.width, ti.height, ti.x, ti.y, out_path);
   403                 randomize_tile(&ti, info);
   302 
   404 
   303                 if ((err = pt_image_tile_async(image, &ti, out_file)))
   405             // just once
   304                     log_errno("pt_image_tile_async: %s: %s", img_path, pt_strerror(err));
   406             if (do_tile(ctx, image, &ti, out_path))
   305 
   407                 goto error;
   306             } else {
   408 
   307                 // render
   409         }
   308                 log_info("\tRender tile %zux%zu@(%zu,%zu) -> %s", ti.width, ti.height, ti.x, ti.y, out_path);
       
   309 
       
   310                 if ((err = pt_image_tile_file(image, &ti, out_file)))
       
   311                     log_errno("pt_image_tile_file: %s: %s", img_path, pt_strerror(err));
       
   312                 
       
   313                 // cleanup
       
   314                 if (fclose(out_file))
       
   315                     log_warn_errno("fclose: out_file");
       
   316             }
       
   317         }
       
   318 
       
   319 error:
   410 error:
   320         // cleanup
   411         // cleanup
   321         // XXX: leak because of async
   412         // XXX: leak because of async
   322         if (!ctx)
   413         if (!ctx)
   323             pt_image_destroy(image);
   414             pt_image_destroy(image);