/**
* Copyright 2013 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of JogAmp Community.
*/
package com.jogamp.opengl.test.junit.jogl.tile;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
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.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import com.jogamp.common.util.awt.AWTEDTExecutor;
import com.jogamp.nativewindow.awt.DirectDataBufferInt;
import com.jogamp.opengl.util.TileRenderer;
/**
* {@link Printable} implementation using NIO {@link DirectDataBufferInt} {@link BufferedImage}
* for offscreen rendered printing.
*
* @see OnscreenPrintable
* @see PrintableBase
*/
public class OffscreenPrintable extends PrintableBase implements Printable {
public final int imageType;
public final String pngFilename;
/**
*
* @param job
* @param printContainer
* @param printDPI
* @param numSamples multisampling value: < 0 turns off, == 0 leaves as-is, > 0 enables using given num samples
* @param tileWidth custom tile width for {@link TileRenderer#setTileSize(int, int, int) tile renderer}, pass -1 for default.
* @param tileHeight custom tile height for {@link TileRenderer#setTileSize(int, int, int) tile renderer}, pass -1 for default.
* @param imageType AWT BufferedImage type (must be one of the integer types)
* @param pngFilename TODO
*/
public OffscreenPrintable(final PrinterJob job, final Container printContainer, final int printDPI, final int numSamples, final int tileWidth, final int tileHeight, final int imageType, final String pngFilename) {
super(job, printContainer, printDPI, numSamples, tileWidth, tileHeight);
this.imageType = imageType;
this.pngFilename = pngFilename;
}
@Override
public int print(final Graphics g, final PageFormat pf, final int page) throws PrinterException {
if (page > 0) { // We have only one page, and 'page' is zero-based
return NO_SUCH_PAGE;
}
lockPrinting.lock();
try {
final Paper paper = pf.getPaper();
final double paperWWidthInch = paper.getWidth() / 72.0;
final double paperWHeightInch = paper.getHeight() / 72.0;
final double paperIWidthInch = paper.getImageableWidth() / 72.0;
final double paperIHeightInch = paper.getImageableHeight() / 72.0;
final double paperWWidthMM = paperWWidthInch * MM_PER_INCH;
final double paperWHeightMM = paperWHeightInch * MM_PER_INCH;
final double paperIWidthMM = paperIWidthInch * MM_PER_INCH;
final double paperIHeightMM = paperIHeightInch * MM_PER_INCH;
final double pfWWidthInch = pf.getWidth() / 72.0;
final double pfWHeightInch = pf.getHeight() / 72.0;
final double pfIWidthInch = pf.getImageableWidth() / 72.0;
final double pfIHeightInch = pf.getImageableHeight() / 72.0;
final double pfWWidthMM = pfWWidthInch * MM_PER_INCH;
final double pfWHeightMM = pfWHeightInch * MM_PER_INCH;
final double pfIWidthMM = pfIWidthInch * MM_PER_INCH;
final double pfIHeightMM = pfIHeightInch * MM_PER_INCH;
System.err.println("PF: Paper whole size "+
Math.round(paperWWidthMM)+" x "+Math.round(paperWHeightMM)+" mm, "+
Math.round(paperWWidthInch)+" x "+Math.round(paperWHeightInch)+" inch");
System.err.println("PF: Paper image size "+paper.getImageableX()+" / "+paper.getImageableY()+" "+
Math.round(paperIWidthMM)+" x "+Math.round(paperIHeightMM)+" mm, "+
Math.round(paperIWidthInch)+" x "+Math.round(paperIHeightInch)+" inch, "+
Math.round(paper.getImageableWidth())+"x"+Math.round(paper.getImageableHeight())+" 72dpi dots");
System.err.println("PF: Page whole size "+
Math.round(pfWWidthMM)+" x "+Math.round(pfWHeightMM)+" mm, "+
Math.round(pfWWidthInch)+" x "+Math.round(pfWHeightInch)+" inch");
System.err.println("PF: Page image size "+pf.getImageableX()+" / "+pf.getImageableY()+" "+
Math.round(pfIWidthMM)+" x "+Math.round(pfIHeightMM)+" mm, "+
Math.round(pfIWidthInch)+" x "+Math.round(pfIHeightInch)+" inch, "+
Math.round(pf.getImageableWidth())+"x"+Math.round(pf.getImageableHeight())+" 72dpi dots");
System.err.println("PF: Page orientation "+pf.getOrientation());
/**
* See: 'Scaling of Frame and GL content' in Class description!
* Note: Frame size contains the frame border (i.e. insets)!
*/
final Insets frameInsets = cont.getInsets();
final int frameWidth = cont.getWidth();
final int frameHeight= cont.getHeight();
final double scaleGraphics = dpi / 72.0;
final int frameSWidth = (int) ( frameWidth * scaleGraphics );
final int frameSHeight = (int) ( frameHeight * scaleGraphics );
final double scaleComp72;
{
final double sx = pf.getImageableWidth() / frameSWidth;
final double sy = pf.getImageableHeight() / frameSHeight;
scaleComp72 = Math.min(sx, sy);
}
System.err.println("PRINT.offscrn thread "+Thread.currentThread().getName());
System.err.println("PRINT.offscrn DPI: scaleGraphics "+scaleGraphics+", scaleComp72 "+scaleComp72);
System.err.println("PRINT.offscrn DPI: frame: border "+frameInsets+", size "+frameWidth+"x"+frameHeight+
" -> scaled "+frameSWidth+ "x" + frameSHeight);
final BufferedImage image = DirectDataBufferInt.createBufferedImage(frameSWidth, frameSHeight, imageType, null /* location */, null /* properties */);
{
System.err.println("PRINT.offscrn image "+image);
final Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setClip(0, 0, frameSWidth, frameSHeight);
g2d.scale(scaleGraphics, scaleGraphics);
// g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
AWTEDTExecutor.singleton.invoke(true, new Runnable() {
public void run() {
cont.printAll(g2d);
}
});
}
if( null != pngFilename ) {
final File fout = new File(pngFilename);
try {
ImageIO.write(image, "png", fout);
} catch (final IOException e) {
e.printStackTrace();
}
}
final Graphics2D g2d = (Graphics2D)g;
g2d.translate(pf.getImageableX(), pf.getImageableY());
g2d.scale(scaleComp72, scaleComp72);
g2d.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null); // Null ImageObserver since image data is ready.
/* tell the caller that this page is part of the printed document */
return PAGE_EXISTS;
} finally {
lockPrinting.unlock();
}
}
}