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