kotlin - 显示heic图片
kotlin - 显示heic图片

package com.example.androidkotlindemo2.hdrimport android.graphics.BitmapFactory
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import com.example.androidkotlindemo2.R
import com.example.androidkotlindemo2.utils.LogUtils
import java.io.File/*** Author : wn* Email : maoning20080809@163.com* Date : 2025/10/26 10:17* Description : Hdr图片显示* 参考:https://dev.vivo.com.cn/documentCenter/doc/837*/
class HdrImageDecoderActivity : AppCompatActivity() , View.OnClickListener{override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.hdr_image_decoder_main)findViewById<Button>(R.id.hdr_show_btn1).setOnClickListener(this)}override fun onClick(v: View?) {v?:returnwhen(v.id){R.id.hdr_show_btn1 -> {show1()}}}private fun show1(){val resultImageView = findViewById<ImageView>(R.id.hdr_show_result)val resultImageView2 = findViewById<ImageView>(R.id.hdr_show_result2)val filePath = "sdcard/DCIM/Camera/IMG_20251026_111918.HEIC"LogUtils.i("AAA", "exist = " + File(filePath).exists())HeifLoader.loadHeifImage(filePath, resultImageView)val options = BitmapFactory.Options()//options.inSampleSize = 20val bitmap = BitmapFactory.decodeFile(filePath)resultImageView2.setImageBitmap(bitmap)}
}
package com.example.androidkotlindemo2.hdrimport android.annotation.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.ImageDecoder
import android.net.Uri
import android.os.Build
import android.util.Log
import android.util.Size
import android.widget.ImageView
import androidx.annotation.RequiresApi
import com.example.androidkotlindemo2.R
import com.example.androidkotlindemo2.utils.LogUtils
import java.io.File
import java.io.InputStream/*** Author : wn* Email : maoning20080809@163.com* Date : 2025/10/26 10:22* Description :*/
object HeifLoader {fun loadHeifImage(filePath: String, imageView: ImageView) {try {val options = BitmapFactory.Options()options.inJustDecodeBounds = falseval baseBitmap = BitmapFactory.decodeFile(filePath, options)LogUtils.i("AAA", "baseBitmap width = " + baseBitmap.width +" , height = " + baseBitmap.height)val source = ImageDecoder.createSource(File(filePath))val drawable = ImageDecoder.decodeDrawable(source) { decoder, _, _ ->// 配置解码参数decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWAREdecoder.isMutableRequired = false//val size = calculateTargetSize(imageView)//LogUtils.i("AAA", "size width = " + size.width +" , height = " + size.height)decoder.setTargetSize(baseBitmap.width, baseBitmap.height)//decoder.setTargetSize(1080, 900)//decoder.setTargetSize(600, 300)}imageView.setImageDrawable(drawable)} catch (e: Exception) {handleDecodeError(imageView, e)}}fun loadHeifImage(context: Context, uri: Uri, imageView: ImageView) {if (!isHeifSupported(context, uri)) {handleUnsupportedFormat(imageView)return}when {Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ->loadWithImageDecoder(context, uri, imageView)Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ->loadWithBitmapFactory(context, uri, imageView)else -> handleUnsupportedFormat(imageView)}}@RequiresApi(Build.VERSION_CODES.P)private fun loadWithImageDecoder(context: Context, uri: Uri, imageView: ImageView) {try {val source = ImageDecoder.createSource(context.contentResolver, uri)val drawable = ImageDecoder.decodeDrawable(source) { decoder, _, _ ->// 配置解码参数decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWAREdecoder.isMutableRequired = falseval size = calculateTargetSize(imageView)decoder.setTargetSize(size.width, size.height)}imageView.setImageDrawable(drawable)} catch (e: Exception) {handleDecodeError(imageView, e)}}@Suppress("DEPRECATION")private fun loadWithBitmapFactory(context: Context, uri: Uri, imageView: ImageView) {try {val inputStream = context.contentResolver.openInputStream(uri)val options = BitmapFactory.Options().apply {inSampleSize = calculateInSampleSize(inputStream, imageView)inPreferredConfig = Bitmap.Config.RGB_565}// 重新打开流inputStream?.close()val newInputStream = context.contentResolver.openInputStream(uri)val bitmap = BitmapFactory.decodeStream(newInputStream, null, options)newInputStream?.close()bitmap?.let { imageView.setImageBitmap(it) }?: handleDecodeError(imageView, NullPointerException())} catch (e: Exception) {handleDecodeError(imageView, e)}}private fun calculateTargetSize(imageView: ImageView): Size {val width = if (imageView.width > 0) imageView.width else 1080val height = if (imageView.height > 0) imageView.height else 1920return Size(width, height)}private fun calculateInSampleSize(inputStream: InputStream?, imageView: ImageView): Int {if (inputStream == null) return 1val options = BitmapFactory.Options()options.inJustDecodeBounds = trueBitmapFactory.decodeStream(inputStream, null, options)inputStream.close()val imageWidth = options.outWidthval imageHeight = options.outHeightval reqWidth = imageView.width.takeIf { it > 0 } ?: 1080val reqHeight = imageView.height.takeIf { it > 0 } ?: 1920var inSampleSize = 1if (imageHeight > reqHeight || imageWidth > reqWidth) {val halfHeight = imageHeight / 2val halfWidth = imageWidth / 2while (halfHeight / inSampleSize >= reqHeight&& halfWidth / inSampleSize >= reqWidth) {inSampleSize *= 2}}return inSampleSize}private fun handleUnsupportedFormat(imageView: ImageView) {imageView.setImageResource(R.drawable.ic_launcher_background)imageView.contentDescription = "HEIF format not supported"}private fun handleDecodeError(imageView: ImageView, e: Exception) {Log.e("HeifLoader", "HEIF decode error", e)imageView.setImageResource(R.drawable.ic_launcher_background)imageView.contentDescription = "Error loading HEIF image"}fun isHeifSupported(context: Context, uri: Uri): Boolean {// 基础系统版本检测if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return false// 检查MIME类型是否为HEIF格式val mimeType = context.contentResolver.getType(uri)val isHeif = mimeType == "image/heic" ||mimeType == "image/heif" ||uri.toString().endsWith(".heic", ignoreCase = true) ||uri.toString().endsWith(".heif", ignoreCase = true)if (!isHeif) return false// Android 9+ 完全支持if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) return true// Android 8.x 需要额外检查return isHeifSupportedOnOreo(context, uri)}@SuppressLint("NewApi")private fun isHeifSupportedOnOreo(context: Context, uri: Uri): Boolean {// 尝试解码HEIF图片以验证支持性return try {val input = context.contentResolver.openInputStream(uri)BitmapFactory.decodeStream(input).run {input?.close()this != null}} catch (e: Exception) {false}}
}
hdr_image_decoder_main.xml布局<?xml version="1.0" encoding="utf-8"?> <LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"xmlns:tools="http://schemas.android.com/tools"xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:orientation="vertical"tools:context=".MainActivity"><androidx.appcompat.widget.AppCompatButtonandroid:id="@+id/hdr_show_btn1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="10dp"android:layout_gravity="center_horizontal"android:textAllCaps="false"android:textSize="30sp"android:text="显示heic图片"/><androidx.appcompat.widget.AppCompatImageViewandroid:id="@+id/hdr_show_result"android:layout_width="match_parent"android:scaleType="centerCrop"android:layout_height="300dp"/><androidx.appcompat.widget.AppCompatImageViewandroid:id="@+id/hdr_show_result2"android:layout_width="match_parent"android:layout_height="300dp"/></LinearLayout>
