HTMLViewer image Desktop vs Web

Need another perspective…

Desktop HTMLViewer show the image - this is what I want but in a WEBHTMLViewer:

Var f As FolderItem = SpecialFolder.UserHome.Child("test.html")
Var tis As TextInputStream  = TextInputStream.Open(f)
Var html As String = tis.ReadAll
HTMLViewer1.LoadPage(f)

WebHTMLViewer does not show the image

Var f As FolderItem = SpecialFolder.UserHome.Child("test.html")
Var tis As TextInputStream = TextInputStream.Open(f)
Var html As String = tis.ReadAll
// HTMLViewer1.LoadPage(f)
HTMLViewer1.LoadHTML(html) // no image

html file:

<!DOCTYPE html><html><body>April 30, 2025<br>
test image<br>
<img src="test.png" alt="test.png"><br>
</body></html>

Suggestions?

Is there a reason you’re not using WebImageViewer? Unlike Desktop, on Web it is actually a view and not an input.

With Web that should make serving the image easy. If you go the HTMLViewer route you will have to serve the image as a WebFile.

Wanting it to be dynamic, but this would solve a different issue if I could get a line of code that would explain how to load it?

I think the problem you are facing is that there is no WebHTMLViewer LoadPage.
If you read the documentation for DesktopHTMLViewer LoadPage:

Any links or temporary files will be resolved relative to the passed base FolderItem.

For web, there is no LoadPage. The HTML is loaded but the reference to the image is lost and your test.png is not where the web servers needs it to be.

If the final HTML that you are going to use provides the image on a server, your application may work.

For example, changing “test.png” to the URL of a photo:

<img src="https://fastly.picsum.photos/id/41/200/200.jpg?hmac=aqB5SyMLH-ssCBN-7HaUvcDxXFFQB42WoqAHsLRIn74" alt="test.png"><br>

It works for Desktop too:

You can create a Feature Request and see if Xojo can add LoadPage to WebHTMLViewer to make it work like Desktop. Avoiding code differences between platforms is one of Xojo’s goals.

I hope this helps (may will not help you if you have html with local reference to images).

With a little trickery, you can load a full HTML document from a variable or constant using the LoadURL method of a WebHTMLViewer:

me.LoadURL( "data:text/html;base64," + EncodeBase64( kHTML, 0 ) )

But that doesn’t solve OP’s problem. The app isn’t going to respond to a relative URL for an image file. A WebFile would need to be maintained (as stated by Tim) then the URL replaced in the source HTML or a mechanism setup in App.HandleURL to serve image assets.

Here’s an example I quickly tossed together that uses an Extends method on the WebHTMLViewer class. It creates a test picture and uses template HTML to load the data. It’s just a starting point.

htmlviewer_loadpage_withpicture.xojo_binary_project.zip (9.0 KB)

EDIT: Example fixed.

Dynamic in what way? If you could be specific about your plans we can help you figure out the best way to use the framework. I think HTMLViewer hacks are a bit far ahead of what you actually need.

With WebImageViewer all you would need to do is set the .Image property to a picture you dragged into the Navigator.

MyImageViewer.Image = imgLogo

You can even do this at design time in the IDE with zero code for an image that doesn’t need to be dynamic.

I am uploading the images to the same directory as the html file.
Regular browser viewing works no issues.

When running through the WebHTMLViewer though, the image doesn’t show up even though the file is there.

I realized I can pre-load the image but that’s not what I need in this case, i.e. not a permanent logo. There are several static webpages with unique images spread throughout each page.

I did try AlbertoD’s suggestion before posting… but I still get no image, nor do I get an error or empty image tag even if the filename is wrong.

https://127.0.0.1:8080/test.png

Next I’m trying to understand Anthonys example.

OK, so this variation appears to work.
In all cases these are relatively short pages so embedding the images is fine.
By encoding, embedding, and decoding the image it is displaying as expected.

I’m not sure yet if this is going to significantly increase the work on the input side I’ll need to go back through that code.

However, someone else may come across this thread and need this example.
Thanks Anthony for making the suggestion!

Var f As FolderItem = SpecialFolder.UserHome.Child("test.html")
Var tis As TextInputStream = TextInputStream.Open(f)
Var html As String = tis.ReadAll

Var pic As FolderItem = SpecialFolder.UserHome.Child("test.png")
tis = TextInputStream.Open(pic)

Var embedMe As String
embedMe = EncodeBase64(tis.ReadAll)
tis.Close

html = html.Replace("test.png",embedMe)  // -- notice only using the first encounter i.e. not using 'ReplaceAll' so the plain alt text text does not change
HTMLViewer1.LoadHTML(html)

and the test file

<!DOCTYPE html><html><body>April 30, 2025<br>
test image <br>
<img src="data:image/giv;base64,test.png" alt="test.png"><br>
</body></html>

A short time ago I was exactly where you were, @Benjamin_Brannen. Xojo Web forces you to change your whole perspective of how files are served.

There’s undoubtedly merit in “the xojo way” but there are also benefits to the classic http server that we’re all used to. So when I encountered your thread, I thought “porque no los dos” and set out to code an example, because this was something that has frustrated me as well.

I ended up spending WAY too many hours on this, but I ended up liking it and will probably continue to work on it and eventually use it in production at some point.

I should preface this by saying this approach is not recommended for any serious file hosting. It reads the whole file into memory when serving it, so it will gobble up as much RAM as the filesizes you give it. You might be able to do something about that by reading it in chunks and sending it to Response.Write but I’m not sure how the framework handles the response buffer internally and that approach might not make a difference at all. Long story short, if you’re only serving a few files that you know of in advance, you’re far better off using WebFiles because Xojo has optimized that class.

In any case, project is attached. The bulk of the work is done in App.ServeStatic. By default this is set up to serve files from your app’s Resources folder (so make sure the CopyFiles step for your OS copies the other files in the zip to Resources), and allows you to navigate to /resources on your server to access it. Those paths can be changed, obviously.

But this approach should allow you to specify a virtual path, an actual path, and serve static files from it in a more traditional fashion, without affecting your ability to serve Xojo WebPages. Check the comment in the method for usage info.

ServeStatic.zip (159.8 KB)

@Christian_Wheel Thank you for this! This is a different approach and I’m adding it to my tools bucket for XOJO.
haha my favorite line -
// These are not the droids you’re looking for

1 Like