From: marcog@ctonline.it (marco greco) Subject: Put blobs in 4gl reports! 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 , 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 #include 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: marcog@ctonline.it rem radioterapia 39 95 447828 fax 446558 (was mar.greco@agora.stm.it) Achea 39 95 503117