0

I am using Printable interface. The exact code for PrintPanel which implements Printable is:

package accessory;

// all necessary imports

public class PrintPanel implements Printable {

BufferedImage printableImages[] = null;
DynPanel printable = null;

public Font printFont = new Font("Arial", Font.BOLD , 10);
public String headerStr = null , footerStr = null;
public boolean draw_pageBorder = false;
public Color borderColor = Color.BLACK;
public int pageBorder_thickness = 2;
public int pageCount = 1;

public PrintPanel(DynPanel panel)
{
printable = panel;
pageCount = 1;
}
public PrintPanel(BufferedImage images[])
{
printableImages = images;
pageCount = images.length;
}
    @Override
   public int print(Graphics g, PageFormat pageFormat, int page) throws PrinterException
{
 System.out.println("entered print command");
 if(page < pageCount )
 {

 //--- Create the Graphics2D object
 Graphics2D g2d = (Graphics2D) g;
 g2d.translate(pageFormat.getImageableX(), pageFormat
         .getImageableY());
 //--- Translate the origin to 0,0 for the top left corner

 int fontHeight = g2d.getFontMetrics().getHeight();
 int fontDescent = g2d.getFontMetrics().getDescent();
 int lineHeight = fontHeight+ fontDescent;

 int fontWidth_header = g2d.getFontMetrics().stringWidth(headerStr);
 int fontWidth_footer = g2d.getFontMetrics().stringWidth(footerStr);
 int remainder_header = (int)Math.ceil( pageFormat.getImageableWidth()  )  - fontWidth_header;
 remainder_header /= 2d;
 int remainder_footer = (int)Math.ceil( pageFormat.getImageableWidth()  )  - fontWidth_footer;
 remainder_footer /= 2d;

  if(draw_pageBorder)
  {

 g2d.setPaint(borderColor);


 g2d.setStroke(new BasicStroke(pageBorder_thickness));
 Rectangle2D.Double border = new Rectangle2D.Double(0, 0, pageFormat
     .getImageableWidth()+4, pageFormat.getImageableHeight()+4);

   g2d.draw(border);
  }
  g2d.setFont(printFont);



 // code for printing DynPanel (JPanel)
 if(printable != null)
 {

      Dimension compSize = printable.getPreferredSize();
         // Make sure we size to the preferred size
         printable.setSize(compSize);
         // Get the the print size
         Dimension printSize = new Dimension();
         printSize.setSize(pageFormat.getImageableWidth(), pageFormat.getImageableHeight());

         // Calculate the scale factor
         double scaleFactor = getScaleFactorToFit(compSize, printSize);
         // Don't want to scale up, only want to scale down
         if (scaleFactor > 1d) {
             scaleFactor = 1d;
         }


         // Calculate the scaled size...
         double scaleWidth = compSize.width * scaleFactor;
         double scaleHeight = compSize.height * scaleFactor;

         // Create a clone of the graphics context.  This allows us to manipulate
         // the graphics context without begin worried about what effects
         // it might have once we're finished
         //Graphics2D g2d = (Graphics2D) g.create();
         // Calculate the x/y position of the component, this will center
         // the result on the page if it can
         double x = ((pageFormat.getImageableWidth() - scaleWidth) / 2d) + pageFormat.getImageableX();
         double y = ((pageFormat.getImageableHeight() - scaleHeight) / 2d) + pageFormat.getImageableY();
 AffineTransform at = new AffineTransform();
 // Translate the offset to out "center" of page
 at.translate(x, y);
 // Set the scaling
 at.scale(scaleFactor, scaleFactor);
 // Apply the transformation
 g2d.transform(at);
 // Print the component

 printable.printAll(g2d);
 }
 else // code for printing BufferedImages 'printableImages'
 {


     try{



            int width = (int) pageFormat.getImageableWidth();
            int height = (int) pageFormat.getImageableHeight();
            int imageWidth  = printableImages[page].getWidth();
            int imageHeight = printableImages[page].getHeight();

            double scaleX = (double)width/imageWidth;
            double scaleY = (double)height/imageHeight;
            AffineTransform scaleTransform = AffineTransform.getScaleInstance(scaleX, scaleY);
            AffineTransformOp bilinearScaleOp = new AffineTransformOp(scaleTransform, AffineTransformOp.TYPE_BILINEAR);

            printableImages[page] = bilinearScaleOp.filter(
                    printableImages[page],
                new BufferedImage(width, height, printableImages[page].getType()));
         System.out.println("Printing IMAGE="+printableImages[page]);

        g2d.drawImage(printableImages[page] ,  (int)pageFormat.getImageableX() , ( (int)pageFormat.getImageableY() + (8 + lineHeight) ),  null);
    } catch (Exception e) {
        // TODO Auto-generated catch block
        System.out.println("ERROR IN PRINTING IMAGE");
        e.printStackTrace();
    }

 }
 if(headerStr != null)
     g2d.drawString( headerStr , (int)pageFormat.getImageableX() + remainder_header , (int)pageFormat.getImageableY() + (8 + lineHeight));
     if(footerStr != null)
     {
      if(footerStr.equals("print_page_index"))
          g2d.drawString( ("Page "+( page + 1) + " of " + pageCount ) , (int)pageFormat.getImageableX() + remainder_footer , (int)pageFormat.getImageableY() + ((int)pageFormat.getImageableHeight() - lineHeight - 8 ));
      else 
     g2d.drawString( footerStr ,  (int)pageFormat.getImageableX() + remainder_footer , (int)pageFormat.getImageableY() + ((int)pageFormat.getImageableHeight() - lineHeight - 8));
     }
//else System.out.println("EMPTY PRINT");
 //g2d.dispose();
if(printable != null) printable.revalidate();
  //  printable.paint(g2d);
 return Printable.PAGE_EXISTS;
}
else return Printable.NO_SUCH_PAGE;

     }



 }

I am using the constructor PrintPanel(BufferedImage images[])

  • Now I am calling a function printDocument() which has the following code:

    private void printDocument()
    {
    
    
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
    
            System.out.println("Initiating print command..");
            long t1 = System.currentTimeMillis();                
            PrinterJob printJob = PrinterJob.getPrinterJob();
            Book book = new Book();
            PageFormat documentPageFormat = new PageFormat();
            documentPageFormat.setOrientation(PageFormat.PORTRAIT);
           BufferedImage pages[] = new BufferedImage[pane.pageCount];
    
            for(int count = 0; count < pane.pageCount; count ++ )   
             pages[count] = pane.pages[count].getSnapshot();
    
    
    
            PrintPanel printImage = new PrintPanel(pages);
    
            printImage.headerStr = "Java Study Frame : " + ( docName != null ? (( docName.replaceAll("\\s+" , "").isEmpty() ? " Untitled JSF Document " : docName ) ) : " Untitled JSF Document " ) ;
            printImage.footerStr = "print_page_index";
    
           printJob.setJobName("Java Study Frame Print");
           long t2 = System.currentTimeMillis();
            System.out.println("Setting printable. Prev time = " + (t2 - t1)/1000 +" seconds!");
            t1 = System.currentTimeMillis();
            printJob.setPrintable(printImage);
             t2 = System.currentTimeMillis();
            System.out.println("Printable set in " + (t2 - t1)/1000 + " seconds !");
    
            if (printJob.printDialog()) {
              try {
                printJob.print();
              } catch (Exception PrintException) {
                PrintException.printStackTrace();
              }
            }
        }
    }); 
    

    }

My Questions

  1. It is literally taking more than 30 seconds every single time for the print Dialog to appear after " initiating print command" is printed onto the console. What is causing it ?
  2. Even upon clicking the "Print" button in the print Dialog its taking a minimum of 40-50 seconds before the print job is actually generated. Why is that ? ( I am printing 1 - 2 pages at the maximum )
  3. It takes mostly 3 - 6 seconds to get to beyond setPrintable() ( prev time = 0 seconds and Printable Set is = 3 - 6 seconds ) which means the statement printJob.printDialog() takes time . What could be causing it ?

  4. As evidenced by other questions , Java printing seems to be slow. If so , is there any other API for Page Printing in Java which I could use ?

  5. Even when I have added only one printableImage the function print() seems to be called multiple times ( 2-3 times) as evidenced by the "entered print command" on the console. Is it correct ?
  6. Eventhough the entire printDocument() is launched in a separate thread it HANGS MY APPLICATION . How can that happen. What am I doing wrong here ?
Swapnil B
  • 79
  • 1
  • 8
  • So, I trimmed back you code to something that was runnable, discard all the parts which weren't required. Loaded 177 images of varying sizes and pushed that through you timing code and for, 28s for loading the my images, 11ms for setting up the print job and 21ms for setting the printable, which suggests that there is something about the code which is missing that is causing the issues – MadProgrammer Sep 09 '18 at 09:00
  • Oh, and as for point 6, your `printDocument` is been run within the context of the Event Dispatching Thread, which is responsible for managing the event queue and paint requests, so yeah, if that's blocking, then your program will hang. Since you seems to be pulling data from the UI, I would not recommend trying to use a second thread anyway – MadProgrammer Sep 09 '18 at 09:01
  • 2. There are lots of reasons this might take time and post will come down to the underlying print service of the OS, the print drivers and the hardware – MadProgrammer Sep 09 '18 at 09:07
  • 3. Actually, it works pretty fast for me, but, this will also be dependent on number of underlying resources which need to be loaded by the Java system, on some systems, this work is delegated to the native print screens, but I would suspect that it's the time it takes to generate the native peer and get the event queue synced (if required) – MadProgrammer Sep 09 '18 at 09:09
  • 4. No - and I would suggest that Java's printing is no more slower then most other printing systems – MadProgrammer Sep 09 '18 at 09:11
  • 5. Yes. This is how printing works. Because the printer only has limited memory, your `print` method may be called a number of times before the whole jobs is complete. This is why it's very important, if you're performing "heavy" printing (like you are), that you optimise the printing path as much as possible, so you aren't recreating new objects or performing long running tasks unnecessarily – MadProgrammer Sep 09 '18 at 09:13
  • I also printed two pages to a PDF, each page required two "passes" and the overall process took under 17 seconds – MadProgrammer Sep 09 '18 at 09:13
  • 5. From the [JavaDocs](https://docs.oracle.com/javase/10/docs/api/java/awt/print/Printable.html) *"the Printable should expect multiple calls for a page index"* – MadProgrammer Sep 09 '18 at 09:23
  • Thank you so much @MadProgrammer for the review. Ia appreciate that. Looks like the OS was busy and that was causing majority of the delay. More so because I was running my project directly from Eclipse IDE which I imagine would be taking a huge chunk of RAM for its own threads! – Swapnil B Sep 10 '18 at 10:53
  • @MadProgrammer Still , it DOES take quite long to print and I read that its in the way Java scans for available printers. I found I had 3-4 printers on the system list. I deleted all the inactive ones and boom , the printDocument() hang time reduces drastically. Is there any work around to this? What if I can not delete other printers? – Swapnil B Sep 10 '18 at 10:55
  • @MadProgrammer I can surely let it run on the EDT but I was worried about the amount of time it got stuck there virtually paralysing my app.. – Swapnil B Sep 10 '18 at 10:56
  • @MadProgrammer I am using macos . Even after keeping only one printer on the system printers list its still taking 10-20 seconds in total. While on using the print command of say Pages app it takes like 4-6 seconds tops. – Swapnil B Sep 10 '18 at 10:57
  • @MadProgrammer Is there no other API for Print Dialog. I would be using Java printerjob. But I could use a seperate print dialog?(or do I probably need to create one ?) – Swapnil B Sep 10 '18 at 11:00
  • I'm running on MacOS and have no issues with the dialog appearing. It could be based on how information is gathered from the print service, but I've never had a significant enough issue to investigate it. No, there are no other print APIs you could use - you'd have to re-invent the entire while, all the way from the print dialogs to the spooling the print job itself – MadProgrammer Sep 10 '18 at 11:04
  • Have you considered trying the JavaFX print API? – MadProgrammer Sep 10 '18 at 11:09
  • @MadProgrammer okay. Nope. Do you think that would be faster ?(printing bufferedImages —> Image) – Swapnil B Sep 10 '18 at 13:11
  • I have absolutely no idea, but at least if there is actually an issue, it's more likely to be addressed – MadProgrammer Sep 10 '18 at 19:10
  • @MadProgrammer Printing Images is kind of tricky in javafx. I will give it a try sometime.For now , java printing seems damn slow. – Swapnil B Sep 16 '18 at 06:30

0 Answers0