Gaining Image Control in Reports
By Lisa Slater Nicholls
This article was first published in FoxTalk in
2006. As far as I know, it is not publicly available elsewhere-but-here
now. It contains essential information about a feature that was added late in RTM, and is therefore scantily documented.
The (very limited source) for this article is available in Spacefold downloads
Eugen Wirsing and Zaheer Mohammad both requested a bit of help
when working with image controls in reports. This feature, added
late in the VFP 9.0 development cycle, has only minimal documentation
(see How to: Add Pictures to Reports). Some clarification is
obviously in order.
When two experienced VFP developers ask me almost the same question
within months of each other, it always makes me think harder
about that question. I'll discuss their initial points of confusion,
but I'll also add some general advice that may help you in related
Where does the object reference go?
Having read MSDN KB article 895602,
Zaheer Mohammad was unsure
how to associate the object reference of the image control with
the layout control representing the picture in the report. It's
no wonder he was confused; the KB article adds this row to the
FRX table programmatically.
In the ReportBuilder's Picture/OLE Bound Properties dialog,
use a control source type of Expression or variable name. Place
a variable name that will be in scope during the report run,
and into which you'll place the reference to the image control,
in the Control source expression.
In Figure 1, I've used a report variable named
this purpose, but you can use a _VFP member property, a member
property of your application object, or anything you prefer,
as long as it has appropriate scope. (The KB article uses a
member property of the running ReportListener, loRL.oBlobImage,
for this purpose, where loRL is a variable declared
the calling program. Even if this worked, ordinarily you don't
tie programs or FRX expressions to
LOCAL variables declared
Figure 1. The control source for a picture hosted by an image
control is a reference to that image control.
In your sample code, a report variable scopes the image control
to the report form. As you see in Figure 2, I've initialized
this variable with a reference to a VFP baseclass image and
I've used the variable's own name as its Value to store.
Figure 2. You can use a report variable to hold the required
Caveat: object references and dynamic ReportListener code
I've used a report variable in your sample code and, in most cases,
I recommend that you use this simple approach to scope your
object reference to the report. However, if you are using a
ReportListener to render your report and if your ReportListener
or its class hierarchy includes any EvaluateContents or AdjustObjectSize
code, be aware that a bug in VFP 9 RTM and SP1 may cause the
object reference held in a report variable to be destroyed.
Use an externally-declared variable or member property instead.
If you're using the FFC ReportListener classes or the standard
REPORTOUTPUT.APP mechanism, this issue does not affect you.
The RTM and SP1 versions of these classes do not include any
code in these two methods.
How do you script dynamic changes to the image?
Once you've established the correct object reference for your
image control, use its PictureVal property to hold binary data
representing the image you wish to display. You can get this
string using FILETOSTR() on an image file on disk, or from a
Blob field to which you've previously stored the result of a
similar FILETOSTR() function call. In your sample code, you
run ShowBlobData.PRG, which creates a cursor with a Blob field
for you, before displaying the contents of this cursor in the
The cursor contains multiple records, each of which stores a
string representing a different image file, so you need to change
the contents of your ImageControl.PictureVal property during
the report run. This was the part that puzzled Eugen Wirsing.
How often, and in what report band, you display the image determines
where you put the code to re-load the PictureVal contents. In
my sample report, the Blob field is displayed once for each
detail band, so I used the detail band's
On Entry Run expression
to store the new value; in other cases, you might display
it in a page header, or on a group level, using appropriate
When you examine the Detail Band Properties dialog, you'll find
the following code in its On Entry run expression:
EXECSCRIPT("BlobImage.PictureVal = MyCursor.BlobField")
You can also place the same line of code you see in the EXECSCRIPT
function call above in a ReportListener' event, but this means
you're dependent on a specific ReportListener-derived class
to process your report. If you don't like the idea of embedding
the code in the FRX, I think you're better off using a UDF,
holding the same line of code, to do the work. You can even
run a UDF assigning the new value using the report variable's
Value to store expression, rather than using
a separate band event, like this:
The one thing you can't do is place the line of code
directly in a band's On Entry or On Exit run expression, without
embedding it in
EXECSCRIPT(), a UDF, or a ReportListener event.
When placed directly in a run expression,
= MyCursor.BlobField appears to VFP only as an
expression to be evaluated, not a value assignment. The expression
evaluates to .T. or .F. and – just like any return value, of
any type, that you might return from a UDF in a band's run expression
– this value is discarded.
Why is this better than General fields?
When you use a Image.PictureVal reference for your report images,
you get a data-driven, dynamic display of pictures rather than
a static image file, just as you do when you bind a report layout
control to a General field – but there are some important differences.
First, you don't necessarily have to store the Blob data in
your table if you don't want it there. You can store only the
filenames, using whatever relative pathing scheme appeals to
you, and load directly using
FILETOSTR() during the report run:
always been possible to do something similar, using indirect
references to image files, or a hidden form with an OLE Bound
control, but it took extra work to ensure that images weren't
More significantly, General fields do
not benefit from the high resolution rendering available in
VFP 9's object-assisted reporting mode; they alone are rendered
at 96DPI no matter how good your original image was or how high
a resolution your printer can display. This is a significant
concern when, as in Zaheer Mohammad's case, your report output
includes bar code images.
Using image controls as picture control
sources for reports combines the best of both worlds: the dynamic
capabilities of General field-sourced images with the rendering
fidelity of file-sourced images.
You don't need a ReportListener
Although the documentation states that results aren't guaranteed
SET REPORTBEHAVIOR 80, in fact for quick previewing
purposes it often works very well. In SP2 we've introduced
the idea of draft mode to describe old-style reporting,
and it's often a good idea to use this mode to preview often
and easily while you are in the early stages of report design.
You can run the sample program
REPORTBEHAVIOR at both settings, to verify this. You won't
get the advantages of high-resolution output when you
80, of course, and the images may not print properly in this