multiframe: Move frame info to allocated record

Avoid the overhead in ImlibImage when not doing multiframe loads.
This commit is contained in:
Kim Woelders 2022-10-27 18:40:36 +02:00
parent b1bbe1d9e8
commit e353a684c2
10 changed files with 200 additions and 126 deletions

View File

@ -131,6 +131,17 @@ typedef struct _ImlibImageTag {
struct _ImlibImageTag *next;
} ImlibImageTag;
typedef struct {
int canvas_w; /* Canvas size */
int canvas_h;
int frame_count; /* Number of frames */
int frame_x; /* Frame origin */
int frame_y;
int frame_flags; /* Frame flags */
int frame_delay; /* Frame delay (ms) */
int loop_count; /* Animation loops */
} ImlibImageFrame;
struct _ImlibImage {
ImlibImageFileInfo *fi;
ImlibLdCtx *lc;
@ -141,14 +152,6 @@ struct _ImlibImage {
char rsvd[3];
int frame;
int canvas_w; /* Canvas size */
int canvas_h;
int frame_count; /* Number of frames */
int frame_x; /* Frame origin */
int frame_y;
int frame_flags; /* Frame flags */
int frame_delay; /* Frame delay (ms) */
int loop_count; /* Animation loops */
};
/* Must match the ones in Imlib2.h.in */
@ -176,6 +179,8 @@ void __imlib_FreeTag(ImlibImage * im, ImlibImageTag * t);
const char *__imlib_GetKey(const ImlibImage * im);
ImlibImageFrame *__imlib_GetFrame(ImlibImage * im);
void __imlib_LoadProgressSetPass(ImlibImage * im,
int pass, int n_pass);
int __imlib_LoadProgress(ImlibImage * im,

View File

@ -677,21 +677,31 @@ EAPI void
imlib_image_get_frame_info(Imlib_Frame_Info * info)
{
ImlibImage *im;
ImlibImageFrame *fp;
CHECK_PARAM_POINTER("image", ctx->image);
CAST_IMAGE(im, ctx->image);
info->loop_count = im->loop_count;
info->frame_count = im->frame_count;
fp = im->pframe;
if (!fp)
{
memset(info, 0, sizeof(Imlib_Frame_Info));
info->canvas_w = info->frame_w = im->w;
info->canvas_h = info->frame_h = im->h;
return;
}
info->loop_count = fp->loop_count;
info->frame_count = fp->frame_count;
info->frame_num = im->frame;
info->canvas_w = im->canvas_w ? im->canvas_w : im->w;
info->canvas_h = im->canvas_h ? im->canvas_h : im->h;
info->frame_x = im->frame_x;
info->frame_y = im->frame_y;
info->canvas_w = fp->canvas_w ? fp->canvas_w : im->w;
info->canvas_h = fp->canvas_h ? fp->canvas_h : im->h;
info->frame_x = fp->frame_x;
info->frame_y = fp->frame_y;
info->frame_w = im->w;
info->frame_h = im->h;
info->frame_flags = im->frame_flags;
info->frame_delay = im->frame_delay ? im->frame_delay : 100;
info->frame_flags = fp->frame_flags;
info->frame_delay = fp->frame_delay ? fp->frame_delay : 100;
}
EAPI void

View File

@ -207,6 +207,8 @@ __imlib_ConsumeImage(ImlibImage * im)
if (im->fi)
__imlib_ImageFileContextPop(im);
free(im->pframe);
free(im);
}
@ -729,8 +731,11 @@ __imlib_LoadProgress(ImlibImage * im, int x, int y, int w, int h)
lc->area += w * h;
lc->pct = (100. * lc->area + .1) / (im->w * im->h);
x += im->frame_x;
y += im->frame_y;
if (im->pframe)
{
x += im->pframe->frame_x;
y += im->pframe->frame_y;
}
rc = !lc->progress(im, lc->pct, x, y, w, h);
@ -762,8 +767,11 @@ __imlib_LoadProgressRows(ImlibImage * im, int row, int nrows)
pct = (100 * nrtot * (lc->pass + 1)) / (im->h * lc->n_pass);
if (pct == 100 || pct >= lc->pct + lc->granularity)
{
col += im->frame_x;
row += im->frame_y;
if (im->pframe)
{
col += im->pframe->frame_x;
row += im->pframe->frame_y;
}
rc = !lc->progress(im, pct, col, row, im->w, nrows);
lc->row = nrtot;
lc->pct += lc->granularity;
@ -772,6 +780,14 @@ __imlib_LoadProgressRows(ImlibImage * im, int row, int nrows)
return rc;
}
__EXPORT__ ImlibImageFrame *
__imlib_GetFrame(ImlibImage * im)
{
if (im->frame > 0 && !im->pframe)
im->pframe = calloc(1, sizeof(ImlibImageFrame));
return im->pframe;
}
/* free and image - if its uncachable and refcoutn is 0 - free it in reality */
void
__imlib_FreeImage(ImlibImage * im)

View File

@ -42,6 +42,17 @@ typedef struct _ImlibImageTag {
struct _ImlibImageTag *next;
} ImlibImageTag;
typedef struct {
int canvas_w; /* Canvas size */
int canvas_h;
int frame_count; /* Number of frames */
int frame_x; /* Frame origin */
int frame_y;
int frame_flags; /* Frame flags */
int frame_delay; /* Frame delay (ms) */
int loop_count; /* Animation loops */
} ImlibImageFrame;
struct _ImlibImage {
ImlibImageFileInfo *fi;
ImlibLdCtx *lc;
@ -52,14 +63,6 @@ struct _ImlibImage {
char rsvd[3];
int frame;
int canvas_w; /* Canvas size */
int canvas_h;
int frame_count; /* Number of frames */
int frame_x; /* Frame origin */
int frame_y;
int frame_flags; /* Frame flags */
int frame_delay; /* Frame delay (ms) */
int loop_count; /* Animation loops */
/* vvv Private vvv */
ImlibLoader *loader;
@ -75,6 +78,8 @@ struct _ImlibImage {
ImlibBorder border;
ImlibImageTag *tags;
ImlibImageDataMemoryFunction data_memory_func;
ImlibImageFrame *pframe;
/* ^^^ Private ^^^ */
};
@ -124,6 +129,8 @@ ImlibImageTag *__imlib_RemoveTag(ImlibImage * im, const char *key);
void __imlib_FreeTag(ImlibImage * im, ImlibImageTag * t);
void __imlib_FreeAllTags(ImlibImage * im);
ImlibImageFrame *__imlib_GetFrame(ImlibImage * im);
void __imlib_SetCacheSize(int size);
int __imlib_GetCacheSize(void);
int __imlib_CurrentCacheSize(void);

View File

@ -65,7 +65,9 @@ _load(ImlibImage * im, int load_data)
int i, j, bg, bits;
int transp;
uint32_t colormap[256];
int fcount, frame, multiframe;
int fcount, frame;
bool multiframe;
ImlibImageFrame *pf;
rc = LOAD_FAIL;
rows = NULL;
@ -85,20 +87,21 @@ _load(ImlibImage * im, int load_data)
transp = -1;
fcount = 0;
frame = im->frame;
if (frame > 0)
pf = __imlib_GetFrame(im);
if (pf)
{
im->frame_count = gif->ImageCount;
im->loop_count = 0; /* Loop forever */
if (im->frame_count > 1)
im->frame_flags |= FF_IMAGE_ANIMATED;
im->canvas_w = gif->SWidth;
im->canvas_h = gif->SHeight;
pf->frame_count = gif->ImageCount;
pf->loop_count = 0; /* Loop forever */
if (pf->frame_count > 1)
pf->frame_flags |= FF_IMAGE_ANIMATED;
pf->canvas_w = gif->SWidth;
pf->canvas_h = gif->SHeight;
D("Canvas WxH=%dx%d frames=%d repeat=%d\n",
im->canvas_w, im->canvas_h, im->frame_count, im->loop_count);
pf->canvas_w, pf->canvas_h, pf->frame_count, pf->loop_count);
#if 0
if (frame > 1 && frame > im->frame_count)
if (frame > 1 && frame > pf->frame_count)
goto quit;
#endif
}
@ -155,16 +158,23 @@ _load(ImlibImage * im, int load_data)
im->w = gif->Image.Width;
im->h = gif->Image.Height;
im->frame_x = gif->Image.Left;
im->frame_y = gif->Image.Top;
if (pf)
{
pf->frame_x = gif->Image.Left;
pf->frame_y = gif->Image.Top;
D("Canvas WxH=%dx%d frame=%d/%d X,Y=%d,%d WxH=%dx%d\n",
pf->canvas_w, pf->canvas_h, gif->ImageCount,
pf->frame_count, pf->frame_x, pf->frame_y, im->w, im->h);
}
else
{
D("WxH=%dx%d\n", im->w, im->h);
}
if (!IMAGE_DIMENSIONS_OK(im->w, im->h))
goto quit;
D("Canvas WxH=%dx%d frame=%d/%d X,Y=%d,%d WxH=%dx%d\n",
im->canvas_w, im->canvas_h, gif->ImageCount, im->frame_count,
im->frame_x, im->frame_y, im->w, im->h);
DL(" CM S=%p I=%p\n", cmap, gif->Image.ColorMap);
if (gif->Image.ColorMap)
cmap = gif->Image.ColorMap;
@ -203,7 +213,7 @@ _load(ImlibImage * im, int load_data)
}
/* Break if no specific frame was requested */
if (frame == 0)
if (!pf)
break;
}
else if (rec == EXTENSION_RECORD_TYPE)
@ -218,20 +228,20 @@ _load(ImlibImage * im, int load_data)
DL(" EXTENSION_RECORD_TYPE(%d): ic=%d: ext_code=%02x: %02x %02x %02x %02x %02x\n", //
rec, gif->ImageCount, ext_code,
ext[0], ext[1], ext[2], ext[3], ext[4]);
if (ext_code == GRAPHICS_EXT_FUNC_CODE
if (pf && ext_code == GRAPHICS_EXT_FUNC_CODE
&& gif->ImageCount == frame - 1)
{
bits = ext[1];
im->frame_delay = 10 * (0x100 * ext[3] + ext[2]);
pf->frame_delay = 10 * (0x100 * ext[3] + ext[2]);
if (bits & 1)
transp = ext[4];
disp = (bits >> 2) & 0x7;
if (disp == 2 || disp == 3)
im->frame_flags |= FF_FRAME_DISPOSE_CLEAR;
im->frame_flags |= FF_FRAME_BLEND;
pf->frame_flags |= FF_FRAME_DISPOSE_CLEAR;
pf->frame_flags |= FF_FRAME_BLEND;
D(" Frame %d: disp=%d ui=%d tr=%d, delay=%d transp = #%02x\n", //
gif->ImageCount + 1, disp, (bits >> 1) & 1, bits & 1,
im->frame_delay, transp);
pf->frame_delay, transp);
}
ext = NULL;
DGifGetExtensionNext(gif, &ext);
@ -244,14 +254,18 @@ _load(ImlibImage * im, int load_data)
}
im->has_alpha = transp >= 0;
im->frame_count = fcount;
multiframe = im->frame_count > 1;
if (multiframe)
im->frame_flags |= FF_IMAGE_ANIMATED;
multiframe = false;
if (pf)
{
pf->frame_count = fcount;
multiframe = pf->frame_count > 1;
if (multiframe)
pf->frame_flags |= FF_IMAGE_ANIMATED;
}
if (!rows)
{
if (frame > 1 && frame > im->frame_count)
if (pf && frame > 1 && frame > pf->frame_count)
QUIT_WITH_RC(LOAD_BADFRAME);
goto quit;

View File

@ -272,6 +272,7 @@ _load(ImlibImage * im, int load_data)
ie_t *ie;
uint32_t *pdst;
uint32_t pixel;
ImlibImageFrame *pf;
rc = LOAD_FAIL;
@ -304,11 +305,12 @@ _load(ImlibImage * im, int load_data)
rc = LOAD_BADIMAGE; /* Format accepted */
frame = im->frame;
if (frame > 0)
pf = __imlib_GetFrame(im);
if (pf)
{
im->frame_count = ico.idir.icons;
pf->frame_count = ico.idir.icons;
if (frame > 1 && frame > im->frame_count)
if (frame > 1 && frame > pf->frame_count)
QUIT_WITH_RC(LOAD_BADFRAME);
}

View File

@ -48,6 +48,7 @@ _load(ImlibImage * im, int load_data)
JxlBasicInfo info;
JxlFrameHeader fhdr;
int frame, delay_unit;
ImlibImageFrame *pf;
#if MAX_RUNNERS > 0
size_t n_runners;
@ -100,6 +101,7 @@ _load(ImlibImage * im, int load_data)
goto quit;
frame = im->frame;
pf = __imlib_GetFrame(im);
delay_unit = 0;
for (;;)
@ -137,23 +139,23 @@ _load(ImlibImage * im, int load_data)
im->h = info.ysize;
im->has_alpha = info.alpha_bits > 0;
if (frame > 0)
if (pf)
{
if (info.have_animation)
{
im->frame_count = 1234567890; // FIXME - Hack
im->loop_count = info.animation.num_loops;
im->frame_flags |= FF_IMAGE_ANIMATED;
im->canvas_w = info.xsize;
im->canvas_h = info.ysize;
pf->frame_count = 1234567890; // FIXME - Hack
pf->loop_count = info.animation.num_loops;
pf->frame_flags |= FF_IMAGE_ANIMATED;
pf->canvas_w = info.xsize;
pf->canvas_h = info.ysize;
}
D("Canvas WxH=%dx%d frames=%d repeat=%d\n",
im->canvas_w, im->canvas_h,
im->frame_count, im->loop_count);
pf->canvas_w, pf->canvas_h,
pf->frame_count, pf->loop_count);
if (frame > 1 && im->frame_count > 0
&& frame > im->frame_count)
if (frame > 1 && pf->frame_count > 0
&& frame > pf->frame_count)
QUIT_WITH_RC(LOAD_BADFRAME);
if (frame > 1)
@ -178,12 +180,14 @@ _load(ImlibImage * im, int load_data)
break;
case JXL_DEC_FRAME:
if (!pf)
break;
JxlDecoderGetFrameHeader(dec, &fhdr);
if (fhdr.is_last)
im->frame_count = frame;
im->frame_delay = fhdr.duration * delay_unit;
pf->frame_count = frame;
pf->frame_delay = fhdr.duration * delay_unit;
D("Frame duration=%d tc=%08x nl=%d last=%d\n",
im->frame_delay, fhdr.timecode, fhdr.name_length, fhdr.is_last);
pf->frame_delay, fhdr.timecode, fhdr.name_length, fhdr.is_last);
break;
case JXL_DEC_FULL_IMAGE:

View File

@ -274,7 +274,7 @@ row_callback(png_struct * png_ptr, png_byte * new_row,
if (im->lc)
{
if (im->frame_count > 1)
if (im->frame > 0)
{
if (done)
__imlib_LoadProgress(im, 0, 0, im->w, im->h);
@ -304,6 +304,7 @@ _load(ImlibImage * im, int load_data)
int w, h, frame, fcount;
bool save_fdat, seen_actl, seen_fctl;
png_chunk_t cbuf;
ImlibImageFrame *pf;
/* read header */
rc = LOAD_FAIL;
@ -338,7 +339,8 @@ _load(ImlibImage * im, int load_data)
info_callback, row_callback, NULL);
frame = im->frame;
if (frame <= 0)
pf = __imlib_GetFrame(im);
if (!pf)
goto scan_done;
/* Animation info requested. Look it up to find the frame's
@ -376,11 +378,11 @@ _load(ImlibImage * im, int load_data)
case PNG_TYPE_acTL:
seen_actl = true;
#define P (&chunk->actl)
im->frame_count = htonl(P->num_frames);
im->loop_count = htonl(P->num_plays);
D("num_frames=%d num_plays=%d\n", im->frame_count,
pf->frame_count = htonl(P->num_frames);
pf->loop_count = htonl(P->num_plays);
D("num_frames=%d num_plays=%d\n", pf->frame_count,
htonl(P->num_plays));
if (frame > im->frame_count)
if (frame > pf->frame_count)
QUIT_WITH_RC(LOAD_BADFRAME);
break;
#undef P
@ -453,29 +455,32 @@ _load(ImlibImage * im, int load_data)
im->w = htonl(pfctl->w);
im->h = htonl(pfctl->h);
#endif
im->canvas_w = w;
im->canvas_h = h;
im->frame_x = htonl(pfctl->x);
im->frame_y = htonl(pfctl->y);
if (pfctl->dispose_op == APNG_DISPOSE_OP_BACKGROUND)
im->frame_flags |= FF_FRAME_DISPOSE_CLEAR;
else if (pfctl->dispose_op == APNG_DISPOSE_OP_PREVIOUS)
im->frame_flags |= FF_FRAME_DISPOSE_PREV;
if (pfctl->blend_op != APNG_BLEND_OP_SOURCE)
im->frame_flags |= FF_FRAME_BLEND;
val = htons(pfctl->delay_den);
if (val == 0)
val = 100;
im->frame_delay = 1000 * htons(pfctl->delay_num) / val;
if (pf)
{
pf->canvas_w = w;
pf->canvas_h = h;
pf->frame_x = htonl(pfctl->x);
pf->frame_y = htonl(pfctl->y);
if (pfctl->dispose_op == APNG_DISPOSE_OP_BACKGROUND)
pf->frame_flags |= FF_FRAME_DISPOSE_CLEAR;
else if (pfctl->dispose_op == APNG_DISPOSE_OP_PREVIOUS)
pf->frame_flags |= FF_FRAME_DISPOSE_PREV;
if (pfctl->blend_op != APNG_BLEND_OP_SOURCE)
pf->frame_flags |= FF_FRAME_BLEND;
val = htons(pfctl->delay_den);
if (val == 0)
val = 100;
pf->frame_delay = 1000 * htons(pfctl->delay_num) / val;
D("WxH=%dx%d(%dx%d) X,Y=%d,%d depth=%d color=%d comp=%d filt=%d interlace=%d disp=%d blend=%d delay=%d/%d\n", //
htonl(pfctl->w), htonl(pfctl->h),
im->canvas_w, im->canvas_h, im->frame_x, im->frame_y,
P->depth, P->color, P->comp, P->filt, P->interl,
pfctl->dispose_op, pfctl->blend_op,
pfctl->delay_num, pfctl->delay_den);
D("WxH=%dx%d(%dx%d) X,Y=%d,%d depth=%d color=%d comp=%d filt=%d interlace=%d disp=%d blend=%d delay=%d/%d\n", //
htonl(pfctl->w), htonl(pfctl->h),
pf->canvas_w, pf->canvas_h, pf->frame_x, pf->frame_y,
P->depth, P->color, P->comp, P->filt, P->interl,
pfctl->dispose_op, pfctl->blend_op,
pfctl->delay_num, pfctl->delay_den);
}
if (frame <= 1)
if (!pf || frame <= 1)
break; /* Process actual IHDR chunk */
/* Process fake IHDR for frame */
@ -493,7 +498,7 @@ _load(ImlibImage * im, int load_data)
/* Needed chunks should now be read */
/* Note - Just before starting to process data chunks libpng will
* call info_callback() */
if (im->frame_count <= 0)
if (!pf || pf->frame_count <= 0)
break; /* Regular PNG - Process actual IDAT chunk */
if (frame == 1 && seen_fctl)
break; /* APNG, First frame is IDAT */
@ -506,10 +511,12 @@ _load(ImlibImage * im, int load_data)
case PNG_TYPE_acTL:
#define P (&chunk->actl)
if (im->frame_count > 1)
im->frame_flags |= FF_IMAGE_ANIMATED;
if (!pf)
continue;
if (pf->frame_count > 1)
pf->frame_flags |= FF_IMAGE_ANIMATED;
D("num_frames=%d num_plays=%d\n",
im->frame_count, htonl(P->num_plays));
pf->frame_count, htonl(P->num_plays));
continue;
#undef P

View File

@ -22,6 +22,7 @@ _load(ImlibImage * im, int load_data)
unsigned char *src;
uint32_t *dst;
int i, j;
ImlibImageFrame *pf;
rc = LOAD_FAIL;
spdoc = NULL;
@ -47,12 +48,13 @@ _load(ImlibImage * im, int load_data)
rc = LOAD_BADIMAGE; /* Format accepted */
frame = im->frame;
if (frame > 0)
pf = __imlib_GetFrame(im);
if (pf)
{
im->frame_count = spectre_document_get_n_pages(spdoc);
D("Pages=%d\n", im->frame_count);
pf->frame_count = spectre_document_get_n_pages(spdoc);
D("Pages=%d\n", pf->frame_count);
if (frame > 1 && frame > im->frame_count)
if (frame > 1 && frame > pf->frame_count)
QUIT_WITH_RC(LOAD_BADFRAME);
}
else

View File

@ -17,6 +17,7 @@ _load(ImlibImage * im, int load_data)
WebPDemuxer *demux;
WebPIterator iter;
int frame;
ImlibImageFrame *pf;
rc = LOAD_FAIL;
@ -34,19 +35,21 @@ _load(ImlibImage * im, int load_data)
rc = LOAD_BADIMAGE; /* Format accepted */
frame = im->frame;
if (frame > 0)
pf = __imlib_GetFrame(im);
if (pf)
{
im->frame_count = WebPDemuxGetI(demux, WEBP_FF_FRAME_COUNT);
im->loop_count = WebPDemuxGetI(demux, WEBP_FF_LOOP_COUNT);
if (im->frame_count > 1)
im->frame_flags |= FF_IMAGE_ANIMATED;
im->canvas_w = WebPDemuxGetI(demux, WEBP_FF_CANVAS_WIDTH);
im->canvas_h = WebPDemuxGetI(demux, WEBP_FF_CANVAS_HEIGHT);
frame = im->frame;
pf->frame_count = WebPDemuxGetI(demux, WEBP_FF_FRAME_COUNT);
pf->loop_count = WebPDemuxGetI(demux, WEBP_FF_LOOP_COUNT);
if (pf->frame_count > 1)
pf->frame_flags |= FF_IMAGE_ANIMATED;
pf->canvas_w = WebPDemuxGetI(demux, WEBP_FF_CANVAS_WIDTH);
pf->canvas_h = WebPDemuxGetI(demux, WEBP_FF_CANVAS_HEIGHT);
D("Canvas WxH=%dx%d frames=%d repeat=%d\n",
im->canvas_w, im->canvas_h, im->frame_count, im->loop_count);
pf->canvas_w, pf->canvas_h, pf->frame_count, pf->loop_count);
if (frame > 1 && frame > im->frame_count)
if (frame > 1 && frame > pf->frame_count)
QUIT_WITH_RC(LOAD_BADFRAME);
}
else
@ -61,18 +64,22 @@ _load(ImlibImage * im, int load_data)
im->w = iter.width;
im->h = iter.height;
im->frame_x = iter.x_offset;
im->frame_y = iter.y_offset;
im->frame_delay = iter.duration;
if (iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND)
im->frame_flags |= FF_FRAME_DISPOSE_CLEAR;
if (iter.blend_method == WEBP_MUX_BLEND)
im->frame_flags |= FF_FRAME_BLEND;
if (pf)
{
pf->frame_x = iter.x_offset;
pf->frame_y = iter.y_offset;
pf->frame_delay = iter.duration;
if (iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND)
pf->frame_flags |= FF_FRAME_DISPOSE_CLEAR;
if (iter.blend_method == WEBP_MUX_BLEND)
pf->frame_flags |= FF_FRAME_BLEND;
D("Canvas WxH=%dx%d frame=%d/%d X,Y=%d,%d WxH=%dx%d alpha=%d T=%d dm=%d co=%d bl=%d\n", //
im->canvas_w, im->canvas_h, iter.frame_num, im->frame_count,
im->frame_x, im->frame_y, im->w, im->h, iter.has_alpha,
im->frame_delay, iter.dispose_method, iter.complete, iter.blend_method);
D("Canvas WxH=%dx%d frame=%d/%d X,Y=%d,%d WxH=%dx%d alpha=%d T=%d dm=%d co=%d bl=%d\n", //
pf->canvas_w, pf->canvas_h, iter.frame_num, pf->frame_count,
pf->frame_x, pf->frame_y, im->w, im->h, iter.has_alpha,
pf->frame_delay, iter.dispose_method, iter.complete,
iter.blend_method);
}
if (!IMAGE_DIMENSIONS_OK(im->w, im->h))
goto quit;