giflib載入GIF檔案

大逗大人發表於2018-12-15

 giflib是一款用C語言寫的載入GIF庫,在效能方面比Glide要好很多,首先來看一下效能對比。

glide載入gif

glide載入gif

giflib載入gif

giflib載入gif

 從上圖中我們可以看出在CPU使用率上,giflib比glide好很多了,記憶體佔用上giflib比glide也要好一些。那麼如何使用giflib尼?

 首先需要下載 framesequencegiflib(以上網站需要翻牆,請自備梯子)

 giflib檔案目錄如下:

giflib載入GIF檔案
 framesequence檔案目錄如下:

giflib載入GIF檔案
 下載完畢後,我們就將framesequence下的jni目錄複製到as的main下,giflib複製到jni/giflib目錄下。目錄結構如下(刪除了與webp相關的檔案):

giflib載入GIF檔案
 這樣就可以開始編譯so檔案了,但是由於giflib使用的是Android.bp進行編譯的(不會呀o(╥﹏╥)o)。所有我就根據Android.bp來重新寫了份Android.mk檔案,然後ndk-build該檔案即可。


#
# Copyright (C) 2014 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := gif
LOCAL_SRC_FILES := \
 giflib/dgif_lib.c \
 giflib/egif_lib.c \
 giflib/gifalloc.c \
 giflib/gif_err.c \
 giflib/gif_hash.c \
 giflib/openbsd-reallocarray.c \
 giflib/quantize.c

LOCAL_CFLAGS += \
    -Werror \
    -Wno-format \
    -Wno-sign-compare \
    -Wno-unused-parameter \
    -DHAVE_CONFIG_H \

LOCAL_SDK_VERSION := 8

include $(BUILD_STATIC_LIBRARY)

include $(CLEAR_VARS)
## Main library

LOCAL_STATIC_LIBRARIES := gif

LOCAL_LDFLAGS := -llog -ljnigraphics

LOCAL_C_INCLUDES := \
 giflib

LOCAL_MODULE := framesequence
LOCAL_SRC_FILES := \
 BitmapDecoderJNI.cpp \
 FrameSequence.cpp \
 FrameSequenceJNI.cpp \
 FrameSequence_gif.cpp \
 JNIHelpers.cpp \
 Registry.cpp \
 Stream.cpp

ifeq ($(FRAMESEQUENCE_INCLUDE_WEBP),true)
 LOCAL_C_INCLUDES += external/webp/include
 LOCAL_SRC_FILES += FrameSequence_webp.cpp
 LOCAL_STATIC_LIBRARIES += libwebp-decode
endif

LOCAL_CFLAGS += \
    -Wall \
    -Werror \
    -Wno-unused-parameter \
    -Wno-unused-variable \
    -Wno-overloaded-virtual \
    -fvisibility=hidden \

LOCAL_SDK_VERSION := 8

include $(BUILD_SHARED_LIBRARY)
複製程式碼

 由於沒有使用CMake,所以應該在build.gradle下進行如下配置

externalNativeBuild{ ndkBuild{ path "src/main/jni/Android.mk" } }

 最後我們點選rebuild即可生成so檔案。那麼如何使用尼?

 在使用之前需要將framesequence目錄下的src裡面的所有檔案拷貝到as的Java目錄下。然後就可以使用了。使用程式碼如下(也可以去閱讀framesequence下的示例程式碼):


    FrameSequenceDrawable mDrawable;
    int mResourceId;

    // This provider is entirely unnecessary, just here to validate the acquire/release process
    private class CheckingProvider implements FrameSequenceDrawable.BitmapProvider {
        HashSet<Bitmap> mBitmaps = new HashSet<Bitmap>();

        @Override
        public Bitmap acquireBitmap(int minWidth, int minHeight) {
            Bitmap bitmap =
                    Bitmap.createBitmap(minWidth + 1, minHeight + 4, Bitmap.Config.ARGB_8888);
            mBitmaps.add(bitmap);
            return bitmap;
        }

        @Override
        public void releaseBitmap(Bitmap bitmap) {
            if (!mBitmaps.contains(bitmap)) throw new IllegalStateException();
            mBitmaps.remove(bitmap);
            bitmap.recycle();
        }

        public boolean isEmpty() {
            return mBitmaps.isEmpty();
        }
    }

    final CheckingProvider mProvider = new CheckingProvider();


//傳入資源,設定相關引數
        InputStream is = getResources().openRawResource(mResourceId);
        FrameSequence fs = FrameSequence.decodeStream(is);//傳入的是InputStream
        mDrawable = new FrameSequenceDrawable(fs, mProvider);
//        mDrawable.setLoopBehavior(LOOP_FINITE);//只播放一次
        mDrawable.setOnFinishedListener(new FrameSequenceDrawable.OnFinishedListener() {
            @Override
            public void onFinished(FrameSequenceDrawable drawable) {
                Toast.makeText(getApplicationContext(),
                        "The animation has finished", Toast.LENGTH_SHORT).show();
            }
        });
        drawableView.setBackgroundDrawable(mDrawable);
//開始播放
 mDrawable.start();
 //暫停播放
 mDrawable.stop();
 //裁剪成圓形
 mDrawable.setCircleMaskEnabled(!mDrawable.getCircleMaskEnabled());
複製程式碼

 目前giflib載入的都是本地的,那麼如何載入線上GIF尼?其實可以把giflib與glide結合起來,由glide負責下載、快取等的實現,giflib來負責GIF的載入。具體實現可以參考我寫的一個demo

相關文章