Object URLs from Image Input Component

Hey all - wondering how to use the Image Input component on mobile:
For context-building an inventory management mobile app where sometimes pictures have to be taken and stored.

imageInput1.value[0] returns the object (blob?) url: blob: https://org-name.retool.com/4eee7476-9716-4772-9b82-d00e23ffafb5

I can open this in a new tab and it returns the image, and can also point an image component to it where the image is displayed in the app.

I'm trying to upload an image taken on the mobile app to Supabase storage and from my understanding need the base64encoded data or binary data to do that. I've tried fetch and always get the error "failed to fetch", and an also XMLHttpRequest(), and no luck. Chrome's Dev Tools show "Not allowed to load local resource: blob: ..."

Does anyone have any ideas or tips on how to get the raw image data so I can upload it to storage? Is there a way to get access to the object before the object url is generated?

Apologies if I'm missing something obvious, I'm new to all this..
Thanks in advance!

1 Like

@Ike looks like this is a current bug in the product! Thanks for reporting. We're working on a fix ASAP.

Update: we've shipped a new API to convert Blob or File URIs to base64 strings, utils.getDataByObjectURL. It's an async API (which means you need to await it) and should be useable in JS Queries and "Run script" event handlers.

Use it like this:

// if imageInput1.value[0] is "blob:http://foo.retool.com/7b4f0d00-6f66-4215-b0d8-d09f982b788e":

const base64 = await utils.getDataByObjectURL(imageInput1.value[0])
4 Likes

Hey there, this works on the web editor for mobile apps, but doesn't seem to be working on the mobile app itself. Images come in as blob URIs on the web editor, but file URIs in the mobile app. The utils.getDataByObjectURL API works great on the web and I get the base64 data and can upload to storage perfectly, but it doesn't seem to work on the mobile app. Do you have any ideas on what I might be missing. Does that API work for file URIs as well? It's slightly frustrating something works in the web editor for mobile apps but not in the actual mobile app itself.

Here is my code if that helps at all:
Thanks in advance!

for (let i = 0; i < imageInput1.files.length; i++) {
  const file = imageInput1.files[i];
  delete file.uri;

const newFileName = test.png;
  const newFile = new File([file], newFileName, { type: file.type });
  const base64 = await utils.getDataByObjectURL(imageInput1.value[i]);

  const imageData = {
  data: base64.slice(base64.indexOf(',') + 1),
  name: newFile.name,
  size: newFile.size,
  type: newFile.type,
  height: file.height,
  width: file.width
};

  uploadImage.trigger({
    additionalScope: {
      i: i,
      imageData: imageData,
      imageName: newFileName
    }
  });

}

formatting issues haha

@Ike can you share your uploadImage implementation?

@bca here it is! Thanks for your help.

Hi @Ike! I believe the issue here is that the File constructor (new File()) is not supported on React Native and we're currently not polyfilling it.

On Web, your call to new File(...) should return an empty object, but it will not break the JS query, and so the upload call still works. (Out of curiosity, does the file in supabase read the values in newFile.name and newFile.size :thinking:?)

On Mobile, the call to new File() will break the entire JS query and the upload will not proceed.

Can you try removing using new File(), and use {{imageInput1.files[i]}} to get the size and type and hard-code a file name to test if it works?

Hey @shawntax

Here's the code that ended up working for me - thank you for your suggestion!

for (let i = 0; i < imageInput1.files.length; i++) {
  const file = imageInput1.files[i];
  delete file.uri;

const newFileName = getCountOfExistingDocs.data[0].count+'-'+poDocType.value+'-'+i+'.png';
  const base64 = await utils.getDataByObjectURL(imageInput1.value[i]);

  const imageData = {
  data: base64.slice(base64.indexOf(',') + 1),
  name: newFileName,
  size: file.size,
  height: file.height,
  width: file.width
};

  uploadImage.trigger({
    additionalScope: {
      i: i,
      imageData: imageData,
      imageName: newFileName
    }
  });

}

As far as I can tell, supabase reads the name because whenever I upload a file without a file type (like 'test.png' vs just 'test', it always shows the type when retrieved as application/octet-stream. (Maybe there's another way to set the file type but this is what was working for me) Anyway - this seems to be fixed and I appreciate all your help!