2

as I googled for problem, somehow java printing API is crippled with limitation that all pictures sent to printer must be printed in 72dpi resolution. We are using jasper report to print documents and no matter how big barcode we draw, barcode reader won't scan it.. any similar experiences? How to solve this issue?

  • 1
    We are using jasper reports as well in conjunction with barcode4j (instead of the included barbecue). We are not experiencing the problems you have. Maybe you could attach a scanned image of the printer output. Is the generated PDF crappy as well? – Tobias Schulte Jan 13 '09 at 07:57
  • I do not handle all the details right now; we are not generating PDF (although it is also posible) - from JasperViewer generated page is being sent to laser printer directly. We need 2D barcode (PDF-417), but our scanner would not scan normal EAN13 barcode as well as before mentioned. –  Jan 15 '09 at 12:42

2 Answers2

4

You need to specify the printer resolution by means of attribute PrinterResolution. You should also know the source resolution so it is correctly converted such as:

PrinterResolution pr = new PrinterResolution(300, 300, PrinterResolution.DPI);
Fernando Miguélez
  • 11,196
  • 6
  • 36
  • 54
1

Java sets the image's DPI to the default java 72dpi if there is no previously defined DPI in image's meta data, so it is not enough to add MediaSizeName, PrinterResolution, MediaPrintableArea attributes to get the best results, you have also to add image's dpi in its meta data, as such way in this answer's methods example : https://stackoverflow.com/a/4833697/8792371 :

 private void setDPI(IIOMetadata metadata) throws IIOInvalidTreeException {

    // for PMG, it's dots per millimeter
    double dotsPerMilli = 1.0 * DPI / 10 / INCH_2_CM;

    IIOMetadataNode horiz = new IIOMetadataNode("HorizontalPixelSize");
    horiz.setAttribute("value", Double.toString(dotsPerMilli));

    IIOMetadataNode vert = new IIOMetadataNode("VerticalPixelSize");
    vert.setAttribute("value", Double.toString(dotsPerMilli));

    IIOMetadataNode dim = new IIOMetadataNode("Dimension");
    dim.appendChild(horiz);
    dim.appendChild(vert);

    IIOMetadataNode root = new IIOMetadataNode("javax_imageio_1.0");
    root.appendChild(dim);

    metadata.mergeTree("javax_imageio_1.0", root);
 }

, then assure the rest of attributes to print in the desired printable area, for example :

        DocFlavor myFormat = DocFlavor.INPUT_STREAM.PNG;
        // Build a set of attributes
        PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();    
        aset.add(MediaSizeName.ISO_A10);  
        aset.add(new MediaPrintableArea(0, 0, 35, 24, MediaPrintableArea.MM));
        aset.add(PrintQuality.HIGH);
        aset.add(new PrinterResolution(203, 203, PrinterResolution.DPI));
        // adding other attributes
        aset.add(OrientationRequested.PORTRAIT);
        aset.add(new Copies(7));
        aset.add(Fidelity.FIDELITY_TRUE);

For more complete example :

import java.awt.EventQueue;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOInvalidTreeException;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.ImageOutputStream;
import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.ServiceUI;
import javax.print.SimpleDoc;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import static javax.print.attribute.ResolutionSyntax.DPI;
import javax.print.attribute.standard.Copies;
import javax.print.attribute.standard.Fidelity;
import javax.print.attribute.standard.MediaPrintableArea;
import javax.print.attribute.standard.MediaSizeName;
import javax.print.attribute.standard.OrientationRequested;
import javax.print.attribute.standard.PrintQuality;
import javax.print.attribute.standard.PrinterResolution;
import javax.print.event.PrintJobEvent;
import javax.print.event.PrintJobListener;
import javax.print.event.PrintServiceAttributeEvent;



public class PNGPrintingExample {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

        EventQueue.invokeLater(() -> {

            try {


                FileInputStream imageFile = null;



                imageFile = new FileInputStream("E:\\1-and-2-1.png");

                BufferedImage input = ImageIO.read(imageFile);
                File output = new File("E:\\To-Be-Printed.png");
                saveGridImage(output,input);

                imageFile = new FileInputStream(output);

                // Set the document type
                DocFlavor myFormat = DocFlavor.INPUT_STREAM.PNG;
                // Build a set of attributes
                PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet(); 

                // setting media size and printing media attributes
                aset.add(MediaSizeName.ISO_A10);  
                aset.add(new MediaPrintableArea(0, 0, 35, 24, MediaPrintableArea.MM));
                aset.add(PrintQuality.HIGH);
                aset.add(new PrinterResolution(203, 203, PrinterResolution.DPI));

                // adding some may be needed attibutes
                aset.add(OrientationRequested.PORTRAIT);
                aset.add(new Copies(7));
                aset.add(Fidelity.FIDELITY_TRUE);

                        DocPrintJob job;
                        Doc myDoc = new SimpleDoc(imageFile, myFormat, null);
                        PrintService[] services =
                                PrintServiceLookup.lookupPrintServices(myFormat, null);
                        PrintService defaultPrintService = PrintServiceLookup
                           .lookupDefaultPrintService();     
                        PrintService selectedPrintService =
                           ServiceUI.printDialog(null, 150, 150,
                           services, defaultPrintService, myFormat, aset);
                        if(selectedPrintService!=null)
                        {
                           System.out.println("selected printer:"
                              +selectedPrintService.getName());

                                    try {

                                        job = selectedPrintService.createPrintJob();
                                        // Create a Doc

                                        PrintJobListener pjlForP = new PrintJobListener() {

                                            public void attributeUpdate(PrintServiceAttributeEvent e){
                                                System.out.println("updated");
                                            }

                                            @Override
                                            public void printJobNoMoreEvents(PrintJobEvent e){
                                                System.out.println("may be sent to "+e.getPrintJob().getPrintService());
                                            }

                                            @Override
                                            public void printDataTransferCompleted(PrintJobEvent pje) {
                                                System.out.println("print Data Transfer Completed");
                                            }

                                            @Override
                                            public void printJobCompleted(PrintJobEvent pje) {
                                                System.out.println("The print job was completed");
                                            }

                                            @Override
                                            public void printJobFailed(PrintJobEvent pje) {
                                                System.out.println("The print job has failed");
                                            }

                                            @Override
                                            public void printJobCanceled(PrintJobEvent pje) {
                                                System.out.println("The print job was cancelled");
                                            }

                                            @Override
                                            public void printJobRequiresAttention(PrintJobEvent pje) {
                                                System.out.println("The print job require attention");
                                            }
                                        };                                        


                                        job.addPrintJobListener(pjlForP);
                                        job.print(myDoc, aset);

                                        imageFile.close();

                                    } catch (PrintException ex) {
                                        Logger.getLogger(BarcodePrintingFromJava.class.getName()).log(Level.SEVERE, null, ex);
                                    }                           


                        }
                        else
                           System.out.println("selection cancelled");                        


            } catch (FileNotFoundException ex) {
                Logger.getLogger(BarcodePrintingFromJava.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(BarcodePrintingFromJava.class.getName()).log(Level.SEVERE, null, ex);
            }
         });



    }


    public static void saveGridImage(File output,BufferedImage gridImage) throws IOException {
       output.delete();

       final String formatName = "png";

       for (Iterator<ImageWriter> iw = ImageIO.getImageWritersByFormatName(formatName); iw.hasNext();) {
          ImageWriter writer = iw.next();
          ImageWriteParam writeParam = writer.getDefaultWriteParam();
          ImageTypeSpecifier typeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
          IIOMetadata metadata = writer.getDefaultImageMetadata(typeSpecifier, writeParam);
          if (metadata.isReadOnly() || !metadata.isStandardMetadataFormatSupported()) {
             continue;
          }

          setDPI(metadata);

          final ImageOutputStream stream = ImageIO.createImageOutputStream(output);
          try {
             writer.setOutput(stream);
             writer.write(metadata, new IIOImage(gridImage, null, metadata), writeParam);
          } finally {
             stream.close();
          }
          break;
       }
    }

    public static void setDPI(IIOMetadata metadata) throws IIOInvalidTreeException {

       // for PNG, it's dots per millimeter
       double dotsPerMilli = 1.0 * DPI / 10 / 2.54;

       IIOMetadataNode horiz = new IIOMetadataNode("HorizontalPixelSize");
       horiz.setAttribute("value", Double.toString(dotsPerMilli));

       IIOMetadataNode vert = new IIOMetadataNode("VerticalPixelSize");
       vert.setAttribute("value", Double.toString(dotsPerMilli));

       IIOMetadataNode dim = new IIOMetadataNode("Dimension");
       dim.appendChild(horiz);
       dim.appendChild(vert);

       IIOMetadataNode root = new IIOMetadataNode("javax_imageio_1.0");
       root.appendChild(dim);

       metadata.mergeTree("javax_imageio_1.0", root);
    }    

}

You may try to comment or delete the image's dpi setting lines, or saving in a defined dpi method's lines, and then do a print job through your printer, to gain the difference, and notion the value of defining the dpi in the image's meta data, and how java would react with dpi definition in the image's meta data.