Images in Internet Connect

Steve Parker
(c) 1999

Perhaps it's because I've been using IC so long. Perhaps it's because, like you, I'm so spoiled by Clarion. Or perhaps it's because I'm not one of the most observant folks you're likely to meet. But it finally occurred to me why IC can sometimes be so difficult for many Clarion developers. The difficulty is that IC apps are not simply dual mode, they are tri-lingual.

In order to become proficient at IC, indeed to have a good grasp of what it does and how it does it, you need a varying degree of competence in three different programming languages: Clarion, HTML and Java/Javascript (knowing your way around a network doesn't hurt, but that's for another journal). While it certainly is possible to wizard up a full function IC app with no more than having completed the tutorial (of course, you can do the same in standard Clarion and in neither case does that mean that the app will function as desired) ... well, it doesn't really seem necessary to pursue that particular line of thought.

Java and Javascript are the languages you are least likely to use since Topspeed supplies all the applets you normally need. Most other applets you are likely to want are also likely to be available as freeware somewhere on the Web. For highly specialized purposes, such as opening and closing a second browser window, you may have some occasion to use Javascript. But there are FAQs on the various knowledge bases on how to do this, so you, one way or another, can ... ah, requisition existing code and use it as boilerplate successfully and without much fiddling.

HTML is somewhat more important. Even if you never write a line of HTML yourself (and that is exceedingly unlikely), without some appreciation of HTML, you stand somewhere between zero and no chance of understanding how your IC app is operating. For example, a basic knowledge of HTML explains why the HTML representation of your window will likely be an entirely different size than it was in Screener. It will also help you comprehend why some of you code does not execute when you expect it to.

There are dozens of "Become an absolute HTML master in 37 minutes" books and Web resources; find one, read it.

The last language you need proficiency in to work with IC is Clarion itself. Ok, I don't think I need to discuss this.

Nowhere is this need to be poly-lingual more apparent than in displaying images.

Clarion Basics

For the rest of this article, let's use


Figure 1

as a not so pretty, but effective, reference.

In Windows, we have two ways of displaying images. Either we can hard-code them


Figure 2

or we do a property assignment:

?Image1{Prop:Text} = Clip(ImageFieldLabel)

usually at runtime. An assignment into an image control is the preferred method for dynamic display of images, as, for example, in a browse or on an update form.

In IC there appear to be three ways: hard-coding (as above, corresponding to the first image in Figure 1), using the Static HTML Code Template (image 2 in Figure 1)


Figure 3

and handcoding (either all of the required code, in an embed as shown below, or using the Dynamic HTML Code Template, as in images 3-6 in Figure 1):


Figure 4

In fact, there are only two. (1) You can code the image reference either by hard-coding it or using the Target.Writeln method. Since both the Static HTML and Dynamic HTML code templates simply supply the Target.Writeln syntax for you, there really is no logical difference between using a code template and typing it all yourself.

However, there is a pragmatic difference. If you use either of the code templates, while your code will always be formatted correctly, it will not be editable in the Embeditor. If you use a standard Internet embed and type all of the code yourself, it will be editable, but you are prone to forgetting to close parentheses and apostrophes, and doubling up reserved characters (like the left angle bracket).

(2) You can rely on the property assignment. Most convenient, this, as it is likely that you used this when you first created and tested your app in Windows.

So, the main difference between Windows and the Web really is that you have additional methods of "hard" coding images. This means, inter alia, that you can display images in a browser that are not displayed when run in Windows. This is quite useful since a browser window can be divided into areas that you typically don't use in Windows windows.

First Things First

One of the most frequent reasons images fail to display is due to a lack of knowledge about the Web.

It is imperative to understand that while Windows supports all sorts of image formats. Browsers are not so flexible.

Browsers, as a rule, support the GIF and JPG image types. Other types may be supported with Plug-Ins or other add-ons. But, in addition to the time required to load add-ons, many work only in Windows or work only with a specific browser.

So, unless you are willing to cut off MAC and UNIX users or users of an "unsupported" browser, only use GIF and JPG files in your IC applications.

Second Things Second

Because we are used to thinking in terms of the code required to accomplish a particular purpose (OOP-think notwithstanding), it is easy to miss the real distinction hidden beneath our image display methods.

Why is it that we use, though we do not need (property assignments being logically sufficient), two different methods of displaying images? Is it that each method satisfies a different purpose? Or is it that each method reflects a different image source and type of reference?.

By and large, hard-coded images are decorative or tend to be. They are also static (or usually so) while images displayed by assignment are dynamic (you don't change your logo each time you scroll or call a form, do you?). More accurately, and this is the critical point, while all these images exist as (usually distinct) files on disk, images displayed on an assignment are referenced from a database field. Hard- and firm-coded images are in no way a part of a database structure.

The Difficulty Is ...

Unless bound in, your images often, if not usually, do not appear when you first test fly your Web app. What is so easy in Windows simply doesn't appear to work in IC. The operative word is "appear."

Consider Windows and suppose your app, CATALOG.EXE, is in the C:\ORDERS directory. Suppose your images are deployed to C:\ORDERS\IMAGES and that your file variable contains only the file name, no path. Would you expect the images to display? Of course, not, the app can't find them.

IC is no different. If the app can't "see" the image, neither will your end user. Indeed, the IC docs state clearly that the image file must be "in any directory exposed to the server application." You have to do the exposing (don't even think it).

What has changed is the application root, the default directory.

In Windows, the default directory is the current directory (i.e., "./"). In IC, the default directory is also the current directory (i.e., "./"). The problem is that what DOS/Windows means by "the current (i.e., root) directory" and what the web server means by that same phrase, can be two different physical locations.

In the above example, DOS/Windows interprets the root directory as C:\ORDERS. In IC, the root directory is /PUBLIC. So, for either the

/logo.gif

or

logo.gif

statement to display the image, LOGO.GIF must be in your IC /PUBLIC directory.

Actually, what I've just said isn't quite true. The AppBroker creates a temporary directory for each instance of your app and that is the actual root directory for the app instance. But, because "files used by IMAGE controls are extracted [from the executable file] to the temporary runtime directory for the connection unless they are found in the /PUBLIC directory" (p. 113), the difference is not logically relevant.

If the image file is in /PUBLIC (whether bound into the app or not), the "root" for the web app, "/LOGO.GIF" and "LOGO.GIF" are effectively identical and the image will display. If LOGO.GIF is bound into the app and is not in /PUBLIC, then the broker will extract it from the EXE to the temp directory and display it. If the file is neither bound in nor deployed to /PUBLIC ... well, see image 5 in Figure 1. 'Nuff said.

The docs also recommend using a built in method for referencing your /PUBLIC directory: WebWindow.Files.GetAlias(). With or without the slash, this function will find your /PUBIC directory (see image 4 and 6 in Figure 1).

But ...

Doesn't this mean that every image you refer to must be in your /PUBLIC directory?-Except for images in HTML pages, no more than you are limited to the application's directory when running in Windows.

In Windows, you might do something like:

?Image1{Prop:Text} = 'C:\ORDERS\IMAGES' & Clip(CAT:ImageFile)

or

?Image1{Prop:Text} = '.\IMAGES' & Clip(CAT:ImageFile)

or, if you use an INI or control file (and read the path into a variable):

?Image1{Prop:Text} = Clip(FilePath_) & Clip(CAT:ImageFile)

In IC, you have three additional options: (1) store images under /PUBLIC, (2) store them in the app directory or (3) store them under the app directory.

Respectively:

(1) Image in /PUBLIC/IMAGES:

If WebServer.Active
  FilePath_ = WebWindow.Files.GetAlias() & 'images/'
End
?Image1{Prop:Text} = Clip(FilePath_) & Clip(CAT:ImageFile)

(2) Image in EXE directory:

If WebServer.Active
  FilePath_ = './' 
End
?Image1{Prop:Text} = Clip(FilePath_) & Clip(CAT:ImageFile)

and

(3) Image in /IMAGES below EXE directory:

If WebServer.Active
  FilePath_ = './images/'
End
?Image1{Prop:Text} = Clip(FilePath_) & Clip(CAT:ImageFile)

should do the job(s).

From a production app, this code:

LOC:Photo = './images/' & REV:Photo
If Exists(LOC:Photo)
  ?Image1{Prop:Text} = LOC:Photo
Else
  ?Image1{Prop:Text} = './images/npic.jpg'
End

will verify that an image file exists and display it. If the file does not exist, a "default" picture will display.

The Rules

The basic rule is to understand what your environment thinks the root directory for your application is and where it expects to find its resources.

On the Web, your root is the temporary directory created by the Broker for that session of the app. Functionally, this is /PUBLIC.

For image files deployed to your /PUBLIC directory, therefore,

Target.WriteLN('<<img src="logo.gif">')
Target.WriteLN('<<img src="/logo.gif">')

and

Target.WriteLN('<<img src="' & WebWindow.Files.GetAlias() & 'logo.gif">')

are functionally identical.

Directories below /PUBLIC are referenced by simply adding the directory name before the file name.

The EXE directory is referenced by pre-pending './' and directories below it, similarly.

For images on an assignment, make exactly the same adjustments. When you think about it, it may not be that big an adjustment:

?Image1{Prop:Text} = './images/' & REV:Photo

will work in both environments. Perhaps substituting

?Image1{Prop:Text} = './' & REV:Photo

for

?Image1{Prop:Text} = REV:Photo

(since they mean the same thing) isn't that much of an adjustment at all.