Search code examples
javaswingprintinggraphics2d

Java Printing Graphics Uniformity


I am printing a number of rectangle that I draw on screen. The rectangles overlap so that it looks like a grid of rows and columns. Everything appears as expected on screen.

I've tried various ways to print (implementing printable), but I can't get the same quality.

  • Using JComponents print method is grainy (even with buffering off).
  • Redrawing directly to the print method Graphics object causes darker lines where rectangles overlap, and lighter lines where they do not (regardless of the alpha composite). I've tried various RenderingHints with this method.
  • Printing a constructed buffered image directly to the printing graphics gives consistent quality, but certain lines appear thicker than others so that an entire column or row would have one thick border along one side. Does anyone know why this might happen?

 

    @Override
    public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
        throws PrinterException {
    if(pageIndex > 2) {
        return Printable.NO_SUCH_PAGE;
    }

    RepaintManager currentManager = RepaintManager.currentManager(this);
    currentManager.setDoubleBufferingEnabled(false);

    Graphics2D g2d = (Graphics2D) graphics;
    g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
            RenderingHints.VALUE_RENDER_QUALITY);
    g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
            RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
            RenderingHints.VALUE_COLOR_RENDER_QUALITY);
    g2d.setRenderingHint(RenderingHints.KEY_DITHERING,
            RenderingHints.VALUE_DITHER_ENABLE);
    g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
            RenderingHints.VALUE_STROKE_NORMALIZE);
    g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
                                RenderingHints.VALUE_FRACTIONALMETRICS_ON);    

    g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
    g2d.scale(.5, .5);    
    if(pageIndex == 0) {
        this.paint(g2d);
    } else if(pageIndex == 1) {
        g2d.drawImage(onScreenBuffer, null, 0, 0);
    } else {
        g2d.setColor(new Color(51, 98, 140));
        g2d.setStroke(new BasicStroke(1f));
        //GridCell inherits from Rectangle2D.Double
        for (final GridCell cell : model.getCells()) {
            g2d.draw(cell);
        }
    }
    return Printable.PAGE_EXISTS;
}

Solution

  • I had pretty much the same problem. Can't recall all the details, but printing DPI is the main issue. You have to make sure you are printing using highest possible DPI, but not the screen DPI which is a default.

    (BTW, you will need to generate your graphics with the bigger DPI in mind).

    There is javax.print.attribute.standard.PrinterResolution:

    Class PrinterResolution is a printing attribute class that specifies an exact resolution supported by a printer or to be used for a print job. This attribute assumes that printers have a small set of device resolutions at which they can operate rather than a continuum.

    PrinterResolution is used in multiple ways:

    1. skipped
    2. When a client needs to print a job using the client's desired resolution exactly (no more, no less), the client specifies an instance of class PrinterResolution as an attribute of the Print Job. This will fail if the Print Job doesn't support that exact resolution, and Fidelity is set to true.

    There are a lot of examples available, for example: Printing to Hard-Printer in java with 300dpi