Hello, I’m an absolute beginner in Genie.jl and in web stack in general. I want to build a webpage which periodically generates a random picture using some julia code, and displays it.
To begin, I want to simply display a picture in the browser. The picture pic.png is my root folder. When I do
route("/") do
html("<img src=\"pic.png\"/>")
end
the picture does not appear in the browser. Could someone help me understand solving this basic task ?
Related question. Suppose that I have a Julia function generate which generates a picture in the form of an RGB array (or any other image format supported by Julia, or a Plots object, etc).
In my webapp, I basically want to call this function, collect the output x = generate(), save it in a file and display the result in an html page.
Is there a way to do this without saving the picture, but to directly embed pic into the html ?
I think the most immediate issue that you’re facing here is the path to image not being correct. I had to put my image into “public” directory for it to be successfully found, otherwise it throws a 404. Also, html() is not a recognized function, I have to use HTML(), all capital.
As for having a random image generated and rendered into HTML from memory, without writing to disk, I’m not sure… I managed to get a random image to generate every time I refresh the page with the following routes.jl code:
using Genie.Router, Images, ImageMagick
import Random.randstring
route("/") do
newfilename = "$(randstring()).png"
randimage = rand(RGB, 1000, 1000)
ImageMagick.save("public/img/$newfilename", randimage)
HTML("<img src='img/$newfilename' />")
end
A notable downside of this approach is that it generates and saves a random image into public/img, but doesn’t delete it thereafter. If I added code to delete the image at the end of the route() block, the image simply didn’t render when I visited the page. So definitely undesirable behavior if you plan for your web-app to be used a lot, for it to flood your disk with all sorts of data and never reclaim the used up space. If you find a better way, I would like to know about it!
Hi, I know nothing of the Genie.jl part.
You can keep track of the created images and delete them when unused in this same method, a global counter can do the job, you can leave just the last few pictures in the folder…
NOTE: This just works if the program is persistent
using Genie.Router, Images, ImageMagick
import Random.randstring
img_counter = 1
img_pool_size = 5
img_name(c) = "rand_img_$c.png"
route("/") do
# delete old images
rm_path = joinpath("public", "img", img_name(counter - img_pool_size))
rm(rm_path; force = true)
# create new img
newfilename = img_name(img_counter)
randimage = rand(RGB, 1000, 1000)
img_counter += 1
save_path = joinpath("public", "img", newfilename)
ImageMagick.save(save_path, randimage)
# html part
html_path = joinpath("img", newfilename)
HTML("<img src='$html_path' />")
end
You can base64 encode the image directly in the HTML. That way you do not need to implement additional image file server functionality or create temporary files.
image_stream = open(image_file) # This opens a file, but you can just as well use a in-memory buffer
data = Base64.base64encode(image_stream)
html = """<img src="data:image/png;base64,$(data)">"""
while with html(“hello”) I simply get the normal behaviour “hello”.
@Krastanov Thanks, this looks really like what I was trying to do ! Unfortunately,
route("/other") do
rndpic = rand(RGB, 100, 100)
data = Base64.base64encode(rndpic)
i = """<img src="data:image/png;base64,$(data)">"""
html("<img src='data:image/png;base64,$(data)'>")
end
You have to encode the png stream. Instead, what you are doing is encoding some raw bitmap, which is not png, so the browser just sees some random data that can not be decoded. To do this properly, first create an in-memory file-like stream, “save” the image to that file-like object in a png format, then encode that file-like object into a base64 string.