Could someone save me from this Runtime Error?

I'm making an app where I can view an image through a WebViewer and a html file in the assets. But I'm getting this Runtime Error.

Runtime Error Image

My Blocks

Designer Components Image

Source Code of image.html file
<!DOCTYPE html>
<html>
<head><title>Image</title>
<meta name="viewport" content="user-scalable=yes, initial-scale=1, width=device-width, height=device-height" />

</head>
<body>
<img style="width: 100%; height: 100%; object-fit: contain" src="appinventor.ai_rayshubham1321.Timetable/files/.Timetable/Timetable.png" />
</body>
</html>

Here is the aia : Timetable.aia (97.6 KB)

About the Error.

The error is reported after the Image is Picked.
After some investigation, I came to know that, the the Image is saved in the directory.
(/storage/emulated/0/Android/data/appinventor.ai_rayshubham1321.Timetable/files/.Timetable)

It happens at the if block or at the Convertor(extension to convert from jpg to png).

I'd be just trying to remove the if block and update things about the Error.

Please help if possible.
Thank You for reading this far.

Extra Info : The collapsed blocks don't contain anything, i.e., they are blank.

Your error reports timetable all in lower case, in your html you show in sentence case Timetable

1 Like

@TIMAI2 I used that sentence case itself. You may see my HTML Code.

Edit : I misclicked Solution for like sorry.

You also appear to have hard coded the package name in the html file. It would be better to pass the package name / file path using the webviewstring.

Looking at the blocks, this does appear to be a very long winded method to achieve something fairly simple....

1 Like

Actually the thing isn't fairly simple. Also, it appears long because of the variables.

What I'm doing is, first the Activity Starter will pick the image, which takes one block. Next, the file path would be received, which takes another block. Next, the file will be copied from its original destination to the app-specifi directory.

The next block is multipurpose. It will first convert the asd file into png (if not already a png file). It will also set the name of the file to TimeTable.png. It will also maintain the case if the file was originally named as Timetable.png.

The next block opens the WebViewer.

So every task is done in one procedure.

 

 

I've now removed the hard-coded package name and changed it to /files/.Timetable/Timetable.png. Waiting for the app to be installed in the background.

@TIMAI2 Could you tell me what to do with the WebViewString Property ? I know nothing about it.

The only thing I can guess is that its involves javascript, where I'm a newb. So could you give me the code ?

1 Like

I beleive there is an issue with the convertor extension. It does not seem to want to traverse a directory with a . in it, i.e. edu.mit.appinventor.aicompanion3. This will be the case for most package names.

Perhaps @Kumaraswamy could take a look and advise? My guess is the code is looking for the first . when it needs to be looking for the last one (lastIndexOf) :wink: I also notice that WEBP is now deprecated, in favour of WEBP_LOSSY and WEBP_LOSSLESS (but this only appears to work on Android < 29).

2 Likes

A rework, using just the File component and an imagepicker (assumes the convertor extn was working!). Copies the html file to the Timetable directory, then no file path required to the image, just the filename.

1 Like

But I don't want to use the ImagePicker.

Btw, is the Convertor extension working for folders without a . in the beginning ?

Did you test this snippet ?

Edit : If the extension works, in that case, first I'll save the file in the ASD, and then I'll move the file to the /.Timetable directory.

Please run the snippet once.

Why not ? It is doing the same thing as GET_CONTENT, saves a copy of the image to the ASD for you, and in my blocks I delete the created file after conversion. What is not to like ?

1 Like

In case the other apps with the FileScope Shared save the image in that directory, I don't want to delete those images.

The original file, as located by the opening of the gallery by the imagepicker is never touched. A copy is made to ~ASD/Pictures/_app_inventor_image_picker/, and my bocks work with and eventually delete that file.

Deletion is not strictly necessary, the image picker will only store up to 10 files, then start deleting the first one to make way for the next.

1 Like

I never knew that ImagePicker will save it to ASD.

Probably cuz whenever I used ImagePicker, Screen1.FileScope = Filescope Shared. LOL :joy:.

Thanks for the info. :blush:

Yes, i am sorry, i currently cannot edit the extension, here is the code (decoded):

package com.kumaraswamy.convertor;

import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
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.annotations.UsesPermissions;
import com.google.appinventor.components.common.ComponentCategory;
import com.google.appinventor.components.runtime.AndroidNonvisibleComponent;
import com.google.appinventor.components.runtime.ComponentContainer;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

@UsesPermissions(permissionNames="android.permission.WRITE_EXTERNAL_STORAGE, android.permission.READ_EXTERNAL_STORAGE")
@DesignerComponent(description="An extension to convert images to different formats :)", category=ComponentCategory.EXTENSION, nonVisible=true, androidMinSdk=21, version=0)
@SimpleObject(external=true)
public final class Convertor
  extends AndroidNonvisibleComponent
{
  public Convertor(ComponentContainer container)
  {
    super(container.$form());
  }
  
  @SimpleFunction
  public void Convert(String target, String output)
    throws Exception
  {
    int pos = output.indexOf('.');
    if (-1 == pos) {
      throw new FileNotFoundException();
    }
    String type = output.substring(pos + 1).toLowerCase();
    Bitmap.CompressFormat format;
    Bitmap.CompressFormat format;
    Bitmap.CompressFormat format;
    switch (type)
    {
    case "png": 
      format = Bitmap.CompressFormat.PNG;
      break;
    case "jpg": 
      format = Bitmap.CompressFormat.JPEG;
      break;
    case "webp": 
      format = Bitmap.CompressFormat.WEBP;
      break;
    default: 
      throw new IllegalStateException("Unexpected value: " + type);
    }
    Bitmap.CompressFormat format;
    FileOutputStream stream = new FileOutputStream(output);Throwable localThrowable3 = null;
    try
    {
      BitmapFactory.decodeFile(target).compress(format, 100, stream);
    }
    catch (Throwable localThrowable1)
    {
      localThrowable3 = localThrowable1;throw localThrowable1;
    }
    finally
    {
      if (stream != null) {
        if (localThrowable3 != null) {
          try
          {
            stream.close();
          }
          catch (Throwable localThrowable2)
          {
            localThrowable3.addSuppressed(localThrowable2);
          }
        } else {
          stream.close();
        }
      }
    }
  }
}
2 Likes

I'm making the extension myself then. I won't be using other extension's source code for my first extension. Bye. :wave:

Try this:

uk.co.metricrat.imageconvertor.aix (6.8 KB)

1 Like

@TIMAI2 Thanks man.

My extension carrier ended just as I was writing the class Constructor.
First I'd use this. Then I'll test the app. Then I'll make an extension myself.

@TIMAI2 What is the quality param ?

It is in the description/tooltip.

0 - 100 for jpg and webp
100 = best visual appearance