Android loads animated webp control and Glide loads GIF

Because dynamic webp is used more and more, here is a way of loading processing. Currently, only the commonly used Android image loading libraries frescocan directly load the animated webp. So how to deal with it? Make a record, otherwise the pit will be stepped for nothing. In essence, webp and gif are continuous pictures composed of a group of pictures. What if you want to parse each frame separately.

Android support

If you want to get the first frame of webp, you can directly use the following method on Android. The default is the first frame, but this method is only useful in 8.0 and above.

  Bitmap  bitmap =  BitmapFactory.decodeFile(filename);

fresco control animated webp

The way to add frescosupport for webp is:

  implementation 'com.facebook.fresco:fresco:1.13.0'
  implementation 'com.facebook.fresco:webpsupport:1.13.0'
//implementation 'com.facebook.fresco:animated-gif:1.13.0'

After adding, you can load webp directly, or you can set to automatically start playing, as follows:

  ImageRequestBuilder imageRequestBuilder = ImageRequestBuilder.newBuilderWithSource(uri);
  PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder();
  builder.setImageRequest(imageRequestBuilder.build());
  builder.setAutoPlayAnimations(true);
  builder.setControllerListener(new BaseControllerListener<ImageInfo>() {
    
    
    @Override
    public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatable) {
    
    
    //加载完成的监听 
    }
  });
  simpleDraweeView.setController(builder.build());

Up to this step is very simple, but what about loading the first frame of webp?
First comes the simplest one, similar to that BitmapFactory.decodeFile(), frescothere is also a method in the same, this method also only supports 8.0 and above

  Bitmap bitmap = WebpSupportStatus
                  .loadWebpBitmapFactoryIfExists()
                  .decodeFile(filename, new BitmapFactory.Options());

So what else can be done? You can also use the following method. This method is used for frescosubscribers, which can process the data after loading, can get every frame of webp, and then do the processing you want, the official website link .

  ImageDecodeOptionsBuilder decodeOptionsBuilder = new ImageDecodeOptionsBuilder();
  decodeOptionsBuilder.setDecodeAllFrames(true);
  decodeOptionsBuilder.setBitmapConfig(Bitmap.Config.ARGB_8888);
  ImagePipelineFactory.getInstance()
          .getImagePipeline()
          .fetchDecodedImage(ImageRequestBuilder
                          .newBuilderWithSource(Uri.fromFile(new File(filename)))
                          .setImageDecodeOptions(new ImageDecodeOptions(decodeOptionsBuilder))
                          .build()
                  , context)
          .subscribe(new BaseDataSubscriber<CloseableReference<CloseableImage>>() {
    
    
              @Override
              protected void onNewResultImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
    
    
                  if (dataSource.getResult().get() instanceof CloseableAnimatedImage) {
    
    
                      CloseableAnimatedImage animatedImage = (CloseableAnimatedImage) dataSource.getResult().get();
                      if (animatedImage.getImage().getFrameCount() > 0) {
    
    
                          Bitmap frameBitmap = Bitmap.createBitmap(animatedImage.getWidth(), animatedImage.getHeight(), Bitmap.Config.ARGB_8888);
                          //添加透明通道
                          frameBitmap.eraseColor(Color.TRANSPARENT);
                          frameBitmap.setHasAlpha(true);
                          animatedImage.getImage().getFrame(0).renderFrame(animatedImage.getWidth(), animatedImage.getHeight(), frameBitmap);
                          try {
    
    
                              //保存成文件
                              File file = new File(filename);
                              File outFile = new File(file.getParent(), file.getName() + ".png");
                              FileOutputStream out = new FileOutputStream(outFile);
                              frameBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
                              out.flush();
                              out.close(); 

                          } catch (FileNotFoundException e) {
    
    
                              e.printStackTrace();
                          } catch (IOException e) {
    
    
                              e.printStackTrace();
                          }
                      }
                  }

              }

              @Override
              protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
    
    

              }
          }, CallerThreadExecutor.getInstance());

There are three things to pay attention to:

  1. The bitmap solved by the following method by default does not have a transparent channel, and you need to process it again.
  2. The second is that the bitmap obtained by this method may be recycled after leaving this method. If you want to use it for a long time, it is recommended to copy it again by yourself. To save the time of decompression, I will save it directly as a copy. png file, and then use it, you can also copy the bitmap directly to use it.
  3. This method can decompress each frame, just select the number of frames you need to process.

Glide4 control GIF

Regarding GIF, the only mainstream loading libraries currently supported are Glideand fresco, which Picassoare not supported by default.

Here, by the way, record how Glide4.0 loads Gif and controls playback. It GlideDrawableImageViewTargethas been abandoned in Glide3 and can be used GifDrawableto control it. There are methods to control GIF, and you can also get every frame of GIF to process. The defined interface method is there, and you can't leave it. Look at the interface and you will know Up.

public void setStartPlayGif(final boolean startPlayGif) {
    
    
    Glide.with(context)
        .asGif()
        .load("gifFile")
        .into(new ImageViewTarget<GifDrawable>(imageView) {
    
    
            @Override
            protected void setResource(@Nullable GifDrawable resource) {
    
    
                if (resource != null) {
    
    
                    if(startPlayGif){
    
    
                        //resource.setLoopCount(1);
                        view.setImageDrawable(resource);
                    } else {
    
     
                        view.setImageBitmap(resource.getFirstFrame());
                    }
                }
            }
        });
}

Guess you like

Origin blog.csdn.net/Ser_Bad/article/details/88345435