Scaling Images in a Web Viewer

Leave a comment

6-3-2007 by Geoff Coffey

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:

  1. 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.

  2. Images should be display: block. This makes it possible for us to size and position the image precisely.

  3. 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.search property, which is just Javascript’s way of fetching the junk after the ? in the page URL. Unfortunately, the value in location.search includes the ? itself, so we use the replace function, 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.

34 Comments

  1. Al

    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)?

  2. Geoff Coffey

    @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

  3. Al

    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-

  4. v

    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.:

    http://maps.google.com/maps?q="&Sites::Lat&","&Sites::Lon&"&ie=UTF8&om=1&z=8&f=l&ll="&Sites::Lat&","&Sites::Lon)

    And while it does map my info, I have to ‘click away’ several menu items, before i can actually see enough of the map….

  5. avinash Jha

    this is very good site for information. thanks for making this site.

  6. Geoff Coffey

    @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.

  7. Geoff Coffey

    @avinash: Thanks!

  8. Sam Barnum

    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.

  9. Geoff Coffey

    @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.

  10. Peter Cook

    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?

  11. [...] @katherine: Good stuff. You might also find this article useful: Scaling Images in a Web Viewer. [...]

  12. Frank Fulchiero

    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?

  13. Matthew Brandon

    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?

  14. steve

    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

  15. Geoff Coffey

    @steve: I may not be understanding your question, but I believe you can simply put your Replace calculation in the web viewer calculation like this:

    "http://myserver/scale-image.html?" &
    Replace (inv_data::IMAGE_NM; 1 ; 19 ; “http://www.test.com/images/”)

    Does that help?

  16. Simon

    @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.

  17. Steve Clews

    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

  18. raphael

    Hi,
    Your code seems to be very usefull for me: I’m working out a photo DB in FM and try to use the embeded web viewer as a dynamic thumbnail displayer.
    Actually it works only for landscape images, in other words those wider than high. The other ones (higher than wide) remain unchanged and only a very tiny bit of them is displayed in the web viewer.
    I suppose the first part of the code doesn’t work:

    if (img.offsetHeight > img.offsetWidth) img.style.height = ’100%’;
    else img.style.width = ’100%’;

    Why?
    Many thanks.
    Raphael (France)

  19. Geoff Coffey

    @raphael:

    Which platform (mac/windows) are you on, and which version of IE or Safari do you have installed?

    Geoff

  20. raphael

    Sorry, I was away abroad. Thank you for caring!
    I’m on Windows (Vista) and have installed Firefox and Opera.
    I’m trying to use your script in Filemaker 9.

    Raph

  21. raphael

    In addition, I tried several things and it seems that img.style.height = ‘100%’ never works (img.style.width = ‘100%’ works perfectly).

  22. @v and Geoff

    When you get a map from google, there is a way to generate a link to the map or embed the map, by pasting the HTML code into your webpage’s code. If you poke around and play with the embedded html code, and use the trick that Geoff mentioned in another post*, you can accomplish the task you asked about…generating a map that is just a map and nothing else.

    *http://sixfriedrice.com/wp/filemaker-9-tip9-web-viewers-without-the-web/

    My question is, does anyone know if using this embedded HTML code is the same as using the google map API that was mentioned? I ask, because I’m working on a solution that embeds a google map into a web viewer, and when I’m finished, the solution will not be free. Ergo, I don’t want to unknowingly use something that isn’t free, i.e., steal it.

  23. Edward Souza

    Hello, Geoff, and hello all,

    First, let me say this is an excellent blog — the material posted here is precious and allow many to learn the inner mechanics of FileMaker. Mr. Coffey has once helped me personally with an asinine error I made. Although he is an busy person, he was nothing but sheer help to me. Thanks for your posts and assistance, Mr. Coffey. :)
    Some questions regarding FMP 10 Advanced, OS X 10.4.11, and Adobe Flash:
    1. Is it possible to use Flash movies (.swf) from within [b]local discs[/b] using WebViewer? For example, if I’ve developed a series of buttons and graphics in Flash which are stored in the same folder as my solution (instead of in an URL), is it possible to embed them FileMaker using WebViewer?
    2. In case it is possible, does the .swf have to be embed in an HTML page in order to work?
    3. Can Flash buttons trigger FMP scripts — perhaps via XML or an external scripting language (in OS X’s case, AppleScript)?

    I know there are some references in the Internet about Flash and FMP interaction; however, the material I could gather does not make any specific reference to WebViewer, and that probably is a logical way to make both “worlds” interact.

    Once again, thank you for everything.

    E*

  24. Geoff Coffey

    Edward:

    Sorry for the slow response. I was on vacation. I really must confess I know very little about Flash. You might take a look at:

    http://fusionplugins.com/reactor/

    But I’ve never used it myself. Please post back if you find any good answers!

    Thanks,

    Geoff

  25. Edward Souza

    I’m sorry for the lateness of this post.
    I read some of the questions regarding Google Maps, and there are ways to have it embedded in webviewer at any size.
    Instead of embedding the map Dynamically, you may choose to have it statically. Using it this way, you are able to specify its size (in pixels), zoom level, and so forth, and it will abide to your given parameters. The only catch is: you need to use the location’s geodesic coordinates (latitude and longitude) with its value in decimal degrees.
    For those who want to try it right way, here is a basic code:

    http://maps.google.com/staticmap?center=40.714728,-73.998672&zoom=14&size=512×512&key=MAPS_API_KEY&sensor=false

    where:

    - “center” is the location in decimal degrees
    - “size” is the map size (it should fit the dimensions of webviewer window)
    - “zoom” is the zoom level desired (from 1 – furthest to 19 – closest)
    - MAPS_API_KEY is a Goggle Maps API key you or your client should have. Google measures the maps and static maps traffic through this.

    There are several more parameters that can be used and played with — you may use location points within the map (using decimal degree coordinates), draw lines from one point to another, and so forth.

    For a more detailed look, please refer to “http://code.google.com/apis/maps/documentation/staticmaps/”.

    On a final note, when using Google static maps, i often disable webviewer’s options, such as “Allow Interaction With WebViewer Content,” “Display Progress Bar,” and “Display Status Messages.” That way I ensure the map will display at its full size.

    I hope this may be of any help to you.

    E*

  26. Parker

    This seems like the perfect solution to a problem we have with FMP 10 and web viewer. We have an FMP db that dynamically accesses images from our website and displays them in an FMP client layout based on data in the layout. The problem we have is that we can not control the size of the images in the web viewer and the images do not display the way we want them to.

    The question I have is this: Since we are not using an FMP web server, how do I use this code to control the image size in a web viewer on an FMP client layout?

    Thanks for posting the info on this website, it’s excellent.

  27. Stephen

    Thanks for the great info, based on the original Javascript code at the very top and Simons comments on 2/10/08 this is my code I’m using at the moment to display images from a web server in a FileMaker database:
    ———————–

    body { border: 0; margin: 0; } img {display: block; margin: 0 auto;}

    function resize_image() {
    var img = document.getElementsByTagName(‘img’).item(0);
    if (img.offsetHeight > img.offsetWidth) img.style.height = ’100%’;
    else img.style.width = ’100%’;
    }

    document.write(“”);

    ———————–
    The last thing I’d like to achieve it to remove the red cross icon when the image file does not exist. I have a database which shows a main image and a secondary image of various items. Not all items have a secondary image. All the images live on a web server and are accessed by calling the above javascript code via the web viewer in my database using a base URL and then a filename based on a unique identifier (serial number) for each record. Because all records are looking for a secondary image, when they are found it works great but when the image is not found I’d just like to have a blank white box in the web viewer and not the red cross suggesting file not found.

    Hope someone can help.

    Thanks very much in advance.

  28. Matthew Richards

    Thank you SO much for posting this very useful tutorial and code. It’s been invaluable for my database project. A couple of things I noticed:

    As Frank pointed out there are problems on some systems with the height scaling properly, and as Simon pointed out the doctype is to blame. I just removed it entirely leaving only the header, seemed to fix the problem and not break anything.

    My web viewer code looks like this:
    “http://yotoen.com/larkfiles/images/scale.html?”&Table::Image

    “Table::Image” is actually another entire URL! e.g.
    http://yotoen.com/larkfiles/images/sec2798.jpg

    So this kind of stacking is possible – very useful when pulling things from other fields / generating URLs from multiple fields or strings.

    Thanks again!

  29. Tim Cimbura

    These are some good ideas and solutions to the problem of resizing an image in a web viewer presented here. I think there is a simpler way that is not limited to square images.

    The technique uses a data URL to build an image that is resized by the browser. Check out the sample database found here:

    http://www.cimbura.com/tech/samplefiles/WebViewerImageResizing.fp7.zip

  30. David Zizza

    The link to the above sample has change. To prevent insanity, use this link:

    http://www.cimbura.com/tech/samplefiles/WebViewerImageResizing.zip

  31. Dubau

    Hello,
    Im very novice in these problems. I use a webviewer in a Filemaker solution to show pdf files ; to do that I pass in a calculated variable some values to obtain that $_my_pdf = file:///Volumes/Data/Desktop/CLSH_Mac/Factures_PDF/E2011_2012/LOCAL/2011/9_septembre/GORDE_GILLES_GORDE_MANON.pdf
    I build a Filemaker model and define its content as $_my_pdf ; this webviewer is resised to suppose 15cmx18cm ; on PC platform no problem : the pdf is scaled to fit to these dimensions ; on the Mac no ! anf I must use the bars to navigate in.
    So I was attired by your script ! But the pdf is on my local machine, not a server ? I don’t see how I can adapt your formula http://myserver/scale-image.html?http://someserver/path/to/image.jpg to my situation ? Perhaps is ther no solution !
    Hope in your help !
    Noël

  32. Steve Emms

    Hay guys, this script works almost perfect. it renders fine in google crome, FM and firefox but on Internet explorer it just shows a white box, i have tryed IE8 and IE9. Please can you help

    Steve

  33. Cecille

    Works beautifully. Thank you so much Six Fried Rice!

  34. Vicky Nesbitt

    Erm any idea how to do this for a web viewer playing Quicktime movies?

Tell Us What You Think

*
* (will not be published)