Base64 Image Data to Image Sprite

Has anyone tried to do this? All of the Base64 extensions can decode and display the image in an image component, but the image has no identity to allow it to then be used as the image for an ImageSprite (or to create a temporary image file).

this should work. I used to draw a shape in canvas and save as png, then set it as picture of imagesprite.

I can have a look at this over the weekend at some point, real world issues (son has new house that needs decorating / moving into...) may get in the way

It already is a png, encoded to Base64 (batches, 104 images per display for the User to select via a WebViewer). What I was thinking of is to decode to a temporary image file, save to ASD, load from there (this is all at runtime), apply the image to a sprite dynamically created with CompCreator.

Thanks Tim - actually, our house could do with some decorating too............

This is how I currently make the Sprites dynamically: User picks an image button, CompCreator creates a Sprite, the image related to the picked button is applied to the sprite. That all works very well, but is not practical for many image choices on one screen and also prevents other sets of images from being swapped-in.

So, the 'buttons' are to be an HTML table, displayed in a web viewer (the button images themselves are B64). I have set this solution up a few times for App Developers that need a lot of buttons. When the User picks an image by tapping a button, the webviewstring passes the related B64 image data to the App. The missing code is how to most efficiently decode the data and plonk the image onto the newly created sprite.

In fact, Tim has made an extension that can apply B64 image data 'directly' to a component, but Sprites are not included.

you can try this:
cn.kevinkun.SpriteBase64.aix (4.6 KB)
spriteplus.aia (26.2 KB)

source code:

package cn.kevinkun.SpriteBase64;

import java.lang.reflect.Field;

import com.google.appinventor.components.annotations.DesignerComponent;
import com.google.appinventor.components.annotations.SimpleFunction;
import com.google.appinventor.components.annotations.SimpleObject;
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.ImageSprite;
import com.google.appinventor.components.runtime.errors.YailRuntimeError;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.util.Base64;

@DesignerComponent(version = 1, versionName = "1.0", description = "set ImageSprite Picture with base64 string.", category = ComponentCategory.EXTENSION, nonVisible = true, iconName = "images/extension.png", helpUrl = "https://kevinkun.cn")
@SimpleObject(external = true)
public class SpriteBase64 extends AndroidNonvisibleComponent {

	public SpriteBase64(ComponentContainer container) {
		super(container.$form());
	}

	@SimpleFunction
	public void PictureFromBase64(ImageSprite sprite, String base64) {
		try {
			byte[] bytes = Base64.decode(base64, Base64.DEFAULT);
			Bitmap myBitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
			BitmapDrawable drawable = new BitmapDrawable(myBitmap);

			Field field = sprite.getClass().getDeclaredField("drawable");
			field.setAccessible(true);
			field.set(sprite, drawable);

			sprite.Width(sprite.Width());

		} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
			e.printStackTrace();
			throw new YailRuntimeError(e.getMessage(), "err");
		}
	}

}

4 Likes

Hi Kevin

That works extremely well, thank you!

I'm in the process of writing a desktop program to create the HTML pages specific to the App.

@TIMAI2 you may put this extension together with your 3 extension.

2 Likes