328 pt_cache_abort(cache); |
328 pt_cache_abort(cache); |
329 |
329 |
330 return err; |
330 return err; |
331 } |
331 } |
332 |
332 |
333 int pt_cache_update_png (struct pt_cache *cache, png_structp png, png_infop info) |
333 #define min(a, b) (((a) < (b)) ? (a) : (b)) |
|
334 |
|
335 /** |
|
336 * Decode the PNG data directly to mmap() - not good for sparse backgrounds |
|
337 */ |
|
338 static int decode_png_raw (struct pt_cache *cache, png_structp png, png_infop info) |
|
339 { |
|
340 // write out raw image data a row at a time |
|
341 for (size_t row = 0; row < cache->header->height; row++) { |
|
342 // read row data, non-interlaced |
|
343 png_read_row(png, cache->data + row * cache->header->row_bytes, NULL); |
|
344 } |
|
345 |
|
346 return 0; |
|
347 } |
|
348 |
|
349 static int decode_png_sparse (struct pt_cache *cache, png_structp png, png_infop info) |
|
350 { |
|
351 // one row of pixel data |
|
352 uint8_t *row_buf; |
|
353 |
|
354 // alloc |
|
355 if ((row_buf = malloc(cache->header->row_bytes)) == NULL) |
|
356 RETURN_ERROR(PT_ERR_MEM); |
|
357 |
|
358 // decode each row at a time |
|
359 for (size_t row = 0; row < cache->header->height; row++) { |
|
360 // read row data, non-interlaced |
|
361 png_read_row(png, row_buf, NULL); |
|
362 |
|
363 // skip background-colored regions to keep the cache file sparse |
|
364 // ...in blocks of PT_CACHE_BLOCK_SIZE bytes |
|
365 for (size_t col_base = 0; col_base < cache->header->width; ){ |
|
366 // size of this block in bytes |
|
367 size_t block_size = min(PT_CACHE_BLOCK_SIZE * cache->header->col_bytes, cache->header->row_bytes - col_base); |
|
368 |
|
369 // ...each pixel |
|
370 for ( |
|
371 size_t col = col_base; |
|
372 |
|
373 // BLOCK_SIZE * col_bytes wide, don't go over the edge |
|
374 col < col_base + block_size; |
|
375 |
|
376 col += cache->header->col_bytes |
|
377 ) { |
|
378 // test this pixel |
|
379 if (bcmp(row_buf + col, cache->header->params.background_color, cache->header->col_bytes)) { |
|
380 // differs |
|
381 memcpy( |
|
382 cache->data + row * cache->header->row_bytes + col_base, |
|
383 row_buf + col_base, |
|
384 block_size |
|
385 ); |
|
386 |
|
387 // skip to next block |
|
388 break; |
|
389 } |
|
390 } |
|
391 |
|
392 // skip this block |
|
393 continue; |
|
394 } |
|
395 } |
|
396 |
|
397 return 0; |
|
398 } |
|
399 |
|
400 int pt_cache_update_png (struct pt_cache *cache, png_structp png, png_infop info, const struct pt_image_params *params) |
334 { |
401 { |
335 struct pt_cache_header header; |
402 struct pt_cache_header header; |
336 int err; |
403 int err; |
337 |
404 |
338 // XXX: check cache_mode |
405 // XXX: check cache_mode |
381 memcpy(&header.palette, palette, num_palette * sizeof(*palette)); |
448 memcpy(&header.palette, palette, num_palette * sizeof(*palette)); |
382 |
449 |
383 log_debug("num_palette=%u", num_palette); |
450 log_debug("num_palette=%u", num_palette); |
384 } |
451 } |
385 |
452 |
|
453 // any params |
|
454 if (params) |
|
455 header.params = *params; |
|
456 |
386 // create .tmp and write out header |
457 // create .tmp and write out header |
387 if ((err = pt_cache_create(cache, &header))) |
458 if ((err = pt_cache_create(cache, &header))) |
388 return err; |
459 return err; |
389 |
460 |
390 |
461 // decode |
391 // write out raw image data a row at a time |
462 if ((err = decode_png_sparse(cache, png, info))) |
392 for (size_t row = 0; row < header.height; row++) { |
463 return err; |
393 // read row data, non-interlaced |
|
394 png_read_row(png, cache->data + row * header.row_bytes, NULL); |
|
395 } |
|
396 |
|
397 |
464 |
398 // move from .tmp to .cache |
465 // move from .tmp to .cache |
399 if ((err = pt_cache_create_done(cache))) |
466 if ((err = pt_cache_create_done(cache))) |
400 // XXX: pt_cache_abort? |
467 // XXX: pt_cache_abort? |
401 return err; |
468 return err; |