从 FrameLayout 生成 GIF

Posted

技术标签:

【中文标题】从 FrameLayout 生成 GIF【英文标题】:Generating GIF from FrameLayout 【发布时间】:2021-10-08 09:37:08 【问题描述】:

您好,我正在尝试从动画视图生成 gif

简而言之,我在 FrameLayout 中有 ImageView 和动画视图,现在我想生成主 FrameLayout 的 gif,最低 sdk 级别为 19。getDrawingCache 位图并将它们按 gif 顺序排列可能会导致内存溢出问题。

当我点击“开始录制”时,我想要该特定视图的 gif 或视频。

【问题讨论】:

能否请您分享您现在的代码,以便我更好地理解并回答? 我不确定我是否理解您想要实现的目标。 嘿@AkshatTiwari 请检查附件图片 嘿@CristianHoldunu,请立即查看 如果我正确理解了您的要求,那么这个问题的答案可能超出了 SO 问题的范围。您将需要一个位图处理管道,可以将位图转换为 gif,您的实现以您想要的速率提供位图。可能是这个? github.com/nbadal/android-gif-encoder 【参考方案1】:

首先,您需要实现这些库:

implementation 'com.blankj:utilcodex:1.30.6'
implementation 'com.waynejo:androidndkgif:0.3.3'
implementation 'com.jiang.android.observablescheduler:schedule:1.0.1'
    第一个是一个有用的库,它包含所有必要的 帮助您的课程,例如 (ImageUtils, PathUtils...)。 第二个是GIF的编解码。 第三个用于替换 AsyncTaskjava.util.concurrent

XML :我试着做和你一样的事情:

<LinearLayout
        android:layout_
        android:layout_
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:gravity="center"
        android:orientation="vertical">

        <RelativeLayout
            android:id="@+id/viewToBeRecorded"
            android:layout_
            android:layout_
            android:layout_gravity="center"
            android:background="@android:color/holo_green_light"
            android:gravity="center">

            <TextView
                android:layout_
                android:layout_
                android:layout_centerHorizontal="true"
                android:layout_centerVertical="true"
                android:gravity="center"
                android:text="View To Be Recorded"
                android:textStyle="bold" />
        </RelativeLayout>

        <Button
            android:id="@+id/changeBg"
            android:layout_
            android:layout_
            android:text="Change Background"
            android:textStyle="bold" />

        <Button
            android:id="@+id/startRecord"
            android:layout_
            android:layout_
            android:text="Start Record"
            android:textStyle="bold" />

        <Button
            android:id="@+id/stopRecord"
            android:layout_
            android:layout_
            android:enabled="false"
            android:text="Stop Record"
            android:textStyle="bold" />
    </LinearLayout>

Java:

public class MainActivity extends AppCompatActivity 
    
    private Button changeBg, startRecord, stopRecord;
    private RelativeLayout viewToBeRecorded;
    private boolean isRecording = false;
    private GifEncoder mGifEncoder;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initializeViews();

        startRecord.setOnClickListener(v -> 
            isRecording = true;
            ToastUtils.showShort("Start recording...");
            startRecord.setEnabled(false);
            stopRecord.setEnabled(true);
            generateGIF();
        );

        stopRecord.setOnClickListener(v -> 
            isRecording = false;
            ToastUtils.showShort("Stop recording...");
            startRecord.setEnabled(true);
            stopRecord.setEnabled(false);
        );

        changeBg.setOnClickListener(v -> 
            Random rnd = new Random();
            int color = Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
            viewToBeRecorded.setBackgroundColor(color);
        );

    

    private void generateGIF() 
        JObservable.create((JObservable.OnSubscribe<String>) mSubscriber -> 
            try 
                File storageDir = new File(PathUtils.getExternalPicturesPath() + "/GIFs");
                FileUtils.createOrExistsDir(storageDir);
                File gifFile = new File(storageDir, "GIF" + System.currentTimeMillis() + ".gif");
                String outputPath = gifFile.getAbsolutePath();
                Bitmap firstFrame = ImageUtils.view2Bitmap(viewToBeRecorded);
                try 
                    mGifEncoder.init(firstFrame.getWidth(), firstFrame.getHeight(), outputPath, GifEncoder.EncodingType.ENCODING_TYPE_SIMPLE_FAST);
                    while (isRecording) 
                        Bitmap frame = ImageUtils.view2Bitmap(viewToBeRecorded);
                        mGifEncoder.encodeFrame(frame, 100);
                        Thread.sleep(20);
                    
                    mGifEncoder.close();
                    mSubscriber.notifyData(outputPath);
                 catch (FileNotFoundException e) 
                    e.printStackTrace();
                
             catch (Exception e) 
                mSubscriber.error(e);
            
        ).workedOn(Schedules.background())
                .subscribeOn(Schedules.mainThread())
                .subscribe(new Subscriber<String>() 
                    @Override
                    public void notifyData(String outputPath) 
                        FileUtils.notifySystemToScan(outputPath);
                        ToastUtils.showShort("GIF saved!");
                    

                    @Override
                    public void error(Throwable t) 
                        Log.e("View2GIF", "generateGIF throw error : " + t.getMessage());
                    
                );

    

    private void initializeViews() 
        viewToBeRecorded = findViewById(R.id.viewToBeRecorded);
        changeBg = findViewById(R.id.changeBg);
        stopRecord = findViewById(R.id.stopRecord);
        startRecord = findViewById(R.id.startRecord);
        mGifEncoder = new GifEncoder();
    

输出:

别忘了补充:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

并确保存储权限已授予

【讨论】:

您好@Mouaad Abdelghafour AITALI 我感谢您的努力,但这对我没有帮助。我在捕获两个位图之间跳过的帧数的位图时导致 gif 滞后问题 @MahendraGohil 您可以更改 sleep 的值,例如 Thread.sleep(20); 这将使您的应用每 20ms 捕获一帧 你好@Mouaad Abdelghafour AITALI 我已经试过了 @MahendraGohil 你没有在你的问题中添加你的动画代码,添加它以便我可以用我的代码测试它 对不起@Mouaad Abdelghafour AITALI,但我已经告诉过我生成位图序列对我不起作用

以上是关于从 FrameLayout 生成 GIF的主要内容,如果未能解决你的问题,请参考以下文章

FrameLayout(帧布局)

FrameLayout系列:FrameLayout三连问

带圆角的 FrameLayout

重力设置动态不适用于 Framelayout

FrameLayout to RelativeLayout ClassCastException 即使没有使用 FrameLayout

在 FrameLayout 中显示 TextView