Get URL from uploaded Image

What I’m trying to do:
I’m using a FileLoader component to upload an image.
This image then needs to be passed to a Custom HTML form which has JCrop selection implemented such that the user can crop the image.

The problem is that the FileLoader component provides an Anvil Media object which I cannot pass into my custom HTML form.

I need a way of extracting a URL from the media object which is available to the front-end - and pass this URL to the HTML form.

You need to set the image source as the url…

self.image.source = file.url

Hey thanks for the response!

I had tried this but the file.url property was None.

For anyone interested, this is how I solved it:

Make a table with three columns: Name (Text), Image (Media Object), and AddedAt (Datetime).

In a server module:


MAX_IMAGES_STORED = 1

@anvil.server.callable()
def get_file_url(file):
    print(f"file.content_type: {file.content_type}")
    if file.content_type != "image/png" and file.content_type != "image/jpg" and file.content_type != "image/jpeg":
        raise Exception(f"file type not allowed")

    
    all_rows = app_tables.input_images.search(tables.order_by('AddedAt'))
    if len(all_rows) > MAX_IMAGES_STORED:
        rows_to_delete = all_rows[:MAX_IMAGES_STORED]
        for row in rows_to_delete:
            row.delete()
            
    row = app_tables.input_images.add_row(Image=file, Name=file.name, AddedAt=datetime.now())
    return row

This code first checks file type (which you may or may not need to do in your case) - then adds the image to the table, making sure to not upload too many images (hence deleting old images)

Adding the file to the table forces it to have a URL - so when returning the row you can access the url in the front-end (client code) as follows:

 try:
      row = anvil.server.call('get_file_url', file)
 except Exception as e:
      alert(f"Error: {e}")
      return
  self.url = row['Image'].url

If your app is private and you don’t need to be extra secure - you can also make the table accessible by the client which will make this much faster. But in my case its a multi-user application and I don’t want the tables accessible in the client-side.

Hope this helps.

Your method is generally the one suggested to obtain a URL for a media object that is loaded or generated on the client. :+1:
If however you know how your JCrop javascript works, you may be able to interface with it directly using the anvil.js module.
Info Here:

and here:

1 Like

We also have a relatively new API for getting URLs from media objects on the client

See the API docs:

import anvil.media
temp_url = anvil.media.TempUrl(file) # takes a MediaObject
print(temp_url.url)
temp_url.revoke()

Calling revoke is generally seen as good practice when you no longer need the url of a BlobMedia/FileMedia object.
And is related to the memory management notes here:

Browsers will release object URLs automatically when the document is unloaded; however, for optimal performance and memory usage, if there are safe times when you can explicitly unload them, you should do so.

2 Likes

Cleanup often means using a Python Context Manager, e.g.,

with anvil.media.TempUrl(file) as temp_url:
    ...

Does that work as-is, or would we write our own wrapper class? (@contextlib.contextmanager isn’t in Skulpt yet.)

2 Likes

Either @stucork is just that fast, or it seems to already work with the context manager according to the docstring that popped up when it autocompleted just now:

Or both, it could definitely be both things. :slightly_smiling_face:

3 Likes

Very likely both. :grinning: Next time, I’ll remember to check the docs first!!

2 Likes

@stucork can we pass this temporary url to the server? If so, how? I am trying to pass an image url to chatgpt on server to execute a prompt. I cannot seem to get it to work.

Just a guess here, but the temporary url is an object, not a string. If you’re trying to pass the object itself, that probably won’t work. The network protocol understands only some basic data types, not arbitrary object types. See Valid arguments and return values.

The good news is that you can extract the url string from the object, so you could pass that instead. Follow Stu’s documentation link, above, for TempUrl, and read to the bottom. You’ll see how to extract the url string from the object.