快速进阶
更新时间:2023-07-26
下面介绍Android端HEIF图片加载SDK配合Glide和Freso库的使用方法,以及SO后下载功能的使用方法。
配合Glide实现HEIF图片解码
- 在gradle中引入Glide库
Gradle
1implementation 'com.baidubce.mediasdk:libheif:1.1.0'
2implementation 'com.github.bumptech.glide:glide:4.15.1'
3annotationProcessor 'com.github.bumptech.glide:compiler:4.15.1'
- 基于百度智能云HEIF图片加载SDK编写Glide解码器插件
Java
1// 以Bytebuffer为输入
2public class HeifByteBufferBitmapDecoder implements ResourceDecoder<ByteBuffer, Bitmap> {
3 private static final String TAG = "HeifByteBufferDecoder";
4 private BitmapPool bitmapPool;
5
6 public HeifByteBufferBitmapDecoder(BitmapPool pool) {
7 bitmapPool = Preconditions.checkNotNull(pool);
8 }
9
10 @Override
11 // 判断输入图片是否为HEIF格式
12 public boolean handles(@NonNull ByteBuffer source, @NonNull Options options) throws IOException {
13 byte[] header = new byte[13];
14 ByteStreams.readHeaderFromStream(13, ByteBufferUtil.toStream(source), header);
15 boolean isHeic = HeifDecoder.isHeic(header.length, header);
16 Log.i(TAG, "isHeic " + isHeic);
17 return isHeic;
18 }
19
20 @Override
21 // 使用百度智能云HEIF图片加载SDK进行解码
22 public Resource<Bitmap> decode(@NonNull ByteBuffer source, int width, int height,
23 @NonNull Options options) throws IOException {
24 byte[] bytes = ByteBufferUtil.toBytes(source);
25 HeifInfo heifInfo = new HeifInfo();
26 HeifDecoder.getInfo(bytes.length, bytes, heifInfo);
27 HeifSize heifSize = heifInfo.getFrameList().get(0);
28 int sourceWidth = heifSize.getWidth();
29 int sourceHeight = heifSize.getHeight();
30 // 缩放处理
31 int requestedWidth = width;
32 int requestedHeight = height;
33 DownsampleStrategy downsampleStrategy =
34 (DownsampleStrategy) options.get(DownsampleStrategy.OPTION);
35 DownsampleStrategy.SampleSizeRounding rounding
36 = downsampleStrategy.getSampleSizeRounding(sourceWidth, sourceHeight, requestedWidth, requestedHeight);
37 float exactScaleFactor = downsampleStrategy.getScaleFactor(sourceWidth, sourceHeight,
38 requestedWidth, requestedHeight);
39 int outWidth = round((double) (exactScaleFactor * (float) sourceWidth));
40 int outHeight = round((double) (exactScaleFactor * (float) sourceHeight));
41 int widthScaleFactor = sourceWidth / outWidth;
42 int heightScaleFactor = sourceHeight / outHeight;
43 int scaleFactor = rounding == DownsampleStrategy.SampleSizeRounding.MEMORY ?
44 Math.max(widthScaleFactor, heightScaleFactor) : Math.min(widthScaleFactor, heightScaleFactor);
45 int powerOfTwoSampleSize = Math.max(1, Integer.highestOneBit(scaleFactor));
46 if (rounding == DownsampleStrategy.SampleSizeRounding.MEMORY
47 && (float) powerOfTwoSampleSize < 1.0F / exactScaleFactor) {
48 powerOfTwoSampleSize <<= 1;
49 }
50 Log.i(TAG, "heifSize: " + heifSize.getWidth() + "," + heifSize.getHeight() +
51 ",sample size: " + powerOfTwoSampleSize);
52 // 创建Bitmap
53 Bitmap bitmap = Bitmap.createBitmap(sourceWidth / powerOfTwoSampleSize, sourceHeight / powerOfTwoSampleSize,
54 Bitmap.Config.ARGB_8888);
55 // 将HEIF图片解码为Bitmap
56 HeifDecoder.toRgba(bytes.length, bytes, bitmap);
57 return BitmapResource.obtain(bitmap, bitmapPool);
58 }
59
60 private static int round(double value) {
61 return (int) (value + 0.5);
62 }
63}
64
65// 以InputStream为输入,内部直接复用上面的HeifByteBufferBitmapDecoder
66public class HeifStreamBitmapDecoder implements ResourceDecoder<InputStream, Bitmap> {
67 private static final String TAG = "HeifStreamBitmapDecoder";
68
69 private final List<ImageHeaderParser> parsers;
70 private final HeifByteBufferBitmapDecoder heifByteBufferBitmapDecoder;
71 private final ArrayPool arrayPool;
72
73 public HeifStreamBitmapDecoder(
74 List<ImageHeaderParser> parsers,
75 HeifByteBufferBitmapDecoder heifByteBufferBitmapDecoder,
76 ArrayPool arrayPool) {
77 this.parsers = parsers;
78 this.heifByteBufferBitmapDecoder = Preconditions.checkNotNull(heifByteBufferBitmapDecoder);
79 this.arrayPool = Preconditions.checkNotNull(arrayPool);
80 }
81
82 @Override
83 @Nullable
84 public Resource<Bitmap> decode(InputStream source, int width, int height, Options options)
85 throws IOException {
86 return heifByteBufferBitmapDecoder.decode(ByteBufferUtil.fromStream(source), width, height, options);
87 }
88
89 @Override
90 public boolean handles(InputStream source, Options options) throws IOException {
91 byte[] header = new byte[13];
92 ByteStreams.readHeaderFromStream(13, source, header);
93 boolean isheif = HeifDecoder.isHeic(header.length, header);
94 Log.i(TAG, "isHeic " + isheif);
95 return isheif;
96 }
97}
- 注册解码器插件
Java
1@GlideModule
2public class HeifGlideModule extends AppGlideModule {
3 @Override
4 public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
5 // 添加刚才编写的两个解码器插件
6 HeifByteBufferBitmapDecoder heifByteBufferBitmapDecoder
7 = new HeifByteBufferBitmapDecoder(glide.getBitmapPool());
8 registry.prepend(ByteBuffer.class, Bitmap.class, heifByteBufferBitmapDecoder);
9
10 HeifStreamBitmapDecoder streamBitmapDecoder =
11 new HeifStreamBitmapDecoder(
12 registry.getImageHeaderParsers(), heifByteBufferBitmapDecoder, glide.getArrayPool());
13 registry.prepend(InputStream.class, Bitmap.class, streamBitmapDecoder);
14 }
15
16 // Disable manifest parsing to avoid adding similar modules twice.
17 @Override
18 public boolean isManifestParsingEnabled() {
19 return false;
20 }
21}
- 使用
Java
1ImageView image = mRootView.findViewById(R.id.image_glide);
2Glide.with(this)
3 .asBitmap()
4 .load(url)
5 .override(100, 100) // 缩放
6 .into(image)
配合Freso实现HEIF图片解码
- 在gradle中引入Freso库
Gradle
1implementation 'com.baidubce.mediasdk:libheif:1.1.0'
2implementation 'com.facebook.fresco:fresco:2.6.0'
- 基于百度智能云HEIF加载SDK编写Freso解码器插件
Java
1public class HeifFrescoDecoder implements ImageDecoder {
2 private static final String TAG = "HeifFrescoDecoder";
3
4 @Override
5 public CloseableImage decode(
6 EncodedImage encodedImage,
7 int length,
8 QualityInfo qualityInfo,
9 ImageDecodeOptions options) {
10 // Decode the given encodedImage and return a
11 // corresponding (decoded) CloseableImage.
12 if (encodedImage == null) {
13 return null;
14 } else {
15 InputStream inputStream = encodedImage.getInputStream();
16 if (inputStream == null) {
17 return null;
18 }
19 Bitmap bitmap;
20 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
21 try {
22 byte[] buffer = new byte[8192];
23 int bytesRead;
24
25 while ((bytesRead = inputStream.read(buffer)) != -1) {
26 outputStream.write(buffer, 0, bytesRead);
27 }
28
29 byte[] heifData = outputStream.toByteArray();
30 // 获取HEIF元数据
31 HeifInfo heifInfo = new HeifInfo();
32 HeifDecoder.getInfo(heifData.length, heifData, heifInfo);
33 HeifSize heifSize = heifInfo.getFrameList().get(0);
34 int sampleSize = encodedImage.getSampleSize();
35 int width = heifSize.getWidth();
36 int height = heifSize.getHeight();
37 Log.i(TAG, "heifSize: " + heifSize.getWidth() + "," + heifSize.getHeight() + ", "
38 + "out sample size: " + sampleSize);
39 // 创建Android Bitmap,考虑缩放
40 bitmap = Bitmap.createBitmap(width / sampleSize, height / sampleSize,
41 Bitmap.Config.ARGB_8888);
42 // 使用百度智能云HEIF图片加载SDK将HEIF图片解码为Bitmap
43 HeifDecoder.toRgba(heifData.length, heifData, bitmap);
44
45 CloseableReference<Bitmap> closeableReference =
46 CloseableReference.of(Preconditions.checkNotNull(bitmap),
47 SimpleBitmapReleaser.getInstance());
48
49 return new CloseableStaticBitmap(
50 closeableReference,
51 ImmutableQualityInfo.FULL_QUALITY,
52 encodedImage.getRotationAngle(),
53 encodedImage.getExifOrientation());
54 } catch (Exception e) {
55 e.printStackTrace();
56 return null;
57 } finally {
58 Closeables.closeQuietly(inputStream);
59 }
60 }
61 }
62}
- 注册解码器插件
Java
1ImagePipelineConfig config = ImagePipelineConfig.newBuilder(this)
2 .setDownsampleEnabled(true)
3 .setImageDecoderConfig(ImageDecoderConfig.newBuilder()
4 .addDecodingCapability(DefaultImageFormats.HEIF,
5 new DefaultImageFormatChecker(),
6 new HeifFrescoDecoder()) // 添加前面编写的解码器插件
7 .build())
8 .build();
9Fresco.initialize(this, config);
- 使用
Java
1SimpleDraweeView draweeView = (SimpleDraweeView) mRootView.findViewById(R.id.image_freso);
2DraweeController draweeController = Fresco.newDraweeControllerBuilder()
3 .setImageRequest(
4 ImageRequestBuilder.newBuilderWithSource(Uri.parse(url))
5 .setCacheChoice(ImageRequest.CacheChoice.DEFAULT)
6 .setResizeOptions(ResizeOptions.forDimensions(100, 100)) // 缩放
7 .build())
8 .build();
9draweeView.setController(draweeController);
在Demo工程的OnlineImageFragment.java中对上面两种用法都做了详细的展示,可以参考。
SO后下载
通过SO后下载,可以减少包体积增量。
- 配置gradle集成无SO的HEIF图片加载SDK
Gralde
1dependencies {
2 implementation 'com.baidubce.mediasdk:libheif-lite:1.1.0'
3}
- 下载SDK压缩包,解压找到arm64-v8a_heif.zip和armeabi-v7a_heif.zip,这两个压缩包中保存有对应架构的SO文件。
- 将SO文件上传到您的服务器(或使用百度智能云对象存储BOS),并记录下载地址,例如 https://xxx.com/arm64-v8a_heif.zip。
- 调用HeifSoLoadManager从指定位置加载对应架构的SO,加载成功后再进行后续的解码
Java
1HeifSoLoadManager.getInstance(this).loadLibraries("https://xxx.com/arm64-v8a_heif.zip", "arm64-v8a", mLoadListener);
2
3private HeifSoLoadManager.LoadListener mLoadListener = new HeifSoLoadManager.LoadListener() {
4
5 @Override
6 public void onLoadError(int errCode, String errMsg) {
7 Log.d(TAG, "external load library error " + errCode + errMsg);
8 }
9
10 @Override
11 public void onLibsDownloadCompleted() {
12 Log.d(TAG, "libs download completed.");
13 }
14
15 @Override
16 public void onLoadSuccess() {
17 Log.d(TAG, "external load library success.");
18 }
19
20 @Override
21 public void onLoadProgress(float progress) {
22 Log.d(TAG, "external load library so progress " + progress);
23 }
24 };