Subject: Put blobs in 4gl reports!
From: [email-masked] (marco greco)
Date: 15 Mar 1996 06:58:34 -0500
Newsgroups: comp.databases.informix

I should have written this document some time ago, when I discovered that the
FAQ contains nothing about printing byte data in reports, and in particular, in
report headers & footers.  A quick look at Emory revealed the absence of public
code on this topic.

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.

To start with, 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, ...)

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

Third (& last):  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:

1) PCL printers print entire pages in one go (as opposite to ESC/P printers,
which print line by line), so it is possible to pack all the images you want to
put in one page in just one blob, print that & position the cursor where the
report should start

2) If you don't know how to filter unneeded printer control codes, the
following shell script will help (this is not exactly fast, so you might
consider taking a few days off, while it runs)

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

3) As an example, 40 & 3 are the correct parameters to filter with the above
script a file created with a Windows 3.11 driver for an HP LJ IID;  13 & 0 for
the same printer & a WorkPerfect Six'O driver

4) For other printers, go work it out yourself!  :) How should I know?  My
employer is not rich enough to buy them all!

5) The code above applies to 4gl compiled.  See the faq / "Changing dinamically
report sizes" for the appropriate changes for RDS.

6) Please note that the above code has been taken out of 4glWorks context, so
I'm not completely positive that it is bug free (though in 4glWorks, as the
name implies, it works), or that it doesn't include useless code

7) If you are going to use the above code, or if you use it already, or if you
just find it useful, do let me know.  It is so lonely when you live
(Informix-wise) in the middle of nowhere .

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:
[email-masked]                  rem radioterapia 39 95 447828 fax 446558
(was [email-masked])        Achea            39 95 503117