Search code examples
javaprintingstreambarcodebufferedimage

java.awt.Image.BufferedImage barcode sent to print results in whitespace


I'm using Barcode4J library to generate barcodes. I am returned a BufferedImage that I can display as an ImageIcon on a JLabel and save to a file but I can't for the life of me print it to a printer, the drawString and drawRect work as expected but the image is blank. I've posted some code below; I don't know how to make it a SSCCE of this but if anyone can point me in any direction I would be most grateful.

    snippet:
import org.krysalis.barcode4j.impl.code128.Code128Bean;
import org.krysalis.barcode4j.output.bitmap.BitmapCanvasProvider;
import org.krysalis.barcode4j.tools.UnitConv;


public class BarcodeBean extends Code128Bean implements Printable{

    BufferedImage _bImage;

    
    public void createBarcode2Print(BarcodeBean bean, String barcodeValue) throws FileNotFoundException, IOException {

        final int dpi = 150;
        
        BufferedImage image;
        BitmapCanvasProvider canvas = null;

        if (barcodeValue == null) {
            barcodeValue = "0123456789-000-0001";
        }
        
        bean.setModuleWidth(UnitConv.in2mm(2.0f / dpi));

        bean.doQuietZone(false);

        try {

            
            canvas = new BitmapCanvasProvider(
                    dpi, BufferedImage.TYPE_BYTE_BINARY, false, 0);
            

            //Generate the barcode
            bean.generateBarcode(canvas, barcodeValue);

            image = canvas.getBufferedImage();
            
            //Signal end of generation
        //    canvas.finish();
            
        } finally {
            
             canvas.finish();
        }

        
        printImage(image);
        
        int stop = 0;

    }
    
    public void printImage(BufferedImage arg_image){
        
        _bImage = arg_image;
        createLabel();
        
    }



    private void createLabel() {
        
        PrinterJob printJob = PrinterJob.getPrinterJob();
        Book book = new Book();
        
        PageFormat format = new PageFormat();
        
        format.setOrientation(PageFormat.PORTRAIT);
        
        java.awt.print.Paper paper = new java.awt.print.Paper();
        

        paper.setSize(612.0, 792.0); //portrait
        
        double hgt = paper.getHeight();
        double wdth = paper.getWidth();
        
        paper.setImageableArea(0, 0, wdth, hgt);
        
        format.setPaper(paper);
        
        book.append(this, format);
        
        printJob.setPageable(book);

            if (printJob.printDialog()) {
                try {

                    printJob.print();

                } catch (PrinterException ex) {

                    ex.printStackTrace();
                }
            }
   


}

    @Override
    public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
        
        Graphics2D graphics2d = (Graphics2D)graphics;
        graphics2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
        
        graphics.setColor(Color.black);
        graphics2d.setColor(Color.black);
        
        int imageWidth = _bImage.getWidth(null);    // 378
        int imageHeight = _bImage.getHeight(null);  // 110
        
        int imageableWidth = (int)pageFormat.getImageableWidth();   // 612
        int imageableHeight = (int)pageFormat.getImageableHeight(); // 792
        

        
        graphics2d.drawString("Print barcode between this and...", 10, 30);
        
        graphics2d.drawRect(10, 40, imageWidth, imageHeight);
        
        graphics2d.drawImage(_bImage, 10, 60, imageWidth, imageHeight, null);
                
        graphics2d.drawString("This.............................", 10, 180);
                
        graphics2d.dispose();
        return Printable.PAGE_EXISTS;
        
    }
        
}

Solution

  • I can't say I know why, it's possible that the Barcode4J is using their own implementation of BufferedImage or something, but, if I make a copy of the BufferedImage returned from Barcode4J, I can make it work.

    What I mean by that is, if I create a new instance of BufferedImage and draw the instance from Barcode4J onto it and use it, I can make it work...

    canvas = new BitmapCanvasProvider(
            dpi, BufferedImage.TYPE_BYTE_BINARY, false, 0);
    bean.generateBarcode(canvas, barcodeValue);
    BufferedImage bardcode = canvas.getBufferedImage();
    
    image = new BufferedImage(bardcode.getWidth(), bardcode.getHeight(), BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2d = image.createGraphics();
    g2d.drawImage(bardcode, 0, 0, null);
    g2d.dispose();
    

    graphics2d.dispose(); ← That might be the problem. Never dispose of a Graphics unless you created it.

    👆 is really good advice! Unfortunately, in this case it didn't help, but you should listen to it anyway!

    Also, this return Printable.PAGE_EXISTS;, could have you running around in circles. You need to tell the caller when there are no more pages to be printed.

    Runnable example...

    enter image description hereenter image description here

    import java.awt.Color;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.image.BufferedImage;
    import java.awt.print.PageFormat;
    import java.awt.print.Paper;
    import java.awt.print.Printable;
    import java.awt.print.PrinterException;
    import java.awt.print.PrinterJob;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import javax.swing.ImageIcon;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import org.krysalis.barcode4j.impl.code128.Code128Bean;
    import org.krysalis.barcode4j.output.bitmap.BitmapCanvasProvider;
    import org.krysalis.barcode4j.tools.UnitConv;
    
    public class Main {
    
        public static void main(String[] args) {
            new Main();
        }
    
        public Main() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    JFrame frame = new JFrame();
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            private BufferedImage barcodeImage;
    
            public TestPane() throws IOException {
                setLayout(new GridBagLayout());
                barcodeImage = createBarcode2Print(new Code128Bean(), "0123456789-000-0001");
    
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridwidth = GridBagConstraints.REMAINDER;
                add(new JLabel(new ImageIcon(barcodeImage)), gbc);
    
                JButton print = new JButton("Print");
                add(print, gbc);
    
                print.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        printIt();
                    }
                });
            }
    
            protected void printIt() {
                PrinterJob pj = PrinterJob.getPrinterJob();
                if (pj.printDialog()) {
                    PageFormat pf = pj.defaultPage();
                    Paper paper = pf.getPaper();
                    pf.setOrientation(PageFormat.PORTRAIT);
                    pf.setPaper(paper);
                    PageFormat validatePage = pj.validatePage(pf);
                    //                System.out.println("Valid- " + dump(validatePage));
                    pj.setPrintable(new BarCodePrintable(barcodeImage), validatePage);
                    try {
                        pj.print();
                    } catch (PrinterException ex) {
                        ex.printStackTrace();
                    }
                }
            }
    
        }
    
        public class BarCodePrintable implements Printable {
    
            private BufferedImage barcodeImage;
    
            public BarCodePrintable(BufferedImage barcodeImage) {
                this.barcodeImage = barcodeImage;
            }
    
            @Override
            public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
                Graphics2D graphics2d = (Graphics2D) graphics;
                graphics2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
    
                graphics.setColor(Color.black);
                graphics2d.setColor(Color.black);
    
                int imageWidth = barcodeImage.getWidth();    // 378
                int imageHeight = barcodeImage.getHeight();  // 110
    
                int imageableWidth = (int) pageFormat.getImageableWidth();   // 612
                int imageableHeight = (int) pageFormat.getImageableHeight(); // 792
    
                graphics2d.drawString("Print barcode between this and...", 10, 30);
    
                graphics2d.drawRect(10, 40, imageWidth, imageHeight);
    
                graphics2d.drawImage(barcodeImage, 10, 60, null);
    
                graphics2d.drawString("This.............................", 10, 180);
    
                //graphics2d.dispose();
                return pageIndex == 0 ? Printable.PAGE_EXISTS : Printable.NO_SUCH_PAGE;
            }
    
        }
    
        public BufferedImage createBarcode2Print(Code128Bean bean, String barcodeValue) throws FileNotFoundException, IOException {
            final int dpi = 300;
    
            BufferedImage image = null;
            BitmapCanvasProvider canvas = null;
    
            if (barcodeValue == null) {
                barcodeValue = "0123456789-000-0001";
            }
    
            bean.setModuleWidth(UnitConv.in2mm(2.0f / dpi));
            bean.doQuietZone(false);
    
            try {
                canvas = new BitmapCanvasProvider(
                        dpi, BufferedImage.TYPE_BYTE_BINARY, false, 0);
                bean.generateBarcode(canvas, barcodeValue);
                BufferedImage bardcode = canvas.getBufferedImage();
    
                image = new BufferedImage(bardcode.getWidth(), bardcode.getHeight(), BufferedImage.TYPE_INT_ARGB);
                Graphics2D g2d = image.createGraphics();
                g2d.drawImage(bardcode, 0, 0, null);
                g2d.dispose();
            } finally {
                canvas.finish();
            }
    
            return image;
        }
    }