当前位置:首页 > 生活百科

aemg动画教程(分享7日MG动画全套教程)

栏目:生活百科日期:2025-03-22浏览:0

1.概述

在深入了解Apng动画播放之前,我们需要对Apng的结构有所了解,具体参见Apng动画介绍,对Apng的整体结构有所了解后,下面我们来讲讲Apng动画的播放,主要包括Apng解析和Apng渲染两个过程。

2. Apng动画播放流程

Apng动画播放流程包括Apng解析和Apng渲染两个过程,Apng解析主要有两种方法,下面我们将会介绍,而Apng渲染主要包括三个步骤:消除(dispose)、合成(blend)、绘制(draw),由此得到Apng动画播放流程图如下:

Apng动画播放流程

3. Apng的解析

Apng的解析主要是将Apng文件转化成Apng序列帧Frame-n,从上面的流程图可知,Apng文件的解析列出了两种方案,下面来分别说说:

1)Apng文件首先经过一个解压(ApngExact)的过程,生成png序列帧保存在本地,然后经过加载(LoadPng)处理生成序列帧Frame-n。假设Apng动画文件总共有90帧,那么经过ApngExact处理后,会生成90张png序列帧保存在本地,每帧通过LoadPng处理生成Bitmap并供后面的Apng渲染使用。

2)Apng是一个独立的文件,我们自己编写读取Apng文件的代码类:ApngReader,当渲染第i帧时,通过ApngReader直接获取第i帧的Bitmap。

比较:

1)方案一是将Apng文件全部解压成png序列图片保存在本地,方案二是把Apng文件当做一个整体去处理,需要第几帧直接读取第几帧,并将该帧以Bitmap的形似保存到内存。

2)方案一解压得到的png图片在后面的渲染中需要转化成Bitamp,而方案二直接就获取了第几帧的Bitmap,相比于方案一,方案二减少了一个从SD卡读取png文件的操作。

4. Apng的渲染

方案一的具体实现大家可以参考github上面的一个项目apng-view,下面我们来讲讲方案二的具体实现,即ApngReader的具体实现。

1) 解析Apng的每一帧我们是将整个文件放到一个buffer里面,并且通过RandomAccessFile、MappedByteBuffer来读取Apng的每一帧,ApngReader的构造函数如下:

publicApngReader(StringapngFile)throwsIOException,FormatNotSupportException{RandomAccessFilef=newRandomAccessFile(apngFile,"r");mBuffer=f.getChannel().map(FileChannel.MapMode.READ_ONLY,0,f.length());f.close();if(mBuffer.getInt()!=PNG_SIG&&&&mBuffer.getInt(4)!=PNG_SIG_VER&&&&mBuffer.getInt(8)!=CODE_IHDR){thrownewFormatNotSupportException("Notapng/apngfile");}mChunk=newApngMmapParserChunk(mBuffer);reset();}

下面来看看读取每一帧的方法:

/***getnextframecontrolinfo&&bitmap**@returnnextframecontrolinfo,ornullifnonextFCTLchunk||nonextIDAT/FDAT*@throwsIOException*/publicApngFramenextFrame()throwsIOException{//resetreadpointersfrompreviousframe'slockmPngStream.clearDataChunks();mPngStream.resetPos();mChunk.unlockRead();//locatenextFCTLchunkbooleanihdrCopied=false;while(mChunk.typeCode!=CODE_fcTL){switch(mChunk.typeCode){caseCODE_IEND:returnnull;caseCODE_IHDR:mPngStream.setIHDR(mChunk.duplicateData());break;caseCODE_acTL:handleACTL(mChunk);ihdrCopied=true;break;default:handleOtherChunk(mChunk);}mChunk.parseNext();}//locatedatFCTLchunkApngFrameframe=newApngFrame();mChunk.assignTo(frame);//locatenextIDATorfdAtchunkmChunk.parseNext();//firstmovenextfromcurrentFCTLwhile(mChunk.typeCode!=CODE_IDAT&&&&mChunk.typeCode!=CODE_fdAT){switch(mChunk.typeCode){caseCODE_IEND:returnnull;caseCODE_IHDR:mPngStream.setIHDR(mChunk.duplicateData());ihdrCopied=true;break;caseCODE_acTL:handleACTL(mChunk);break;default:handleOtherChunk(mChunk);}mChunk.parseNext();}//locatedatfirstIDATorfdATchunk//collectallconsecutivedatchunksbooleanneedUpdateIHDR=true;intdataOffset=mChunk.getOffset();while(mChunk.typeCode==CODE_fdAT||mChunk.typeCode==CODE_IDAT){if(needUpdateIHDR&&&&(!ihdrCopied||mChunk.typeCode==CODE_fdAT)){mPngStream.updateIHDR(frame.getWidth(),frame.getHeight());needUpdateIHDR=false;}if(mChunk.typeCode==CODE_fdAT){mPngStream.addDataChunk(newFdat2IdatChunk(mChunk));}else{mPngStream.addDataChunk(newApngMmapParserChunk(mChunk));}mChunk.parseNext();}//lockpositionforthisframe'simageasOutputStreammChunk.lockRead(dataOffset);frame.imageStream=mPngStream;returnframe;}

2) Apng的消除操作Apng的消除操作是在ApngFrameRender的render方法做的,方法如下:

/***渲染当前帧画面**@paramframeapng中当前帧*@return渲染合成后的当前帧图像*/publicBitmaprender(ApngFrameframe,BitmapframeBmp){//执行消除操作dispose(frame);//合成当前帧blend(frame,frameBmp);returnmRenderFrame;}

dispose(ApngFrame frame)方法如下:

/***帧图像析构消除-提交结果*/privatevoiddispose(ApngFrameframe){//lastframedisposeopswitch(mLastDisposeOp){caseAPNG_DISPOSE_OP_NONE://noopbreak;caseAPNG_DISPOSE_OP_BACKGROUND://clearrectmRenderCanvas.clipRect(mDisposeRect);mRenderCanvas.drawColor(Color.TRANSPARENT,PorterDuff.Mode.CLEAR);mRenderCanvas.clipRect(mFullRect,Region.Op.REPLACE);break;caseAPNG_DISPOSE_OP_PREVIOUS://swapworkandcachebitmapBitmapbmp=mRenderFrame;mRenderFrame=mDisposedFrame;mDisposedFrame=bmp;mRenderCanvas.setBitmap(mRenderFrame);mDisposeCanvas.setBitmap(mDisposedFrame);break;}//currentframedisposeopmLastDisposeOp=frame.getDisposeOp();switch(mLastDisposeOp){caseAPNG_DISPOSE_OP_NONE://noopbreak;caseAPNG_DISPOSE_OP_BACKGROUND://cacherectfornextcleardisposeintx=frame.getxOff();inty=frame.getyOff();mDisposeRect.set(x,y,x+frame.getWidth(),y+frame.getHeight());break;caseAPNG_DISPOSE_OP_PREVIOUS://cachebmpfornextrestoredisposemDisposeCanvas.clipRect(mFullRect,Region.Op.REPLACE);mDisposeCanvas.drawColor(Color.TRANSPARENT,PorterDuff.Mode.CLEAR);mDisposeCanvas.drawBitmap(mRenderFrame,0,0,null);break;}}

3) Apng的合成操作Apng的合成操作是在每一帧经过dispose之后做的,具体方法是blend(ApngFrame frame, Bitmap frameBmp),代码如下:

/***帧图像合成*/privatevoidblend(ApngFrameframe,BitmapframeBmp){intxOff=frame.getxOff();intyOff=frame.getyOff();mRenderCanvas.clipRect(xOff,yOff,xOff+frame.getWidth(),yOff+frame.getHeight());if(frame.getBlendOp()==APNG_BLEND_OP_SOURCE){mRenderCanvas.drawColor(Color.TRANSPARENT,PorterDuff.Mode.CLEAR);}mRenderCanvas.drawBitmap(frameBmp,xOff,yOff,null);mRenderCanvas.clipRect(mFullRect,Region.Op.REPLACE);}

4) Apng的绘制Apng的每一帧经过消除、合成操作之后,就可以在View上面draw,具体代码如下:

/***drawtheappointedframe*/privatevoiddrawFrame(AnimParamsanimItem,ApngFrameframe,BitmapframeBmp){if(surfaceEnabled&&&&!isInterrupted()){//starttodrawtheframetry{Matrixmatrix=newMatrix();matrix.setScale(mScale,mScale);Bitmapbmp=mFrameRender.render(frame,frameBmp);//saveBitmap(bmp,index);index++;Canvascanvas=getHolder().lockCanvas();//anti-aliasingcanvas.drawColor(Color.TRANSPARENT,PorterDuff.Mode.CLEAR);float&[]tranLeftAndTop=ApngUtils.getTranLeftAndTop(canvas,bmp,animItem.align,mScale,animItem.percent);canvas.setDrawFilter(newPaintFlagsDrawFilter(0,Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));matrix.postTranslate(tranLeftAndTop&[0],tranLeftAndTop&[1]);canvas.drawBitmap(bmp,matrix,null);getHolder().unlockCanvasAndPost(canvas);//unlockthecanvas}catch(Exceptione){Log.e(TAG,"drawerrormsg:"+Log.getStackTraceString(e));}}}

实例我们是在SurfaceView上面来绘制Apng的每一帧,例子如下:

Activity代码:

publicclassMainActivityextendsActivity{privateApngSurfaceViewmApngSurfaceView;privatestaticfinalStringCOLOR_BALL_IMAGE_PATH="assets://color_ball.png";//privatestaticfinalStringCAR_IMAGE_PATH="assets://car.png";@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mApngSurfaceView=(ApngSurfaceView)findViewById(R.id.apng_surface_view);ButtonstartPlay=(Button)findViewById(R.id.start_play);startPlay.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){playAnim();}});}privatevoidplayAnim(){Filefile=FileUtils.processApngFile(COLOR_BALL_IMAGE_PATH,this);if(file==null)return;AnimParamsanimItem=newAnimParams();animItem.align=2;animItem.imagePath=file.getAbsolutePath();animItem.isHasBackground=true;animItem.percent=0.5f;mApngSurfaceView.addApngForPlay(animItem);}}

Layout代码:

&<?xmlversion="1.0"encoding="utf-8"?&>&<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@android:color/white"tools:context=".MainActivity"&>&<com.apng.ApngSurfaceViewandroid:id="@+id/apng_surface_view"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_gravity="center"/&>&<Buttonandroid:id="@+id/start_play"android:text="@string/play"android:layout_width="wrap_content"android:layout_height="wrap_content"/&>&</RelativeLayout&>

我们把一张Apng图片放到Asset目录下,通过ApngSurfaceView来播放。

5. 说明

例子演示:

“aemg动画教程(分享7日MG动画全套教程)” 的相关文章

easypoi合并单元格导入(EasyPoi导入导出最全案例)

下面例子为创建产生一个excel,合并单元格,然后为合并后的单元格添加边框packagetest;importjava.io.FileOutputStream;...

cpu带u和不带u的区别有什么(cpu后缀字母含义)

我们生活当中最容易接触到的就是手机电脑,但是唯一看不懂的就是各种各样的参数,比如电脑的CPU也不例外,各种各样的后缀(如i9-9900K、i5-9400F),都...

其实不愿意写网创项目类文章

来了些新读者关注,感谢卢松松博客和男哥的推荐。有读者后台问我,渔哥,为什么不多写点网创项目类的文章?我很早就知道,网创类的文章肯定更多人喜欢看,如果多写点这类题...

2019中国手机用户数量公布,盘点中国手机行业发展趋势

1月9日消息,根据中国信通院披露的数据显示,2019年12月,国内手机市场总体出货量3044.4万部,同比下降14.7%,其中2G手机146.1万部、4G手机2...

iPhone合约机划算吗(不建议购买合约机的建议)

说到合约机,估计很多人的第一反应都觉得坑爹,这也难怪,长久以来,国内的三大运营商一直仗着自己的垄断地位,各种忽悠用户。有时候,所谓的定制机算下来比买裸机都要贵,...

qq群排名更新需要多久,qq群秒恢复5星方法

微信的封闭环境,让运营汪不得不重新找出路微信群可不可以将它搬到QQ群中呢?答案当然是可以QQ平台是开放式的,微信平台的封闭式的这段时间导致大家对QQ群感兴趣了但...

如何看电脑系统配置(查看电脑配置和型号)

请记住,文件系统不是应用于整个磁盘,而是应用于磁盘上的分区。也就是说,一个物理磁盘可以不只有一个分区,它可以包含多个分区,而这些不同的分区又具有不同的文件系统。...

企业管理系统有哪些软件(常见的十大erp系统软件)

企业管理软件排行榜企业不论规模大小,在原料、人力、租金等成本急剧上升的今天,都面临着降低经营成本、提高管理效率的巨大压力,而企业资源集成化管理效率的高低,直接决...

信用证流程图文字版解释,最新信用证的流程图及流程描述

DocumentaryCredit、CleanCredi、IrrevocableL/C等都是贸易往来中所会涉及的信用证种类,而IrrevocableL/C所对应...

word页眉与上一节不同怎么设置(页眉设置同前节的方法)

我们在使用Word编辑文档的时候,页眉常被用来显示文档标题、公司logo等信息,有了页眉的文档显得比较规范。编辑页眉的方法也很简单,直接在页头位置双击进入编辑状...