Android上圖片涉及到的要點:html
顏色空間-YUV與RGBjava
圖片格式及其文件頭ios
exif :使用開源庫Android-Exif-Extended或者support包裏的ExifInterface. 建議前者,內部時直接讀文件頭,沒有api的限制.git
Android-Exif-Extended示例:
public native static boolean nativeCompress(Bitmap bitmap,int quality,String outPath);
public static boolean compressOringinal(String srcPath,int quality,String outPath){
Bitmap bitmap = BitmapFactory.decodeFile(srcPath);
boolean success = nativeCompress(bitmap,quality,outPath);//libjpeg壓縮
if(success){
ExifInterface exif = new ExifInterface();
try {
exif.readExif( srcPath, ExifInterface.Options.OPTION_ALL );
exif.writeExif( outPath );//所有exif信息拷到新文件那兒去
} catch (IOException e) {
e.printStackTrace();
}finally {
return true;
}
}
return success;
}
複製代碼
camera api是Android兼容性問題最大的地方,沒有之一.因此,不要做死去用原生的,或者本身從頭開始寫一套. 直接用開源的.github
固然,原生api的使用仍是要掌握的,有幾個比較好的博客供參考:api
Android相機開發系列:很全面數組
Android多媒體之Camera的相關操做:至關於一個概述
注意點:
注意兼容性:
Intent takeIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri photoUri = getMediaFileUri(TYPE_TAKE_PHOTO);
takeIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(takeIntent, CODE_TAKE_PHOTO);
複製代碼
調用系統拍照,Intent須要加上讀和寫權限. 若是沒有寫權限,部分4.4如下手機會crash:
```
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
或者這種實現:
List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
```
複製代碼
抄官方demo誰都會,但後果就是致使容易跟第三方庫內部實現衝突. 這裏的重點在於與其餘已內部實現Uri兼容性的第三方庫的兼容:
//官方demo:原封不動搬過來,就可能會有跟第三方庫衝突.由於別人通常也是原封不動搬過來的
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
//正確示範:
<provider
android:name="org.devio.takephoto.permission.TFileProvider"//name要本身繼承v4裏的fileprovider
android:authorities="${applicationId}.takephoto.fileprovider"//本身附加字符串,後面要提供解析方法
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths_takephoto" />//記得加後綴.尤爲做爲庫提供時,防止被同名覆蓋.
</provider>
//xml裏:
<paths>
<!--外置SD卡-->
<root-path
path=""
name="camera_photos" />
//若是是庫,通常只提供上面一個就夠了,下面的由app本身的module去提供.
<!--Context.getFilesDir()-->
<files-path
name="files"
path=""/>
<!--Context.getCacheDir()-->
<cache-path
name="cache"
path=""/>
<!--Environment.getExternalStorageDirectory()-->
<external-path
name="external"
path=""/>
<!--Context.getExternalFilesDir(null)-->
<external-files-path
name="external_file_path"
path=""/>
<!--Context.getExternalCacheDir()--> <!--直到support-v4:25.0.0才支持-->
<external-cache-path
name="external_cache_path"
path=""/>
</paths>
//而後提供解析這個uri的方式(sd卡):
public static String parseOwnUri(Context context, Uri uri) {
if (uri == null) {
return null;
}
String path;
if (TextUtils.equals(uri.getAuthority(), context.getPackageName() + ".takephoto.fileprovider") {
path = new File(uri.getPath().replace("camera_photos/", "")).getAbsolutePath();
} else {
path = uri.getPath();
}
return path;
}
複製代碼
本質上仍是由於從7.0開始強制執行sctrickmode,也能夠寫代碼讓它不執行:只是不建議這樣作罷了.
/過濾URI檢查
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
複製代碼
能夠調用系統intent去圖庫裏選一張圖,可是不一樣手機的圖庫選擇千差萬別,返回的uri依據手機廠商和版本的不一樣而狀況不一樣,有的是contentprovider形式,有的是file uri形式,Android 7.0以上如下還不一致. 另外,系統intent不支持多選. 搞來搞去,不如本身查media center數據庫,本身作ui. 基本上成熟的app都是經過這種形式實現,網上開源庫也一大把.
有系統intent,可是不一樣手機千差萬別,大多數不好勁.果斷用開源的. 開源庫中,ucrop秒殺其餘裁剪庫: github.com/Yalantis/uC…
固然,也仍有不足之處: 選擇區域後裁剪該區域,不是基於原圖來裁,而是基於界面上預覽圖來裁剪,因此會自帶壓縮效果.
對於手機圖片來講,80%質量和100%質量並沒有肉眼可見的明顯區別,而文件大小相差近一倍.徹底沒有必要設爲100%的質量,而若是是相機拍攝的原圖而非進行尺寸壓縮後的圖,70%的質量已經足夠.
因此,通常來講: 通過尺寸壓縮的圖,可設置質量80%. 原圖大小,可將質量設置爲70%. 二者均可用下面的libjpeg來壓縮.
Bitmap.compress->skia->libjpeg->file,file->libjpeg->skia->bitmap 全部的問題均可以從這裏找到答案.
參考:www.voidcn.com/article/p-w…
彩蛋: 本身寫的圖片壓縮工具app
結合app業務的二次封裝技巧: 透明fragment接收onactivityResult,達到最終靜態方法+回調的一行代碼調用的效果:
TakePhotoUtil.startPickOne(fragmentActivity, isForCamera, new TakeOnePhotoListener() {
@Override
public void onSuccess(String usableFilePath) {
showImg(usableFilePath);
}
@Override
public void onFail(String filePath, String msg) {
MyToast.errorBigL(msg);
//toTakePhotoMode();
}
@Override
public void onCancel() {
// toTakePhotoMode();
}
});
複製代碼
ps. 透明fragment的封裝技巧參考: RxPermissionsFragment
示例: 78re52.com1.z0.glb.clouddn.com/resource/go…
代碼示例:QiniuUtils
普通圖片: fresco/glide. 通常是本身封裝一層,便於切換,以及作一些全局性的處理. ImageLoader
對fresco/glide/picasso的優缺點的討論:mPaaS 3.0 多媒體組件發佈 | 支付寶百億級圖片組件 XMedia 錘鍊之路(圖片緩存篇)
大圖: 分區域解碼 subsampling-scale-image-view