74
|
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 |
|