谷歌公布,Android P 版本支持HEIF格式图片。HEIF 全称为 High Efficiency Image Format,即高效率图片格式。相比于 JPEG 等目前互联网通用的图片格式,HEIF 图片有何价值?在HEIF图片的适配过程中,应用会遭遇哪些典型性问题?该如何进行适配?
一. 什么是HEIF图片
1.HEIF(High Efficiency Image Format),即高效率图片格式。2015年由 ISO 批准发布,由 MPEG 标准组织制定,采用 HEVC 编码格式。
2.苹果自2017.9.20发布的 iOS11 开始拍照保存支持HEIF格式(iPhone 7及以上机型)。
3.谷歌 O 版本 MR1 支持 HEIF 静态图的软件解码,Android P 支持 HEIF 软件解码、软件编码。
二. HEIF图片价值:
1.与 JPEG 同等图片质量的压缩率是 JPEG 的2.39倍,可节省约50%空间,节省网络传输流量。
2.支持存储多张图片(图片集合、序列图等,如连拍)。
3.支持动态图片(类似 Gif 动图)。
4.支持图片深度信息、透明度信息。
目标:替代 JPEG,成为主流图片类型
三. 适配HEIF图片格式典型问题
1.在支持 HEIF 编解码的手机无法打开HEIF格式文件。
2.尽管手机支持 HEIF 编解码,应用仍无法扫描到用户手机本地的HEIF格式图片,无法分享或者发送本地 HEIF 格式图片给其他用户。
3.将 HEIF 格式图片,通过支持 HEIF 编解码的手机发送到不支持 HEIF 编解码的手机,会出现图片无法查看的问题。
四. 适配指导
1.判断手机是否支持 HEIF 格式
谷歌未提供统一接口,推荐应用通过手机系统版本来判断是否支持 HEIF 格式编解码。目前,Android O 版本 MR1 支持 HEIF 静态图的软件解码,Android P 支持 HEIF 软件解码、软件编码。
以华为 Android P 版本手机HEIF格式编解码为例,参考实现代码
tic boolean isSupportHeif() { Log.e(TAG, "Build.MANUFACTURER:" + Build.MANUFACTURER + ", Build.VERSION.SDK_INT:" + Build.VERSION.SDK_INT);if("HUAWEI".equals(Build.MANUFACTURER) && Build.VERSION.SDK_INT>27) { return true; } return false; }
2.如何读取和显示HEIF图片文件
①通过 Android P 版本新增的类 ImageDecoder 加载图片。
参考实现代码
public static Drawable getHeifImageFromSdcardUseImageDecoder(String path) throws IOException { File file = new File(path); ImageDecoder.Source source = ImageDecoder.createSource(file); return ImageDecoder.decodeDrawable(source); } mImageHeif = findViewById(R.id.imageView2);if (HeifUtils.isSupportHeif()) { try { Drawable drawble = HeifUtils.getHeifImageFromSdcardUseImageDecoder("/sdcard/bird_burst.heic"); mImageHeif.setImageDrawable(drawble); textHeif.setText("load heif image use ImageDecoder"); } catch (IOException e) { e.printStackTrace(); } }
显示效果:
②通过历史版本已有类 BitmapFactory 加载图片。
该方法工作量最小,只需放开 Android P 版本手机 HEIF 图片文件加载,无需修改图片加载代码。需要注意的是,应用需默认支持 HEIF 图片的加载查看。
参考实现代码
public static Bitmap getHeifImageFromSdcardUseBitmapFactory(String path) { return BitmapFactory.decodeFile(path); }if (HeifUtils.isSupportHeif()) { Bitmap bmp = HeifUtils.getHeifImageFromSdcardUseBitmapFactory("/sdcard/bird_burst.heic"); mImageHeif.setImageBitmap(bmp); textHeif.setText("load heif image use BitmapFactory"); }
显示效果:
3.图片扫描推荐方式
方式一(推荐):通过 ContentProvider 扫描
实现本地图片的上传、分享或者是发送功能,需要扫描手机本地的图片。如果应用通过自身扫描的方式,需根据手机版本判断手机支持的图片编解码格式,所以推荐使用 ContentProvider 扫描手机中的图片。通过这种方法扫描,系统会将支持的所有解码格式的图片文件返回给应用,不需要应用自身再去做格式判断。
参考实现代码
public static void getAllImagesLocal(final Context context) { new Thread(new Runnable() { @Override public void run() { Cursor cursor = context.getContentResolver().query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null); while (cursor.moveToNext()) { String path = cursor.getString(cursor .getColumnIndex(MediaStore.Images.Media.DATA)); Log.e(TAG, "image path:" + path); } } }).start(); }
通过抓取日志,能够看到应用如果在支持 HEIF 编解码的手机执行,系统会将HEIF格式图片扫描结果返回给应用,如果在不支持 HEIF 格式的手机执行,系统则不会将 HEIF 格式图片扫描结果返回。
支持 HEIF 格式的手机执行抓取的日志
Line 4653: 06-09 11:14:37.976 17127 17173 E HeifUtils: image path:/storage/emulated/0/Pictures/autumn_1440x960.heic Line 4654: 06-09 11:14:37.976 17127 17173 E HeifUtils: image path:/storage/emulated/0/Pictures/old_bridge_1440x960.heic Line 4655: 06-09 11:14:37.976 17127 17173 E HeifUtils: image path:/storage/emulated/0/tencent/MicroMsg/wallet/luckyMoneyEffect/1/package/input.png Line 4656: 06-09 11:14:37.976 17127 17173 E HeifUtils: image path:/storage/emulated/0/tencent/MicroMsg/wallet/luckyMoneyEffect/1/package/list.png Line 4657: 06-09 11:14:37.976 17127 17173 E HeifUtils: image path:/storage/emulated/0/tencent/MicroMsg/wallet/luckyMoneyEffect/1/package/cover.png Line 4658: 06-09 11:14:37.976 17127 17173 E HeifUtils: image path:/storage/emulated/0/tencent/MicroMsg/wallet/luckyMoneyEffect/1/package/chat.png Line 4659: 06-09 11:14:37.976 17127 17173 E HeifUtils: image path:/storage/emulated/0/bird_burst.heic Line 4660: 06-09 11:14:37.976 17127 17173 E HeifUtils: image path:/storage/emulated/0/Hydrangeas.jpg Line 4661: 06-09 11:14:37.976 17127 17173 E HeifUtils: image path:/storage/emulated/0/Download/bird_burst.heic Line 4662: 06-09 11:14:37.976 17127 17173 E HeifUtils: image path:/storage/emulated/0/Download/Hydrangeas.jpg
方式二(不推荐):应用自身进行扫描
应用通过自身扫描,判断哪些是可支持的图片文件,需要增加对 HEIF 格式的判断, HEIF 格式文件的后缀有两种:.heif和.heic
4.HEIF 格式转 JPEG
使用场景:
HEIF 格式转成 JPEG 格式主要考虑向下兼容的问题。通过支持 HEIF 格式的手机向不支持此格式的手机发送 HEIF 图片,如果直接发送原始 HEIF 格式,会出现图片无法使用的情况。因此,为了避免这种情况,可以考虑在发送之前将 HEIF 格式图片转换成 JPEG 格式再发送。应用可以选择使用谷歌原生的接口来进行转换。
参考实现代码
try { Bitmap bmp = HeifUtils.getHeifImageFromSdcardUseBitmapFactory("/sdcard/bird_burst.heic"); File file = new File("/sdcard/download/bird_burst1.jpg"); FileOutputStream out = new FileOutputStream(file); bmp.compress(Bitmap.CompressFormat.JPEG, 100, out); out.flush(); out.close(); Uri uri = Uri.fromFile(file); sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri)); } catch (Exception e) { e.printStackTrace(); }
HEIF 图片格式的诸多优势使它具有很好的市场前景,这次谷歌 Android P 版本对此格式的支持也充分说明了这一点,建议各位广大开发者赶紧适配。