src/pngtile/main.c
changeset 74 7c8226668e87
child 77 29c57814204a
equal deleted inserted replaced
73:5dfb245b814d 74:7c8226668e87
       
     1 #include "shared/log.h"
       
     2 
       
     3 #include "pngtile.h"
       
     4 
       
     5 #include <getopt.h>
       
     6 #include <stdio.h>
       
     7 #include <stdbool.h>
       
     8 
       
     9 /**
       
    10  * Command-line options
       
    11  */
       
    12 static const struct option options[] = {
       
    13     { "help",           false,  NULL,   'h' },
       
    14     { "quiet",          false,  NULL,   'q' },
       
    15     { "verbose",        false,  NULL,   'v' },
       
    16     { "debug",          false,  NULL,   'D' },
       
    17     { "force-update",   false,  NULL,   'U' },
       
    18     { "no-update",      false,  NULL,   'N' },
       
    19     { "background",     true,   NULL,   'B' },
       
    20     { "width",          true,   NULL,   'W' },
       
    21     { "height",         true,   NULL,   'H' },
       
    22     { "x",              true,   NULL,   'x' },
       
    23     { "y",              true,   NULL,   'y' },
       
    24     { "zoom",           true,   NULL,   'z' },
       
    25     { "threads",        true,   NULL,   'j' },
       
    26     { 0,                0,      0,      0   }
       
    27 };
       
    28 
       
    29 /**
       
    30  * Print usage/help info on stderr
       
    31  */
       
    32 void help (const char *argv0)
       
    33 {
       
    34     fprintf(stderr, "Usage: %s [options] <image> [...]\n", argv0);
       
    35     fprintf(stderr,
       
    36         "Open each of the given image files, check cache status, optionally update their cache, display image info, and\n"
       
    37         "optionally render a tile of each.\n"
       
    38         "\n"
       
    39         "\t-h, --help           show this help and exit\n"
       
    40         "\t-q, --quiet          supress informational output\n"
       
    41         "\t-v, --verbose        display more informational output\n"
       
    42         "\t-D, --debug          equivalent to -v\n"
       
    43         "\t-U, --force-update   unconditionally update image caches\n"
       
    44         "\t-N, --no-update      do not update the image cache\n"
       
    45         "\t-B, --background     set background pattern for sparse cache file: 0xHH..\n"
       
    46         "\t-W, --width          set tile width\n"
       
    47         "\t-H, --height         set tile height\n"
       
    48         "\t-x, --x              set tile x offset\n"
       
    49         "\t-y, --y              set tile z offset\n"
       
    50         "\t-z, --zoom           set zoom factor (<0)\n"
       
    51         "\t-j, --threads        number of threads\n"
       
    52     );
       
    53 }
       
    54 
       
    55 int main (int argc, char **argv)
       
    56 {
       
    57     int opt;
       
    58     bool force_update = false, no_update = false;
       
    59     struct pt_tile_info ti = {0, 0, 0, 0, 0};
       
    60     struct pt_image_params update_params = { };
       
    61     int threads = 2;
       
    62     int tmp, err;
       
    63     
       
    64     // parse arguments
       
    65     while ((opt = getopt_long(argc, argv, "hqvDUNB:W:H:x:y:z:j:", options, NULL)) != -1) {
       
    66         switch (opt) {
       
    67             case 'h':
       
    68                 // display help
       
    69                 help(argv[0]);
       
    70                 
       
    71                 return EXIT_SUCCESS;
       
    72 
       
    73             case 'q':
       
    74                 // supress excess log output
       
    75                 set_log_level(LOG_WARN);
       
    76 
       
    77                 break;
       
    78 
       
    79             case 'v':
       
    80             case 'D':
       
    81                 // display additional output
       
    82                 set_log_level(LOG_DEBUG);
       
    83 
       
    84                 break;
       
    85             
       
    86             case 'U':
       
    87                 // force update of image caches
       
    88                 force_update = true;
       
    89                 
       
    90                 break;
       
    91             
       
    92             case 'N':
       
    93                 // supress update of image caches
       
    94                 no_update = true;
       
    95 
       
    96                 break;
       
    97 
       
    98             case 'B':
       
    99                 // background pattern
       
   100                 {
       
   101                     unsigned int b1 = 0, b2 = 0, b3 = 0, b4 = 0;
       
   102                     
       
   103                     // parse 0xXXXXXXXX
       
   104                     if (sscanf(optarg, "0x%02x%02x%02x%02x", &b1, &b2, &b3, &b4) < 1)
       
   105                         FATAL("Invalid hex value for -B/--background: %s", optarg);
       
   106                     
       
   107                     // store
       
   108                     update_params.background_color[0] = b1;
       
   109                     update_params.background_color[1] = b2;
       
   110                     update_params.background_color[2] = b3;
       
   111                     update_params.background_color[3] = b4;
       
   112 
       
   113                 } break;
       
   114 
       
   115             case 'W':
       
   116                 ti.width = strtol(optarg, NULL, 0); break;
       
   117 
       
   118             case 'H':
       
   119                 ti.height = strtol(optarg, NULL, 0); break;
       
   120 
       
   121             case 'x':
       
   122                 ti.x = strtol(optarg, NULL, 0); break;
       
   123 
       
   124             case 'y':
       
   125                 ti.y = strtol(optarg, NULL, 0); break;
       
   126 
       
   127             case 'z':
       
   128                 ti.zoom = strtol(optarg, NULL, 0); break;
       
   129 
       
   130             case 'j':
       
   131                 if ((tmp = strtol(optarg, NULL, 0)) < 1)
       
   132                     FATAL("Invalid value for -j/--threads: %s", optarg);
       
   133 
       
   134                 threads = tmp; break;
       
   135 
       
   136             case '?':
       
   137                 // useage error
       
   138                 help(argv[0]);
       
   139 
       
   140                 return EXIT_FAILURE;
       
   141 
       
   142             default:
       
   143                 // getopt???
       
   144                 FATAL("getopt_long returned unknown code %d", opt);
       
   145         }
       
   146     }
       
   147     
       
   148     // end-of-arguments?
       
   149     if (!argv[optind])
       
   150         EXIT_WARN(EXIT_FAILURE, "No images given");
       
   151     
       
   152 
       
   153 
       
   154     struct pt_ctx *ctx = NULL;
       
   155     struct pt_image *image = NULL;
       
   156     enum pt_cache_status status;
       
   157 
       
   158     // build ctx
       
   159     log_debug("Construct pt_ctx with %d threads", threads);
       
   160 
       
   161     if ((err = pt_ctx_new(&ctx, threads)))
       
   162         EXIT_ERROR(EXIT_FAILURE, "pt_ctx_new: threads=%d", threads);
       
   163 
       
   164     
       
   165     // process each image in turn
       
   166     log_debug("Processing %d images...", argc - optind);
       
   167 
       
   168     for (int i = optind; i < argc; i++) {
       
   169         const char *img_path = argv[i];
       
   170 
       
   171         log_debug("Loading image from: %s...", img_path);
       
   172 
       
   173         // open
       
   174         if ((err = pt_image_open(&image, ctx, img_path, PT_OPEN_UPDATE))) {
       
   175             log_errno("pt_image_open: %s: %s", img_path, pt_strerror(err));
       
   176             continue;
       
   177         }
       
   178 
       
   179         log_info("Opened image at: %s", img_path);
       
   180         
       
   181         // check if stale
       
   182         if ((status = pt_image_status(image)) < 0) {
       
   183             log_errno("pt_image_status: %s: %s", img_path, pt_strerror(status));
       
   184             goto error;
       
   185         }
       
   186         
       
   187         // update if stale
       
   188         if (status != PT_CACHE_FRESH || force_update) {
       
   189             if (status == PT_CACHE_NONE)
       
   190                 log_debug("\tImage cache is missing");
       
   191 
       
   192             else if (status == PT_CACHE_STALE)
       
   193                 log_debug("\tImage cache is stale");
       
   194             
       
   195             else if (status == PT_CACHE_INCOMPAT)
       
   196                 log_debug("\tImage cache is incompatible");
       
   197 
       
   198             else if (status == PT_CACHE_FRESH)
       
   199                 log_debug("\tImage cache is fresh");
       
   200             
       
   201             if (!no_update) {
       
   202                 log_debug("\tUpdating image cache...");
       
   203 
       
   204                 if ((err = pt_image_update(image, &update_params))) {
       
   205                     log_warn_errno("pt_image_update: %s: %s", img_path, pt_strerror(err));
       
   206                 }
       
   207 
       
   208                 log_info("\tUpdated image cache");
       
   209 
       
   210             } else {
       
   211                 log_warn("\tSupressing cache update");
       
   212             }
       
   213 
       
   214         } else {    
       
   215             log_debug("\tImage cache is fresh");
       
   216         }
       
   217 
       
   218         // show info
       
   219         const struct pt_image_info *info;
       
   220         
       
   221         if ((err = pt_image_info(image, &info))) {
       
   222             log_warn_errno("pt_image_info: %s: %s", img_path, pt_strerror(err));
       
   223 
       
   224         } else {
       
   225             log_info("\tImage dimensions: %zux%zu", info->img_width, info->img_height);
       
   226             log_info("\tImage mtime=%ld, bytes=%zu", (long) info->image_mtime, info->image_bytes);
       
   227             log_info("\tCache mtime=%ld, bytes=%zu, blocks=%zu (%zu bytes)", 
       
   228                     (long) info->cache_mtime, info->cache_bytes, info->cache_blocks, info->cache_blocks * 512
       
   229             );
       
   230         }
       
   231 
       
   232         // render tile?
       
   233         if (ti.width && ti.height) {
       
   234             char tmp_name[] = "pt-tile-XXXXXX";
       
   235             int fd;
       
   236             FILE *out;
       
   237             
       
   238             // temporary file for output
       
   239             if ((fd = mkstemp(tmp_name)) < 0) {
       
   240                 log_errno("mkstemp");
       
   241                 
       
   242                 continue;
       
   243             }
       
   244 
       
   245             // open out
       
   246             if ((out = fdopen(fd, "w")) == NULL) {
       
   247                 log_errno("fdopen");
       
   248 
       
   249                 continue;
       
   250             }
       
   251             
       
   252             // ensure it's loaded
       
   253             log_debug("\tLoad image cache...");
       
   254 
       
   255             if ((err = pt_image_load(image)))
       
   256                 log_errno("pt_image_load: %s", pt_strerror(err));
       
   257 
       
   258             // render
       
   259             log_info("\tAsync render tile %zux%zu@(%zu,%zu) -> %s", ti.width, ti.height, ti.x, ti.y, tmp_name);
       
   260 
       
   261 
       
   262             if ((err = pt_image_tile_async(image, &ti, out)))
       
   263                 log_errno("pt_image_tile: %s: %s", img_path, pt_strerror(err));
       
   264         }
       
   265 
       
   266 error:
       
   267         // cleanup
       
   268         // XXX: leak because of async: pt_image_destroy(image);
       
   269         ;
       
   270     }
       
   271 
       
   272     log_info("Waiting for images to finish...");
       
   273 
       
   274     // wait for tile operations to finish...
       
   275     pt_ctx_shutdown(ctx);
       
   276 
       
   277     log_info("Done");
       
   278 
       
   279     return 0;
       
   280 }
       
   281