鸿蒙自定义一个GifImage组件

创建一个空的工程

image-20210228112344661

在这个空工程下创建一个空的Module,指定Module为一个HarmonyOS libraryModule名称为Gif

image-20210228112528838

新建一个Gif类,继承自Image

package com.example.timestory.slice.Utils;

import com.example.timestory.slice.Utils.decoder.GifDecoder;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Image;
import ohos.app.Context;
import ohos.global.resource.NotExistException;
import ohos.global.resource.RawFileEntry;
import ohos.global.resource.ResourceManager;
import ohos.global.resource.WrongTypeException;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author PengHuAnZhi
 * @createTime 2021/3/2 19:48
 * @projectName TimeStory
 * @className Gif.java
 * @description TODO
 */
public class Gif extends Image {

    private List<PixelMap> pixelMapList = new ArrayList<>();

    private static HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, 0x000110, "GifImage");
    // 动画
    private AnimatorValue animatorValue;
    private ImageSource imageSource;
    private GifDecoder gifDecoder;
    private Boolean ispaused = false;
    private int duration;
    private float speed = 1;

    public void setSpeed(float speed1) {
        float EPSINON = (float) 0.00001;
        if (speed1 > EPSINON) {
            this.speed = speed1;
        }
        HiLog.info(label, "speed数据值" + (speed));
        animatorValue.stop();
        animatorValue.setDuration((long) (speed * duration));
        animatorValue.start();
        invalidate();
    }

    public Gif(Context context) {
        super(context);
    }

    public Gif(Context context, AttrSet attrSet) throws IOException, NotExistException, WrongTypeException {
        super(context, attrSet);
        gifDecoder = new GifDecoder();
        ResourceManager resourceManager = context.getResourceManager();
        ImageSource.SourceOptions sourceOptions = new ImageSource.SourceOptions();
        sourceOptions.formatHint = "image/gif";

        if (attrSet.getAttr("image_src").isPresent()) {
            String id = attrSet.getAttr("image_src").get().getStringValue();
            Pattern pattern = Pattern.compile("[^0-9]");
            Matcher matcher = pattern.matcher(id);
            String all = matcher.replaceAll("");
            RawFileEntry rawFileEntry = resourceManager.getRawFileEntry(resourceManager.getMediaPath(Integer.parseInt(all)));
            ImageSource imageSource = ImageSource.create(rawFileEntry.openRawFile(), sourceOptions);
            gifDecoder.read(rawFileEntry.openRawFile(), (int) rawFileEntry.openRawFileDescriptor().getFileSize());

            if (imageSource != null) {
                init(imageSource);
            }
        } else {
            invalidate();
        }

    }


    private int i;
    // 动画侦听函数
    private final AnimatorValue.ValueUpdateListener mAnimatorUpdateListener
            = (animatorValue, v) -> {
        setPixelMap(pixelMapList.get((int) (v * pixelMapList.size())));
        invalidate();
    };

    private void init(ImageSource imageSource) {
        pixelMapList.clear();
        duration = 0;
        //  invalidate();
        ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
        decodingOptions.allowPartialImage = true;
        i = 1;
        if (gifDecoder.getFrameCount() > 0) {
            while (i < gifDecoder.getFrameCount()) {
                pixelMapList.add(imageSource.createPixelmap(i, decodingOptions));
                duration += gifDecoder.getDelay(i);
                i++;
            }
        } else {
            while (imageSource.createPixelmap(i, decodingOptions) != null) {
                pixelMapList.add(imageSource.createPixelmap(i, decodingOptions));
                duration += gifDecoder.getDelay(i);
                i++;
            }
        }
        // 启动动画
        HiLog.info(label, "持续时间" + duration);
        animatorValue = new AnimatorValue();
        animatorValue.setCurveType(Animator.CurveType.LINEAR);
        animatorValue.setDelay(100);
        animatorValue.setLoopedCount(Animator.INFINITE);
        animatorValue.setDuration(duration == 0 ? 3000 : duration);
        animatorValue.setValueUpdateListener(mAnimatorUpdateListener);
        animatorValue.start();
    }

    public void load(RawFileEntry rawFileEntry) throws IOException {
        gifDecoder.read(rawFileEntry.openRawFile(), (int) rawFileEntry.openRawFileDescriptor().getFileSize());
        ImageSource.SourceOptions sourceOption = new ImageSource.SourceOptions();
        imageSource = ImageSource.create(rawFileEntry.openRawFile(), sourceOption);
        if (imageSource != null) {
            init(imageSource);
        }
    }

    public void pause() {
        if (!ispaused) {
            ispaused = true;
        }
        animatorValue.pause();
        invalidate();
    }

    public void play() {
        if (ispaused) {
            ispaused = false;
        }
        animatorValue.start();
    }
}

然后引入解码工具包(工具包代码总计上千行,不贴出了,需要可私信我)

image-20210302195135090

然后在布局文件引用即可

image-20210302195417789

便于组件分享,使用Gradle工具发布har包,PackageDebugHarPackageDebugHar都可

image-20210228114933204

生成的har包可以在build/ourputs/har/debug/harbuild/ourputs/har/release/har目录下找到

image-20210228115051412

har包复制,粘贴到需要使用的工程的lib目录下(没有自己创建)

image-20210302195911692

由于build.gradle配置文件本身配置了扫描har包,所以完全不需其他配置即可使用

image-20210302200026548

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要在 MFC 中创建 GIF 文件,并不是一件简单的事情,因为 GIF 文件格式相对来说比较复杂。下面是一个大致的步骤: 1. 创建 GIF 文件头,包括文件标识符、版本号、逻辑屏幕宽度、高度、全局颜色表等信息。 2. 创建 GIF 图像数据块,包括图像标识符、图像左上角坐标、图像宽度、高度、局部颜色表、LZW 压缩后的数据等信息。 3. 创建 LZW 压缩算法,将图像像素数据转换为 LZW 码流。 4. 将 LZW 码流写入 GIF 图像数据块中。 5. 创建 GIF 文件结束标志。 6. 将所有数据写入文件中,保存为 GIF 格式。 下面是一个简单的示例代码,可以创建一个 100x100 像素的红色矩形,并将其保存为 GIF 文件: ```cpp void CreateGifFile(const wchar_t* gifPath) { // 创建 GIF 文件头 BYTE gifHeader[] = { 'G', 'I', 'F', '8', '9', 'a', 0x64, 0x00, 0x64, // 逻辑屏幕宽度和高度(100x100) 0xF0, // 全局颜色表标志和颜色深度(全局颜色表存在,颜色深度为 4) 0x00, // 背景色索引 0x00, // 像素宽高比 }; // 创建红色矩形像素数据 BYTE pixelData[100 * 100] = { 0 }; for (int y = 30; y < 70; y++) { for (int x = 30; x < 70; x++) { pixelData[y * 100 + x] = 1; } } // 创建 GIF 图像数据块 BYTE gifImage[] = { ',', // 图像标识符 0x00, 0x00, // 图像左上角坐标 0x64, 0x00, 0x64, // 图像宽度和高度(100x100) 0x00, // 局部颜色表标志和交错标志 0x04, // 局部颜色表大小(4个颜色) 0x00, // LZW 最小码字宽度(4个像素) }; // 创建颜色表 BYTE colorTable[] = { 0xFF, 0x00, 0x00, // 红色 0x00, 0xFF, 0x00, // 绿色 0x00, 0x00, 0xFF, // 蓝色 0xFF, 0xFF, 0xFF, // 白色 }; // 创建 LZW 压缩码流 BYTE compressedData[10000] = { 0 }; int compressedDataLen = CompressDataLZW(pixelData, 100 * 100, compressedData); // 创建 GIF 文件结束标志 BYTE gifTrailer[] = { 0x3B }; // 将所有数据写入文件中 FILE* fp = NULL; _wfopen_s(&fp, gifPath, L"wb"); fwrite(gifHeader, sizeof(BYTE), sizeof(gifHeader), fp); fwrite(colorTable, sizeof(BYTE), sizeof(colorTable), fp); fwrite(gifImage, sizeof(BYTE), sizeof(gifImage), fp); fwrite(compressedData, sizeof(BYTE), compressedDataLen, fp); fwrite(gifTrailer, sizeof(BYTE), sizeof(gifTrailer), fp); fclose(fp); } ``` 以上代码创建了一个红色矩形,并将其保存为 GIF 格式的文件。其中 `CompressDataLZW` 函数是一个 LZW 压缩算法的实现,您需要自行编写。此外,由于 GIF 文件格式比较复杂,以上代码可能不适用于所有情况,需要根据实际情况进行修改和优化。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值