[F/OS] ๐Ÿ–ผ๏ธ ViewUtil - Turn/Convert A Component To An Image!

:computer: Introduction

An open source extension that saves a component as an image.

Thanks to @Jerin_Jacob for the Convert component to image, I took inspiration from his extension.

:date: Release date: 2022-03-23T03:30:00Z

:package: Package name: com.gordonlu.viewutil.aix

:clock11: Version: 2

:open_book: Documentation

Event blocks

Failed

image

This event is fired when the extension has encountered an error. Possible reasons: quality is not a number between 0 and 100, wrong path, etc.

Parameters: error = text

Saved

image

This event is fired when the extension has saved the image at the path.

Parameters: path = text

Method blocks

SaveComponentAsImage

image

Saves the component as an image with the given path, compress format and the given quality. The quality parameter shall be a value between 0 and 100, and the path parameter shall be an absolute path.

The compressFormat parameter only accepts "JPEG" or "PNG". If not, then the file format should be "JPEG". The path should be something like: storage/emulated/0/Android/data/appinventor.ai_gordonlu0749.Save/filesimage.jpg.

Parameters: component = component, path = text, compressFormat = text, quality = number (int)

Property blocks

Jpg

image

A compressed format block.

Returns: "JPEG"

Png

image

A compressed format block.

Returns: "PNG"

:inbox_tray: Downloads

AIX:
com.gordonlu.viewutil.aix (7.0 KB)

AIA:
Save.aia (15.4 KB)

:lock: Open Source

Here you go.

package com.gordonlu.viewutil;

import android.app.Activity;
import android.content.Context;
import com.google.appinventor.components.annotations.*;
import com.google.appinventor.components.common.ComponentCategory;
import com.google.appinventor.components.runtime.AndroidNonvisibleComponent;
import com.google.appinventor.components.runtime.ComponentContainer;
import com.google.appinventor.components.runtime.EventDispatcher;

import com.google.appinventor.components.runtime.AndroidViewComponent;
import android.view.View;
import android.graphics.Bitmap;
import java.io.FileOutputStream;
import android.graphics.Bitmap.CompressFormat;

@DesignerComponent(
        version = 1,
        description = "A non-visible extension to save a component as an image.",
        category = ComponentCategory.EXTENSION,
        nonVisible = true,
        iconName = "https://docs.google.com/drawings/d/e/2PACX-1vQCI87PHLBF0jb8QWyYmIRQSjjNW3EFXf-qpsWCvBYkUQ9vEgPAB8SpxcMpblxNpbIYrjCjLrRLIU2c/pub?w=16&h=16")

@SimpleObject(external = true)
//Libraries
@UsesLibraries(libraries = "")
//Permissions
@UsesPermissions(permissionNames = "")

public class ViewUtil extends AndroidNonvisibleComponent {

    //Activity and Context
    private Context context;
    private Activity activity;

    public ViewUtil(ComponentContainer container){
        super(container.$form());
        this.activity = container.$context();
        this.context = container.$context();
    }

    @SimpleFunction(description = "Saves the component as an image with the given path, compress format and the given quality.")
    public void SaveComponentAsImage(AndroidViewComponent component, String path, String compressFormat, int quality) {
        // https://stackoverflow.com/a/3527902/17802442
        try {
            View view = component.getView();
            view.setDrawingCacheEnabled(true);
            Bitmap b = view.getDrawingCache();
            CompressFormat cp = CompressFormat.JPEG;
            if (compressFormat == "PNG") {
            cp = CompressFormat.PNG;
            }
            b.compress(cp, quality, new FileOutputStream(path));
            Saved(path);
        }
        catch(Throwable e) {
          Failed(e.getMessage());  
}
    }
    @SimpleProperty(description = "A compress format block.")
    public String Jpeg() {
        return "JPEG";
    }
    @SimpleProperty(description = "A compress format block.")
    public String Png() {
        return "PNG";
    }
    @SimpleEvent(description = "This event is fired when the extension has failed to save the image.")
    public void Failed (String error) {
        EventDispatcher.dispatchEvent(this, "Failed", error);
    }
    @SimpleEvent(description = "This event is fired when the extension has saved the image.")
    public void Saved (String path) {
        EventDispatcher.dispatchEvent(this, "Saved", path);
    }
}

The DownloadToAsd extension is here, in case if you want to get the ASD path.

:heavy_check_mark: Tests

All of these tests are successful in saving the image in storage/emulated/0/Download and the ASD (application-specific directory).

:hammer_and_wrench: Companion:

  • Android 11 API 30, Xiaomi 11 5G NE Lite.

:hammer_and_wrench: APK:

  • Android 8.1 API 27, Google Pixel XL emulator.

  • Android 9 API 28, Google Pixel 5 emulator.

  • Android 11 API 30, Xiaomi 11 5G NE Lite.

  • Android 11 API 30, Google Pixel 2 emulator.

:hammer_and_wrench: Requirements:

  • In Screen1 properties, set DefaultFileScope to Legacy.

  • You must have the write external storage permission (a.k.a. Files/photos and media).

  • For details on how to read external storage, please search the forum.

If you have any bugs, reply here.


:+1: Rate my extension! :-1:

  • Good extension!
  • Bad extension.

0 voters

Made with Niotron IDE.

Kindly :email: PM me if you have any questions! Also, if you like my extension, please :heart: like it! It takes some effort for me to make it...

Votes and likes tell me the general user feedback of my extension. If you read this extension, please take 20 seconds to drop by and give a like!

If you have any features that you want to add and you know the code, PM me or directly reply below using the image button.

By downloading my extension, you agree the terms and conditions in my website


Gordon Lu

:speech_balloon: Message :earth_africa: Website :e-mail: E-mail

9 Likes

Is this extension changes components into image? If yes then it is very usefull extension for me

Yes, it changes components into images.

1 Like

:grinning: :grinning: :grinning: :grinning_face_with_smiling_eyes:

Do note that this extension is still not capable of taking screenshots of screens. That will be a feature for later.

If you want whole screens, use Jerin's extension, and if you want the screen to include status + navigation bars, use @Taifun's screenshot extension.

My screenshot extension is already launched, waiting for approval.

Perfect extension :grinning_face_with_smiling_eyes::+1:, add other file types

1 Like

Extension is stabilized, which I like...

Anyways, nice extension!

2 Likes

Thank you all.

Hmmm...in Android API they removed and added new file types. Because of this, PNG and JPEG are the only types that support all types.

2 Likes

:chocolate_bar: Version 2!

  • Updated events and added new ones.

Failed

image

This event is fired when the extension has encountered an error. Possible reasons: quality is not a number between 0 and 100, wrong path, etc.

Parameters: error = text

Saved

image

This event is fired when the extension has saved the image at the path.

Parameters: path = text

EDIT: Added to here.

3 Likes

Can you add a return block returing base64 of component image without saving it

1 Like

Good extension but still don't understand the main idea and how it can be beneficial actually , thanks for providing the aia file to understand what is doing too

Could be beneficial if you have labels in an arrangement that has weather data, and you want to export them.

3 Likes