i currently have an issue with my printerjob, it works great for portrait images, but for landscape images, it cuts part of the image and fills in a white space instead.
This is my code
EDIT
PrintService printService = PrintServiceLookup.lookupDefaultPrintService();
BufferedImage bufferedImage = ImageIO.read(new File("house.jpg"));
boolean isLandscape = bufferedImage.getWidth() > bufferedImage.getHeight();
PrinterJob printerJob = PrinterJob.getPrinterJob();
printerJob.setPrintService(printService);
printerJob.setCopies(copies);
PageFormat pageFormat = printerJob.defaultPage();
pageFormat.setOrientation(isLandscape ? PageFormat.LANDSCAPE : PageFormat.PORTRAIT);
Paper paper = new Paper();
paper.setSize(pageFormat.getWidth(), pageFormat.getHeight());
paper.setImageableArea(0.0, 0.0, paper.getWidth(), paper.getHeight());
pageFormat.setPaper(paper);
printerJob.setPrintable(new Printable(){
@Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException{
if (pageIndex == 0) {
Graphics2D g2 = (Graphics2D)graphics;
double xScale = 1;
double xTranslate = 0;
double yScale = 1;
double yTranslate = 0;
double widthScale = (pageFormat.getImageableWidth() / bufferedImage.getWidth()) * xScale;
double heightScale = (pageFormat.getImageableHeight() / bufferedImage.getHeight()) * yScale;
AffineTransform affineTransform = AffineTransform.getScaleInstance(widthScale, heightScale);
affineTransform.translate(xTranslate, yTranslate);
g2.drawRenderedImage(bufferedImage, affineTransform);
g2.translate((int)pageFormat.getImageableX(), (int)pageFormat.getImageableY());
return PAGE_EXISTS;
}else return NO_SUCH_PAGE;
}
}, pageFormat);
printerJob.print();
This allows me to print portrait pictures to fit the given paper and without borders (fit to paper), i need it to do the same for landscape pictures please.
This are examples of what happens when i try with a portrait and landscape image so u see what i mean. The images should always fit to the paper size and borderless, which in this case is 10x15cm,
Portrait image:
Landscape image:
Don't use PageFormat#getWidth
or PageFormat#getHeight
, use PageFormat#getImageableWidth
and PageFormat#getImageableHeight
instead
From the JavaDocs
Return the height/width, in 1/72nds of an inch, of the imageable area of the page. This method takes into account the orientation of the page.
You should also translate the printer Graphics
by the ImageableX/Y
...
g2.translate((int)pageFormat.getImageableX(), (int)pageFormat.getImageableY());
Runnable example
This is a simple runnable example. This code was able to take the original (left) and print it both in portrait and landscape without issue...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
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 javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PrintTest100 {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
try {
PrinterJob pj = PrinterJob.getPrinterJob();
pj.setJobName(" Print Component ");
PageFormat pf = pj.defaultPage();
// pf.setOrientation(PageFormat.LANDSCAPE);
// pf = pj.validatePage(pf);
pj.setPrintable(new ImagePrintable(ImageIO.read(new File("..."))), pf);
if (!pj.printDialog()) {
return;
}
try {
pj.print();
} catch (PrinterException ex) {
ex.printStackTrace();
}
} catch (IOException exp) {
exp.printStackTrace();
}
}
});
}
public static class ImagePrintable implements Printable {
private int currentPage = -1;
private Image cachedScaledImage = null;
private BufferedImage master;
public ImagePrintable(BufferedImage master) {
this.master = master;
}
public double getScaleFactor(int iMasterSize, int iTargetSize) {
double dScale = 1;
if (iMasterSize > iTargetSize) {
dScale = (double) iTargetSize / (double) iMasterSize;
} else {
dScale = (double) iTargetSize / (double) iMasterSize;
}
return dScale;
}
public double getScaleFactorToFit(BufferedImage img, Dimension size) {
double dScale = 1;
if (img != null) {
int imageWidth = img.getWidth();
int imageHeight = img.getHeight();
dScale = getScaleFactorToFit(new Dimension(imageWidth, imageHeight), size);
}
return dScale;
}
public double getScaleFactorToFit(Dimension original, Dimension toFit) {
double dScale = 1d;
if (original != null && toFit != null) {
double dScaleWidth = getScaleFactor(original.width, toFit.width);
double dScaleHeight = getScaleFactor(original.height, toFit.height);
dScale = Math.min(dScaleHeight, dScaleWidth);
}
return dScale;
}
@Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
int result = Printable.NO_SUCH_PAGE;
if (pageIndex == 0) {
result = Printable.PAGE_EXISTS;
Graphics2D graphics2D = (Graphics2D) graphics;
graphics2D.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
int width = (int) Math.round(pageFormat.getImageableWidth());
int height = (int) Math.round(pageFormat.getImageableHeight());
if (currentPage != pageIndex || cachedScaledImage == null) {
currentPage = pageIndex;
double scaleFactor = getScaleFactorToFit(new Dimension(master.getWidth(), master.getHeight()), new Dimension(width, height));
int imageWidth = (int) Math.round(master.getWidth() * scaleFactor);
int imageHeight = (int) Math.round(master.getHeight() * scaleFactor);
cachedScaledImage = master.getScaledInstance(imageWidth, imageHeight, Image.SCALE_SMOOTH);
}
double x = ((pageFormat.getImageableWidth() - cachedScaledImage.getWidth(null)) / 2);
double y = ((pageFormat.getImageableHeight() - cachedScaledImage.getHeight(null)) / 2);
graphics2D.drawImage(cachedScaledImage, (int) x, (int) y, null);
graphics2D.setColor(Color.RED);
graphics2D.drawRect(0, 0, width - 1, height - 1);
}
return result;
}
}
}
nb: I had an issue with Yosemite, trying to figure out how to change the print orientation from the dialog, in the end, I gave up and forced it by changing the PageFormat
from the PrintJob
. I've used this same type of code in countless applications without issues before...
Updated
Original Image: 1920x1200