--- a/include/pngtile.h Sat Jan 09 16:03:11 2010 +0200
+++ b/include/pngtile.h Sun Jan 24 23:03:12 2010 +0200
@@ -8,6 +8,7 @@
*/
#include <stddef.h>
#include <stdio.h> // for FILE*
+#include <stdint.h>
/**
* "Global" context shared between images
@@ -52,6 +53,14 @@
};
/**
+ * Modifyable params for update
+ */
+struct pt_image_params {
+ /** Don't write out any contiguous regions of this color. Left-aligned in whatever format the source image is in */
+ uint8_t background_color[4];
+};
+
+/**
* Info for image tile
*
* The tile may safely overlap with the edge of the image, but it should not be entirely outside of the image
@@ -109,8 +118,10 @@
/**
* Update the given image's cache.
+ *
+ * @param params optional parameters to use for the update process
*/
-int pt_image_update (struct pt_image *image);
+int pt_image_update (struct pt_image *image, const struct pt_image_params *params);
/**
* Load the image's cache in read-only mode without trying to update it.
--- a/src/lib/cache.c Sat Jan 09 16:03:11 2010 +0200
+++ b/src/lib/cache.c Sun Jan 24 23:03:12 2010 +0200
@@ -330,7 +330,74 @@
return err;
}
-int pt_cache_update_png (struct pt_cache *cache, png_structp png, png_infop info)
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+
+/**
+ * Decode the PNG data directly to mmap() - not good for sparse backgrounds
+ */
+static int decode_png_raw (struct pt_cache *cache, png_structp png, png_infop info)
+{
+ // write out raw image data a row at a time
+ for (size_t row = 0; row < cache->header->height; row++) {
+ // read row data, non-interlaced
+ png_read_row(png, cache->data + row * cache->header->row_bytes, NULL);
+ }
+
+ return 0;
+}
+
+static int decode_png_sparse (struct pt_cache *cache, png_structp png, png_infop info)
+{
+ // one row of pixel data
+ uint8_t *row_buf;
+
+ // alloc
+ if ((row_buf = malloc(cache->header->row_bytes)) == NULL)
+ RETURN_ERROR(PT_ERR_MEM);
+
+ // decode each row at a time
+ for (size_t row = 0; row < cache->header->height; row++) {
+ // read row data, non-interlaced
+ png_read_row(png, row_buf, NULL);
+
+ // skip background-colored regions to keep the cache file sparse
+ // ...in blocks of PT_CACHE_BLOCK_SIZE bytes
+ for (size_t col_base = 0; col_base < cache->header->width; ){
+ // size of this block in bytes
+ size_t block_size = min(PT_CACHE_BLOCK_SIZE * cache->header->col_bytes, cache->header->row_bytes - col_base);
+
+ // ...each pixel
+ for (
+ size_t col = col_base;
+
+ // BLOCK_SIZE * col_bytes wide, don't go over the edge
+ col < col_base + block_size;
+
+ col += cache->header->col_bytes
+ ) {
+ // test this pixel
+ if (bcmp(row_buf + col, cache->header->params.background_color, cache->header->col_bytes)) {
+ // differs
+ memcpy(
+ cache->data + row * cache->header->row_bytes + col_base,
+ row_buf + col_base,
+ block_size
+ );
+
+ // skip to next block
+ break;
+ }
+ }
+
+ // skip this block
+ continue;
+ }
+ }
+
+ return 0;
+}
+
+int pt_cache_update_png (struct pt_cache *cache, png_structp png, png_infop info, const struct pt_image_params *params)
{
struct pt_cache_header header;
int err;
@@ -383,17 +450,17 @@
log_debug("num_palette=%u", num_palette);
}
+ // any params
+ if (params)
+ header.params = *params;
+
// create .tmp and write out header
if ((err = pt_cache_create(cache, &header)))
return err;
-
-
- // write out raw image data a row at a time
- for (size_t row = 0; row < header.height; row++) {
- // read row data, non-interlaced
- png_read_row(png, cache->data + row * header.row_bytes, NULL);
- }
-
+
+ // decode
+ if ((err = decode_png_sparse(cache, png, info)))
+ return err;
// move from .tmp to .cache
if ((err = pt_cache_create_done(cache)))
--- a/src/lib/cache.h Sat Jan 09 16:03:11 2010 +0200
+++ b/src/lib/cache.h Sun Jan 24 23:03:12 2010 +0200
@@ -62,9 +62,17 @@
/** Palette entries, up to 256 entries used */
png_color palette[PNG_MAX_PALETTE_LENGTH];
+
+ /** Parameters used */
+ struct pt_image_params params;
};
/**
+ * Handle sparse data at this granularity (pixels)
+ */
+#define PT_CACHE_BLOCK_SIZE 64
+
+/**
* Construct the image cache info object associated with the given image.
*/
int pt_cache_new (struct pt_cache **cache_ptr, const char *path, int mode);
@@ -84,7 +92,7 @@
/**
* Update the cache data from the given PNG image.
*/
-int pt_cache_update_png (struct pt_cache *cache, png_structp png, png_infop info);
+int pt_cache_update_png (struct pt_cache *cache, png_structp png, png_infop info, const struct pt_image_params *params);
/**
* Open the existing .cache for use. If already opened, does nothing.
--- a/src/lib/image.c Sat Jan 09 16:03:11 2010 +0200
+++ b/src/lib/image.c Sun Jan 24 23:03:12 2010 +0200
@@ -119,7 +119,7 @@
/**
* Open the PNG image, and write out to the cache
*/
-static int pt_image_update_cache (struct pt_image *image)
+static int pt_image_update_cache (struct pt_image *image, const struct pt_image_params *params)
{
png_structp png;
png_infop info;
@@ -145,7 +145,7 @@
JUMP_ERROR(err);
// pass to cache object
- if ((err = pt_cache_update_png(image->cache, png, info)))
+ if ((err = pt_cache_update_png(image->cache, png, info, params)))
JUMP_ERROR(err);
// finish off, ignore trailing data
@@ -221,9 +221,9 @@
return pt_cache_status(image->cache, image->path);
}
-int pt_image_update (struct pt_image *image)
+int pt_image_update (struct pt_image *image, const struct pt_image_params *params)
{
- return pt_image_update_cache(image);
+ return pt_image_update_cache(image, params);
}
int pt_image_load (struct pt_image *image)
--- a/src/util/main.c Sat Jan 09 16:03:11 2010 +0200
+++ b/src/util/main.c Sun Jan 24 23:03:12 2010 +0200
@@ -15,6 +15,7 @@
{ "verbose", false, NULL, 'v' },
{ "debug", false, NULL, 'D' },
{ "force-update", false, NULL, 'U' },
+ { "background", true, NULL, 'B' },
{ "width", true, NULL, 'W' },
{ "height", true, NULL, 'H' },
{ "x", true, NULL, 'x' },
@@ -38,6 +39,7 @@
"\t-v, --verbose display more informational output\n"
"\t-D, --debug equivalent to -v\n"
"\t-U, --force-update unconditionally update image caches\n"
+ "\t-B, --background set background pattern for cache update\n"
"\t-W, --width set tile width\n"
"\t-H, --height set tile height\n"
"\t-x, --x set tile x offset\n"
@@ -52,11 +54,12 @@
int opt;
bool force_update = false;
struct pt_tile_info ti = {0, 0, 0, 0, 0};
+ struct pt_image_params update_params = { };
int threads = 2;
int tmp, err;
// parse arguments
- while ((opt = getopt_long(argc, argv, "hqvDUW:H:x:y:z:j:", options, NULL)) != -1) {
+ while ((opt = getopt_long(argc, argv, "hqvDUB:W:H:x:y:z:j:", options, NULL)) != -1) {
switch (opt) {
case 'h':
// display help
@@ -83,6 +86,23 @@
break;
+ case 'B':
+ // background pattern
+ {
+ unsigned int b1, b2, b3, b4;
+
+ // parse 0xXXXXXXXX
+ if (sscanf(optarg, "0x%02x%02x%02x%02x", &b1, &b2, &b3, &b4) != 4)
+ FATAL("Invalid hex value for -B/--background: %s", optarg);
+
+ // store
+ update_params.background_color[0] = b1;
+ update_params.background_color[1] = b2;
+ update_params.background_color[2] = b3;
+ update_params.background_color[3] = b4;
+
+ } break;
+
case 'W':
ti.width = strtol(optarg, NULL, 0); break;
@@ -100,7 +120,7 @@
case 'j':
if ((tmp = strtol(optarg, NULL, 0)) < 1)
- FATAL("Invalid value for -j/--threads");
+ FATAL("Invalid value for -j/--threads: %s", optarg);
threads = tmp; break;
@@ -168,7 +188,7 @@
log_debug("\tUpdating image cache...");
- if ((err = pt_image_update(image))) {
+ if ((err = pt_image_update(image, &update_params))) {
log_warn_errno("pt_image_update: %s: %s", img_path, pt_strerror(err));
}