APPENDIX M How to put Blobs into Reports


by Marco Greco marcog@ctonline.it

Date: 15 Mar 1996 06:58:34 -0500

Frankly, the fact that no one has ever thought of putting byte data in reports seems really odd: it is the kind of thing that allows for professionally looking printouts (think of company logos being put in reports, or scanned signatures or, well uhm..., etc!).

What's more, working out how to do it is relatively straight forward: what I propose here can be easily derived from Jonathan Leffler's way to dinamically change a report size (though believe it or not, I've found it on my own by peeking at a report c code: at the time I was not on the net and I wasn't even aware of Jonathan existence).

Doubly odd.

If this is the case, I would like to share here my little piece of knowledge.

What kind of byte data can you put in reports?

Ok, let's be honest: only whatever you have available that's in your printer language (ESC/P, PCL, ...)

Where do you get it from?

Put aside the obvious answer (Go learn your printer language! :), any application able to print to a file can be successfully used to produce the blob of your dreams: we used Corel Draw! to produce the company logo.

After having printed it to a file (using our printer's standard Windows printer driver), useless control codes (e.g. printer resets, paper size selections, no. of copies) were removed by means of a small c app and pronto! our logo was ready to be included in our reports.

How do you actually print byte data?

A first approach is to put your fancy logo in a text variable and just print that within the report.

This has two main disadvantages:

  1. You can't print your logo in page headers & footers -- You will have to fiddle with "before/after group of" clauses to put your blob in every page.
  2. 4gl tries to make sense of the line count of text data -- This means that if the print statement encounters what it thinks to be a <CR>, it will print a number of spaces to take into account the left margin, thus defacing your blob.

For the same reason, the lineno and pageno counts will probably be screwed up, and so useless - unless you want to print the blob alone.

The other approach is to altogether bypass Informix rtsl & print the logo on your own.

We use the routines below, which (shameless plug!) are taken from my application framework 4glWorks (sooner or later you'll see it on the net!)

---- cut here ----

#include <stdio.h>
#include <fglrep.h>
int page_len();
int ptr_put();
int file_put();
FILE *strm;
FILE *outfpsv;
extern int status;
extern struct repdesc *c_rp;
page_len()
{
    int i;
    popint(&i);
    c_rp->tot=c_rp->tot-c_rp->plength+i;
    c_rp->plength=i;
    outfpsv=c_rp->outfp;
    return(0);
}
ptr_put()
{
    char bf[82];
    popquote(bf, 80);
    trail(bf);
    status=(fputs(bf,outfpsv)==NULL);
    return(0);
}
file_put()
{
    char c[90];
    char bf[131];
    int i;
    popquote(c,89);
    strm=fopen(c,"r");
    if (status=(strm==NULL))
	return(0);
    else
    do
    {
	i=fread(bf,1,128,strm);
	status=(fwrite(bf,1,i,outfpsv)!=i);
    } while (i==128);
    fclose(strm);
    return(0);
}

---- end cut ----

The first routine is to be called once at the beginning of the report to dinamically set the report page length (You'll have to take into account the space consumed by your blobs) & make a copy of the output stream for later use: experience shows that the output stream in the currp record is not always available - my understanding is that it is made unavailable whenever the report header is being cached.

The second is a little handy routine that sends control codes to the printer without changing the column count.

The third outputs a file to the previously saved stream. If you want to print blobs taken out of your DB, just locate your blob in a file, and then use the routine to print it.

Note that it is indeed possible (though dangerous) to call the above routines from within 4gl functions. This practice is useful for developing a common block of printer control actions that can be later used in each & every report, as demonstrated in the following sample code.

function do_some_report()
    define	hea, foo	text,
		ptr_init
#
#  here I should have declared (and haven't for brevity's sake) a handful
#  of char variables containing printer control codes. Their use will be 
#  obvious from their names, and I assume that they have been fetched,
#  together with hea & foo, from some "printer" table 
#
				char(40)
    locate hea in "hea"			#Online only!
    locate foo in "foo"			#for SE use files!
#
#  fetch printer data & declare report cursor here
#
    start report sample to printer
    foreach whatever_curs into whatever_rec.*
	output to report sample(whatever_rec.*)
    end foreach
    finish report sample
    free hea
    free foo
end function
report sample(sample_rec)
    define sample_rec	record
#
#  I hadn't the faintiest before! Why should I know now?
#
			end record,
	   end_rep	integer
#
# Output section / order [external] by here
#
format
    page header
	call header_setup(pageno)
	let end_rep=false
#
#  print statements here
#
    on every row
#
#  more print statements
#
    on last row
	let end_rep=true
    page footer
#
#  yet more print statements
#
	call footer_setup(end_rep)
end report
function header_setup(p)
    define p	smallint
    if p=1
    then
	call page_len(blob_corrected_report_length)
	call ptr_put(ptr_init)
	call ptr_put(ptr_select_number_of_copies)
    end if
    call ptr_put(ptr_move_to_header_blob_location)
    call file_put("hea")
    call ptr_put(ptr_move_to_page_start_location)
    call ptr_put(ptr_select_the_correct_font_since_the_header_printout_may_have_screwed_it_up)
    call ptr_put(ptr_select_char_pitch_and_height)
end function
function footer_setup(l)
    define l	integer
    call ptr_put(ptr_move_to_footer_blob_location)
    call file_put("foo")
    if l
    then
	call ptr_put(ptr_reset)
    else
	call ptr_put(ptr_skip_to_next_page)
    end if
end function

A few more comments before packing up:

a=`ls -o $1 | cut -c21-31`
a=`expr $a - $2 - $3`
dd if=$1 of=$1.o bs=1 skip=$2 count=$a 1>/dev/null 2>&1

with $1 filename, $2 leading chars to skip, $3 trailing chars to skip and $1.o output file

Ok class, all free. Thanks for the attention.

marco

__________________________________________________________________________

rem radioterapia, which I immeritately manage, seldom agrees with what I say

marco greco   (Catania, Italy)   Work:
marcog@ctonline.it               rem radioterapia 39 95 447828 fax 446558
(was mar.greco@agora.stm.it)     Achea            39 95 503117