Generating GIF from FrameLayout

Viewed 256

Hi I'm trying to generate gif from animated view

In brief, I've ImageView and animated view inside FrameLayout, now i want to generate gif of main FrameLayout, minimum sdk level 19. getDrawingCache bitmap and arrange them in sequence to gif may cause memory out of bound issue.

enter image description here

when i click "start rec" i want gif or video of that particular view.

1 Answers

First, you need to implement these libraries :

implementation 'com.blankj:utilcodex:1.30.6'
implementation 'com.waynejo:androidndkgif:0.3.3'
implementation 'com.jiang.android.observablescheduler:schedule:1.0.1'
  1. The first one is a useful library, which contains all the necessary classes to help you, such as (ImageUtils, PathUtils...).
  2. The second one is for the encoding and decoding GIF.
  3. The Third one is for replacing the AsyncTask class with java.util.concurrent

The XML : I tried to make the same thing you did :

<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:gravity="center"
        android:orientation="vertical">

        <RelativeLayout
            android:id="@+id/viewToBeRecorded"
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:layout_gravity="center"
            android:background="@android:color/holo_green_light"
            android:gravity="center">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                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_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Change Background"
            android:textStyle="bold" />

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

        <Button
            android:id="@+id/stopRecord"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            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();
    }

OUTPUT :

enter image description here

Don't forget to add :

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

and make sure the Storage permission is granted

Related