Frequently Asked Questions (last revised: 3/6/09) logo

[General ] [Pageable & Flowable ] [J2Printer/J2Printer14/J2PrinterWebStart ] [Headers & Footers ]
[J2TextPrinter ] [J2TablePrinter ] [J2TreePrinter ] [J2ListPrinter ] [J2PanelPrinter ] [J2ComponentPrinter ]
[J2FlowPrinter ] [Installation ] [Licensing ] [Error Messages ] [Miscellaneous ]


Q1: Was there a J2PrinterWorks 1.0?
A: No.  J2PrinterWorks is the successor product to our earlier products J2TextPrinter and J2TablePrinter, which were both released as versions 1.0, 1.1, 1.2, and 1.3.  The J2TextPrinter and J2TablePrinter classes within J2PrinterWorks were the 2.0 versions of the earlier J2TextPrinter and J2TablePrinter products, so it made sense to number the initial release of J2PrinterWorks to be 2.0 as well.

Q2: What happened to the "J2PrinterWorks Text Edition" and the "J2PrinterWorks Table Edition"?
A: Beginning with the J2PrinterWorks 5.0 release, the two J2PrinterWorks subset editions were dropped in favor of the (former) J2PrinterWorks Complete product.  Because of the overwhelming customer preference for  J2PrinterWorks Complete, the increasing difficulty of maintaining separate build, test, and distribution paths, and the added complexity of supporting three separate releases, it was decided to converge the J2PrinterWorks family on a single complete J2PrinterWorks product priced at an intermediate price point.  All J2PrinterWorks Text Edition and Table Edition customers on annual maintenance were upgraded to the full J2PrinterWorks 5.0 product at no charge.

Q3: How do I convert my code to J2PrinterWorks from J2TextPrinter 1.x or J2TablePrinter 1.x?
A: See "Converting from 1.x" section of this documentation.

Q4: Does my component need to be on the screen in order to print?
A: For Swing components, it is not necessary that your JTextPane, JTable, JTree, JList, JPanel, etc. be in a JFrame visible on the screen at the time of printing or to have ever been displayed at all (however, this is not necessarily true for third-party components, see below J2PanelPrinter Q8).  You may be printing from a server application and have no display.  Or you may have, for example, a JTextPane displayed but wish to print from a different non-GUI copy of the JTextPane.  The latter situation can arise when you want to set the printing JTextPane properties different from your on-screen JTextPane display, such as to force white backgrounds, different page width, borders, or fonts appropriate for a printed page.  In such cases, you can use code like:
  JTextPane pane2 = new JTextPane();
  pane2.setSize(pane2.getPreferredSize());  // setting a size is required
  printer.print(new J2TextPrinter(pane2));
Even if you do use a JFrame, you  can still specify JFrame.setVisible(false) so it does not appear on the screen, or alternatively JFrame.setLocation(10000,10000) to move it off-screen.

Q5: How do I control the size of my printed components?
A: Either get them drawn on the screen explicitly with the sizes you want, or setPreferredSize (not setSize) for your components, which J2PrinterWorks will use to determine their sizes.  If your components are not displayed, J2PrinterWorks internally puts your component in a non-visible JFrame and calls pack(), which Java redraws based on the preferred sizes of your components.

Q6: Can I build a web page that prints on the user's printer?
A: Yes, but there are multiple issues you need to be aware of.  First, you can build a server-side application that prints, but it can only print on printers known to the server machine, which may or may not include the printer desired by your user.  To print on the user's printer, the appropriate technique is to build an applet which downloads to the user's machine and prints on the printers known to the user's machine.  However, Java specifies that it is a security violation to print from a regular (untrusted) applet, just as it is a security violation for an applet to read or write files on the user's machine.  As a result, Java will automatically prompt the user with "An applet would like to print.  Is this OK?", so the user can say "yes" or "no".  In order to print from an applet without this prompt, you need to "sign" your applet or set up the security policy on the user's machine to grant your applet the printing privilege (see "How do I sign an applet" under Miscellaneous ).  

Another consideration is that J2PrinterWorks uses the Java 2 printing model, that is, it requires JDK 1.2 or later.  Therefore you need to assure that your user's browser has a Java plug-in for JDK 1.2 or later.  This is generally true for recent most recent verions of most popular browsers.  If the user's browser does not have the Java plug-in for JDK 1.2 or later, it is readily available by free download from Sun, and it is possible to configure your web page so that it offers to download and install the Java 2 plug-in if it is detected that the user's browser does not have it.

Alternatives to using a Java applet to print are to install a regular Java application on the user's machine, or to download and use a Java Web Start application on the user's machine.

 Q7: Is J2PrinterWorks a report generator?
A:  Not really.  J2PrinterWorks is a solution for printing the contents of Java components and assumes you wish to define and arrange these yourself to create a document or report representing your data.  A true report generator is a tool that will take your data and use it to create and arrange components with specific contents for you, such as forms, reports, charts, etc.  There are several Java report generator solutions in the marketplace such as InetSoft Style Report, Elixir Report, or Big Faceless Report Generator that you may prefer to buy (though report generators tend to be expensive).  But if you already have or can readily produce the report document you want using Java components, J2PrinterWorks is the ideal solution for printing it out.

Q8: Since Java has a printing API, what do I need J2PrinterWorks for, can't I just do all this myself?
A:  Sure.  But be forewarned that Java printing is an elaborate, complex API that's not easy to use, with many subtle nuances to making it work right.  In addition, there is minimal support for breaking your content properly over page boundaries or combining Java components into a single document, not to mention headers, footers, margins, print preview, background printing, etc. etc.  You won't find all that many books, articles, or sample programs out there to help you, especially when you move beyond the basics.  In addition, printing is likely not the primary goal of your application and is something often left until the end when you then discover just how hard it is. J2PrinterWorks represents thousands of lines of code you really don't want to figure out on your own.  We strongly suggest you consider the value of your time before undertaking Java printing yourself.

Pageable & Flowable

Q1: What is a Pageable?
A: Pageable is a Java 2 interface that is part of the Java JDK as defined by Sun and which appears in the package java.awt.print .  Pageable defines a set of paginated pages, i.e., a indexed sequence of printable pages.  Pageable requires 3 implemented methods: getNumberOfPages() specifying the number of pages in the Pageable, getPrintable(int n) specifying the Printable (a Java 2 class that prints a single page) for the nth page, and getPageFormat(int n) specifying the PageFormat (another Java 2 class that describes the paper characteristics, i.e., orientation, size, margins) on which the nth page is to be printed.  Printing a multi-page document in Java requires implementing a Pageable for your document content.  This requires that you calculate in advance all the page breaks for your document content (not an easy task).  J2PrinterWorks contains a number of components such as J2TextPrinter, J2TablePrinter, J2TreePrinter, J2ListPrinter, J2ComponentPrinter, and J2PanelPrinter that will take any JTextPane, JTable, JTree, JList, Component, or JPanel, respectively, and implement a corresponding Pageable.

Q2: What is a Flowable?
A: Flowable is an interface defined by Wildcrest Associates that appears in the package com.wildcrest.j2printerworks.  Flowable defines a print operation that can be advanced by specified rectangular amounts through a given piece of content such as a JTextPane or a JTable, starting at the beginning and continuing in print order to the end.  Flowable can be used to paginate a given piece of content starting and ending in the middle of any page, and a sequence of Flowables can be printed back-to-back over a series of pages.  The J2PrinterWorks abstract class J2Pageable can take any individual Flowable and create a Pageable from it.  For example, J2TextPrinter subclasses J2Pageable and implements the Flowable methods for any JTextPane and, as a result, J2Pageable implements the corresponding Pageable methods using these Flowable methods.  In addition, the container class J2FlowPrinter can take any sequence of Flowables and create an overall Pageable as well as single Flowable from them.
Q3: Can I make my own Flowables?
A: Yes.  By implementing the Flowable interface, you can create a printable component that can paginate and be intermixed back-to-back with other Flowable instances.  Moreover, if you extend the abstract base class J2Pageable and implement its Flowable interface, you will also have a full J2PrinterWorks Pageable with support for headers, footers, margins, orientation, scale, etc.  To see sample code for implementing your own Flowable, click here.

J2Printer, J2Printer14, and J2PrinterWebStart

Q1: What are the differences between J2Printer and J2Printer14?
A: J2Printer14 is a subclass of J2Printer.  J2Printer14 inherits all the methods of J2Printer and adds several more methods that let you use the new Java printing features of JDK 1.4 including printer discovery, programmatic printer selection, printer attributes, and cross-platform print dialogs.  J2Printer works under any JDK 1.2.x or later.  J2Printer14 only works under JDK 1.4.x or later.

Q2: What are the differences between J2Printer and J2PrinterWebStart?
A: J2PrinterWebStart is a subclass of J2Printer.  J2PrinterWebStart inherits all the methods of J2Printer but implements them so they can run under the Java Web Start JNLP APIs.  Since the Java Web Start JNLP APIs don't quite support all the printing capabilities of the full Java PrinterJob printing model, a few method that J2PrinterWebStart inherits from J2Printer have no effect under Java Web Start (see "J2Printer" section of this documentation).

Q3: Should I use the PrintRequestAttributeSet API or the J2Printer methods like setPaperSize to set my printing settings?
A: Either or both.  You can set the values of the number of copies, print job name, paper size, orientation, and margins (printable area) using either API and even intermix calls from the two APIs under JDK 1.4.x or later.  J2Printer14 will keep all the values in synch between the two systems, ensuring that setting values under either API will update the values under the other.  However, it is probably a less confusing coding style to stay within one system or the other.  Also, if you are using JDK 1.4.x or later, you are much better off using the PrintRequestAttributeSet style since it allows you to do many more things.
Q4: The cross-platform print dialog comes up saying Pages 1 to 1.  Can this be fixed?
A: This is a bug in Java (see "Known Problems").  Java does show your number of pages correctly as the upper bound in the native print dialog.  For the cross-platform dialog, you can fix this in your code by setting the PageRanges attribute:
      PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
      aset.add(new PageRanges(1,j2printer14.getPageable().getNumberOfPages()));

Q5: How can I "print to file"?
A: The user can always select the "print to file" option in the standard print dialog to save their printing output to a file instead of to an actual printer.  If you wish to accomplish the same thing programatically, under JDK 1.4 or later, you can use the J2Printer14 class to specify the printer attribute javax.print.attribute.standard.Destination, which implements both the PrintJobAttribute and PrintRequestAttribute interfaces, in order to redirect your printing output to a local disk file, e.g., file:out.prn

In addition, the J2Printer14 method printToPS can be used to send your printing output to a Postscript file.  The J2Printer method printToHTML can be used to send your printing output to a series of HTML pages, including .jpg files for each of the individual page images.  Likewise, the J2Printer method getPageImage can be used to get an Image for any individual page and the method saveImageToFile can save such any Image to a file. 

The method printToPDF can be used to send your printing output to a PDF file.  This method requires the use of the free, open source component iText.jar available from http://www.lowagie.com/iText.  In addition you can also use printToPS to create Postscript files and use 3rd party programs such as Adobe Acrobat Distliller or PS2PDF (part of Ghostscript) to convert these to PDF files.  See the sample code provided in the J2Printer14 documentation under "Print to PDF".

Q6: The cross-platform print and page setup dialogs come up slow, what can be done about this?
A: Due to a bug in Java (Bug Parade 6233074), the cross-platform print and page setup dialogs on Windows can take as long as 10 seconds to come up the first time if your default printer is a network printer (the native dialogs are fast, the cross-platform dialogs after the first time are fast, having your default printer be a direct connect printer is fast).  This bug has been reported to Sun.  We have added a J2PrinterWorks feature to help mitigate this problem.  When you call the J2Printer14 constructor, we start a separate low priority background thread which invisibly invokes the operations that are taking the 10 seconds.  If the user invokes the print or page setup dialogs after these 10 seconds have passed, the dialogs will appear to them to come up right away.  However, if the user invokes the print or page setup dialogs before the 10 seconds have passed, they will have to wait the remainder of the 10 seconds.  Thus, if you are using cross-platform dialogs, be sure to instantiate J2Printer14 early in your application so as to get this 10 second start-up cost out of the way.

Q7: Hitting the "Print" button on the print preview dialog behaves differently than it used to, why?
A: Upon hitting the "Print" button on the print preview dialog, J2PrinterWorks used to always close the print preview dialog and bring up the print dialog (this is the same as applications such as Excel, Wordpad, and Photoshop).  However, since the cross-platform print dialog can take a long time to come up (see Q6 above) this behavior makes it look like the application has died.  In addition, if you hit "Cancel" on the print dialog, you really should go back to the print preview dialog.  In the new design, by default when you hit the "Print" button, the print preview dialog stays up and displays a "busy" cursor.  If the user hits "Cancel" on the print dialog, then the print preview dialog comes back to the front.  If the user hits the "OK" (or "Print") button on the print dialog, then by default the print and print preview dialogs both go away and printing begins (this is the same as, for example, Internet Explorer).  In addition, we have added a new J2Printer method setPrintPreviewCloseOnPrint(int) with arguments J2Printer.BEFORE, .WAIT, and .NEVER, where BEFORE means close the print preview before beginning the process of bringing up the print dialog (this is the former standard J2PrinterWorks behavior), WAIT (the new default behavior) means close the print preview dialog only after the user hits "OK" on the print dialog (this is the behavior of Internet Explorer), and NEVER means leave the print preview dialog up even after hitting "OK" (or "Print") on the print dialog (this is the same as Word, PowerPoint, Outlook, and Netscape). 

Q8: The print preview dialog changes the look & feel of my application, why?
A: The print preview dialog toolbar is created using either the SystemLookAndFeel if you are using setCrossPlatformDialogs(false) or CrossPlatformLookAndFeel if you are using setCrossPlatformDialogs(true) so that the print preview dialog matches the other print dialogs.  The print preview dialog does this by remembering your application's look and feel using UIManager.getLookAndFeel(), setting the System or CrossPlatform look and feel, creating the print preview dialog toolbar UI elements using this look and feel, then restoring your application's look and feel using UIManager.setLookAndFeel().  If you make look and feel changes in your application by modifications to the existing look and feel and not by changing the look and feel with the UIManager, the UIManager won't know about your modifications and the print preview dialog won't be able to restore them correctly.  The correct solution is to make a LookAndFeel subclass that performs your extensions by overriding the LookAndFeel's initialize() method and then using UIManager.setLookAndFeel() to activate your new look and feel.  Alternatively, you can first call the J2Printer method getPrintPreviewToolBar() to get the one-time creation of the print preview toolbar UI elements out of the way and then make whatever UI changes to your application.  These changes should be left alone as long as you don't do anything to cause the print preview toolbar UI elements to be recreated (see Q9).  A third option is to listen for whether any changes have been made to the LookAndFeel and, if so, restore your modifications using code like:
UIManager.addPropertyChangeListener(new PropertyChangeListener(){
    public void propertyChange(PropertyChangeEvent e){
        if( changingFromYourLookAndFeel(e) )

Q9: I customized the print preview toolbar but then my changes got lost, why?
A: The print preview class creates the print preview toolbar once the first time you call getPrintPreviewToolBar(), returning a reference to this toolbar.  You can then modify this toolbar and/or the components (buttons, labels, etc.) contained within it to change labels, icons, tooltips, sizes, borders, colors, order, etc. (see J2Printer section "Customizable Print Preview toolbar).   The print preview dialog uses this same toolbar each time it displays, so that the changes you make will then stay in effect.   There are three exceptions, however.  One is if you change locales during the running of your program.  In this case, all-new strings for labels and tooltips must be read in and the toolbar is then rebuilt, causing any changes you made previously to be lost.  The second is if you call setPrintPreviewString, since this also changes the strings and necessitates rebuilding the toolbar.  The third is if you change the value of setCrossPlatformDialogs(boolean), in which case the look and feel of the toolbar will be changed, requiring the toolbar to be rebuilt.
Q10: Can I change printers in the Windows native page setup dialog and have that show up as the selected printer in the native print dialog?
A: Yes, but you need to use JDK 1.4 or later and print using the J2Printer14 subclass with setCrossPlatformDialogs(false) to invoke the native page setup and print dialogs.  Only JDK 1.4 or later has the API needed to make the latter solution work, since it is essentially the same as programmatic printer discovery and selection.  Under J2Printer14, you can also call setPrinter("printer-name") and that will determine the selected printer in the native and cross-platform print dialogs as well as in the native page setup dialog.  Note that, unlike Java's native page setup dialog on Windows, the Java cross-platform page setup dialog does not give you a way to see or change printers, thus avoiding the problem.  If you must print using the J2Printer base class, another way to avoid the problem is to call setSeparatePrintThread(false).

Headers and Footers

Q1: I can't change the headers, they always say EVALUATION USE ONLY, why?
A: This is a restriction of the Free Trial Version of J2PrinterWorks.  You need to purchase a product license for J2PrinterWorks to enable the feature of changing the headers.  

Q2: I  purchased J2PrinterWorks but I still can't change the headers, they always say EVALUATION USE ONLY, why?
A: You need to include your serial number when calling the J2Printer (or J2Printer14) constructor, like this:
   J2Printer printer = new J2Printer("your serial number");    // or J2Printer14
Or you can call the J2Printer method setParam() using your serial number after you instantiate your J2Printer (or J2Printer14) instance:
   J2Printer printer = new J2Printer();    // or J2Printer14
   printer.setParam("your serial number");

Q3: I  purchased J2PrinterWorks and set my serial number but my headers still say EVALUATION USE ONLY, why?
A: You must set the serial number using the J2Printer constructor or setParam method before you instantiate any printing components (J2TextPrinter, etc.). 

Q4: Well, I'm doing all that and it still says EVALUATION USE ONLY, why?!
A:  If this is still a problem, the likely explanation is that you also have a copy of the evaluation version somewhere earlier in your classpath or in your IDE's required libraries or in your JRE's /lib/ext folder, and therefore you are getting it and not the product version when you run your application.  This is all too easy to do given the complexities of Java classpaths.  

Try searching your system for all copies of J2PrinterWorks.jar.  Normally you can just double-click on J2PrinterWorks.jar to find out what version it is, but you can't always trust this. By the rules of Java classloading, if  you have the evaluation version of J2PrinterWorks.jar in your JRE's /lib/ext folder, you'll get the evaluation version of the classes even if you double-click directly on the product version jar!  This will also happen if you include the evaluation version of J2PrinterWorks classes in a .jar of your own and have that in the /lib/ext folder. 

A way to determine the version you are really running from inside your program is to call the J2Printer method getVersion(), which will return as a string the version number of the J2PrinterWorks you are actually using (it will say, for example, "J2PrinterWorks 5.0" for the product version but "J2PrinterWorks 5.0EVAL" for the Free Trial Version).  However, even this only reports the version number of the J2Printer.class you are using, so there is still an opportunity for confusion if you've somehow mixed up the J2Printer.class from one version with other J2PrinterWorks classes from a different version!

Q5: Can I use page numbering and/or date/time formatting in a JLabel header or footer?
A: Yes.  Just include the same indicators like:   Page ### of @@@   or:   |||EEE, MMM d,yyyy|||    anywhere in your JLabel text.  This works in either HTML or non-HTML JLabel text.

Q6: My HTML JLabel fonts appear to be one size too big under JDK 1.3.x when compared to JDK 1.4.x and later, why?
A: This was a long-standing problem that was finally fixed in JDK 1.4 (see Bug Parade 4285636 ). The tag:
     <font face=serif size=3>
comes out one size too big under JDK 1.3 and 1.3.1 compared to JDK 1.4 and later or compared to standard browsers.  To make your fonts come out consistently between JDK 1.3.x and JDK 1.4 and later, specify all your fonts in relative size:
      <font face=serif size=-1>
      <font face=serif size=+0>
      <font face=serif size=+1>
The same also applies to HTML in JTextPane or JEditorPane.  You can also use the HTML tags <big> and <small>  to go up or down one size, respectively.

Q7: My HTML JLabel fonts appear to be SansSerif, BOLD, 12, black under JDK 1.4 and later but Serif, PLAIN, 14, blue under JDK 1.3.x, why?
A: Java changed the default HTML JLabel font under JDK 1.4.  In addition, under JDK 1.4.x and later, you can change the default HTML font by first calling JLabel.setFont(), but under JDK 1.3.x this is ignored. Therefore, you have to specify the font face, style, size, and color in the HTML explicitly to make them come out the same on 1.3.x vs 1.4.x and later.  J2PrinterWorks includes a JLabel subclass called J2Label which makes it easier to create consistent JLabel usage across all JDKs.

Q8: If the default HTML JLabel font under JDK 1.4 and later is bold, since there is no "un-bold" or "plain" command in HTML, how do I get a plain font?
A: In JDK 1.4.x and later you can call JLabel.setFont() to set a PLAIN font, then setText to specify your HTML. Alternatively, J2PrinterWorks includes a JLabel subclass called J2Label which provides a default PLAIN font under any JDK version.

Q9: Using a JLabel for the right header or footer with right justified text, text runs over the right edge.  Why?
A: This was a Java bug (see "Known Problems"), since fixed in JDK 1.5.  It primarily occurred for small, size=-3, text and for SansSerif (= Arial = Helvetica) font.  Workarounds for earlier JDK's include: 1) use bigger font size, 2) use Serif font, or 3) if you need a sans serif font, try alternatives such as Lucida Sans.

Q10: How do I display an image using HTML in a JLabel (or a JTextPane)?
A: A standard HTML <img src=imageURL> tag works fine, e.g.:
      JLabel label = new JLabel("<html><img src=imageURL></html>");
However, getting the src=imageURL part right depends on where you get your image from. 
To read an image from a web server, use:
      "<img src=http://www.domain.com/path/image.gif>"
To read an image from your jar, use:
    "<img src=" + ClassLoader.getSystemResource("image.gif") + ">"
To read an image from a local file, there are bugs in earlier JDKs (e.g., Bug Parade 4456393) that make it difficult to use relative paths consistently across JDKs.  Instead, it is better to use an absolute path:
        "<img src=file:///path/image.gif>"
To get the absolute path relative to the working directory of your program, use code like:
    String path = new File(".").getAbsolutePath();
If path can include spaces, you need quotes around your src= argument.  In addition, remember that if you specify your HTML in a literal String, any such quotes need to be escaped, that is, specified using:   \"
For applets, to read an image from the same web server directory where your applet code is located, use:
    "<img src=" + getCodeBase() + "image.gif" + ">"
Note that an easier alternative to using HTML for getting an image into a JLabel from the local file system is to use an ImageIcon:
    JLabel label = new JLabel(new ImageIcon("image.gif"));

Q11: I tried to print two images back-to-back using a JPanel containing two JLabel instances read using HTML, but I get a gap between them.  How can I avoid this?
A: This appears to be an inherent problem when using HTML to load an image into a JLabel.  There are three approaches that won't introduce a gap. 
One approach is to use ImageIcon rather than HTML to get your image into the JLabel instances (see Q10). 
Another is to print using a J2FlowPrinter as follows:
    J2FlowPrinter flowPrinter = new J2FlowPrinter();
    flowPrinter.add(new J2PanelPrinter(new ImageIcon("imgA.gif").getImage()));
    flowPrinter.add(new J2PanelPrinter(new ImageIcon("imgB.gif").getImage()));
The third is to use a container designed for Images such as the J2PrinterWorks ImagePanel:
    JPanel panel = new JPanel();
    panel.setLayout(new GridLayout(2,1,0,0));      
    panel.add(new ImagePanel(new ImageIcon("imgA.gif").getImage()));
    panel.add(new ImagePanel(new ImageIcon("imgB.gif").getImage()));
    J2PanelPrinter panelPrinter = new J2PanelPrinter(panel);

Q12: How can I get my logo to print in a header or footer and not look "blocky"?
A: See Question #11 under J2TextPrinter below.  The basic idea is to create a high resolution image of your logo at, say, 4X the size, then display it using HTML in a JLabel that scales it back down to 1/4th the size.  So, for a 1"x1" logo, you would use:
    <img src=288x288Logo.gif width=72 height=72>


Q1: Can J2TextPrinter print RTF documents with embedded images?
A: The current Java JTextPane implementation is not able to read RTF documents containing embedded images.  However, you can read in an RTF document without images, and then use the method JTextPane.insertIcon(Image) to embed a graphics images at a given position in the RTF document.  Alternatively, the J2FlowPrinter component of J2PrinterWorks lets you print RTF in a J2TextPrinter instance, followed immediately by a J2PanelPrinter instance containing an Image, followed immediately by more RTF in a second J2TextPrinter instance.

Q2: Can J2TextPrinter print RTF documents with embedded tables?
A: The current Java JTextPane implementation is not able to read RTF documents containing embedded tables.  However, you can read in an RTF document without tables, and then use the method JTextPane.insertCompoent(JTable) to embed a JTable at a given position in the RTF document.  However, if your JTable doesn't fit on the page, it will not be paginated neatly on a JTable row boundary but rather on the calculated pixel boundary.  A better approach is to use the J2FlowPrinter component of J2PrinterWorks to print the first part of your RTF in a J2TextPrinter instance, followed immediately by a J2TablePrinter instance for printing a JTable of any size (which will be paginated properly on row boundaries), followed immediately by more RTF in a second J2TextPrinter instance.

Q3: Is there any other solution for the features JTextPane RTF does not support?
A: There is a commercially-available RTF converter from Novosoft which is callable from Java and can convert RTF (including embedded graphics and tables) to the XML XSL FO format.  This package references converters which can transform XSL FO to HTML, PDF, Postscript, and other formats.  You may find it advantageous to do a one-time conversion or even conversion on-the-fly for your RTF content.

Q4: Can J2PrinterWorks print to a Postscript or PDF document?
A: Yes. The method printToPS in the J2Printer14 class supports printing your document to a Postscript file.  This feature requires JDK 1.4 or later.  The method printToPDF supports printing your document to a PDF file (this does not require JDK 1.4 or later).  This method requires that you also have the free, open source component iText.jar available from http://www.lowagie.com/iText.  You can also use printToPS to print to Postscript and use third-party programs to convert to PDF, see Q5 under "J2Printer, J2Printer14, and J2PrinterWebStart" above.

Q5: Can J2PrinterWorks print a preexisting PDF document?
A: Yes.  J2PrinterWorks includes a method printPDFFile which can print the contents of any PDF file.  A method displayPDFFile is also available which can display the contents of any PDF file.  Both of these methods require that the free Adobe Acrobat Reader program (available from http://www.adobe.com) be available on the user's machine.  At present, this capability is only available on Windows.

Q6: Can I embed an Image in an HTML document?
A: Due to a bug in the Java JTextPane implementation (see Bug Parade 4671653 and Bug Parade 4636235), you cannot embed an instance of the Java class Image into an HTML document in a JTextPane using the method JTextPane.insertIcon(Image).  However, the HTML document itself can contain images using the usual <IMG SRC=image.gif> tag.  Also, the J2FlowPrinter component of J2PrinterWorks lets you print HTML in a J2TextPrinter instance, followed immediately by a J2PanelPrinter instance containing an Image, followed immediately by more HTML in a second J2TextPrinter instance.

Q7: When I print, my text document appears to be scaled smaller.  Why?
A: Usually, J2TextPrinter will reflow your JTextPane to fit to the width of the page.  However, it can't do this if you have specified setWYSIWYG(true) and have too much text on a line for the page, or if you define an HTML document which contains objects (like big images or HTML tables with absolute widths or using "nowrap") with a width which is wider than the available width of the page.  In these cases, J2TextPrinter is unable to reflow your JTextPane to fit the available page width, and instead it will automatically shrink-to-fit the document so that it fits to one page wide, resulting in smaller fonts.

Q8: My HTML JTextPane fonts appear to be one size too big under JDK 1.3.x when compared to JDK 1.4.x and later, why?
A: This was a long-standing problem prior to JDK 1.4 that was finally fixed (see Bug Parade 4285636 ). The tag:
     <font face=serif size=3>
comes out one size too big under JDK 1.3.x compared to JDK 1.4.x and later or compared to standard browsers.  To make your fonts come out consistently between JDK 1.3.x and JDK 1.4.x and later specify all your fonts in relative size:
      <font face=serif size=-1>
      <font face=serif size=+0>
      <font face=serif size=+1>
You can also use the HTML tags <big> and <small> .  The same also applies to HTML in JLabel (see discussion under J2Label).

Q9: The print preview and print dialogs for my HTML document take 30 seconds to come up.  Pages also turn slow in print preview and gets slower for later pages.  Why?
A: This can happen if your HTML document is big and all (or most) of your HTML document is contained within a single cell of one overall HTML table, as some HTML editors like to do for layout purposes. In this case J2TextPrinter gets no help from Java in determining where page breaks go and has to analyze your document one character at a time figuring out what fits on a page. Bringing up the print preview or print dialogs requires one complete pass through your document to count the pages before display begins, so that's why they are slow.  The print preview dialog must reanalyze all the pages from the beginning of the document up to the page you are currently displaying, so that's why later pages get slower.  The solution is to remove the outer HTML table so that your top level text is not inside an HTML table.  See "Working with  HTML".

Q10: I have some bold or italic words in the middle of my text which look right on the screen but print shifted left or right (or clipped at the right edge).  Why?
A: This was a long-standing Java bug, finally fixed in JDK 1.5, see Bug Parade 4724061 and Bug Parade 4352983.    This was one of the worst problems with JTextPane, making it difficult to create and print nicely formatted documents interspersed with bold and italic words.  If you need to use a JDK prior to 1.5, we have an elaborate but serviceable workaround for this problem, see J2TextPrinter Known Problems.

Q11: My JTextPane contains an image which looks good on the screen but "blocky" when printed, why?
A: This problem occurs because your image is right for screen resolution, say, 72 dpi, but then printed at printer resolution, say, 288 dpi.  Java uses the same 72 dpi coordinate system when printing, but it knows that the printer is at 4X higher resolution.  So if you have a 72x72 image that displays as 1"x1" on the screen, Java does a 4X pixel replication of the 72x72 pixels to get 288x288 pixels so as to print the same 1"x1" on the page, which results in the blocky effect. 

The solution is to provide a 288x288 image in the first place, but then scale it down to 1/4th the size to make it come out the right in 72 dpi coordinates.  Java is smart when it prints to the printer and will use all 4X original pixels rather than pixel replication, which eliminates the blocky effect.  If your image is specified using HTML, all you need to do is go:
    <img src=288x288image.gif width=72 height=72>

If you are embedding an Image in your JTextPane using the insertIcon method, then instead create your Image at printer resolution, use our ImagePanel class to display it, call the ImagePanel setScale method to shrink it back down to 72 dpi, and embed the ImagePanel in your JTextPane using insertComponent (see Question #6 under J2PanelPrinter below for sample code).

Q12: How can I force my JTextPane to repaint and/or relayout after I make changes?
A: JTextPane sometimes doesn't want to repaint or relayout after making changes, even if you call repaint(), invalidate(), etc., particularly if your JTextPane contains embedded components or if your JTextPane updates aren't made from the event dispatching thread or when the JTextPane is initially displayed.  However, a way that always appears to update reliably is to call:

Q13: J2TextPrinter instances in a J2FlowPrinter do not print back-to-back with the other Flowables, instead there's a blank line or gap separating them, why?
A: By default, JTextPane has a white border of 3 pixels on all four sides, so back-to-back J2TextPrinter instances will have a 6 pixel gap separating them.  To eliminate this gap, set the underlying JTextPane border to an EmptyBorder with zero insets, i.e.
    yourJTextPane.setBorder(new EmptyBorder(0,0,0,0));
For successive J2TextPrinter instances in the same font, this will result in uniform line spacing across the multiple instances.

Q14: When I print a J2TextPrinter, I don't want "widows" (the first line of a new paragraph by itself at the bottom of a page).  How can I prevent this?
A: To eliminate "widows", break your JTextPane into multiple JTextPane instances, one per paragraph (you may also wish to set all the borders to an EmptyBorder with insets of zero, see Q13 above).  Create J2TextPrinter instances for each JTextPane.  Now create a J2FlowPrinter and use addFlowable to alternate the J2TextPrinter instances with VerticalGap instances with a test gap of, say, 1.0 and a regular gap of 0.0.   Each VerticalGap will test whether there is less than one inch left on the page and if so, it will skip to the top of the next page, otherwise it will put in a gap of zero length and the following J2TextPrinter will have at least one inch to display multiple lines before the page break.

Q15: I get a CloningException when I print J2TextPrinter from an applet, why?
A: It appears that under some browsers, newer JDK's regard serialization (the underlying mechanism of J2TextPrinter cloning) as a security access violation when performed by untrusted applets (similar to reading or writing a file).  The same problem generally does not occur when running applets in your IDE on your local system.  The easiest fix for this problem is to call yourJ2TextPrinter.setCloningUsed(false), since cloning is usually not necessary for printing most JTextPane content.  Alternatively, you can sign your applet.

Q16: I'm using special Unicode characters which display and print OK but are missing when I print to PDF, what can I do?
A: We have observed this problem for characters in high-level Unicode pages like "Geometrical Shapes", "Dingbats", and "Mathematical Operators".  Java can display and print documents that use these characters OK, but somehow iText fails to print these characters to PDF.  This appears to be a font loading problem.  We have discovered a workaround, which is to include somewhere in your J2TextPrinter document at least one character from certain other character sets (ones known to work include Hebrew, Arabic, Devanagari, etc.,).  This will cause the Unicode fonts to load and now iText will print to PDF the Geometrical Shapes, Dingbats, Mathematical Operators, etc. characters properly.  The character you include must be a printing rather than a non-printing character (e.g., the character &#1475; = \u05c3 is a Hebrew character which can be used as a colon).

However, we have discovered that this workaround still fails to work for some specialized Unicode characters.  As a result, we have added a set of printToPDFNoFonts() methods for printing the current document to a PDF (.pdf) file with no reliance on PDF fonts. All text is instead rendered completely to pixels using  iText.  This ensures that all fonts, including all higher-order Unicode fonts characters, will display and print properly, but with the disadvantage that since page images are now stored as fully rendered bitmaps, the resulting PDF files are much larger.

Q16: I can't get the images referenced in my HTML file (or the HTML file itself) to print using JTextPane.  What am I doing wrong?
A: One way to display and print the contents of an HTML file is using the JTextPane method setPage:
    JTextPane pane = new JTextPane();
    URL url = file.toURL();

Using the setPage method, you can specify images either using local file references (<IMG SRC="image.gif">) for images in the same folder as your HTML file, or you can use URLs (<IMG SRC="http://www.yourwebsite.com/image.gif">), just like for a regular web page.  

However, it is important to realize that by default setPage loads images asynchronously and returns immediately, before the images are loaded.  If your code immediately goes on to print after calling setPage, it is very likely your JTextPane will be empty or incomplete when you print, especially if it is large, contains images, or any of it is loaded from over a network.  The situation can be avoided in an interactive application, where you would typically display your HTML page and the user would hit a "Print" button only after they see that their document is done loading.  Otherwise, to find out when the images are done loading when using setPage, one solution is to set up a PropertyChangeListener on the JTextPane instance and wait for the PropertyChangeEvent called "page" (see Sun javadoc documentation for parent class JEditorPane method setPage).  Another solution is to use an HTMLEditorKit that forces setPage to employ synchronous loading, i.e. not return until the whole HTML page is loaded, which can be accomplished using the following code:

    yourJTextPane.setEditorKit(new HTMLEditorKit() {
        public Document createDefaultDocument() {
            Document doc = super.createDefaultDocument();
            ( (HTMLDocument) doc).setAsynchronousLoadPriority( -1);
            return doc;

An alternative to using setPage is to use the JTextPane method setText, passing in your HTML as a String argument.  In this case you have to read in the HTML from a file using coventional I/O such as:
     File file = new File("Test.html");
     BufferedReader reader;
     try { reader = new BufferedReader(new FileReader(file)); } catch (FileNotFoundException e) {}
     StringBuffer buffer = new StringBuffer();
     String inLine;
     try {
          while ( (inLine = reader.readLine()) != null) {
     } catch (IOException e) {}
     String str = buffer.toString();

Then, you can specify your JTextPane using the setText method, as follows:
    JTextPane pane = new JTextPane();

This works fine if the string is pure, self-contained HTML, as the HTML string itself will be loaded before setText returns.  However, if the HTML string contains references to external image files, you can still have the same kind of asynchronous loading problem for the images that you have with setPage.

To solve this problem, we provide in J2TextPrinter a convenience factory method makeHTMLPane to create a JTextPane from an HTML string as follows:
     JTextPane pane = J2TextPrinter.makeHTMLPane(str);
The big advantage to using our makeHTMLPane method is that it creates a JTextPane that uses a special HTMLEditorKit we provide which, unlike the default, uses synchronous loading of images, so that images are assured to be loaded when this method returns.  Another alternative is to use the custom HTMLEditorKit technique described above which will cause the entire HTML page to load synchronously.

Another problem to be aware of when you use setText (or makeHTMLPane) to specify your HTML is that the <IMG SRC=...> tags must all be in the form of URLs.  That means they can be in the form <IMG SRC="http://www.yourwebsite.com/image.gif"> if accessing the images over a network, but they must be in the form <IMG SRC="file://host/path/image.gif"> for accessing local image files (not <IMG SRC="image.gif"> as for normal HTML web pages and when using the setPage method).   If the file names in your HTML file are normal OS file names (C://path/image.gif), then you can use the routine fixSrcTags(String str) provided in the sample program J2TextPrinterTestApplication.java to convert all the file names in your HTML string from OS style to URL style.  See also "Headers and Footers" Q10 above which describes other alternatives for programmatically specifying images using HTML.

Q17: After printing, can I change the contents of my JTextPane and have the same J2TextPrinter print the new contents?
A: Yes, but you have to call setPane again for your JTextPane before you print a second time in order to get the J2TextPrinter to recognize the new contents.  This is because J2TextPrinter copies your JTextPane contents into an internal JTextPane so that it can reflow the text to the printed page width without disrupting the on-screen appearannce of your JTextPane, but it only does this the first time you print.  Calling setPane will cause the J2TextPrinter to recopy your JTextPane and capture the new contents.


Q1: J2TablePrinter 1.x was able to print a JTable across multiple horizontal and vertical pages in "down then over" order as well as "over then down" order.  Is this still possible?
A: No.  Because the new Flowable-based printing architecture defines a Flowable in "over then down" order, the J2TablePrinter of J2PrinterWorks is no longer able to print in "down then over" order and now always prints in "over then down" order.

Q2: For a JTable that paginates over multiple pages horizontally, do the headers and footers on the FIRST page apply to all the TOP pages?
A: Yes.  The FIRST header and footer settings apply to all the TOP pages and the REST settings apply to the non-TOP pages.

Q3: How do I control the size of my JTable column widths?
A: JTable contains clever (perhaps too clever) logic for allocating column widths when the overall JTable size changes.  To explicitly control the size of your individual JTable columns, it is highly advised that you first call
Then you will be able to control the size of JTable columns by calling
for each column in your table.  See J2PrinterWorksTestApplication.java for examples.   Also, if you have a JTable much larger than a page width and use SHRINK_TO_FIT scaling to fit to one page , you may find that the default font size to be way too small once scaled down.  The easiest way to address this problem is to adjust the sizes of your JTable columns in advance so that the overall JTable size more nearly approximates the printed page.   Alternatively, you can increase your font sizes so that they are more in proportion to your JTable size.

Q4: How can I get multi-line text in my JTable cells?
A: The easiest solution is to define a custom table cell renderer using a JTextArea for your multi-line text, here's how:

      TableCellRenderer textAreaRenderer = new TableCellRenderer() {
        public Component getTableCellRendererComponent(JTable table, Object value,
                          boolean isSelected, boolean hasFocus, int row, int col) {
        JTextArea jta = new JTextArea(table.getValueAt(row,col).toString());
        jta.setLineWrap(true); jta.setWrapStyleWord(true);

        // to autosize the row heights to fit exactly, add the following 3 lines:
        jta.setSize(table.getColumnModel().getColumn(col).getWidth(), Integer.MAX_VALUE);
        int desiredHeight = (int) jta.getPreferredSize().getHeight();
        if (desiredHeight>table.getRowHeight(row)) table.setRowHeight(row,desiredHeight);

        return jta;
      Enumeration cols = table.getColumnModel().getColumns();
      while(cols.hasMoreElements())    //set the renderer for each column

An excellent source of source code snippets for a wide variety of other JTable extensions and modifications may be found here.

Q5: I used setMaximumPages to print my JTable on one page, but when the user printed to a different printer (or changed the margins, headers, footers, paper size, etc.) the JTable covered more than one page.  Why?
A: The setMaximumPages method does not set a persistent property but rather is a one-time operation, i.e., it simply performs repeated calls on setScale reducing the scale by 0.5% until the JTable fits the specified number of pages.  When the setMaximumPages is done, the resulting scale is whatever it is.  Then, when the user selects a new printer (which may have different physical print area), or new margins, headers, footers, paper size, etc. the scale factor set by the last call on setMaximumPages may no longer produce the correct number of pages.  The solution is to call setMaximumPages again after any change to the page properties.  Alternatively, for the specific case of scaling to print one page wide and/or high for a JTable, we strongly recommend you NOT use setMaximumPages and instead switch to the new J2TablePrinter capability SHRINK_TO_FIT.

Q6: I'm using a custom Look & Feel and my JTable won't print, why?
A: Unfortunately, it is very easy to create a custom Look & Feel that will display but not print a JTable.  The problem is that the custom Look & Feel can't produce the JTable headers at the higher printing resolutions required.  This problem only occurs if you are using J2TablePrinter headers, which you can confirm by setting tablePrinter.setColumnHeaderPrinting(J2TablePrinter.NO_PAGES) and seeing if you can now print your JTable.  Among the custom Look & Feel implementations that are known to have this problem are Kunststoff 2.0 on Windows and the Macintosh Look & Feel on OS X under JDK 1.3.1 (the Aqua Look & Feel on OS X under JDK 1.4.1 is fine). 

To fix the above problems, the easiest thing to do is switch your application to the "Metal" (Cross-Platform) Look & Feel provided in Java, which always prints correctly.  You can switch your application to this Look & Feel by calling either
Likewise, the Motif Look & Feel provided in Java also works correctly, which you can use by calling

If you want your application to use the custom Look & Feel for display, you can still print using a non-custom Look & Feel for just your JTable, or even just for a second copy of your JTable used only for printing.  In turns out there is no MetalTableUI or MetalTableHeaderUI defined in Java, but there is a BasicTableHeaderUI that will print correctly, so you can use:
    table.getTableHeader().setUI(new javax.swing.plaf.basic.BasicTableHeaderUI());

The 2.0.1 release of Kunststoff fixed this problem to some extent and a JTable will now print out.  However, the resulting JTableHeader still doesn't look right, instead of a nice gradient, you get a two-level gray appearance.  But since Kunststoff 2.0.1 comes with sources, you can make JTableHeader print with the BasicTableHeaderUI, thereby eliminating the problem.  To do this, edit KunststoffTableHeaderUI.java and immediately after the line:
    super.paint(g, c);
insert the following line:
    if (g instanceof java.awt.print.PrinterGraphics) return;

We have also found that the WindowsLookAndFeel provided with Java prints correctly but causes printing to slow down considerably when printing JTable headers due to a bug in Java which causes Java to make hundreds of extra print callbacks to our code.  This problem has been fixed in the forthcoming JDK 1.6 release (and already in the 1.6 "early access" release).  For earlier JDKs, the above workarounds of using the cross-platform, Metal, or Motif Look and Feel capabilities or the BasicTableHeaderUI will also address this problem.

We have also gotten reports of slow printing because of excessive print callbacks as well as huge print spooling files for older JDKs on Windows if the Windows Display Properties control panel the "Theme" is set to other than "Windows Classic" or "Windows XP", the "Appearance" is set to other than "Windows Classic style" for Windows and button and other than "Windows Standard" for Color scheme, and if under "Settings: Advanced" the DPI setting is other than "Normal size (96 dpi)".  It appears that alternatives to these settings can cause Java to perform extensive bitmap operations when printing JTables.

Q7: When I resize my JTable row heights the fonts get smaller, but when when resize my column widths the font size stays the same and instead gets truncated with "...".  Why?7
A: This behavior is inherent in Java's implementation of JTable.  Java makes the fonts smaller if the row height gets smaller, but keeps the font size the same and truncates wtih "..." when the column width gets smaller.  If you want the font to resize in all cases, create a JTable subclass that overrides setSize and makes the font smaller as the column width decreases.  Alternatively, you can use a multi-line TableCellRenderer (see Q4 above) so that the text will wrap when you reduce your column width.

Q8: When my JTable prints, the columns, which were exactly the right size on the screen, come out truncated with "..." when printed, why?
A: If your column widths are specified as an exact fit on the screen, then the mapping from screen resolution and font sizes to printer resolution and fonts sizes (all integer values) may not be exact.  As a result, the default TableCellRenderer (a JLabel) may be slightly too small for the string at the new font size, and the default behavior of JLabel is that it truncates with "..." when it is too narrow for its content.  This will result in "..." in the printed output, even though it was fine on the screen.  There are several workarounds:

 1) Add a few pixels to your JTable column sizes, use

then for each column call
    TableColumn column  = table.getColumnModel().getColumn(n);

2) Decrease your font size a bit after you set the column sizes but before you print

3) Override the default TableCellRenderer (see Q4 above) and either use a JTextArea which will wrap your table cells to multiple lines, or use a JLabel whose size is increased by 5-10 pixels over what Java thinks is right, e.g.
    Dimension dim = label.getPreferredSize();
dim.width = dim.width + 10;

4) In combination with any of the above, you can use
to make a separate JTable used just for printing if you wish to keep your screen version the unchanged.

Q9: Can I change a TableModel within the same JTable and have J2TablePrinter print the new contents?
A: Yes.  It used to be that you had to call setTable for your same JTable again after any change to the TableModel, but this is no longer the case.  Note, however, that you cannot change the TableModel while printing is underway.  Java printing by its nature needs to have the complete document formed before printing begins and it must remain unchnaged until the Java phase of printing completes, i.e., you can only change the TableModel (or anything else about your document) after printingDone() is called or, equivalently, after the "printingUnderway" event is fired with isPrintingUnderway() false.

Q10: When I print a J2TablePrinter, I don't want just the table header or just one row to appear by itself at the bottom of a page.  How can I prevent this?
A: Use J2FlowPrinter and add a VerticalGap with a test gap of a couple inches and regular gap of zero right before your J2TablePrinter instance (see J2TextPrinter Q14 which describes the same technique used for "widow" control).


Q1: Is it possible for J2TreePrinter to print my JTree so that it paginates horizontally?
A: No.  There is no natural place to break a JTree horizontally.  Hence, J2TreePrinter automatically performs a shrink-to-fit operation to make your JTree fit within the available page width, then it paginates the resulting JTree vertically as needed over multiple pages.  If you are willing to paginate your JTree broken on pixel boundaries, you can use J2PanelPrinter in TILE mode to print your JTree across multiple pages horizontally  (but it will be broken vertically on pixel boundaries as well, rather than row/node boundaries as in a J2TreePrinter).


Q1: Can you print with VERTICAL_WRAP except do all the columns on a page before going to the next page?
A: No.  We will consider adding this "columns by pages" printing layout in a future release if there is sufficient interest, please contact us if you desire this feature.


Q1: Can J2PanelPrinter paginate (i.e., print over multiple pages) a JTextPane? a JTable? a JTree? a JList?
A: J2PanelPrinter has four pagination modes: SHRINK_TO_FIT, SHRINK_TO_WIDTH, TILE, and BREAK_ON_COMPONENTS (see "J2PanelPrinter").  When any of these modes needs to paginate its contents over multiple pages, the contents are broken on calculated pixel boundaries that may slice right through the middle of the lines of a JTextPane, rows of a JTable, nodes of a JTree, or items of a JList.  To correctly paginate these components on their "natural" boundaries, you need to use J2TextPrinter, J2TablePrinter, J2TreePrinter, and J2ListPrinter, respectively.  Alternatively, the new J2ComponentPrint can print these components effectively using BREAK_ON_COLOR mode to break on white space or JTable gridline color.

Q2: For a JPanel that paginates over multiple pages horizontally, do the headers and footers on the FIRST page apply to just the first page or all the "top" pages?

A: The FIRST header and footer settings apply to all the "top" pages and the REST settings apply to the non-top pages.

Q3: When I print a JLabel, I always get blue text, or a non-white background, or a bold font.  How do I fix this?
A: Under JDK 1.4 and later, JLabel defaults to a bold font.  This is a particular problem if you are using HTML to specify your JLabel since there is no "un-bold" HTML command.  Also, JDK 1.3 and later default to a non-opaque background.  And JDK 1.3 defaults to blue text whereas JDK 1.4 and later default to black.  To control these inconsistencies, you can instantiate your JLabel, then set the Font, foreground Color, and background Color explicitly.  The other solution is to use the J2PrinterWorks convenience class J2Label which is a JLabel subclass which has a default plain (and small) font using black text on an opaque white background.

Q4: You say J2PanelPrinter can print any Component, and a JFrame (JDialog, JWindow, etc.) is a Component, but I can't use it to print my JFrame (JDialog, JWindow, etc.).  Why?
A: Java does not allow a Frame, JFrame, JDialog, or JWindow to appear inside another container, which prevents them from being printing in their entirety.  However, you can get J2PanelPrinter to print JFrame.getContentPane() and thereby print the contents of your JFrame (but without the outside window frame).
Q5: I'm using a custom Look & Feel and certain Swing components in my JPanel won't print, why?
A: See similar discussion for JTable under J2TablePrinter above.  We have since learned that JButton and other Swing components can have a similar problem with custom Look & Feel libraries like Kunststoff.  The same workarounds can be used:
    1) change your whole application to "Metal" (cross-platform) Look & Feel using UIManager.setLookAndFeel()
    2) change the Look & Feel for the particular component (or a copy used only for printing) to "Metal" or "Basic" using setUI()
    3) in the case of Kunststoff where the source code is available, you can modify KunststoffButtonUI.java and/or other component renderers by adding the same "instanceof" test given in the J2TablePrinter discussion above, causing those components to revert to "Metal" or "Basic" Look & Feel only when printing.  Alternatively, you can disable the use of Kunststoff gradients for all component printing at one time by adding the "instanceof" test as the first line in the two drawGradient() methods in KunststoffUtilities.java.

Q6: I'm using J2PanelPrinter to print image which looks good on the screen but "blocky" when printed, why?
A: This problem occurs if your image is displayed at screen resolution, for example, 72 or 100 dpi, but then printed at printer resolution, for example, 288 or 400 dpi. When printed, Java expands your low resolution image using pixel replication, hence the blocky or pixelated effect.  The solution is to provide your image at printer resolution (for example, 4 times bigger), then scale it down to the screen resolution size using our ImagePanel class, as in the following code:
    ImagePanel ip = new ImagePanel(new ImageIcon("4TimesBiggerImage.gif").getImage());
    J2PanelPrinter panelPrinter = new J2PanelPrinter(ip);

Q7: My JLabel looks right on the screen but when J2PanelPrinter prints it the last characters get trnncated or changed to "...", why?
A: This problem occurs when Java rescales your JLabel for printing.  Java rescales the fonts to printer resolution but doesn't adjust the JLabel width correctly (we believe this is the same problem as Bug Parade 4724061 and Bug Parade 4352983.).  The easiest solution is to add a little extra room to your JLabel preferred size, for example:
    Dimension dim = label.getPreferredSize();
    dim.width = dim.width + 10;

Q8: My third-party component won't print (it leaves a blank space) using J2PanelPrinter, what can I do?
A: We have observed that ILOG components in particular have this problem if they are not visible on the screen during printing (this includes if they are in a JTabbedPane in a tab that is not currently selected).  This appears to be because, unlike the standard Swing components, the ILOG "print" method honors the setVisiible state of the component.  However, it appears the ILOG "paint" method will always print.  Therefore, a solution is to subclass the ILOG component and override "print" to call "paint", for example:
public class MyIlvJScrollManagerView extends IlvJScrollManagerView {
      public MyIlvJScrollManagerView(IlvManagerView view) { super(view); }
      public void print(Graphics g) { paint(g); }


Q1: What is the difference between J2ComponentPrinter and J2PanelPrinter?
A: J2CompoentPrinter is similar to J2PanelPrinter in many ways, but is more general and can be used in place of J2PanelPrinter for most purposes.  The TILE and BREAK_ON_COMPONENTS modes are the same in J2ComponentPrinter and J2PanelPrinter, except that with J2ComponentPrinter you can invoke these modes independently in the horizontal and vertical directions.  Likewise, the SHRINK_TO_FIT mode of J2ComponentPrinter can be invoked independently in the horizontal and vertical directions and also honors the getMaximumPaginationGap() concept, whereas J2PanelPrinter has a special rule governing when to skip to a new page.  The BREAK_ON_COLOR mode of J2ComponentPrinter has no counterpart in J2PanelPrinter and makes J2ComponentPrinter capable of paginating a broader range of components effectively.  Note, however, that J2ComponentPrinter is only available in the J2PrinterWorks Complete product, whereas J2PanelPrinter is available in both J2PrinterWorks Complete as well as the J2PrinterWorks Text Edition and J2PrinterWorks Table Edition subset products.

Q2: J2ComponetPrinter BREAK_ON_COLOR mode is slow for my big component, what can I do?
A: By default, the BREAK_ON_COLOR image analysis evaluates color values at every pixel, which ensures accurate break-on-color pagination but can be slow for large multi-page Components. The J2ComponentPrinter method setBreakOnColorIncrement(int) lets you increase this value to, for example, 10 (meaning evaluate only 1 out of every 10 pixels).  This will result in much faster processing and will still generally produce accurate results, though raising it too high increases the risk of inaccurate pagination depending upon the contents of the Component.

In addition, by default, the BREAK_ON_COLOR internal data tables recompute automatically every time you print or print preview the Component to take into account any properties of the Component or its underlying data that might have changed since setComponent was called.  These calcuations can be slow for large multi-page Components. Calling the J2ComponentPrinter method setAutomaticRecalculation(false) will cause this calculation to be performed only once when setComponent is called, greatly speeding up all uses of this J2ComponentPrinter thereafter.  However, it is important to note that if you set this value to false, it becomes your obligation to call setComponent every time your Component or its underlying data changes.


Q1: Can I include the same Flowable instance twice in the same J2FlowPrinter instance?
A:  No.  Each Flowable instance maintains its printing position state as it is paginated in "raster" order.  At the start of paginating each J2FlowPrinter instance, the printing position states of all of its Flowables are reset.  These states advance as the J2FlowPrinter is printed.  Therefore, the same Flowable cannot appear at two different places in the same J2FlowPrinter instance.  However, the same Flowable can appear in two different J2FlowPrinter instances within the same overall document.

Q2: Can I scale individual Flowables independently within a J2FlowPrinter instance?
A:  Yes.  This feature was introduced in J2PrinterWorks 3.0.  

Q3: Can Flowables be made to flow side-by-side (if they fit) before they flow down the page?
A:  No.  However, we are considering adding this capability in a future release, please contact Wildcrest Associates if you are interested in this feature.

Q4: Can Flowables be used to print a two-column page layout?
A:  No.  However, we are considering adding this capability in a future release, please contact Wildcrest Associates if you are interested in this feature.


Q1: What are the limitations of the Free Trial Version of J2PrinterWorks?
A: In the Free Trial Version of J2PrinterWorks, the left, center, or right headers contain the message "EVALUATION USE ONLY" and Wildcrest Associates copyright notices, and the methods for changing these are disabled.  In addition, the Free Trial Version of J2PrinterWorks appends to the end of every printed document an extra "Thank You" page, thanking you for trying J2PrinterWorks and inviting you to buy the product release.  All other features of J2PrinterWorks are identical to the product release.

Q2: How to I uninstall J2PrinterWorks?
A: Simply delete the J2PrinterWorks installation folder.  J2PrinterWorks uses no hidden files, files in system folders, or modifications to your environment variables or the registry.

Q3: How do I determine my current version number of J2PrinterWorks?
A: Double-click on your copy of J2PrinterWorks.jar (but see the next question).

Q4: I'm double-clicking my current version of J2PrinterWorks.jar but I'm getting the wrong version number (or the EVAL version), why?
A: By the rules of Java classloading, if  you have an old version of J2PrinterWorks.jar in your JRE's /lib/ext folder, you'll get the old version of the classes even if you double-click on the new jar!  This will also happen if you include old J2PrinterWorks classes in a .jar of your own and have that in the /lib/ext folder.  To be assured of the correct result, you need to run J2PrinterWorks.jar from a "clean" JRE.  For more information, read the related questions and answers in the "Headers & Footers" section, above.

Q5: How do I download the latest version of J2PrinterWorks for which I am licensed?
A: Use your browser, go to http://www.wildcrest.com/Product/J2PrinterWorks, and enter your name, email address, and product serial number.

Q6: Will J2PrinterWorks work on my OS platform (e.g., Windows, Macintosh, Solaris, Linux, OS/2, HP/UX, AIX, etc.)?
A: This depends on the quality of the Java implementation on the particular OS and how complex your printing application is.  The Windows, Solaris, and Linux implementations from Sun are generally the most compatible.  The Mac OS X Java JDK 1.4.x releases from Apple are also very good.
Q7: My version of IBM's VisualAge for Java complains when it tries to load J2PrinterWorks.jar.  Why?
A: IBM's VisualAge for Java complains when you try to load J2PrinterWorks.jar because it is unable to find the class PrintRequestAttributeSet.  This class was new in JDK 1.4 and is only used by our J2Printer14 class.  IBM's VisualAge for Java still uses JDK 1.2.2 and doesn't know about the new JDK 1.4 classes.  However, despite the error message, you will be able to use J2PrinterWorks inside VisualAge as long as you don't use the J2Printer14 class. Alternatively, you can simply remove J2Printer14 from J2PrinterWorks.jar using the Java jar tool (or WinZip).

Q8: Does J2PrinterWorks work under Java Web Start (using JNLP API)?
A: Yes.  This feature was introduced in J2PrinterWorks 3.0.

Q9: Are there any DLL's or native implementations in J2PrinterWorks?
A: No.  J2PrinterWorks is implemented 100% in Java and uses nothing but official Java API's.

Q10: I am getting "EVALUATION USE ONLY" in my headers, even after I bought the product, why?
A: See Q1-Q4 in the "Headers & Footers" section above.


Q1: Can I ship the J2PrinterWorks .class files with programs I write without paying extra (i.e., are they "run-time royalty-free")?
A: Yes.  J2PrinterWorks licensing is on a "per developer" basis.  Only developers who write code that calls the J2PrinterWorks APIs need to be licensed for J2PrinterWorks.  Once they have purchased a J2PrinterWorks license, these developers can write any number of applications using J2PrinterWorks and distribute or deploy any number of copies including copies of the J2PrinterWorks .class files for use by their software without any additional royalties.

Q2: Do I have to ship the whole J2PrinterWorks.jar file with programs I write?
A:  No.  You can use the Java jar utility (or WinZip) to split the J2PrinterWorks.jar file into individual classes and distribute only the classes you need with your software, either as "loose" classes or bundled into your own .jar file(s).  In particular, many development tools will automatically extract just the classes your program uses and package them with your program .jar file.  Doing this allows you to reduce the size of J2PrinterWorks by excluding development-time-only classes you don't need to run your program, such as the "BeanInfo" and "PropertyEditor" classes, as well as any run-time classes your program happens not to use.

Q3: What developers need licenses to use J2PrinterWorks?
A: Only developers who write Java code that calls the J2PrinterWorks APIs need to be licensed for J2PrinterWorks.  Programmers working on other sections of your application do not need to be licensed.  Test and build engineers do not need to be licensed (unless they write test code that calls the J2PrinterWorks APIs).  Distributors and web site managers who deploy programs that use J2PrinterWorks do not need to be licensed.  End users of programs that include J2PrinterWorks do not need to be licensed. 

Q4: What do I do if I lose my serial number?
A: Please contact Wildcrest Associates and provide the purchaser's name, organization, mailing address,  email address, date of purchase, and/or other order information sufficient to allow us to locate your name in our customer records.
Q5: If I buy a J2PrinterWorks Source Code Individual License, do I also need to buy a J2PrinterWorks Binary Individual License?
A:  No.  The J2PrinterWorks Source Code Individual License comes with a (not separately transferable) J2PrinterWorks Binary Individual License.  This Binary License covers both the unmodified J2PrinterWorks classes and any classes produced from modified J2PrinterWorks source code. Thus, a J2PrinterWorks Source Code License lets the licensee modify the J2PrinterWorks source code and ship the resulting modified .class files (though not the source code) bundled with their software.

However, a common situation where organizations do purchase both Source Code and Binary licenses is when they want both a Source Code Individual License (so one designated developer can see and change the source code to produce modified J2PrinterWorks .class files) and a Binary Site License (so all the developers at their site can develop and ship software that uses the original or modified J2PrinterWorks .class files).

Q6: Can I distribute modified J2PrinterWorks source code to other developers?
A:  You can only distribute modified J2PrinterWorks source code to other J2PrinterWorks Source Code Licensees.  These include any other developers who purchased a Source Code Individual License, developers at your company if you have a Source Code Site License, or developers at another company which has its own Source Code Site License.

Q7: Can I distribute .class files derived from modified J2PrinterWorks source code to other developers?
A:  You can only distribute .class files derived from modified J2PrinterWorks source code to other J2PrinterWorks Binary Licensees.  These include any other developers who purchased a Binary Individual License, developers at your company if you also have a Binary Site License, or developers at another company which has its own Binary Site License.  Of course per Q5 above, as a Source Code Licensee, you can freely distribute .class files derived from modified J2PrinterWorks source code when they are bundled as part of your own software, provided they are only available for end user (non-programming) use.

Error Messages

Q1: What does "Flowable unable to make progress" mean?
A: This means that you have some portion of your content that is both indivisible and wider or taller than the printable area of a page. 

"Flowable unable to make progress" can never happen for J2PanelPrinter, since any of its four pagination modes will allow the J2PanelPrinter to make progress. 

J2TreePrinter will never have a width problem since it will always shrink-to-fit within a single page width.  But "Flowable unable to make progress" can happen if the JTree has any individual row height taller than a page. 

Likewise, J2ListPrinter will never have a width problem since it will always shrink-to-fit within a single page width, but "Flowable unable to make progress" can happen if the JList has any individual row height taller than a page.

As of J2PrinterWorks 2.1a, "Flowable unable to make progress" can no longer happen for J2TablePrinter.  Beginning with J2PrinterWorks 2.1a, if your JTable had individual cells wider or taller than a page, J2TablePrinter truncated them to the size of a full page and continue with the next row or column.  Beginning with J2PrinterWorks 4.0, J2PrinterWorks paginates (tiles) oversize cells over page boundaries.

As of J2PrinterWorks 3.0, "Flowable unable to make progress" can no longer happen for J2TextPrinter.  J2TextPrinter never had a width problem since it will always shrink-to-fit within a single page width.  And under J2PrinterWorks 3.0, if you have an embedded image or component or text character taller than a page, J2TextPrinter will paginate (tile) through this content on pixel boundaries.

There is one exception to the above statements, which is that "Flowable unable to make progress" can happen for any of the above J2Pageable subclasses if an image or other content is specified in a header or footer that is bigger than a page.


Q1: How do I sign an applet?
A: First, you do not need to sign an applet in order to print if you don't mind Java asking the user each time if it is OK to print (in addition, the user can check a box saying "Don't ask again", in which case it will not ask again until the next time the browser is run).  Otherwise, you can sign your applet so that it can print under both Netscape Navigator and Microsoft Internet Explorer.  The Java 2 security model specifies how this is done.  Basically the idea is that you create a single jar containing your applet and the J2PrinterWorks classes, then you use the Java security tools to sign the jar with a public key certificate obtained from a certification authority such as VeriSign (alternatively, you can sign both the J2PrinterWorks.jar and your own applet jar(s) separately).  The user still has to grant you access the first time that they run the applet, but after that the applet will never again have to ask, even if the browser exits and is rerun.

Another approach is for you (or an administrator) to modify the java.policy file that resides in your java_home/jre/lib/security directory to add the following lines:
   grant {
      permission java.lang.RuntimePermission "queuePrintJob";
Copying this modified policy file into a user's java_home/jre/lib/security folder (or certain other places), will grant the necessary privileges so that applets won't have to ask permission to print even the first time.

Sun has lots documentation on the Java 2 security model, check out the following links:




Worked Examples


The Java security model has evolved over time.  For Internet Explorer it used to be that you needed to package your applet in a specially-constructed .cab file that included your signature information.  However, this was only implemented by Microsoft for JDK 1.1, since Microsoft does not support Java 2.  Since J2PrinterWorks requires Java 2, and since Java 2 is available for Internet Explorer only via Sun's Java Plug-In, Sun's Java 2 security model will enable your applets to use J2PrinterWorks under Internet Explorer.

For Netscape it used to be that you needed to create a signed .jar file and include a special Netscape class called by a few lines of code in your applet.  However, as of JDK 1.3, Netscape began shipping Sun's Java Plug-In to provide Java support in Navigator, allowing you to use Sun's Java 2 security model, and as of JDK 1.4 Sun dropped support for the Netscape security model so that Sun's Java 2 security model must be used.  Therefore, using Sun's Java 2 security model is also the best way to sign applets so that Netscape Navigator can use J2PrinterWorks.

Q2: How do I sign a Java Web Start application?
A: The situation for signing Java Web Start applications is in many ways similar to the situation for signing Java applets, see links cited in the previous question.  In addition, the following documentation for signing Java Web Start applications is available:

Java Web Start

Java Web Start does not have a specific printing privilege exactly comparable to the Java applet situation above, and it is easiest to just grant all permissions for a trusted Java Web Start application.  In order to do this, the basic idea is to add the following security tag to your .jnlp file:
Also, all the jars that make up your Java Web Start application have to be signed.

It is also possible to skip the whole signing process and just put the lines:
grant {
     permission java.security.AllPermission;
into the user's jre\lib\security\javaws.policy file in the case where you have administrative control over the user's machine.

Q3: My printing is slow and/or my print spooling size is huge.  Why is this and what can I do about it?
A: JDK 1.2.x  printing was very slow, especially for any documents that contained images.  Printing could take many minutes per page and print spooling sizes could take many megabytes even for small documents.  JDK 1.3/1.3.1 achieved a major improvement over JDK 1.2.2 in both speed and space requirements.  In turn, JDK 1.4, 1.5, and 1.6 each achieved further improvements on JDK 1.3/1.3.1.  So the single best thing you can do to improve your printing performance is run under the latest JDK runtime (note that you do not need to develop under the latest JDK 1.4 or use the JDK 1.4+ printing features).

Java printing has three phases:
     1) the time to call the PrinterJob printing methods themselves (this just takes few seconds)
     2) the time for Java to perform "call-backs" on your Pageable and Printable interface to draw the pages (under JDK 1.2.2 this can take 30 seconds/page or even several minutes/page if the page contains images)
     3) the time for the OS to spool your printing and actually print pages out on the printer (highly variable based on printer and OS, this can be seconds to minutes).

Phase 3 is always done in a background thread of the OS, outside the control of Java.  Normally, Phases 1 and 2 will be done in the Java calling thread, usually the user interface thread of the application if the user invokes a print menu item or button, so that the user has to wait until Phases 1 and 2 complete before doing anything else.  The J2PrinterWorks background printing thread support moves Phase 2 to separate Java thread.  This means that calls on J2PrinterWorks methods will return in just a few seconds, and the user regains interactive control.

You can turn off the J2PrinterWorks background printing thread feature if you want printing to take place from the calling thread by calling setSeparatePrintingThread(false) .  In this case the print method will block until it is done rather than returning immediately.  This simplifies (and speeds up slightly) the J2PrinterWorks internal printing process and is appropriate in server-based applications where there is no user interaction to get back to.  Of course, you can always create a separate thread in your program different from your UI thread to call J2PrinterWorks and achieve the same result as the background printing thread feature of J2PrinterWorks.

Note that if you call setSeparatePrintingThread(false) and call J2PrinterWorks from your UI thread, the print progress events that are fired by J2PrinterWorks will not get through to your UI thread (which might like to show a printing progress indicator), since this thread will be blocked until printing completes.

Certain LookAndFeel and/or desktop theme settings can also lead to very slow printing and excessive spool file size under older JDKs.  See Q6 under "J2TablePrinter" above.

Q4: J2PrinterWorks is using a lot of memory space and I get "Out of Memory" errors.  What can I do about it?
A:  This was a big problem under JDK's prior to 1.4 and is still being improved in the more recent JDKs, so the first thing to do is upgrade to the latest JDK.  Nonetheless, depending on the size and content of your document and your particular printer and printer driver, Java can take up a considerable amount of memory when imaging your document. For certain printers (especially bitmap printers like inkjets, Postscript printers aren't as bad), Java will allocate a full array of color pixel values for as much as your entire page at printer resolution for rendering, and may do this for multiple pages without freeing up memory.  In addition certain components consume a lot of memory when rendered, especially JTextArea, JEditorPane, and JTextPane which create large numbers of objects each time a line layout operation is performed (see Bug Parade 4203712, which is fixed in JDK 1.5).  After printing, garbage collection will free these resources, but you need enough memory during printing (or print preview) to make it through.  The default maximum heap size of Java is only 16MB, and Java will run out of memory once this limit is reached, regardless of how much actual memory your machine may have.  Usually 16MB will only work for modest print documents.  The solution is to allocate a much bigger maximum heap size on your java command line.  For example,
    java -mx1024m -classpath etc YourApplication
will set 1024 MB of memory as the maximum heap size.  This only specifies a maximum and will not be allocated unless needed and available.

If you are getting "Out of Memory" errors after printing multiple documents from the same application, there are some other things you should do.   First, it is wasteful if you instantiate a new J2Printer instance for each printed document.  Instead you can instantiate one J2Printer instance at the beginning of your program and reuse this for each of your multiple documents, using setPageble() (or clearPageable()) to start off the next document.   Likewise, rather than instantiating a new J2TextPrinter, J2TablePrinter, etc. objects for each document, you can instantiate them once early in your program and then reuse them by calling, e.g., setPane, setTable, etc. when you form each new printing document. In addition, the J2PrinterWorks printing components J2TextPrinter, J2TablePrinter, J2TreePrinter, J2ListPrinter, J2ComponentPrinter, and J2FlowPrinter each have a dispose() method so you can force the release of any heap-allocated storage retained by that component.  Note that if you are using setSeparatePrintThread(true), you need to make sure to wait until each print job completes before making any of the above calls, otherwise you can overwrite printing objects with your next document before Java printing is done with the previous document (but you only need to wait until the printingDone() event is fired, not for paper to come out of the printer).

Q5: Is printing thread safe?
A:  No, J2Printer's background printing support provides no thread safety.   You need to ensure that the JTextPane, JTable, etc. being printed by J2Printer doesn't change out from under J2Printer, otherwise unpredictable results may occur.  J2Printer's use of the JTextPane or JTable, etc. is read-only, so it is usually OK to scroll and view your components while the printing of it is underway, but it is not OK to modify (including resize) or delete them. Likewise, you should not change other J2PrinterWorks parameters like margins, headers, footers, etc. while separate thread printing is underway, otherwise unpredictable results will occur.  Thread safety problems typically manifest themselves as intermittent errors, where small, often unrelated changes in your program or document (or just running it again) can affect when or whether an error occurs, what the error is, or the printed output itself.

If you suspect you have thread-safety problems, any of the following can be used to avoid the problem:
1) Use setSeparatePrintThread(false)
2) Make a second JTextPane,  JTable, JTree, JList, or JPanel using the same model as your original and use it to print, e.g.:
     JTextPane pane2 = new JTextPane();
     pane2.setSize(pane2.getPreferredSize());  // setting a size is required
     printer.print(new J2TextPrinter(pane2));
3) Use the J2PrinterWorks clone method to clone your JTextPane, JTable, JTree, JList, Component, or JPanel component (or clone its model and use it with a new component instance) and print using the new copy (however, due to bugs in Java in some JDK's, some components can't be cloned or do not clone properly)
4) Create a second JTextPane,  JTable, JTree, JList, Component, or JPanel to be used exclusively for printing and update its contents in parallel with your original.

Q6: Why are there differences between my printout and print preview (or between printouts on two different printers)?
A: J2PrinterWorks creates its print preview view by executing the exact same Java graphics operations it uses when it prints to a printer.  The only difference is that the graphics context used as a target for the rendering is an in-memory image array instead of the printer driver.  This ensures that "WYSIWYG" printing is as good as Java can provide.  However, in the case where the printer has its own printer description language (PDL), the printer driver performs an additional step of translating the Java graphics commands to the PDL graphics commands.  Since these two graphics systems are different and generally have different coodinate systems, different resolutions, different color spaces, different fonts, etc., this translation can be imperfect, despite the goal of WYSIWYG printing.  Similar problems can arise even when printing to a bitmap printer, since often it is the underlying OS graphics system that renders the printer bitmap image, and comparable problems arise in the translation from the Java graphics environment  to the OS graphics environment.

If printing errors arise only on a given printer, it is often a good idea to check the printer driver being used for that printer.  Often there are newer drivers available from the manufacturer that fix problems in the earlier print drivers that may have shipped with the printer or that were originally shipped as part of the OS.  In addition, in broad families of printers, such as those from HP, many more printer drivers will work for a given printer than just the one designated by name for that printer.  Some customers find that they get more reliable printing by using a "generic" Postscript driver or a "generic" HP Deskjet driver than the specific named driver associated with their printer because these drivers are often more thoroughly tested and debugged than any others.

Q7: Will I get print progress events if I print with setSeparatePrintThread(false)?
A: Not without your creating a separate thread yourself.  If you call the J2PrinterWorks print method from your UI thread and have setSeparatePrintThread(false), then your UI thread is blocked until printing (through "phase 2" in Q2 above) completes.  However, when the print progress events fire, they do call "yield" on their thread, so if you have created a separate UI thread of your own, print progress events can get through to your code.

Q8: The "Search" function in this J2PrinterWorks Documentation appears to require that my Internet connection be working.  Why?
A: Normally J2PrinterWorks uses a local copy of the J2PrinterWorks Documentation files installed on your machine.  But the "Search" function in the J2PrinterWorks Documentation uses a special indexed copy of the J2PrinterWorks Documentation files maintained on the Wildcrest Associates web site using a third-party search engine (from "FreeFind ") accessed on-line from their site.  Thus, if you use the "Search" function, you Internet connection needs to be open to get at these resources.

Copyright 2009, Wildcrest Associates (http://www.wildcrest.com )