diff options
author | Kim Woelders <kim@woelders.dk> | 2022-01-10 03:46:06 +0100 |
---|---|---|
committer | Kim Woelders <kim@woelders.dk> | 2022-01-16 20:53:58 +0100 |
commit | 5dfccd57134f0f7ed9eaafe9e15d1bf25886e31a (patch) | |
tree | bfd429b125038c8f01e956a7d1d2454542b5a6ba | |
parent | 83f55515fb44a0dfa785f3385456813fff6c82d3 (diff) | |
download | imlib2-5dfccd57134f0f7ed9eaafe9e15d1bf25886e31a.tar.gz |
PNG loader: Rewrite to use callback API
Preparing for multiframe support.
-rw-r--r-- | src/modules/loaders/loader_png.c | 246 |
1 files changed, 171 insertions, 75 deletions
diff --git a/src/modules/loaders/loader_png.c b/src/modules/loaders/loader_png.c index 67aa08c..bd6777b 100644 --- a/src/modules/loaders/loader_png.c +++ b/src/modules/loaders/loader_png.c @@ -1,18 +1,29 @@ #include "loader_common.h" #include <png.h> +#include <stdint.h> #include <sys/mman.h> -/* this is a quick sample png loader module... nice and small isn't it? */ - -/* PNG stuff */ -#define PNG_BYTES_TO_CHECK 4 +#define DBG_PFX "LDR-png" #define USE_IMLIB2_COMMENT_TAG 0 +#define _PNG_MIN_SIZE 60 /* Min. PNG file size (8 + 3*12 + 13 (+3) */ +#define _PNG_SIG_SIZE 8 /* Signature size */ + typedef struct { - unsigned char **lines; -} ImLib_PNG_data; + ImlibImage *im; + char load_data; + char rc; + + char interlace; +} ctx_t; + +#if 0 +static const unsigned char png_sig[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a +}; +#endif #if USE_IMLIB2_COMMENT_TAG static void @@ -22,62 +33,44 @@ comment_free(ImlibImage * im, void *data) } #endif -int -load2(ImlibImage * im, int load_data) +static void +user_error_fn(png_struct * png_ptr, const char *txt) { - int rc, ok; - void *fdata; - png_uint_32 w32, h32; - char hasa; - png_structp png_ptr = NULL; - png_infop info_ptr = NULL; - int bit_depth, color_type, interlace_type; - ImLib_PNG_data pdata; - int i; - - /* read header */ - rc = LOAD_FAIL; - pdata.lines = NULL; - - if (im->fsize < PNG_BYTES_TO_CHECK) - return rc; - - fdata = - mmap(NULL, PNG_BYTES_TO_CHECK, PROT_READ, MAP_SHARED, fileno(im->fp), 0); - if (fdata == MAP_FAILED) - return LOAD_BADFILE; - - ok = png_sig_cmp(fdata, 0, PNG_BYTES_TO_CHECK) == 0; +#if 0 + D("%s: %s\n", __func__, txt); +#endif +} - munmap(fdata, PNG_BYTES_TO_CHECK); +static void +user_warning_fn(png_struct * png_ptr, const char *txt) +{ + D("%s: %s\n", __func__, txt); +} - if (!ok) - return rc; +static void +info_callback(png_struct * png_ptr, png_info * info_ptr) +{ + int rc; + ctx_t *ctx = png_get_progressive_ptr(png_ptr); + ImlibImage *im = ctx->im; + png_uint_32 w32, h32; + int bit_depth, color_type, interlace_type; + int hasa; - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) - goto quit; + rc = LOAD_BADIMAGE; /* Format accepted */ - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) - goto quit; + png_get_IHDR(png_ptr, info_ptr, &w32, &h32, &bit_depth, &color_type, + &interlace_type, NULL, NULL); - rc = LOAD_BADIMAGE; /* Format accepted */ + D("%s: WxH=%dx%d depth=%d color=%d interlace=%d\n", __func__, + w32, h32, bit_depth, color_type, interlace_type); - if (setjmp(png_jmpbuf(png_ptr))) - QUIT_WITH_RC(LOAD_BADIMAGE); + im->w = w32; + im->h = h32; - png_init_io(png_ptr, im->fp); - png_read_info(png_ptr, info_ptr); - png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *) (&w32), - (png_uint_32 *) (&h32), &bit_depth, &color_type, - &interlace_type, NULL, NULL); if (!IMAGE_DIMENSIONS_OK(w32, h32)) goto quit; - im->w = (int)w32; - im->h = (int)h32; - hasa = 0; if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) hasa = 1; @@ -87,7 +80,7 @@ load2(ImlibImage * im, int load_data) hasa = 1; UPDATE_FLAG(im->flags, F_HAS_ALPHA, hasa); - if (!load_data) + if (!ctx->load_data) QUIT_WITH_RC(LOAD_SUCCESS); /* Load data */ @@ -128,38 +121,143 @@ load2(ImlibImage * im, int load_data) png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); #endif + /* NB! If png_read_update_info() isn't called processing stops here */ + png_read_update_info(png_ptr, info_ptr); + if (!__imlib_AllocateData(im)) QUIT_WITH_RC(LOAD_OOM); - pdata.lines = malloc(im->h * sizeof(unsigned char *)); - if (!pdata.lines) - QUIT_WITH_RC(LOAD_OOM); + rc = LOAD_SUCCESS; - for (i = 0; i < im->h; i++) - pdata.lines[i] = (unsigned char *)(im->data + i * im->w); + quit: + ctx->rc = rc; + if (!ctx->load_data || rc != LOAD_SUCCESS) + png_longjmp(png_ptr, 1); +} - if (im->lc) - { - int y, pass, n_passes, nrows = 1; +static void +row_callback(png_struct * png_ptr, png_byte * new_row, + png_uint_32 row_num, int pass) +{ + ctx_t *ctx = png_get_progressive_ptr(png_ptr); + ImlibImage *im = ctx->im; + DATA32 *dptr; + const DATA32 *sptr; + int x, y, x0, dx, y0, dy; + int done; - n_passes = png_set_interlace_handling(png_ptr); - for (pass = 0; pass < n_passes; pass++) - { - __imlib_LoadProgressSetPass(im, pass, n_passes); + DL("%s: png=%p data=%p row=%d, pass=%d\n", __func__, png_ptr, new_row, + row_num, pass); - for (y = 0; y < im->h; y += nrows) - { - png_read_rows(png_ptr, &pdata.lines[y], NULL, nrows); + if (!im->data) + return; - if (__imlib_LoadProgressRows(im, y, nrows)) - QUITx_WITH_RC(LOAD_BREAK, quit1); - } + if (ctx->interlace) + { + x0 = PNG_PASS_START_COL(pass); + dx = PNG_PASS_COL_OFFSET(pass); + y0 = PNG_PASS_START_ROW(pass); + dy = PNG_PASS_ROW_OFFSET(pass); + + DL("x0, dx = %d,%d y0,dy = %d,%d cols/rows=%d/%d\n", + x0, dx, y0, dy, + PNG_PASS_COLS(im->w, pass), PNG_PASS_ROWS(im->h, pass)); + y = y0 + dy * row_num; + + sptr = (const DATA32 *)new_row; /* Assuming aligned */ + dptr = im->data + y * im->w; + for (x = x0; x < im->w; x += dx) + { +#if 0 + dptr[x] = PIXEL_ARGB(new_row[ii + 3], new_row[ii + 2], + new_row[ii + 1], new_row[ii + 0]); + D("x,y = %d,%d (i,j, ii=%d,%d %d): %08x\n", x, y, + ii / 4, row_num, ii, dptr[x]); +#else + dptr[x] = *sptr++; +#endif } + + done = pass >= 6 && (int)row_num >= PNG_PASS_ROWS(im->h, pass) - 1; + if (im->lc && done) + __imlib_LoadProgress(im, im->frame_x, im->frame_y, im->w, im->h); } else { - png_read_image(png_ptr, pdata.lines); + y = row_num; + + dptr = im->data + y * im->w; + memcpy(dptr, new_row, sizeof(DATA32) * im->w); + + done = (int)row_num >= im->h - 1; + + if (im->lc) + { + if (im->frame_count > 1) + { + if (done) + __imlib_LoadProgress(im, im->frame_x, im->frame_y, im->w, + im->h); + } + else if (__imlib_LoadProgressRows(im, y, 1)) + { + png_process_data_pause(png_ptr, 0); + ctx->rc = LOAD_BREAK; + } + } } +} + +int +load2(ImlibImage * im, int load_data) +{ + int rc; + void *fdata; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + ctx_t ctx = { 0 }; + + /* read header */ + rc = LOAD_FAIL; + + if (im->fsize < _PNG_MIN_SIZE) + return rc; + + fdata = mmap(NULL, im->fsize, PROT_READ, MAP_SHARED, fileno(im->fp), 0); + if (fdata == MAP_FAILED) + return LOAD_BADFILE; + + /* Signature check */ + if (png_sig_cmp(fdata, 0, _PNG_SIG_SIZE)) + goto quit; + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, + user_error_fn, user_warning_fn); + if (!png_ptr) + goto quit; + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + goto quit; + + rc = LOAD_BADIMAGE; /* Format accepted */ + + ctx.im = im; + ctx.load_data = load_data; + ctx.rc = rc; + + if (setjmp(png_jmpbuf(png_ptr))) + QUIT_WITH_RC(ctx.rc); + + /* Set up processing via callbacks */ + png_set_progressive_read_fn(png_ptr, &ctx, + info_callback, row_callback, NULL); + + png_process_data(png_ptr, info_ptr, fdata, im->fsize); + + rc = ctx.rc; + if (rc <= 0) + goto quit; rc = LOAD_SUCCESS; @@ -167,7 +265,7 @@ load2(ImlibImage * im, int load_data) #ifdef PNG_TEXT_SUPPORTED { png_textp text; - int num; + int i, num; num = 0; png_get_text(png_ptr, info_ptr, &text, &num); @@ -181,13 +279,11 @@ load2(ImlibImage * im, int load_data) #endif #endif - quit1: - png_read_end(png_ptr, info_ptr); quit: - free(pdata.lines); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); if (rc <= 0) __imlib_FreeData(im); + munmap(fdata, im->fsize); return rc; } |