mirror of
https://gitee.com/houstudio/Cdroid.git
synced 2024-12-05 05:37:53 +08:00
reduce gif memory usage
This commit is contained in:
parent
91006c3f92
commit
41dd98e959
@ -77,22 +77,25 @@ int AnimatedImageDrawable::getAlpha()const{
|
||||
|
||||
constexpr int FINISHED=-1;
|
||||
void AnimatedImageDrawable::draw(Canvas& canvas){
|
||||
if (mStarting) {
|
||||
mStarting = false;
|
||||
if (!mStarting) {
|
||||
mStarting = true;
|
||||
postOnAnimationStart();
|
||||
}
|
||||
canvas.save();
|
||||
Cairo::RefPtr<Cairo::ImageSurface>image = mAnimatedImageState->mImage;
|
||||
ImageDecoder*mDecoder = mAnimatedImageState->mDecoder;
|
||||
const long nextDelay = mDecoder->getFrameDuration(mCurrentFrame);
|
||||
mDecoder->readImage(image,mCurrentFrame);
|
||||
const long nextDelay = mDecoder->getFrameDuration(mCurrentFrame);
|
||||
// a value <= 0 indicates that the drawable is stopped or that renderThread
|
||||
// will manage the animation
|
||||
LOGV("%p draw Frame %d/%d nextDelay=%d",this,mCurrentFrame,mAnimatedImageState->mFrameCount,nextDelay);
|
||||
if(mStarting){
|
||||
if (nextDelay > 0) {
|
||||
if (mRunnable == nullptr) {
|
||||
mRunnable = std::bind(&AnimatedImageDrawable::invalidateSelf,this);
|
||||
mRunnable = [this](){
|
||||
invalidateSelf();
|
||||
mCurrentFrame=(mCurrentFrame+1)%mAnimatedImageState->mFrameCount;
|
||||
};
|
||||
}
|
||||
scheduleSelf(mRunnable, nextDelay + SystemClock::uptimeMillis());
|
||||
} else if (nextDelay<=0){// == FINISHED) {
|
||||
|
@ -22,46 +22,7 @@ APNGDecoder::APNGDecoder() {
|
||||
APNGDecoder::~APNGDecoder() {
|
||||
}
|
||||
|
||||
int APNGDecoder::readImage(Cairo::RefPtr<Cairo::ImageSurface>image,int& frameIndex) {
|
||||
if(!mFrames.empty()){
|
||||
ImageFrame*frm = mFrames[frameIndex];
|
||||
#if 1
|
||||
const int dststride = image->get_stride();
|
||||
const int srcstride = frm->width*4;
|
||||
int u, v, al;
|
||||
const int bop= frm->disposalMethod&0xFF;
|
||||
uint8_t* dst = (image->get_data() + frm->y*dststride + frm->x*4);
|
||||
uint8_t* src = frm->pixels;
|
||||
for(int y=0;y<frm->height;y++){
|
||||
uint8_t*dp = dst;
|
||||
uint8_t*sp = src;
|
||||
for(int x=0;x<frm->width;x++,dp+=4,sp+=4){
|
||||
if((sp[3]==255)||(dp[3]==0)||(bop==APNG_BLEND_OP_SOURCE)||(frameIndex==0))*(uint32_t*)dp= *(uint32_t*)sp;
|
||||
else if(sp[3]!=0){
|
||||
u = sp[3]*255;
|
||||
v = (255-sp[3])*dp[3];
|
||||
al = 255*255-(255-sp[3])*(255-dp[3]);
|
||||
dp[0] = (sp[0]*u + dp[0]*v)/al;
|
||||
dp[1] = (sp[1]*u + dp[1]*v)/al;
|
||||
dp[2] = (sp[2]*u + dp[2]*v)/al;
|
||||
dp[3] = al/255;
|
||||
}
|
||||
}
|
||||
dst += dststride;
|
||||
src += srcstride;
|
||||
}
|
||||
#else
|
||||
Cairo::RefPtr<Cairo::Context>ctx = Cairo::Context::create(image);
|
||||
Cairo::RefPtr<Cairo::ImageSurface>frame=Cairo::ImageSurface::create(frm->pixels,Cairo::Surface::Format::ARGB32,int(frm->width),int(frm->height),int(frm->width*4));
|
||||
ctx->set_operator(((frm->disposalMethod&0xFF)&&(frameIndex))?Cairo::Context::Operator::OVER:Cairo::Context::Operator::SOURCE);
|
||||
ctx->set_source(frame,frm->x,frm->y);
|
||||
ctx->rectangle(frm->x,frm->y,frm->width,frm->height);
|
||||
ctx->fill();
|
||||
#endif
|
||||
LOGV("FRAME[%d](%d,%d,%d,%d)disposalMethod=%x delay=%d",frameIndex,frm->x,frm->y,frm->width,frm->height,frm->disposalMethod,frm->duration);
|
||||
frameIndex = (frameIndex+1)%mFrameCount;
|
||||
return frm->duration;
|
||||
}
|
||||
int APNGDecoder::readImage(Cairo::RefPtr<Cairo::ImageSurface>image,int frameIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -72,104 +33,6 @@ static void istream_png_reader(png_structp png_ptr, png_bytep png_data, png_size
|
||||
};
|
||||
|
||||
int APNGDecoder::load(std::istream&istream) {
|
||||
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (!png_ptr) {
|
||||
LOGE("Error creating read struct");
|
||||
return false;
|
||||
}
|
||||
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr) {
|
||||
LOGE("Error creating info struct");
|
||||
png_destroy_read_struct(&png_ptr, NULL, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||
LOGE("Error during libpng init_io");
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
png_set_read_fn(png_ptr,(void*)&istream,istream_png_reader);
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
int bit_depth, color_type;
|
||||
png_get_IHDR(png_ptr, info_ptr,(uint32_t*)&mImageWidth, (uint32_t*)&mImageHeight, &bit_depth, &color_type, NULL, NULL, NULL);
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_PALETTE) {
|
||||
png_set_palette_to_rgb(png_ptr);
|
||||
}
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
|
||||
png_set_expand_gray_1_2_4_to_8(png_ptr);
|
||||
}
|
||||
|
||||
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
|
||||
png_set_tRNS_to_alpha(png_ptr);
|
||||
}
|
||||
|
||||
if (bit_depth == 16) {
|
||||
png_set_strip_16(png_ptr);
|
||||
}
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
|
||||
png_set_gray_to_rgb(png_ptr);
|
||||
}
|
||||
|
||||
png_set_bgr(png_ptr);
|
||||
png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER);
|
||||
png_read_update_info(png_ptr, info_ptr);
|
||||
color_type = png_get_color_type(png_ptr, info_ptr);
|
||||
|
||||
mFrameCount = png_get_num_frames(png_ptr, info_ptr);
|
||||
mFrames.reserve(mFrameCount);
|
||||
uint32_t imgBytes = 0;
|
||||
ImageFrame*snap = new ImageFrame;
|
||||
snap->x = snap->y = 0;snap->disposalMethod = 0;
|
||||
snap->width = mImageWidth ; snap->height = mImageHeight;
|
||||
snap->pixels= new uint8_t[mImageWidth*mImageHeight*4];
|
||||
auto tm1=SystemClock::currentTimeMillis();
|
||||
for (png_uint_32 ifrm = 0; ifrm < mFrameCount; ++ifrm) {
|
||||
png_uint_16 delay_num , delay_den;
|
||||
png_byte dispose_op , blend_op;
|
||||
ImageFrame* frame = new ImageFrame;
|
||||
|
||||
png_read_frame_head(png_ptr, info_ptr);
|
||||
png_get_next_frame_fcTL(png_ptr, info_ptr, &frame->width, &frame->height, &frame->x, &frame->y,
|
||||
&delay_num, &delay_den, &dispose_op, &blend_op);
|
||||
frame->disposalMethod = (dispose_op<<8)|blend_op;
|
||||
frame->duration = delay_num * 1000 / (delay_den ? delay_den : 1000);// Convert to milliseconds
|
||||
frame->pixels = new uint8_t[frame->width * frame->height * 4];
|
||||
|
||||
std::vector<png_bytep> row_pointers(frame->height);
|
||||
imgBytes += frame->width * frame->height * 4;
|
||||
if(ifrm==0){
|
||||
memset(frame->pixels,0,frame->width * frame->height * 4);
|
||||
}else{
|
||||
switch(snap->disposalMethod>>8){
|
||||
case APNG_DISPOSE_OP_PREVIOUS:memcpy(frame->pixels,snap->pixels,frame->width*frame->height*4);break;
|
||||
case APNG_DISPOSE_OP_BACKGROUND:memset(frame->pixels,0,frame->width * frame->height * 4);break;
|
||||
case APNG_DISPOSE_OP_NONE:break;
|
||||
}
|
||||
}
|
||||
for (png_uint_32 y = 0; y < frame->height; ++y) {
|
||||
row_pointers[y] = frame->pixels + y* frame->width * 4;
|
||||
}
|
||||
png_read_image(png_ptr, row_pointers.data());
|
||||
if((dispose_op==APNG_DISPOSE_OP_PREVIOUS)&&((snap->disposalMethod>>8)!=APNG_DISPOSE_OP_PREVIOUS)){
|
||||
memcpy(snap->pixels,frame->pixels,frame->width * frame->height * 4);
|
||||
}
|
||||
LOGV("FRAME[%d](%d,%d,%d,%d)op=%d/%d",ifrm,frame->x,frame->y,frame->width,frame->height,dispose_op,blend_op);
|
||||
snap->disposalMethod=(dispose_op<<8)|blend_op;
|
||||
mFrames.push_back(frame);
|
||||
}
|
||||
auto tm2=SystemClock::currentTimeMillis();
|
||||
LOGD("image(%dx%d)%d frames %d bytes color_type=%d/%d/%d time=%dms",mImageWidth,mImageHeight,mFrameCount,imgBytes,
|
||||
color_type,PNG_COLOR_TYPE_RGB,PNG_COLOR_TYPE_RGB_ALPHA,tm2-tm1);
|
||||
delete []snap->pixels;
|
||||
delete snap;
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
return mFrameCount;
|
||||
return 0;
|
||||
}
|
||||
}/*namesapce*/
|
||||
|
@ -7,19 +7,21 @@
|
||||
|
||||
namespace cdroid{
|
||||
|
||||
typedef struct {
|
||||
std::vector<int>delays;
|
||||
GifFileType*gif;
|
||||
}GIFPrivate;
|
||||
|
||||
GIFDecoder::GIFDecoder(){
|
||||
GIFPrivate*priv = new GIFPrivate;
|
||||
priv->gif=nullptr;
|
||||
mPrivate=priv;
|
||||
}
|
||||
|
||||
static int GIFRead(GifFileType *gifFile, GifByteType *buff, int rdlen){
|
||||
std::istream*is=(std::istream*)gifFile->UserData;
|
||||
is->read((char*)buff,rdlen);
|
||||
return is->gcount();
|
||||
}
|
||||
static int gifDrawFrame(GifFileType*gif,int¤t_frame,size_t pxstride,uint8_t *pixels,bool force_DISPOSE_1);
|
||||
|
||||
GIFDecoder::~GIFDecoder(){
|
||||
DGifCloseFile((GifFileType*)mPrivate,nullptr);
|
||||
GIFPrivate*priv=(GIFPrivate*)mPrivate;
|
||||
DGifCloseFile((GifFileType*)priv->gif,nullptr);
|
||||
delete priv;
|
||||
}
|
||||
|
||||
#define ARGB(a, r, g, b) ( ((a) & 0xff) << 24 ) | ( ((r) & 0xff) << 16 ) | ( ((g) & 0xff) << 8 ) | ((b) & 0xff)
|
||||
@ -28,96 +30,14 @@ GIFDecoder::~GIFDecoder(){
|
||||
#define TRANSPARENCY(ext) ((ext)->Bytes[0] & 1)
|
||||
#define DELAY(ext) (10*((ext)->Bytes[2] << 8 | (ext)->Bytes[1]))
|
||||
|
||||
#if 10
|
||||
void GIFDecoder::setFramePixels(int frameIndex){
|
||||
int x,y;
|
||||
ImageFrame*frame = mFrames[frameIndex];
|
||||
const int pxstride = frame->width*4;
|
||||
GifFileType*gif = (GifFileType*)mPrivate;
|
||||
SavedImage *gifFrame = &gif->SavedImages[frameIndex];
|
||||
const GifImageDesc *frameInfo=&(gifFrame->ImageDesc);
|
||||
ColorMapObject *colorMap=(frameInfo->ColorMap?frameInfo->ColorMap:gif->SColorMap);
|
||||
GifColorType* bg = &colorMap->Colors[gif->SBackGroundColor];
|
||||
GifColorType* color = nullptr;
|
||||
ExtensionBlock *ext = nullptr;
|
||||
uint8_t* pixels= frame->pixels;
|
||||
uint32_t* line = nullptr;
|
||||
for (int j = 0; j < gifFrame->ExtensionBlockCount; j++) {
|
||||
if (gifFrame->ExtensionBlocks[j].Function == GRAPHICS_EXT_FUNC_CODE) {
|
||||
ext = &(gifFrame->ExtensionBlocks[j]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
frame->duration = DELAY(ext);
|
||||
frame->disposalMethod = DISPOSE(ext);
|
||||
// For DISPOSE = 1, we assume its been drawn
|
||||
if (ext && DISPOSE(ext) == 1 /*&& force_DISPOSE_1*/ && frameIndex > 0) {
|
||||
//gifDrawFrame(gif,frameIndex-1,pxstride, pixels, true);
|
||||
} else if (ext && DISPOSE(ext) == 2 && bg) {
|
||||
uint8_t*px= frame->pixels;
|
||||
for (y = 0; y < frame->height; y++) {
|
||||
line = (uint32_t *) px;
|
||||
for (x = 0; x < frame->width; x++) {
|
||||
line[x] = ARGB(255, bg->Red, bg->Green, bg->Blue);
|
||||
}
|
||||
px = (px + pxstride);
|
||||
}
|
||||
//current_frame=(current_frame+1)%gif->ImageCount;
|
||||
} else if (ext && DISPOSE(ext) == 3 && frameIndex > 1) {
|
||||
//gifDrawFrame(gif,frameIndex-2,pxstride, pixels, true);
|
||||
}//else current_frame=(current_frame+1)%gif->ImageCount;
|
||||
const bool isTransparent = TRANSPARENCY(ext);
|
||||
const int transparentIndex = TRANS_INDEX(ext);
|
||||
if (frameInfo->Interlace) {
|
||||
int n = 0, inc = 8, p = 0,loc=0;
|
||||
uint8_t* px = frame->pixels;
|
||||
for (y = 0; y < frameInfo->Height; y++) {
|
||||
for (x = 0; x < frameInfo->Width; x++) {
|
||||
loc = y * frameInfo->Width + x;
|
||||
if (ext && isTransparent && (gifFrame->RasterBits[loc] == transparentIndex)) {
|
||||
continue;
|
||||
}
|
||||
color = (ext && gifFrame->RasterBits[loc] == TRANS_INDEX(ext)) ? bg
|
||||
: &colorMap->Colors[gifFrame->RasterBits[loc]];
|
||||
if (color)
|
||||
line[x] = ARGB(255, color->Red, color->Green, color->Blue);
|
||||
}
|
||||
px = (px + pxstride * inc);
|
||||
n += inc;
|
||||
if (n >= frameInfo->Height) {
|
||||
n = 0;
|
||||
switch (p) {
|
||||
case 0:
|
||||
px = (pixels + pxstride * (4/*+ frameInfo->Top*/));
|
||||
inc = 8; p++; break;
|
||||
case 1:
|
||||
px = (pixels + pxstride * (2/*+ frameInfo->Top*/));
|
||||
inc = 4; p++; break;
|
||||
case 2:
|
||||
px = (pixels + pxstride * (1/*+ frameInfo->Top*/));
|
||||
inc = 2; p++; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uint8_t* px = frame->pixels;//( px + pxstride * frameInfo->Top);
|
||||
for (y = 0; y < frameInfo->Height; y++) {
|
||||
line = (uint32_t *) px;
|
||||
for (x = 0; x < frameInfo->Width; x++) {
|
||||
int loc = y * frameInfo->Width + x;
|
||||
if (ext && isTransparent && (gifFrame->RasterBits[loc] == transparentIndex)) {
|
||||
continue;
|
||||
}
|
||||
color = (ext && gifFrame->RasterBits[loc] == TRANS_INDEX(ext)) ? bg
|
||||
: &colorMap->Colors[gifFrame->RasterBits[loc]];
|
||||
if (color)
|
||||
line[x] = ARGB(255, color->Red, color->Green, color->Blue);
|
||||
}
|
||||
px +=pxstride;
|
||||
}
|
||||
}
|
||||
static int GIFRead(GifFileType *gifFile, GifByteType *buff, int rdlen){
|
||||
std::istream*is=(std::istream*)gifFile->UserData;
|
||||
is->read((char*)buff,rdlen);
|
||||
return is->gcount();
|
||||
}
|
||||
#endif
|
||||
|
||||
static int gifDrawFrame(GifFileType*gif,int¤t_frame,size_t pxstride,uint8_t *pixels,bool force_DISPOSE_1);
|
||||
|
||||
int GIFDecoder::load(std::istream&is){
|
||||
int err;
|
||||
GifFileType*gifFileType = DGifOpen(&is,GIFRead,&err);
|
||||
@ -126,47 +46,25 @@ int GIFDecoder::load(std::istream&is){
|
||||
DGifSlurp(gifFileType);
|
||||
|
||||
mFrameCount = gifFileType->ImageCount;
|
||||
mPrivate = gifFileType;
|
||||
((GIFPrivate*)mPrivate)->gif = gifFileType;
|
||||
mImageWidth = gifFileType->SWidth;
|
||||
mImageHeight= gifFileType->SHeight;
|
||||
for(int i=0 ; i < mFrameCount;i++){
|
||||
SavedImage *frame = &(gifFileType->SavedImages[i]);
|
||||
GifImageDesc *frameInfo=&(frame->ImageDesc);
|
||||
ImageDecoder::ImageFrame*frm=new ImageDecoder::ImageFrame();
|
||||
frm->x = frameInfo->Left;
|
||||
frm->y = frameInfo->Top;
|
||||
frm->width = frameInfo->Width;
|
||||
frm->height= frameInfo->Height;
|
||||
frm->pixels= new unsigned char[frm->width*frm->height*4];
|
||||
mFrames.push_back(frm);
|
||||
setFramePixels(i);
|
||||
LOGV("frame[%d](%d,%d,%d,%d)disposalMethod=%d delay=%d",i,frm->x,frm->y,frm->width,frm->height,frm->disposalMethod,frm->duration);
|
||||
}
|
||||
LOGD("GIF %d frames loaded size(%dx%d)",mFrameCount,mImageWidth,mImageHeight);
|
||||
return mFrameCount;
|
||||
}
|
||||
|
||||
|
||||
int GIFDecoder::readImage(Cairo::RefPtr<Cairo::ImageSurface>image,int& frameIndex){
|
||||
if(!mFrames.empty()){
|
||||
ImageFrame*frm = mFrames[frameIndex];
|
||||
const int dststride = image->get_stride();
|
||||
const int srcstride = frm->width*4;
|
||||
uint8_t* dst = (image->get_data() + frm->y*dststride + frm->x*4);
|
||||
uint8_t* src = frm->pixels;
|
||||
for(int y=0;y<frm->height;y++){
|
||||
uint32_t*ld =(uint32_t*)dst;
|
||||
uint32_t*ls =(uint32_t*)src;
|
||||
for(int x=0;x<frm->width;x++)
|
||||
ld[x]= ls[x];
|
||||
dst += dststride;
|
||||
src += srcstride;
|
||||
}
|
||||
frameIndex = (frameIndex+1)%mFrameCount;
|
||||
image->mark_dirty();
|
||||
return frm->duration;
|
||||
int GIFDecoder::readImage(Cairo::RefPtr<Cairo::ImageSurface>image,int frameIndex){
|
||||
GIFPrivate*priv=(GIFPrivate*)mPrivate;
|
||||
const int duration=gifDrawFrame(priv->gif,frameIndex,image->get_stride(),image->get_data(),false);
|
||||
if(priv->delays.size()<frameIndex+1){
|
||||
priv->delays.push_back(duration);
|
||||
}
|
||||
return gifDrawFrame((GifFileType*)mPrivate,frameIndex,image->get_stride(),image->get_data(),false);
|
||||
return duration;
|
||||
}
|
||||
|
||||
int GIFDecoder::getFrameDuration(int frameIndex)const{
|
||||
GIFPrivate*priv=(GIFPrivate*)mPrivate;
|
||||
return priv->delays.at(frameIndex);
|
||||
}
|
||||
|
||||
static int gifDrawFrame(GifFileType*gif,int¤t_frame,size_t pxstride,uint8_t *pixels,bool force_DISPOSE_1) {
|
||||
|
@ -18,10 +18,6 @@ ImageDecoder::ImageDecoder(){
|
||||
}
|
||||
|
||||
ImageDecoder::~ImageDecoder(){
|
||||
for(auto f:mFrames){
|
||||
delete []f->pixels;
|
||||
delete f;
|
||||
}
|
||||
}
|
||||
|
||||
int ImageDecoder::getWidth()const{
|
||||
@ -37,7 +33,7 @@ int ImageDecoder::getFrameCount()const{
|
||||
}
|
||||
|
||||
int ImageDecoder::getFrameDuration(int idx)const{
|
||||
int duration = ( (idx>=0) && (idx<mFrameCount) ) ? mFrames[idx]->duration:INT_MAX;
|
||||
int duration = 0;//( (idx>=0) && (idx<mFrameCount) ) ? mFrames[idx]->duration:INT_MAX;
|
||||
// Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
|
||||
// We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
|
||||
// a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
|
||||
|
@ -9,38 +9,20 @@
|
||||
namespace cdroid{
|
||||
|
||||
class ImageDecoder{
|
||||
public:
|
||||
enum DisposalMethod{
|
||||
Unspecified,
|
||||
DoNotDispose,
|
||||
RestoreToBackground,
|
||||
RestoreToPrevious
|
||||
};
|
||||
struct ImageFrame {
|
||||
unsigned char * pixels;
|
||||
unsigned int x;
|
||||
unsigned int y;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int duration;
|
||||
unsigned int disposalMethod;
|
||||
};
|
||||
|
||||
protected:
|
||||
void*mPrivate;
|
||||
int mFrameCount;
|
||||
int mImageWidth;
|
||||
int mImageHeight;
|
||||
std::vector<ImageFrame*>mFrames;
|
||||
public:
|
||||
ImageDecoder();
|
||||
virtual ~ImageDecoder();
|
||||
virtual int load(std::istream&)=0;
|
||||
int getWidth()const;
|
||||
int getHeight()const;
|
||||
int getFrameCount()const;
|
||||
int getFrameDuration(int)const;
|
||||
virtual int readImage(Cairo::RefPtr<Cairo::ImageSurface>image,int& frameIndex)=0;
|
||||
virtual int getFrameCount()const;
|
||||
virtual int getFrameDuration(int)const;
|
||||
virtual int readImage(Cairo::RefPtr<Cairo::ImageSurface>image,int frameIndex)=0;
|
||||
static ImageDecoder*create(Context*ctx,const std::string&resourceId);
|
||||
static Drawable*createAsDrawable(Context*ctx,const std::string&resourceId);
|
||||
};
|
||||
@ -50,8 +32,8 @@ public:
|
||||
GIFDecoder();
|
||||
~GIFDecoder()override;
|
||||
int load(std::istream&)override;
|
||||
int readImage(Cairo::RefPtr<Cairo::ImageSurface>image,int& frameIndex)override;
|
||||
void setFramePixels(int frameIndex);
|
||||
virtual int getFrameDuration(int)const;
|
||||
int readImage(Cairo::RefPtr<Cairo::ImageSurface>image,int frameIndex)override;
|
||||
};
|
||||
|
||||
class APNGDecoder:public ImageDecoder{
|
||||
@ -59,7 +41,7 @@ public:
|
||||
APNGDecoder();
|
||||
~APNGDecoder()override;
|
||||
int load(std::istream&)override;
|
||||
int readImage(Cairo::RefPtr<Cairo::ImageSurface>image,int& frameIndex)override;
|
||||
int readImage(Cairo::RefPtr<Cairo::ImageSurface>image,int frameIndex)override;
|
||||
};
|
||||
|
||||
class WebpDecoder:public ImageDecoder{
|
||||
@ -67,7 +49,7 @@ public:
|
||||
WebpDecoder();
|
||||
~WebpDecoder();
|
||||
int load(std::istream&)override;
|
||||
int readImage(Cairo::RefPtr<Cairo::ImageSurface>image,int& frameIndex)override;
|
||||
int readImage(Cairo::RefPtr<Cairo::ImageSurface>image,int frameIndex)override;
|
||||
};
|
||||
}/*endof namespace*/
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user