话说天下分久必合,合久必分。大诺王朝内阁首辅康培凯康大学士,刚愎自用,固步自封,不思进取,致使天下群雄并起。乱世之中,世家门阀Apple,微软尽揽朝中精英于门下。而新进贵族Google则营前插着两面大旗,只见左边那面用西文写着“I am free”,右面则用汉字写着“你懂的”。至此,江湖好汉莫不相投与此。在这个修道不如修Bug的年代,贫道也只有顺应时代的潮流,开始了两点一线的Android开发码工生活。
虽然Android秉承了太祖的团结一切可以团结的力量平民哲学思想,但是他终归出生于贵族家庭。带着一点小傲娇,有点不接地气儿。
话说,一个风和日丽的早春上午,贫道刚结束了一个编辑图片功能的阶段开发,在QQ上和众道友们激扬文字,指点江山,纵谈当前天下大势。谈到精彩之处,贫道不禁轻摇手中免费发放的时代报,颇有当年武侯隆中对的气势,好不得意。突然叮当一声,只见屏幕右下角,弹出个邮件提示框,贫道一看是一封Bug报告信。顿时,刚才的好心情一哄而散,然后很不情愿地点开了报告链接,只见上面写着Image is destroyed。贫道头上一阵黑线,用人类的正常思维实在想不出Image is destroyed的是个什么状况。还好该测试人士给出了一张展示bug的图片,点进去一看,又是一阵恶寒。只见满屏的马赛克充斥其中,贫道暗想,虽然是测试,也不能这样假公济私,蹭机浏览收集成人专用图片。而且这得多暴露啊,满屏的马赛克,想到这贫道暗暗鄙视了一下这个测试人员,好歹拿一张马赛克美女图啥的,给大家乐一下。独乐乐,不如众乐乐嘛。此时贫道故作镇定地向测试员问起了该bug的情况,结果却得到了一个惊人的消息,此马赛克并非天然形成,而是经过了图片的载入,编辑,保存,再载入,编辑,保存,如此大小周天往复几次,就成了这个效果。听到这,贫道暗叹连连,赶忙拿了测试图片,开始找寻原因。
回到座位点开图片一看,是一个只比吕布智商高了20的家伙,号称只吃涮羊肉的灰太狼像(见图1)。在贫道旋转,上下左右颠倒,剪切等一系列的操作后,的确一层似曾相识的薄马赛克浮现了出来(见图2)。
图1 图2
难道是图片绘制时不够精确?根据平常玩游戏的经验,调用了Paint的setAntiAlias反锯齿函数来提高绘画质量。然后筹措满志的按下了Run,但是残酷的现实打破了贫道妄图速战速决的期望。马赛克君如同小强附体,顽强的生存了下来。
贫道再次审视了代码,又做出一个判断,是否是图片旋转或者上下左右颠倒时,坐标移动的误差积累所引起的呢?在忍痛割舍了旋转和颠倒功能后,再一次Run了下程序,涛声依旧。
难道是图片的颜色位数问题,但一看代码,都是四个8(Config.ARGB_8888),好吉利的设置。
常言说的好,欲使其灭亡,必先使其疯狂。贫道重新写了个测试程序(见以下的程序代码)。屏蔽了所有的编辑效果,只保留了载入和保存。在恶狠狠地按下了Run后,贫道的世界观开始崩溃了。马赛克君岿然不动,好似老中医的小广告似的牢牢的贴在了图片上。
MainActivity.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <ImageView android:id="@+id/img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:scaleType="fitCenter" /></RelativeLayout>
MainActivity.java
package com.example.testcompress;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileOutputStream;import android.os.Bundle;import android.app.Activity;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Bitmap.CompressFormat;import android.view.Menu;import android.widget.ImageView;public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Bitmap bmp = BitmapFactory.decodeFile("/mnt/sdcard/wolf.jpg"); for(int i = 0 ; i < 30 ; i++){ ImageView mv = (ImageView)findViewById(R.id.img); mv.setImageBitmap(bmp); File file = null; try { file = new File("/mnt/sdcard/wolf_tmp.jpg"); file.delete(); ByteArrayOutputStream stream = new ByteArrayOutputStream(); bmp.compress(CompressFormat.JPEG, 100, stream); FileOutputStream os = new FileOutputStream(file); os.write(stream.toByteArray()); os.close(); } catch (Exception ex) { file = null; } bmp = BitmapFactory.decodeFile("/mnt/sdcard/wolf_tmp.jpg"); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.activity_main, menu); return true; }}
贫道双手挠头,陷入了沉思中。就在漫天的飞屑铺满桌面的时候,贫道突然发现,灰太狼这货居然是裸奔的,难道被SDK判断为少儿不宜,需要做骑兵处理。于是立马换成了老少皆宜的desert.jpg文件(见图3)。事实证明我们又一次低估了马赛克君的无耻程度,这次沧桑无垠的沙漠获得了和苍老师一样的待遇,漫天的马赛克(见图4)。
图3 图4
这时旁边同事的电脑又传来了“我相信真相只有一个”那熟悉的声音。脑海里顿时出现貌似忠良,实乃国贼的秦桧,严嵩,汪精卫形象。渐渐这些名字逐渐汇聚为compress的字样。没错最终的元凶就是这个貌似二师兄,实乃伏地魔的Bitmap.compress。在屡次的保存中,由于jpg压缩算法的问题,随着保存次数的增加,导致像素丢失越来越严重,最后马赛克化。再狡猾的狐狸还是斗不过猎人,贫道对着网页中的Google标志,鄙视的朝下竖起了大拇指。
为了再踩上一万只脚,我又测试了下png格式(修改代码如下)。同样都是一个妈生的,PNG图片几乎无损(见图5)。
MainActivity.java
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Bitmap bmp = BitmapFactory.decodeFile("/mnt/sdcard/wolf.png"); for(int i = 0 ; i < 30 ; i++){ ImageView mv = (ImageView)findViewById(R.id.img); mv.setImageBitmap(bmp); File file = null; try { file = new File("/mnt/sdcard/wolf_tmp.png"); file.delete(); ByteArrayOutputStream stream = new ByteArrayOutputStream(); bmp.compress(CompressFormat.PNG, 100, stream); FileOutputStream os = new FileOutputStream(file); os.write(stream.toByteArray()); os.close(); } catch (Exception ex) { file = null; } bmp = BitmapFactory.decodeFile("/mnt/sdcard/wolf_tmp.png"); } }
图5
所以在此,贫道友情提示一下,为了保持图的还原度,在Android开发中请尽量使用PNG格式图片,日本国图片除外。同时也将此提示写在了中午用过的餐巾纸上,裱糊后,与诸君共勉。
此文已在cnblog上同步发表。
- 2楼a3830286636天前 09:19
- Android的JPG保存方法降质比较厉害,保存大概3、4次后出现明显马赛克,保存PNG虽然能防止但速度太慢,所以我公司现在保存JPG都是调自己写的一套JPG库来保存
- Re: SuperFPE6天前 09:32
- 回复a383028663n用Java还是NDK
- Re: a3830286636天前 10:31
- 回复SuperFPEnNDK,自己用C写的SO库
- 1楼dztdztdzt6天前 15:00
- lz文笔甚是给力啊