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
Related
I am printing tickets with a thermal printer, but when the content is very long, exceeding 9'', the printing is cut off and the receipt comes out without all the content, being 9'' more or less the maximum length that the receipt comes out. printed paper.
I have tried to change the different values of the paper in its height, but the result is always the same. I do not know what to do. Please help
package com.printer.Utils;
import com.printer.Entities.Branch;
import com.printer.Entities.Journal;
import com.printer.Entities.ProductOrder;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
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.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.List;
public class PaintReceipt implements Printable {
public PaintReceipt() {
}
public PageFormat getPageFormat(PrinterJob pj) {
PageFormat pf = pj.defaultPage();
Paper paper = pf.getPaper();
double bodyHeight = bHeight;
double headerHeight = 5.0;
double footerHeight = 5.0;
double width = cm_to_pp(8);
double height = cm_to_pp(200000);
paper.setSize(width, height);
paper.setImageableArea(0, 5, width, height- cm_to_pp(1));
pf.setOrientation(PageFormat.PORTRAIT);
pf.setPaper(paper);
return pf;
}
protected static double cm_to_pp(double cm) {
return toPPI(cm * 0.393600787);
}
protected static double toPPI(double inch) {
return inch * 72d;
}
#Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
throws PrinterException {
int result = NO_SUCH_PAGE;
if (pageIndex == 0) {
Graphics2D g2d = (Graphics2D) graphics;
g2d.translate((int) pageFormat.getImageableX(), (int) pageFormat.getImageableY() +pageFormat.getImageableY());
try {
int y = 20;
int yShift = 10;
int yShiftMin = 8;
int headerRectHeight = 15;
g2d.setFont(new Font("Monospaced", Font.BOLD, 9));
//g2d.drawImage(icon.getImage(), 50, 20, 90, 30, rootPane);y+=yShift+30;
g2d.drawString("--------------------------------------", 0, y);
y += yShift;
g2d.drawString(" Fecha/Hora", 0, y);
y += yShift;
g2d.drawString(" " + dateCreate + "", 0, y);
} catch (Exception e) {
e.printStackTrace();
}
result = PAGE_EXISTS;
}
return result;
}
}
Here I instantiate the class, in getPageFormat set the size of the paper and command to print
public void PrintPDF() {
try {
PrintService myPrintService = findPrintService("RONGTAPrinter");
PaintReceipt receipt = new PaintReceipt();
PrinterJob pj = PrinterJob.getPrinterJob();
pj.setPrintService(myPrintService);
//Get format page
pj.setPrintable(receipt, receipt.getPageFormat(pj));
DocPrintJob job = myPrintService.createPrintJob();
PrintJobWatcher pjDone = new PrintJobWatcher(job);
pj.print();
} catch (PrinterException e) {
e.printStackTrace();
}
}
I am working on an app to control Parrot Ar.Drone 2.0 using Javadrone API and library.
I am able to connect into drone and make it take off/land successfully. There are 2 java files : DroneTestVideo.java, VideoPanel.java.
The DroneTestVideo.java file is responsible for connecting into drone and get data, while VideoPanel.java file serves as set images.
Javadrone API can be download here.
However, I have no idea why I'failing to get live images from drone. It just show me a black screen with the words:
"No video connection"
Here is my code:
DroneTestVideo.java
package dronetest;
import com.codeminders.ardrone.ARDrone;
import com.codeminders.ardrone.ARDrone.VideoChannel;
import com.codeminders.ardrone.DroneStatusChangeListener;
import com.codeminders.ardrone.NavData;
import com.codeminders.ardrone.NavDataListener;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class DroneTestVideo extends javax.swing.JFrame implements DroneStatusChangeListener, NavDataListener{
private static final long CONNECT_TIMEOUT = 10000L;
private ARDrone drone;
private final VideoPanel video = new VideoPanel();
public DroneTestVideo() {
initComponents();
initDrone();
videoPanel.add(video);
takeoff();
}
private void initDrone() {
try{
drone = new ARDrone();
drone.addStatusChangeListener(this);
drone.addStatusChangeListener(new DroneStatusChangeListener() {
public void ready() {
org.apache.log4j.Logger.getLogger(getClass().getName()).debug("updateLoop::ready()");
}
});
System.err.println("Configure");
drone.selectVideoChannel(ARDrone.VideoChannel.HORIZONTAL_ONLY);
drone.setCombinedYawMode(true);
drone.enableAutomaticVideoBitrate();
System.err.println("Connecting to the drone");
drone.connect();
drone.waitForReady(CONNECT_TIMEOUT);
drone.clearEmergencySignal();
System.err.println("Connected to the drone");
} catch (IOException ex) {
Logger.getLogger(DroneTestVideo.class.getName()).log(Level.SEVERE, null,ex);
}
drone.addNavDataListener(this);
video.setDrone(drone);
}
private void takeoff()
{
try {
System.err.println("**********\nTRIM\n**********");
drone.trim();
Thread.sleep(2000);
System.err.println("**********\nTAKEOFF\n**********");
drone.takeOff();
Thread.sleep(7000);
drone.land();
} catch (IOException ex) {
Logger.getLogger(DroneTestVideo.class.getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
Logger.getLogger(DroneTestVideo.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new DroneTestVideo().setVisible(true);
}
});
}
}
VideoPanel.java
package dronetest;
import com.codeminders.ardrone.ARDrone;
import com.codeminders.ardrone.DroneVideoListener;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
public class VideoPanel extends javax.swing.JPanel implements DroneVideoListener{
private AtomicReference<BufferedImage> image = new AtomicReference<BufferedImage>();
private AtomicBoolean preserveAspect = new AtomicBoolean(true);
private BufferedImage noConnection = new BufferedImage(320, 240, BufferedImage.TYPE_INT_RGB);
public VideoPanel() {
initComponents();
Graphics2D g2d = (Graphics2D) noConnection.getGraphics();
Font f = g2d.getFont().deriveFont(24.0f);
g2d.setFont(f);
g2d.drawString("No video connection", 40, 110);
image.set(noConnection);
}
public void setDrone(ARDrone drone) {
drone.addImageListener(this);
System.err.println("setDrone function here!");
}
public void setPreserveAspect(boolean preserve) {
preserveAspect.set(preserve);
}
public void frameReceived(BufferedImage im) {
image.set(im);
repaint();
}
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int width = getWidth();
int height = getHeight();
drawDroneImage(g2d, width, height);
}
private void drawDroneImage(Graphics2D g2d, int width, int height) {
BufferedImage im = image.get();
if (im == null) {
return;
}
int xPos = 0;
int yPos = 0;
if (preserveAspect.get()) {
g2d.setColor(Color.BLACK);
g2d.fill3DRect(0, 0, width, height, false);
float widthUnit = ((float) width / 4.0f);
float heightAspect = (float) height / widthUnit;
float heightUnit = ((float) height / 3.0f);
float widthAspect = (float) width / heightUnit;
if (widthAspect > 4) {
xPos = (int) (width - (heightUnit * 4)) / 2;
width = (int) (heightUnit * 4);
} else if (heightAspect > 3) {
yPos = (int) (height - (widthUnit * 3)) / 2;
height = (int) (widthUnit * 3);
}
}
if (im != null) {
g2d.drawImage(im, xPos, yPos, width, height, null);
}
}
}
You are not updating your screen, so no new calls to drawDroneImage will be called into the VideoPanel.
You should set a loop to refresh the JPanel (call it repaint()).
And more, you need to implement DoubleBuffering Strategies to get a smoother image transaction.
I have a JPictureBox extends from a java.awt.Component see code here http://pastebin.com/SAJc6Sht. But it only works well when there is no image stretching. Especially for the big picture, it slows program dramatically. How to increase drawing speed of JPictureBox for large image?
#Override
public void paint(Graphics g) {
super.paint(g);
int x = 0;
int y = 0;
int w = 0;
int h = 0;
if (image != null) {
switch (sizeMode) {
case AUTO_SIZE:
case NORMAL:
w = image.getWidth();
h = image.getHeight();
break;
case CENTER_IMAGE:
w = image.getWidth();
h = image.getHeight();
x = (getWidth() - w) / 2;
y = (getHeight() - h) / 2;
break;
case STRETCH_IMAGE:
w = getWidth();
h = getHeight();
break;
case ZOOM:
w = (int) Math.round(image.getWidth() * zoomFactor);
h = (int) Math.round(image.getHeight() * zoomFactor);
break;
case FIT_BOTH:
if (image.getWidth() > image.getHeight()) {
w = getWidth();
h = (int) (w / getAR());
if (h > getHeight()) {
h = getHeight();
w = (int) (h * getAR());
}
} else {
h = getHeight();
w = (int) (h * getAR());
if (w > getWidth()) {
w = getWidth();
h = (int) (w / getAR());
}
}
break;
case FIT_WIDTH:
w = getWidth();
h = (int) (w / getAR());
break;
case FIT_HEIGHT:
h = getHeight();
w = (int) (h * getAR());
break;
}
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2d.drawImage(image, x, y, w, h, this);
} else if (errorIcon != null) {
w = errorIcon.getIconWidth();
h = errorIcon.getIconHeight();
x = (getWidth() - w) / 2;
y = (getHeight() - h) / 2;
errorIcon.paintIcon(this, g, x, y);
}
}
Basically, you want to off load the scaling of the image to a background thread, scaling is time consuming and you don't want to do within the context of the Event Dispatching Thread.
This then raises a few more issues. You don't want to scale the image until you really have to to and you really only want the latest result.
Instead of trying to scale the image on EVERY change, you can setup a small, single repeat timer which you reset each time you want to make a change. This will consolidate the multiple resize requests down to as few requests as possible. This example uses a javax.swing.Timer set to a short 125 millisecond delay. So it will wait at least 125 milliseconds between requests for a change before actually triggering the update.
Next, it uses a ExecutorService set up with a single thread. This provides us with the means to "attempt" to cancel any pre-existing operations, as we don't want there result and start our latest request.
Next, the actual scaling operation employs a two step scale, first, it tries to do a fast, low quality scale which can be put on the screen quickly and then performs a slower, high quality scale which is updated at some time in the future...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.Scrollable;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(new TestPane()));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel implements Scrollable {
private BufferedImage master;
private Image scaled;
private double zoom = 1d;
private ExecutorService service;
private List<Future> scaleTasks;
private final Timer zoomTimer;
public TestPane() {
scaleTasks = new ArrayList<>(5);
service = Executors.newSingleThreadExecutor();
try {
master = ImageIO.read(new File("Some image some where"));
scaled = master;
} catch (IOException ex) {
ex.printStackTrace();
}
zoomTimer = new Timer(125, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Update Zoom to " + getZoom());
updateToZoomFactor(getZoom());
}
});
zoomTimer.setRepeats(false);
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "plus");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "minus");
am.put("plus", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
double zoom = getZoom() + 0.1;
setZoom(zoom);
}
});
am.put("minus", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
double zoom = getZoom() - 0.1;
setZoom(zoom);
}
});
}
#Override
public Dimension getPreferredSize() {
return scaled == null
? new Dimension(master.getWidth(), master.getHeight())
: new Dimension(scaled.getWidth(this), scaled.getHeight(this));
}
public BufferedImage getMaster() {
return master;
}
public void setZoom(double value) {
if (value < 0.1) {
value = 0.1;
} else if (value > 2) {
value = 2d;
}
if (value != zoom) {
zoom = value;
zoomTimer.restart();
}
}
public double getZoom() {
return zoom;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (scaled != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - scaled.getWidth(this)) / 2;
int y = (getHeight() - scaled.getHeight(this)) / 2;
g2d.drawImage(scaled, x, y, this);
g2d.dispose();
}
}
protected void setScaledResult(final Image image) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
scaled = image;
invalidate();
revalidate();
repaint();
}
});
}
protected void updateToZoomFactor(double zoom) {
Future[] tasks = scaleTasks.toArray(new Future[scaleTasks.size()]);
for (Future task : tasks) {
if (!task.isCancelled()) {
task.cancel(true);
} else {
scaleTasks.remove(task);
}
}
service.submit(new RescaleTask(zoom));
}
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(400, 400);
}
#Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return 128;
}
#Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return 128;
}
#Override
public boolean getScrollableTracksViewportWidth() {
return false;
}
#Override
public boolean getScrollableTracksViewportHeight() {
return false;
}
protected class RescaleTask implements Callable<Image> {
private double zoom;
protected RescaleTask(double zoom) {
this.zoom = zoom;
}
#Override
public Image call() throws Exception {
if (zoom == 1) {
scaled = getMaster();
} else {
int width = (int) (getMaster().getWidth() * zoom);
int height = (int) (getMaster().getHeight() * zoom);
Image scaled = getMaster().getScaledInstance((int) width, (int) height, Image.SCALE_FAST);
if (!Thread.currentThread().isInterrupted()) {
setScaledResult(scaled);
if (zoom < 1) {
scaled = getScaledDownInstance(getMaster(), (int) width, (int) height);
} else {
scaled = getScaledUpInstance(getMaster(), (int) width, (int) height);
}
if (!Thread.currentThread().isInterrupted()) {
setScaledResult(scaled);
} else {
System.out.println("Was interrupted during quality scale");
}
} else {
System.out.println("Was interrupted during fast scale");
}
}
return scaled;
}
protected BufferedImage getScaledDownInstance(BufferedImage img,
int targetWidth,
int targetHeight) {
int type = (img.getTransparency() == Transparency.OPAQUE)
? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
if (targetHeight > 0 || targetWidth > 0) {
int w = img.getWidth();
int h = img.getHeight();
do {
System.out.println(w + "x" + h + " -> " + targetWidth + "x" + targetHeight);
if (w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(Math.max(w, 1), Math.max(h, 1), type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
} while (w != targetWidth || h != targetHeight);
} else {
ret = new BufferedImage(1, 1, type);
}
return ret;
}
protected BufferedImage getScaledUpInstance(BufferedImage img,
int targetWidth,
int targetHeight) {
int type = BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
int w = img.getWidth();
int h = img.getHeight();
do {
if (w < targetWidth) {
w *= 2;
if (w > targetWidth) {
w = targetWidth;
}
}
if (h < targetHeight) {
h *= 2;
if (h > targetHeight) {
h = targetHeight;
}
}
// createCompatibleImage(w, h, type)
BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
tmp = null;
} while (w != targetWidth || h != targetHeight);
return ret;
}
}
}
}
nb: This is little over kill, but demonstrates some key ideas
One of the other things that might help is to convert the image to a compatible color model for the GraphicsDevice, for example...
master = ImageIO.read(new File("Some image some where"));
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
BufferedImage compatible = gc.createCompatibleImage(master.getWidth(), master.getHeight(), Transparency.TRANSLUCENT);
Graphics2D g2d = compatiable.createGraphics();
g2d.drawImage(master, 0, 0, this);
g2d.dispose();
master = compatible;
I have searched for a while on the internet but I didn't find any solution for my problem.
I know that you can get the current mouse position with
PointerInfo a = MouseInfo.getPointerInfo();
Point b = a.getLocation();
The problem is in a multi environment screen I am just getting the mouse position relative to the main screen. Which means if the second screen is to the left of the main screen I receive for example X: -917.0 Location Y: -137.0. I know that these values depend on the screen resolution and the order of the monitors.
Is there any possibility to obtain the mouse position on the current active screen?
Kind regards
Basically, what I did was take the PointerInfo and subtract the GraphicsDevice bounds from it, if the result was less the 0 (because the screen was left of the main screen), I multiplied the result by -1
The heart of the solution looks like this...
// Pointer info
PointerInfo pi = MouseInfo.getPointerInfo();
Point mp = pi.getLocation();
// The devices bounds
Rectangle bounds = getDeviceBounds(pi.getDevice());
// Create new "virtual" point based on the mouse point
virtualPoint = new Point(mp);
// Subtract the x/y position of the device
virtualPoint.x -= bounds.x;
virtualPoint.y -= bounds.y;
// Clip negative values...
if (virtualPoint.x < 0) {
virtualPoint.x *= -1;
}
if (virtualPoint.y < 0) {
virtualPoint.y *= -1;
}
The following example shows the actual desktop mouse position (as reported by MouseInfo) on the first line and the second line shows the "screen" position within the context of the GraphicsDevice
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class WheresMyMouse {
public static void main(String[] args) {
new WheresMyMouse();
}
public WheresMyMouse() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private double scale;
private List<Rectangle> screenBounds;
private Point virtualPoint;
private Point screenPoint;
public TestPane() {
screenBounds = getScreenBounds();
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
PointerInfo pi = MouseInfo.getPointerInfo();
Point mp = pi.getLocation();
Rectangle bounds = getDeviceBounds(pi.getDevice());
screenPoint = new Point(mp);
virtualPoint = new Point(mp);
virtualPoint.x -= bounds.x;
virtualPoint.y -= bounds.y;
if (virtualPoint.x < 0) {
virtualPoint.x *= -1;
}
if (virtualPoint.y < 0) {
virtualPoint.y *= -1;
}
repaint();
}
});
timer.start();
}
#Override
public void invalidate() {
super.invalidate();
Rectangle virtualBounds = getVirtualBounds();
scale = getScaleFactorToFit(virtualBounds.getSize(), getSize());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int xOffset = 0;
int yOffset = 0;
List<Rectangle> scaledBounds = new ArrayList<>(screenBounds.size());
for (Rectangle bounds : screenBounds) {
bounds = scale(bounds);
scaledBounds.add(bounds);
if (bounds.x < xOffset) {
xOffset = bounds.x;
}
if (bounds.y < yOffset) {
yOffset = bounds.y;
}
}
if (xOffset < 0) {
xOffset *= -1;
}
if (yOffset < 0) {
yOffset *= -1;
}
for (Rectangle bounds : scaledBounds) {
bounds.x += xOffset;
bounds.y += xOffset;
g2d.setColor(Color.DARK_GRAY);
g2d.fill(bounds);
g2d.setColor(Color.GRAY);
g2d.draw(bounds);
}
FontMetrics fm = g2d.getFontMetrics();
g2d.setColor(Color.WHITE);
if (screenPoint != null) {
int x = 0;
int y = fm.getAscent();
g2d.drawString(screenPoint.toString(), x, y);
screenPoint.x += xOffset;
screenPoint.y += yOffset;
screenPoint.x *= scale;
screenPoint.y *= scale;
g2d.fillOval(screenPoint.x - 2, screenPoint.y - 2, 4, 4);
}
if (virtualPoint != null) {
int x = 0;
int y = fm.getAscent() + fm.getHeight();
g2d.drawString(virtualPoint.toString(), x, y);
}
g2d.dispose();
}
protected Rectangle scale(Rectangle bounds) {
Rectangle scaled = new Rectangle(bounds);
scaled.x *= scale;
scaled.y *= scale;
scaled.width *= scale;
scaled.height *= scale;
return scaled;
}
}
public static Rectangle getScreenBoundsAt(Point pos) {
GraphicsDevice gd = getGraphicsDeviceAt(pos);
Rectangle bounds = null;
if (gd != null) {
bounds = gd.getDefaultConfiguration().getBounds();
}
return bounds;
}
public List<Rectangle> getScreenBounds() {
List<Rectangle> bounds = new ArrayList<>(25);
GraphicsDevice device = null;
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice lstGDs[] = ge.getScreenDevices();
ArrayList<GraphicsDevice> lstDevices = new ArrayList<GraphicsDevice>(lstGDs.length);
for (GraphicsDevice gd : lstGDs) {
GraphicsConfiguration gc = gd.getDefaultConfiguration();
Rectangle screenBounds = gc.getBounds();
bounds.add(screenBounds);
}
return bounds;
}
public static Rectangle getDeviceBounds(GraphicsDevice device) {
GraphicsConfiguration gc = device.getDefaultConfiguration();
Rectangle bounds = gc.getBounds();
return bounds;
}
public static GraphicsDevice getGraphicsDeviceAt(Point pos) {
GraphicsDevice device = null;
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice lstGDs[] = ge.getScreenDevices();
ArrayList<GraphicsDevice> lstDevices = new ArrayList<GraphicsDevice>(lstGDs.length);
for (GraphicsDevice gd : lstGDs) {
Rectangle screenBounds = getDeviceBounds(gd);
if (screenBounds.contains(pos)) {
lstDevices.add(gd);
}
}
if (lstDevices.size() == 1) {
device = lstDevices.get(0);
}
return device;
}
public static Rectangle getVirtualBounds() {
Rectangle bounds = new Rectangle(0, 0, 0, 0);
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice lstGDs[] = ge.getScreenDevices();
for (GraphicsDevice gd : lstGDs) {
bounds.add(getDeviceBounds(gd));
}
return bounds;
}
public static double getScaleFactor(int iMasterSize, int iTargetSize) {
double dScale = 1;
dScale = (double) iTargetSize / (double) iMasterSize;
return dScale;
}
public static 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;
}
}
private Point mousePosition ()
{
final PointerInfo pi = MouseInfo.getPointerInfo ();
final Point mp = pi.getLocation ();
SwingUtilities.convertPointFromScreen (mp, this);
return mp;
}
I would like to know if there is a proper way of printing a BufferedImage in Java.
Basically I have created a photo manipulation program which works fine, I can save images etc.
But my real goal is to send it to the printer software so that you can select the amount of pages you want to print and page type.
So my shortened question is, how do I send a buffered image to the printer so that a printer selection screen will popup etc and then be able to print?
If anyone can show me an example of this, it would be greatly appreciated.
Here's one from one of my Java projects. This code will scale and print one image on a printer page.
You call it like this:
printButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
//Start a Thread
new Thread(new PrintActionListener(image)).start();
}
});
Here's the Runnable:
import java.awt.Graphics;
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;
public class PrintActionListener implements Runnable {
private BufferedImage image;
public PrintActionListener(BufferedImage image) {
this.image = image;
}
#Override
public void run() {
PrinterJob printJob = PrinterJob.getPrinterJob();
printJob.setPrintable(new ImagePrintable(printJob, image));
if (printJob.printDialog()) {
try {
printJob.print();
} catch (PrinterException prt) {
prt.printStackTrace();
}
}
}
public class ImagePrintable implements Printable {
private double x, y, width;
private int orientation;
private BufferedImage image;
public ImagePrintable(PrinterJob printJob, BufferedImage image) {
PageFormat pageFormat = printJob.defaultPage();
this.x = pageFormat.getImageableX();
this.y = pageFormat.getImageableY();
this.width = pageFormat.getImageableWidth();
this.orientation = pageFormat.getOrientation();
this.image = image;
}
#Override
public int print(Graphics g, PageFormat pageFormat, int pageIndex)
throws PrinterException {
if (pageIndex == 0) {
int pWidth = 0;
int pHeight = 0;
if (orientation == PageFormat.PORTRAIT) {
pWidth = (int) Math.min(width, (double) image.getWidth());
pHeight = pWidth * image.getHeight() / image.getWidth();
} else {
pHeight = (int) Math.min(width, (double) image.getHeight());
pWidth = pHeight * image.getWidth() / image.getHeight();
}
g.drawImage(image, (int) x, (int) y, pWidth, pHeight, null);
return PAGE_EXISTS;
} else {
return NO_SUCH_PAGE;
}
}
}
}