A recent post on the TechNet mailing list posed an interesting question:
When displaying an image in a web viewer, is there any way to scale the image to fit?
Of course container fields have this ability built right in (by way of the Format -> Graphic command). But there are several reasons you might want to show pictures in a web viewer instead. Most notably, the images might already be on a web site. There’s no reason to copy them into the FileMaker database too, wasting space and adding more to your already busy schedule. Is there any way to give web viewers container-like scaling ability?
This question inspired me, so I put together a solution that can be used generically. The result is a simple web page that can, using Javascript, load an image, figure out how big it is, and scale it appropriately. First, here’s the source of the page. If you’re curious about how it works, read on.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<style>body { border: 0; margin: 0; } img {display: block; margin: 0 auto;}</style>
<script type="text/javascript">
function resize_image() {
var img = document.getElementsByTagName('img').item(0);
if (img.offsetHeight > img.offsetWidth) img.style.height = '100%';
else img.style.width = '100%';
}
</script>
</head>
<body onload='resize_image();'>
<script type="text/javascript">
document.write("<img src='" + location.search.replace(/^\?/, "") + "'>");
</script>
</body>
</html>
To use this in your own systems, copy the source code into a new file. Name it “scale-image.html” (or anything you want) and put it on your web server. To show a properly scaled image in a web viewer, you load this web page, and tell it what image to load in the query string (in other words, add a question mark and then the image URL to the end of the page URL). Sounds complicated, but really it isn’t. Here are a few examples:
-- load an image with a complete URL like this:
http://myserver/scale-image.html?http://someserver/path/to/image.jpg
-- if the image is on the same web server, you can simplify:
http://myserver/scale-image.html?/path/to/image.jpg
-- and things get even easier if the images are in the same folder as the page:
http://myserver/scale-image.html?image.jpg
Of course you can use any image type your browser supports: You’re not limited to JPEGs. Finally, note that this page only works properly if the web viewer itself is perfectly square (ie: 120px by 120px or 300px by 300px). Use the Object Info pallette (View -> Object Info) to easily size your web viewer. If there is enough interest, I can revise the code to work in web viewers with any aspect ratio.
How Does it Work?
If you’re new to dynamic HTML the web page may seem a little mysterious, but it is actually pretty easy to understand if you are familiar with HTML and Javascript. Let’s dissect it.
First, you see a pretty typical top-of-the-page. We declare the version of HTML we’re using, and start the page as normal.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
The first important bit is this:
<style>body { border: 0; margin: 0; } img {display: block; margin: 0 auto;}</style>
This embedded CSS stylesheet tells the web viewer a few important things:
The page body should have no margin or padding. In other words, we want the contents of the page to push right up to the edge of the web viewer, with no gap. Normally, page content is indented a little on all sides, but we want our image to fill things up completely.
Images should be
display: block. This makes it possible for us to size and position the image precisely.On the top and bottom, the image should have no margin, and the right and left margin should be
auto. In other words, the image should start at the very top of the web viewer and it should center itself right-to-left.
Next, we define a Javascript function. This code doesn’t run right away, but later it will be called. It does the actual work of resizing the image. Here’s the function:
<script type="text/javascript">
function resize_image() {
var img = document.getElementsByTagName('img').item(0);
if (img.offsetHeight > img.offsetWidth) img.style.height = '100%';
else img.style.width = '100%';
}
</script>
In CSS, if we set just the width of the image to 100% then the image will automatically be scaled so it is exactly the width of the web viewer. If you don’t set the height at all then the web viewer will keep the image’s aspect ratio. In other words, it will let the image be as tall as it needs to be so it doesn’t look squished. Likewise, if we set just the height to 100%, the width will scale accordingly. All we need to do is decide if the image should be just as wide as the web viewer, or just as tall.
If you think about it for a minute, you’ll agree that this depends on whether the image is taller than it is wide, or wider than it is tall. A tall image will fill the web viewer from top to bottom, and won’t be quite as wide as the web viewer itself. A wide image, on the other hand, will fill it from right to left, and be a little shorter.
So this function first get ahold of the image, storing a reference to it in a variable called img. It looks at the offsetHeight and offsetWidth of the image (these are just funny ways to refer to its height and width). If the height is bigger, it sets the height to 100%. If the width is bigger, it sets the width to 100% instead.
Remember though that this function is only defined at this point. We haven’t actually run the code yet. The reason is simple: the image doesn’t exist yet. Next, the HTML looks like this:
<body onload='resize_image();'>
<script type="text/javascript">
document.write("<img src='" + location.search.replace(/^\?/, "") + "'>");
</script>
</body>
In this very short HTML body, we use another Javascript snippet. This time we generate an HTML img tag with a src attribute that refers to the image we’re supposed to load.
The image URL itself is loaded from the
location.searchproperty, which is just Javascript’s way of fetching the junk after the?in the page URL. Unfortunately, the value inlocation.searchincludes the?itself, so we use thereplacefunction, with a regular expression to remove it.
Now we have a web page with an image in it. If you look at the very top of the last code snippet, you’ll see where we call the resize_image function: in the body’s onload handler. This tells the web viewer to run the Javascript resize code only after the page (and the image on it) have finished loading.
When the function runs, it adjusts the size setting for the image, and the image is properly scaled. Luckily, Javascript is very quick, so all you see is a perfectly scaled image from the start.
This sample was thrown together quickly, so it has room for improvement. To whit:
The web viewer has to be square. It would be better if it inspected the page size and adjusted its decision making accordingly, so it could scale an image in any size web viewer.
The image is centered left-to-right, but not top-to-bottom. Centering vertically in CSS is a bit of a nuisance, but there are several ways to do it, like this, this, and this. I think for the sake of simplicity, I would look at two approaches: Calculate the appropriate to margin in Javascript, and set it; or just put the whole thing in a single-cell table.


Al
7-11-2007
Does this on scale images. Will it scale entire web pages as well?
if not, is there a simple way to scale a web page in a webviewer (like the iPhone does)?
Geoff Coffey
7-12-2007
@al: I don’t think there is a simple HTML-ish way to do it. Scaling images is something browsers do, but not whole pages.
But that’s not to say it couldn’t be done in FileMaker. You could use the “copy in preview mode” trick to get the job done. Let me know if you want more details. I’ll see if I can write it up in the next week or so.
Geoff
Al
7-12-2007
Geoff — That would be very helpful. I’m a trader and could do some very useful things if I could have a number of scaled web pages on one or two screens. I’ve been using FM for years, but just discovered this site. It’s great! Thanks.
-al-
v
7-28-2007
I do not know much about dynamic HTML and it is always a hard call to invest time to learn something only to find out it cannot do what you initially intended to do with it… I was wondering, if that technique of having a dynamic page on your webserver would work in combination with the google maps API, so a webviewer could show just the map part with your record (say a contact) mapped, instead of all the other stuff google maps opens with. Right now I make a simple url call, e.g.:
And while it does map my info, I have to ‘click away’ several menu items, before i can actually see enough of the map….
avinash Jha
8-2-2007
this is very good site for information. thanks for making this site.
Geoff Coffey
8-13-2007
@v: Somehow I missed your comment, so sorry for the slow reply. I feel your pain. The google maps api will do what you want, but there’s a (huge) catch. Using the maps API is completely free if you’re building a free public service (ie, a public web site). If you want to use it internally, privately, in your own apps, etc…, then you have to shell out $10,000 per year. If this is out of your price range, I suggest you use the Contact link on the Google Maps API site to send feedback. I did, and Google called me to talk about it the very same day. They said they’re getting a lot of feedback about the pricing model, and taking it all in.
I suggested they move to a tiered pricing scheme, where you pay for what you use, instead of a single huge price, with huge limits. Who knows if they’ll listen, but that’s they way it is for now.
Geoff Coffey
8-13-2007
@avinash: Thanks!
Sam Barnum
9-2-2007
Using the web viewer to copy a layout is a very cool idea.
I just tried a really rough draft, and it seems like it worked! Just make a layout where the only thing on it is a web viewer. Make sure the web viewer is a reasonable size, so the contents of the web page don’t get truncated. Then enter preview mode and copy to the clipboard, and you’ve got a screenshot of the web page. Paste this into a container field, and it will show at whatever size the container field is.
Geoff Coffey
9-3-2007
@sam: I did the same exact thing after the comment was made. But I never got around to writing it up. It’s a bit of a hack, but it works, and is kind of cool. If you send me a link to your file, I can add it to your comment.
Peter Cook
9-12-2007
I tried your technique and it works great on a Mac with the image in the Web Viewer scaling OK in Safari. But I get no image at all when using exactly the same Web Viewer calculation viewed in IE 6 in Windows. Any ideas why?
FileMaker 9 Tip#9: Web Viewers without the Web : SFR FileMaker Blog
9-28-2007
[…] @katherine: Good stuff. You might also find this article useful: Scaling Images in a Web Viewer. […]
Frank Fulchiero
10-15-2007
Works fine in FMP9 on OSX, but in FMP9/WinXP, if the image is taller than it is wide, I do not get the scale effect, just the upper left corner. The image scaling only works if the original is wider than tall.
Has anyone else noticed this, or is it just me?
Matthew Brandon
11-26-2007
I’ve tried this out and it works great when viewing directly in Safari but when I try to look at the same page in filemaker, I get a scroll bar. I am wondering if this has something to do with the new auto resize feature in FMP. It works great with auto resize turned off. The problem is that I need users to be able to resize the FMP window and have the content auto adjust to that window.
Any solutions?
steve
1-7-2008
Interesting thought, I have a webviewer configured to display an image dynamically based on an image location file name from another field in my database.
Replace (inv_data::IMAGE_NM; 1 ; 19 ; “http://www.test.com/images/” )
I need to resize them, and this seems like the best solution, but not sure how to do so dynamically based on the above calculation.
Any insight? Thanks
Geoff Coffey
1-20-2008
@steve: I may not be understanding your question, but I believe you can simply put your
Replacecalculation in the web viewer calculation like this:Does that help?
Simon
2-10-2008
@Frank: I believe the DOCTYPE is causing IE6 to use quirks mode rather than standards mode and therefore ignore the margin:auto on XP. Removing this should help. You will also need to add a text-align:center to the body style s well.
Hope this helps.
Steve Clews
7-17-2008
I have been looking for a method to import pics to FMPro on the fly when we upload data to our website.
This is better I don’t have to paste the pics or import them into FMPro they just arrive as soon as I have uploaded the data to the site.
Magic
many thanks
Steve