I am trying to take severial jpg images with the same dimensions(30*30) and create a single image. Like this:
Image i = new BufferedImage(30, 30, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = (Graphics2D) i.getGraphics();
if (this instanceof Node) {
Image img;
img = getImageFromFile(Node.icon);
g2.drawImage(img, 0, 0, null);
}
if(this instanceof ForceNode){
Image img;
img = getImageFromFile(ForceNode.forceicon);
g2.drawImage(img, 0, 0, null);
}
if(this instanceof TunnelNode){
Image img;
img = getImageFromFile(TunnelNode.tunnelicon);
g2.drawImage(img, 0, 0, null);
}
....
public Image getImageFromFile(File file) {
Image image = null;
try {
image = ImageIO.read(file);
} catch (IOException e) {
Logger.getLogger(HackerGame.class.getName()).log(Level.SEVERE, null, e);
return null;
}
return image;
}
I realize there are some issues with G2D not being strictly necessary, but my issue is this:
These images needs to be put on top of each other to create a whole image. Eash of the images are small areas of the whole picture, that needs to be put on top of(Not next to) each other to create the actual image. The problem right now however is that the last drawImage method overwrites the entire image, so i am left with the last "bit of image" instead of my compiled image.
I suspect this is because the white areas of my pictures are not being treated as transparent, but how do i get around this. I have next to no experience with image encoding so i am sort of going by trial and error:)
Anyway HELP!
Solution:
public void generateIcon() {
BufferedImage i = new BufferedImage(30, 30, BufferedImage.TYPE_INT_ARGB);
if (this instanceof Node) {
i = compileImages(i, Node.icon);
}
if(this instanceof ForceNode){
i = compileImages(i, ForceNode.forceicon);
}
if(this instanceof TunnelNode){
i = compileImages(i, TunnelNode.tunnelicon);
}
if (this instanceof EntranceNode) {
i = compileImages(i, EntranceNode.entranceicon);
}
if (this instanceof NetworkNode) {
i = compileImages(i, NetworkNode.networkicon);
}
if(this instanceof DataNode){
i = compileImages(i, DataNode.dataicon);
}
//if(this instanceof )
nodeicon = i;
}
public BufferedImage compileImages(BufferedImage image, File f) {
BufferedImage im = null;
try {
im = ImageIO.read(f);
for(int i = 0 ; i<image.getWidth();i++){
for(int j = 0 ; j<image.getHeight();j++){
int rgb = im.getRGB(i, j);
//System.out.println(i + " " + j + " " + rgb);
if(!(rgb < 1 && rgb > -2)){
image.setRGB(i, j, rgb);
//System.out.println("Printing " + i + " " + j + " " + rgb);
}
}
}
} catch (IOException e) {
Logger.getLogger(HackerGame.class.getName()).log(Level.SEVERE, null, e);
return null;
}
return image;
}
Iterate the pixels of the source images. If they are not white (use getRGB(x,y)to compare them), write them to the destination image.
Related
I'm trying to find an image that I create previously inside an empty template with this function that insert text on it receiving color, content and font and return the path of generate image:
the template
public String insertTextOnBlanck(String colorLetter,String text,Font font) {
//path is a private varibable initialized with the constructor
File blankFile = new File("images/dinamic/"+path);
BufferedImage image = null;
String exit_path = null;
try {
image = ImageIO.read(blankFile);
int type = image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType();
Graphics2D g2 = image.createGraphics();
FontMetrics metrics = g2.getFontMetrics(font);
BufferedImage resizeImage = resizeImage(image,type, text,metrics);
image.flush();
int w = resizeImage.getWidth();
int h = resizeImage.getHeight();
g2 = resizeImage.createGraphics();
g2.setColor(Color.decode(colorLetter));
g2.setFont(font);
// Get the FontMetrics
int x = (w - metrics.stringWidth(text)) / 2;
int y = (metrics.getAscent() + (h - (metrics.getAscent() + metrics.getDescent())) / 2);
g2.setBackground(Color.decode("#d1e8f8"));
g2.drawString(text, x, y);
g2.dispose();
//create image with text
exit_path = "images/dinamic/changed_"+path;
File file = new File(exit_path);
ImageIO.write(resizeImage, "png", file);
resizeImage.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return exit_path;
}
and this works the fist time when i call this other function
public void dinamicClick(String path,String input,String fontLetter,String colorLetter, int fontType,int size) throws FindFailed {
DinamicImg DimImg = new DinamicImg();
DimImg.setPath(path);
String modPath = DimImg.insertTextOnBlanck(
colorLetter,
input,//Inventario de recurso
new Font(fontLetter,fontType, size)
);
Iterator<Match> myIt = s.findAll(modPath);
while (myIt.hasNext()) {
Location loc = myIt.next().getTarget();
s.click(loc);
}
myIt.remove();
removeFile(modPath);
}
the removeFile function is:
private void removeFile(String toRemove) {
File file = new File(toRemove);
if(file.delete()){
System.out.println(file.getName() + " is deleted!");
}else{
System.out.println("Delete operation is failed.");
}
}
The result:
but next calls dont work at all, just when i change the name of exit path, so i thought was a cache problem but adding ImageIO.setUseCache(false); at start of "insertTextOnBlanck" function still doesn`t work. Im out of ideas please help, thanks.
I resolve it , with the libary org.sikuli.script.ImagePath you ve to reset the paths of the internal cache of SikuliX with ImagePath.reset().
I am attempting to pull an image from a url using URLImage.createToStorage. However I want that picture to appear rounded so I add a Mask to the image. However when I run the label only shows the placeholder image, not the url image. When I comment out the code that adds the rounded mask to the image the image displays. Is there something wrong with my rounded image code. I used Display.getInstance().callSerially().
//Where I display the image.
public void setUpProfile(Form f) {
Label imageLabel = findMyImage(f);
Image img = getImageFromRes("myprofile.png");
Image scaled = img.scaledWidth(f.getWidth() / 2);
EncodedImage enc = EncodedImage.createFromImage(scaled, false);
Display.getInstance().callSerially(new Runnable() {
#Override
public void run() {
imageLabel.setIcon(getRoundedImage(URLImage.createToStorage(enc,
"profileImage8", me.getPicture(), URLImage.RESIZE_SCALE_TO_FILL)));
f.revalidate();
}
});
findProfNameLabel(f).setText(me.getName());
findProfAgeLabel(f).setText(me.getAge() + " Years old");
findProfPrefLabel(f).setText("Interested in " + me.getPref());
}
public Image getRoundedImage(Image img) {
int w = img.getWidth();
int h = img.getHeight();
Image maskImage = Image.createImage(w, h);
Graphics g = maskImage.getGraphics();
g.setColor(0xffffff);
g.fillArc(0, 0, w, h, 0, 360);
Object mask = maskImage.createMask();
Image ret = img.applyMask(mask);
return ret;
}
The setUpProfile() method is called in the beforeShow of the Form.
EDIT: I edited in the working setUpProfile() method which uses URLImage.createMaskAdapter. and achieves a rounded image.
public void setUpProfile(Form f) {
Label imageLabel = findMyImage(f);
Image mask = getImageFromRes("rounded-mask.png");
Image placeholder = getImageFromRes("myprofile.png").scaled(mask.getWidth(), mask.getHeight());
EncodedImage enc = EncodedImage.createFromImage(placeholder.applyMask(mask.createMask()),
false);
System.out.println("SetUpProfile picture " + me.getPicture());
imageLabel.setIcon(URLImage.createToStorage(enc, "profileImage8",
me.getPicture(), URLImage.createMaskAdapter(mask)));
findProfNameLabel(f).setText(me.getName());
findProfAgeLabel(f).setText(me.getAge() + " Years old");
findProfPrefLabel(f).setText("Interested in " + me.getPref());
}
You can achieve this by creating a custom ImageAdapter that generates a round-mask automatically for you while downloading the image.
public static final URLImage.ImageAdapter RESIZE_SCALE_WITH_ROUND_MASK = new URLImage.ImageAdapter() {
#Override
public EncodedImage adaptImage(EncodedImage downloadedImage, EncodedImage placeholderImage) {
Image tmp = downloadedImage.scaledLargerRatio(placeholderImage.getWidth(), placeholderImage.getHeight());
if (tmp.getWidth() > placeholderImage.getWidth()) {
int diff = tmp.getWidth() - placeholderImage.getWidth();
int x = diff / 2;
tmp = tmp.subImage(x, 0, placeholderImage.getWidth(), placeholderImage.getHeight(), true);
} else if (tmp.getHeight() > placeholderImage.getHeight()) {
int diff = tmp.getHeight() - placeholderImage.getHeight();
int y = diff / 2;
tmp = tmp.subImage(0, y, Math.min(placeholderImage.getWidth(), tmp.getWidth()),
Math.min(placeholderImage.getHeight(), tmp.getHeight()), true);
}
Image roundMask = Image.createImage(tmp.getWidth(), tmp.getHeight(), 0xff000000);
Graphics gr = roundMask.getGraphics();
gr.setColor(0xffffff);
gr.fillArc(0, 0, tmp.getWidth(), tmp.getHeight(), 0, 360);
Object mask = roundMask.createMask();
tmp = tmp.applyMask(mask);
return EncodedImage.createFromImage(tmp, false);
}
#Override
public boolean isAsyncAdapter() {
return true;
}
};
Then apply it this way:
public void setUpProfile(Form f) {
Label imageLabel = findMyImage(f);
Image img = getImageFromRes("myprofile.png");
Image scaled = img.scaledWidth(f.getWidth() / 2);
EncodedImage enc = EncodedImage.createFromImage(scaled, false);
Display.getInstance().callSerially(new Runnable() {
#Override
public void run() {
imageLabel.setIcon(URLImage.createToStorage(enc,
"profileImage8", me.getPicture(), RESIZE_SCALE_WITH_ROUND_MASK));
f.revalidate();
}
});
findProfNameLabel(f).setText(me.getName());
findProfAgeLabel(f).setText(me.getAge() + " Years old");
findProfPrefLabel(f).setText("Interested in " + me.getPref());
}
Intention: Get BufferedImage from resource (be it in IDE or running JAR).
Problem: Getting an Image always works, converting to BufferedImage requires knowledge of size, but size always returns -1, even after waiting with MediaTracker. In IDE, size after MediaTracker is proper, before it is -1. Waiting with while-loop until size >-1 seems to never end in running JAR. (Tried with code language level 6 and 8 using JDK/JRE 8.)
Output of SSCCE in IDE:
IMAGE: sun.awt.image.ToolkitImage#15975490
WIDTH: -1
DURATION: 38 ms
WIDTH: 32
BUFFEREDIMAGE: BufferedImage#6adede5: type = 1 DirectColorModel:
rmask=ff0000 gmask=ff00 bmask=ff amask=0 IntegerInterleavedRaster:
width = 32 height = 32 #Bands = 3 xOff = 0 yOff = 0 dataOffset[0] 0
EDIT: MediaTracker's "isErrorAny()" returns false.
Output of SSCCE in running JAR:
IMAGE: sun.awt.image.ToolkitImage#2a84aee7
WIDTH: -1
DURATION: 23 ms
WIDTH: -1
Exception in thread "main"
java.lang.IllegalArgumentException: Width (-1) and height (-1) cannot
be <= 0
at java.awt.image.DirectColorModel.createCompatibleWritableRaster(Unknown
Source)
at java.awt.image.BufferedImage.(Unknown Source)
at ImageSizeProblem.createBufferedImageFromImage(ImageSizeProblem.java:82)
at ImageSizeProblem.main(ImageSizeProblem.java:26)
EDIT: MediaTracker's "isErrorAny()" returns true. But I have no way of finding out what the error is - also, the image does load properly, since it can be successfully used in an JToolBar via making an ImageIcon from it. (I already tried abusing ImageIcon's getIconWidth() or getImage() methods - they bring no improvement at all.)
SSCCE:
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.net.URL;
public class ImageSizeProblem {
public static void main(final String[] args) {
final Image img = createImageFromResource("test.png");
System.out.println("IMAGE: " + img);
System.out.println("WIDTH: " + img.getWidth(null));
final long startTime = System.currentTimeMillis();
waitForImage(img);
final long duration = System.currentTimeMillis() - startTime;
System.out.println("\nDURATION: " + duration + " ms");
System.out.println("\nWIDTH: " + img.getWidth(null));
final BufferedImage buffImg = createBufferedImageFromImage(img, false);
System.out.println("\nBUFFEREDIMAGE: " + buffImg);
System.exit(0);
}
private static Image createImageFromResource(final String resourceFileName_dontForgetToAddItsFolderToClasspath) {
final Toolkit kit = Toolkit.getDefaultToolkit();
final URL url = ClassLoader.getSystemResource(resourceFileName_dontForgetToAddItsFolderToClasspath);
if (url != null) {
final Image img = kit.createImage(url);
if (img == null) {
System.err.println("Image resource could not be loaded.");
return null;
}
return img;
} else {
System.err.println("Image resource not found.");
return null;
}
}
private static boolean waitForImage(final Image img) {
final MediaTracker mediaTracker = new MediaTracker(new JPanel());
mediaTracker.addImage(img, 1);
try {
mediaTracker.waitForID(1);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
return !mediaTracker.isErrorAny();
}
// improved version of http://stackoverflow.com/a/13605411/3500521
private static BufferedImage createBufferedImageFromImage(final Image img, final boolean withTransparency) {
if (img instanceof BufferedImage) {
return (BufferedImage) img;
} else if (img == null) {
return null;
}
final int w = img.getWidth(null);
final int h = img.getWidth(null);
final BufferedImage bufferedImage;
if (withTransparency) {
bufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
} else {
bufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
}
final Graphics2D g = bufferedImage.createGraphics();
g.drawImage(img, 0, 0, null);
g.dispose();
return bufferedImage;
}
}
Note that the image used for testing was loaded and used successfully in another application via new ImageIcon(image) in a JToolBar. Getting the size from the ImageIcon also returns -1, also from the image returned by ImageIcon.getImage().
The problem was path depth.
I also tried Avira, because the problem is technically a program accessing its own file, which could well seem suspicious, but while Avira was uninstalling, I tried the executables in a different location with a shorter path, and everything worked like a charm.
I'm trying to implement animated textures into an OpenGL game seamlessly. I made a generic ImageDecoder class to translate any BufferedImage into a ByteBuffer. It works perfectly for now, though it doesn't load animated images.
I'm not trying to load an animated image as an ImageIcon. I need the BufferedImage to get an OpenGL-compliant ByteBuffer.
How can I load every frames as a BufferedImage array in an animated image ?
On a similar note, how can I get the animation rate / period ?
Does Java handle APNG ?
The following code is an adaption from my own implementation to accommodate the "into array" part.
The problem with gifs is: There are different disposal methods which have to be considered, if you want this to work with all of them. The code below tries to compensate for that. For example there is a special implementation for "doNotDispose" mode, which takes all frames from start to N and paints them on top of each other into a BufferedImage.
The advantage of this method over the one posted by chubbsondubs is that it does not have to wait for the gif animation delays, but can be done basically instantly.
BufferedImage[] array = null;
ImageInputStream imageInputStream = ImageIO.createImageInputStream(new ByteArrayInputStream(data)); // or any other source stream
Iterator<ImageReader> imageReaders = ImageIO.getImageReaders(imageInputStream);
while (imageReaders.hasNext())
{
ImageReader reader = (ImageReader) imageReaders.next();
try
{
reader.setInput(imageInputStream);
frames = reader.getNumImages(true);
array = new BufferedImage[frames];
for (int frameId : frames)
{
int w = reader.getWidth(0);
int h = reader.getHeight(0);
int fw = reader.getWidth(frameId);
int fh = reader.getHeight(frameId);
if (h != fh || w != fw)
{
GifMeta gm = getGifMeta(reader.getImageMetadata(frameId));
// disposalMethodNames: "none", "doNotDispose","restoreToBackgroundColor","restoreToPrevious",
if ("doNotDispose".equals(gm.disposalMethod))
{
image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = (Graphics2D) image.getGraphics();
for (int f = 0; f <= frameId; f++)
{
gm = getGifMeta(reader.getImageMetadata(f));
if ("doNotDispose".equals(gm.disposalMethod))
{
g.drawImage(reader.read(f), null, gm.imageLeftPosition, gm.imageTopPosition);
}
else
{
// XXX "Unimplemented disposalMethod (" + getName() + "): " + gm.disposalMethod);
}
}
g.dispose();
}
else
{
image = reader.read(frameId);
// XXX "Unimplemented disposalMethod (" + getName() + "): " + gm.disposalMethod;
}
}
else
{
image = reader.read(frameId);
}
if (image == null)
{
throw new NullPointerException();
}
array[frame] = image;
}
}
finally
{
reader.dispose();
}
}
return array;
private final static class GifMeta
{
String disposalMethod = "none";
int imageLeftPosition = 0;
int imageTopPosition = 0;
int delayTime = 0;
}
private GifMeta getGifMeta(IIOMetadata meta)
{
GifMeta gm = new GifMeta();
final IIOMetadataNode gifMeta = (IIOMetadataNode) meta.getAsTree("javax_imageio_gif_image_1.0");
NodeList childNodes = gifMeta.getChildNodes();
for (int i = 0; i < childNodes.getLength(); ++i)
{
IIOMetadataNode subnode = (IIOMetadataNode) childNodes.item(i);
if (subnode.getNodeName().equals("GraphicControlExtension"))
{
gm.disposalMethod = subnode.getAttribute("disposalMethod");
gm.delayTime = Integer.parseInt(subnode.getAttribute("delayTime"));
}
else if (subnode.getNodeName().equals("ImageDescriptor"))
{
gm.imageLeftPosition = Integer.parseInt(subnode.getAttribute("imageLeftPosition"));
gm.imageTopPosition = Integer.parseInt(subnode.getAttribute("imageTopPosition"));
}
}
return gm;
}
I don't think Java supports APNG by default, but you can use an 3rd party library to parse it:
http://code.google.com/p/javapng/source/browse/trunk/javapng2/src/apng/com/sixlegs/png/AnimatedPngImage.java?r=300
That might be your easiest method. As for getting the frames from an animated gif you have to register an ImageObserver:
new ImageIcon( url ).setImageObserver( new ImageObserver() {
public void imageUpdate( Image img, int infoFlags, int x, int y, int width, int height ) {
if( infoFlags & ImageObserver.FRAMEBITS == ImageObserver.FRAMEBITS ) {
// another frame was loaded do something with it.
}
}
});
This loads asynchronously on another thread so imageUpdate() won't be called immediately. But it will be called for each frame as it parses it.
http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/image/ImageObserver.html
I wrote a program that generates a BufferedImage to be displayed on the screen and then printed. Part of the image includes grid lines that are 1 pixel wide. That is, the line is 1 pixel, with about 10 pixels between lines. Because of screen resolution, the image is displayed much bigger than that, with several pixels for each line. I'd like to draw it smaller, but when I scale the image (either by using Image.getScaledInstance or Graphics2D.scale), I lose significant amounts of detail.
I'd like to print the image as well, and am dealing with the same problem. In that case, I am using this code to set the resolution:
HashPrintRequestAttributeSet set = new HashPrintRequestAttributeSet();
PrinterResolution pr = new PrinterResolution(250, 250, ResolutionSyntax.DPI);
set.add(pr);
job.print(set);
which works to make the image smaller without losing detail. But the problem is that the image is cut off at the same boundary as if I hadn't set the resolution. I'm also confused because I expected a larger number of DPI to make a smaller image, but it's working the other way.
I'm using java 1.6 on Windows 7 with eclipse.
Regarding the image being cut-off on the page boundary, have you checked the clip region of the graphics? I mean try :
System.out.println(graphics.getClipBounds());
and make sure it is correctly set.
I had the same problem. Here is my solution.
First change the resolution of the print job...
PrinterJob job = PrinterJob.getPrinterJob();
// Create the paper size of our preference
double cmPx300 = 300.0 / 2.54;
Paper paper = new Paper();
paper.setSize(21.3 * cmPx300, 29.7 * cmPx300);
paper.setImageableArea(0, 0, 21.3 * cmPx300, 29.7 * cmPx300);
PageFormat format = new PageFormat();
format.setPaper(paper);
// Assign a new print renderer and the paper size of our choice !
job.setPrintable(new PrintReport(), format);
if (job.printDialog()) {
try {
HashPrintRequestAttributeSet set = new HashPrintRequestAttributeSet();
PrinterResolution pr = new PrinterResolution((int) (dpi), (int) (dpi), ResolutionSyntax.DPI);
set.add(pr);
job.setJobName("Jobname");
job.print(set);
} catch (PrinterException e) {
}
}
Now you can draw everything you like into the new high resolution paper like this !
public class PrintReport implements Printable {
#Override
public int print(Graphics g, PageFormat pf, int page) throws PrinterException {
// Convert pixels to cm to lay yor page easy on the paper...
double cmPx = dpi / 2.54;
Graphics2D g2 = (Graphics2D) g;
int totalPages = 2; // calculate the total pages you have...
if (page < totalPages) {
// Draw Page Header
try {
BufferedImage image = ImageIO.read(ClassLoader.getSystemResource(imgFolder + "largeImage.png"));
g2.drawImage(image.getScaledInstance((int) (4.8 * cmPx), -1, BufferedImage.SCALE_SMOOTH), (int) (cmPx),
(int) (cmPx), null);
} catch (IOException e) {
}
// Draw your page as you like...
// End of Page
return PAGE_EXISTS;
} else {
return NO_SUCH_PAGE;
}
}
It sounds like your problem is that you are making the grid lines part of the BufferedImage and it doesn't look good when scaled. Why not use drawLine() to produce the grid after your image has been drawn?
Code for Convert image with dimensions using Java and print the converted image.
Class: ConvertImageWithDimensionsAndPrint.java
package com.test.convert;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
public class ConvertImageWithDimensionsAndPrint {
private static final int IMAGE_WIDTH = 800;
private static final int IMAGE_HEIGHT = 1000;
public static void main(String[] args) {
try {
String sourceDir = "C:/Images/04-Request-Headers_1.png";
File sourceFile = new File(sourceDir);
String destinationDir = "C:/Images/ConvertedImages/";//Converted images save here
File destinationFile = new File(destinationDir);
if (!destinationFile.exists()) {
destinationFile.mkdir();
}
if (sourceFile.exists()) {
String fileName = sourceFile.getName().replace(".png", "");
BufferedImage bufferedImage = ImageIO.read(sourceFile);
int type = bufferedImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : bufferedImage.getType();
BufferedImage resizedImage = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, type);
Graphics2D graphics2d = resizedImage.createGraphics();
graphics2d.drawImage(bufferedImage, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null);//resize goes here
graphics2d.dispose();
ImageIO.write(resizedImage, "png", new File( destinationDir + fileName +".png" ));
int oldImageWidth = bufferedImage.getWidth();
int oldImageHeight = bufferedImage.getHeight();
System.out.println(sourceFile.getName() +" OldFile with Dimensions: "+ oldImageWidth +"x"+ oldImageHeight);
System.out.println(sourceFile.getName() +" ConvertedFile converted with Dimensions: "+ IMAGE_WIDTH +"x"+ IMAGE_HEIGHT);
//Print the image file
PrintActionListener printActionListener = new PrintActionListener(resizedImage);
printActionListener.run();
} else {
System.err.println(destinationFile.getName() +" File not exists");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Reference of PrintActionListener.java
package com.test.convert;
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;
}
}
}
}
Output:
04-Request-Headers_1.png OldFile with Dimensions: 1224x1584
04-Request-Headers_1.png ConvertedFile converted with Dimensions: 800x1000
After conversion of a image a Print window will be open for printing the converted image. The window displays like below, Select the printer from Name dropdown and Click OK button.
You can use either of the following to improve the quality of the scaling. I believe BiCubic gives better results but is slower than BILINEAR.
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
I would also not use Image.getScaledInstance() as it is very slow. I'm not sure about the printing as I'm struggling with similar issues.