# HG changeset patch # User Tero Marttila # Date 1264366992 -7200 # Node ID 148a120ea7d59d2a1a62bdd94208177f381a0ec0 # Parent 866eb1aad566594816c391ed83c6b3c0be72125e skip contiguous regions of some background color diff -r 866eb1aad566 -r 148a120ea7d5 include/pngtile.h --- 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 #include // for FILE* +#include /** * "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. diff -r 866eb1aad566 -r 148a120ea7d5 src/lib/cache.c --- 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))) diff -r 866eb1aad566 -r 148a120ea7d5 src/lib/cache.h --- 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. diff -r 866eb1aad566 -r 148a120ea7d5 src/lib/image.c --- 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) diff -r 866eb1aad566 -r 148a120ea7d5 src/util/main.c --- 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)); }