FB II Compiler







Disk I/O














Made with FB


Handle printing

I was talking to Chris Stazny yesterday about Printing stuff. Let me see if I have it right:

1. Always send all pages in your document off to the Print Manager.

The Print Manager is smart enough to extract the correct number of copies of your complete document with the correct page range as read from the standard print dialog.

2. build on the following sequence



  ROUTE _toPrinter 'route drawing to Chooser printer
  FN PrintFirstPage
  ROUTE _toScreen 'route drawing to Screen
  CLEAR LPRINT 'eject first page

  ROUTE _toPrinter
  FN PrintNthPage
  ROUTE _toScreen 'route drawing to Screen
  CLEAR LPRINT 'eject nth page

  ROUTE _toPrinter
  FN PrintLastPage
  ROUTE _toScreen
  CLOSE LPRINT 'done printing, eject last page, close the printer


Note that counterintuitively (to me anyhow) ROUTE _toScreen comes before a CLEAR LPRINT or CLOSE LPRINT. (You will also probably need to use a Command Period detection system to abort printing. I have omitted that in the simple example above.)

3. If your document is very complex and certain or all of its pages take a long time to image, it is possible to image only the required page range. Talk to Chris about this.

I have concluded that PowerPC and G3 machines are so fast that the overhead for imaging all pages in a document (leaving it to the Print Manager to decide what to actually print) is, except in very unusual cases, negligible.

I have found this to be true, even when imaging quite large color images.

4) If you try and interpret the print Dialog's page range and/or number of copies yourself and you don't know what you're doing, you end up fighting the Print Manager. The 'fight' can cause seemingly random extra pages and/or copies to be printed.

5) If you are using the PRINT command, always use a semi-colon at the end.

e.g PRINT temp$;

If you are printing at the bottom of your page and you omit the semicolon a <c/r> is appended; this can cause your next print comand to start at the top of a unintended new page....

I always start by using a framed text edit field in my printing so that:

1) I can see the exact box where the text will go.

2) Any text overflow will be masked and not cause an unexpected new page to be printed.

When every thing is OK, I change the framed text edit fields to _noFrame.

6) I achieved a dramatic increase in page construction productivity when the Adobe Acrobat Printer Driver was installed in the Chooser when I installed the Adobe Acrobat Distiller- no more wasted paper and waiting for my very slow printer to output. I estimated that my productivity in this tedious process increased by a factor of at least ten. If you have to design a lot of printer output, I highly recommend the purchase of Distiller just for Chooser acces to the Adobe Acrobat Printer Driver.

I'm not an expert at this and I may have some of it wrong. Any corrections or additions cheerfully accepted...


<< Note that counterintuitively (to me anyhow) ROUTE _toScreen comes before a CLEAR LPRINT or CLOSE LPRINT. >>

In my experience, this is not necessary. I find that this works just as


  ROUTE _toPrinter 'route drawing to Chooser printer
  FN PrintFirstPage
  CLEAR LPRINT 'eject first page

  FN PrintNthPage
  CLEAR LPRINT 'eject nth page

  FN PrintLastPage
  CLOSE LPRINT 'done printing, eject last page;
ROUTE _toScreen

i.e., only one ROUTE _toPrinter and one ROUTE _toScreen are necessary for the entire job, and the ROUTE _toScreen can come after the CLOSE LPRINT. I think it would only be necessary to ROUTE _toScreen during the print job if, for example, you also wanted to send output to a screen window at the same time a print job is progressing. Inter-page rerouting may also be necessary if you need to monitor button clicks & such while the print job is progressing.

Putting CLOSE LPRINT before ROUTE _toScreen, as I've done, may have a drawback--If you do a CLOSE LPRINT, but then the system needs to do something with the "current port" before you do the ROUTE _toScreen, then it may get confused about where exactly the "current port" is. I don't think this should be a problem as long as the two statements appear right next to each other, as in my example.

I must say that I was surprised to find that the Print Manager really does handle "page range" and "number of copies" correctly. I remember older Mac systems in which this wasn't the case--the programmer had to read the Print Record (PRHANDLE), extract the relevant information, and handle the page range & copy count programatically.


Well I did an end run arround the problem I was having with printing. Instead of sending all the print and drawing commands to the printer, I draw into a gWorld and copybits to the printer instead. I was not able to figure out why I could not get printing directly to the printer to work.

What I have is a big image that I want to print. It is much larger that one sheet of paper so I want to print out sheets that tile together.

I have been trying to create the print routine based on this one from the FB handbook examples:

_firstPage = 62 'PRHANDLE field offsets
_lastPage = 64
_copies = 66
LOCAL FN printingRoutine 'this routine handles printing
  DEF LPRINT 'print... dialog
  LONG IF PRCANCEL = _false 'printing cancelled?
    WINDOW #2, "", (50,50)-(370,100),_dialogShadow
    TEXT _sysFont, 12
    msg$ = "To abort printing, hold in the -period keys..."
    EDIT FIELD #1,msg$, (10,10)-(310,40),_statNoFramed
    gPrtAbort% = _false 'reset abort flag

    fromPage% ={[PRHANDLE]+_firstPage} 'get first page to print
    toPage% ={[PRHANDLE]+_lastPage} 'get last page to print
    copies% ={[PRHANDLE]+_copies} 'get how many copies to print

    LONG IF (toPage% <= 0) OR (toPage% => _iPrPgMax)'change 1 to actual pages
      toPage% = _iPrPgFst
    END IF

    ROUTE _toPrinter 'set output to printer
    COORDINATE WINDOW '1/72" coordinates for page
    pageNum% = 0 'init variable
    DO 'print until the last page
      INC(pageNum%) 'increment page count
      FN checkAbortKeys 'see if cmd-period pressed
      LONG IF gPrtAbort% = _false 'only print if abort is false
        LONG IF pageNum% => fromPage% 'check if printing in range
          FN printPage(pageNum%,copies%) 'call print routine
          CLEAR LPRINT 'finish page, go to next page
        END IF
      END IF
    UNTIL pageNum% => toPage% OR gPrtAbort% = _true
    ROUTE _toScreen 'set ouput pack to screen
    CLOSE LPRINT 'close the printer driver
    WINDOW CLOSE #2 'close abort window
    EDIT FIELD #2, "Print routine done!", (20,200)-(300,232),_statFramed

The line that gets the number of copies: "copies% ={[PRHANDLE]+_copies}" always seems to return 1 no matter how many copies are entered in the print dialogue box. Can this FN be replaced by the Print Manager examples above some how?

Joe Lertola

<< FN printPage(pageNum%,copies%) 'call print routine
CLEAR LPRINT 'finish page, go to next >>

I'm skeptical about this pair of lines. It looks like your intent is to have FN printPage perform the necessary drawing commands a certain number of times (the value of "copies%"), followed by a single call to CLEAR LPRINT after the FN returns. I think you need to call CLEAR LPRINT after _each_ time you draw the page. If copies% = 12, then you should call CLEAR LPRINT 12 times, not once.

<< The line that gets the number of copies: "copies% ={[PRHANDLE]+_copies}" always seems to return 1 no matter how many copies are entered in the print dialogue box. >>

I'm speculating that this is a (relatively) new feature of the system software. Based on a few experiments with new & old Mac's, I _think_ what's happening is this:

In the "old" system software (how old? Don't know) it was the programmer's responsibility to handle page ranges and number-of-copies programatically, by reading those values from the Print Record, and drawing only the appropriate range of pages, and executing a loop, generating the drawing commands repeatedly for the appropriate number of copies.

Nowadays, the system software (or is it just certain printer drivers? I don't know) handle the looping and page-ranging for you. If the user enters "7" in the dialog box, then 7 copies get printed even though your program only executes the drawing commands once. If the user enters "3" as the first page number, then pages 1 and 2 don't get printed, even if your program "tries" to generate them. Using this "new" method, your program should generate the full range of pages, and generate each page only once. The system software will automatically take care of the copies & range that the user requested.

But in order to make this new "automatic" method work with _older_ application software, which is written to loop through copies and to truncate the page range, it's necessary for the system software to "fool" your application. Though the user enters "7" copies, the system only reports "1" to your program. That way, your print loop is fooled into executing only once, and the system will "multiply" that output by 7 for you. (If your loop executed 7 times, the (new) system would print 7 copies for _each_ loop--giving you 49 copies! You don't want that.)

Likewise, my guess is that the newer system "fools" your program into thinking it's supposed to print the entire range of pages, regardless of what the user actually entered in the dialog box. That way, your program merrily generates the entire range, and the system simply ignores the first "n" and the last "m" pages you generate.