// locate next FCTL chunk
boolean ihdrCopied = false;
while (mChunk.typeCode != CODE_fcTL) {
switch (mChunk.typeCode) {
case CODE_IEND:
return null;
case CODE_IHDR:
mPngStream.setIHDR(mChunk.duplicateData());
break;
case CODE_acTL:
handleACTL(mChunk);
ihdrCopied = true;
break;
default:
handleOtherChunk(mChunk);
}
mChunk.parseNext();
}
// located at FCTL chunk
ApngFrame frame = new ApngFrame();
mChunk.assignTo(frame);
// locate next IDAT or fdAt chunk
mChunk.parseNext();// first move next from current FCTL
while (mChunk.typeCode != CODE_IDAT && mChunk.typeCode != CODE_fdAT) {
switch (mChunk.typeCode) {
case CODE_IEND:
return null;
case CODE_IHDR:
mPngStream.setIHDR(mChunk.duplicateData());
ihdrCopied = true;
break;
case CODE_acTL:
handleACTL(mChunk);
break;
default:
handleOtherChunk(mChunk);
}
mChunk.parseNext();
}
// located at first IDAT or fdAT chunk
// collect all consecutive dat chunks
boolean needUpdateIHDR = true;
int dataOffset = 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(new Fdat2IdatChunk(mChunk));
} else {
mPngStream.addDataChunk(new ApngMmapParserChunk(mChunk));
}
mChunk.parseNext();
}
// lock position for this frame’s image as OutputStream
mChunk.lockRead(dataOffset);
frame.imageStream = mPngStream;
return frame;
}
- Apng的消除操作Apng的消除操作是在ApngFrameRender的render方法做的,方法如下:
/** * 渲染当前帧画面 * * @param frame apng中当前帧 * @return 渲染合成后的当前帧图像 */ public Bitmap render(ApngFrame frame, Bitmap frameBmp) { // 执行消除操作 dispose(frame); // 合成当前帧 blend(frame, frameBmp); return mRenderFrame; }
dispose(ApngFrame frame)方法如下:
/** * 帧图像析构消除 - 提交结果 */ private void dispose(ApngFrame frame) { // last frame dispose op switch (mLastDisposeOp) { case APNG_DISPOSE_OP_NONE: // no op break; case APNG_DISPOSE_OP_BACKGROUND: // clear rect mRenderCanvas.clipRect(mDisposeRect); mRenderCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); mRenderCanvas.clipRect(mFullRect, Region.Op.REPLACE); break; case APNG_DISPOSE_OP_PREVIOUS: // swap work and cache bitmap Bitmap bmp = mRenderFrame; mRenderFrame = mDisposedFrame; mDisposedFrame = bmp; mRenderCanvas.setBitmap(mRenderFrame); mDisposeCanvas.setBitmap(mDisposedFrame); break; } // current frame dispose op mLastDisposeOp = frame.getDisposeOp(); switch (mLastDisposeOp) { case APNG_DISPOSE_OP_NONE: // no op break; case APNG_DISPOSE_OP_BACKGROUND: // cache rect for next clear dispose int x = frame.getxOff(); int y = frame.getyOff(); mDisposeRect.set(x, y, x + frame.getWidth(), y + frame.getHeight()); break; case APNG_DISPOSE_OP_PREVIOUS: // cache bmp for next restore dispose mDisposeCanvas.clipRect(mFullRect, Region.Op.REPLACE); mDisposeCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); mDisposeCanvas.drawBitmap(mRenderFrame, 0, 0, null); break; } }
- Apng的合成操作Apng的合成操作是在每一帧经过dispose之后做的,具体方法是blend(ApngFrame frame, Bitmap frameBmp),代码如下:
/** * 帧图像合成 */ private void blend(ApngFrame frame, Bitmap frameBmp) { int xOff = frame.getxOff(); int yOff = 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); }
- Apng的绘制Apng的每一帧经过消除、合成操作之后,就可以在View上面draw,具体代码如下:
/** * draw the appointed frame */ private void drawFrame(AnimParams animItem, ApngFrame frame, Bitmap frameBmp) { **自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。** **深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!** **因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**        **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!** **由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新** **如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)**  ### 最后 今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。 最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套**腾讯、头条、阿里、美团等公司2021年的面试题**,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含**知识脉络 + 诸多细节**,由于篇幅有限,这里以图片的形式给大家展示一部分。 还有 **高级架构技术进阶脑图、Android开发面试专题资料**,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。  **【算法合集】**  **【延伸Android必备知识点】**  **【Android部分高级架构视频学习资源】** **Android精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧! > **本文已被[CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》]( )收录** [**一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!**](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0) **AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算** rums/4304bb5a486d4c3ab8389e65ecb71ac0) **AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算**