Using PrinterJob to print an Image (Graphics2D) - java

Is there a way I can rig a PrinterJob in Java to NOT actually print to a printer so that I can get the graphics objects for each page? I tried setting the PrintService to null, but Java wouldn't allow that.
This is so that I can retrieve an accurate Print Preview for the document without essentially rebuilding PrinterJobs functions from the ground-up in a different context.
Here's the code for the print function in my program:
public int print(Graphics graphics, PageFormat pageFormat, int page) throws PrinterException {
deepCopyString = string;
FontMetrics metrics = graphics.getFontMetrics(font);
int lineHeight = metrics.getHeight();
arrangePage(graphics, pageFormat, metrics);
if (page > pageBreaks.length){
return NO_SUCH_PAGE;
}
Graphics2D g = (Graphics2D) graphics;
g.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
g.setFont(font);
int begin = (page == 0) ? 0 : pageBreaks[page-1];
int end = (page == pageBreaks.length) ? lines.length : pageBreaks[page];
int y = 0;
int x = 0;
for (int line = begin; line < end; line++){
x = 0;
y += lineHeight;
checkSyntax(line);
String l = lines[line];
for (int c = 0; c < l.length(); c++){
applySyntax(c, line);
metrics = graphics.getFontMetrics(font);
String ch = Character.toString(l.charAt(c));
g.setFont(font);
g.drawString(ch, x, y);
x += metrics.charWidth(l.charAt(c));
//System.out.println(c + "/"+l.length());
}
//g.drawString(lines[line], 0, y);
}
reset();
records.add(g);
return PAGE_EXISTS;
}
You can already see that the Graphics objects are recorded so that I can paint them in another component, but it's rather useless seeing as it will go ahead and send these to my printer before the record can be completed.
This may be a bad idea in general, and I'm pretty new to printing. If this is seriously a bad way to go about this, feel free to direct me to a source that'll explain a better way.

Basically, you want to create you own Graphics context to which you can paint. You also need to construct a PageFormat that can be past to the print method.
public class TestPrint implements Printable {
private BufferedImage background;
public static final float DPI = 72;
public static void main(String[] args) {
new TestPrint();
}
public TestPrint() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
try {
background = ImageIO.read(new File("C:/Users/shane/Dropbox/MegaTokyo/MgkGrl_Yuki_by_fredrin.jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}
float width = cmToPixel(21f, DPI);
float height = cmToPixel(29.7f, DPI);
Paper paper = new Paper();
float margin = cmToPixel(1, DPI);
paper.setImageableArea(margin, margin, width - (margin * 2), height - (margin * 2));
PageFormat pf = new PageFormat();
pf.setPaper(paper);
BufferedImage img = new BufferedImage(Math.round(width), Math.round(height), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fill(new Rectangle2D.Float(0, 0, width, height));
try {
g2d.setClip(new Rectangle2D.Double(pf.getImageableX(), pf.getImageableY(), pf.getImageableWidth(), pf.getImageableHeight()));
print(g2d, pf, 0);
} catch (PrinterException ex) {
ex.printStackTrace();
}
g2d.dispose();
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JLabel(new ImageIcon(img)));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public float cmToPixel(float cm, float dpi) {
return (dpi / 2.54f) * cm;
}
public int print(Graphics graphics, PageFormat pageFormat, int page) throws PrinterException {
if (page > 0) {
return NO_SUCH_PAGE;
}
Graphics2D g = (Graphics2D) graphics;
g.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
if (background != null) {
int x = (int)Math.round((pageFormat.getImageableWidth() - background.getWidth()) / 2f);
int y = (int)Math.round((pageFormat.getImageableHeight() - background.getHeight()) / 2f);
g.drawImage(background, x, y, null);
}
g.setColor(Color.BLACK);
g.draw(new Rectangle2D.Double(0, 0, pageFormat.getImageableWidth() - 1, pageFormat.getImageableHeight() - 1));
return PAGE_EXISTS;
}
}
Now, obviously, there are going to be difference to what is printed to the screen and what's printed to the printer, because we're not actually using the same hardware device, but the basic concept applies

Related

Printing to a Dymo labelprinter from Java

I'm trying to print a label on my Dymo LabelWriter 450, but am having a hard time.
The issue I am dealing with now is that I can't even seem to fill the entire label, there seems to be a left margin of about 0.6mm that I don't get when I print using the Dymo software.
Ideally I would use an SDK, but I am unable to find a Dymo Java SDK.
This is the result I'm looking for
This is what I've got so far
I modified some code from this answer to get to this result.
public class PrinterTest {
public static void main(String[] args) {
PrinterJob printerJob = PrinterJob.getPrinterJob();
if (printerJob.printDialog()) {
PageFormat pageFormat = printerJob.defaultPage();
Paper paper = pageFormat.getPaper();
double width = fromCMToPPI(1.9);
double height = fromCMToPPI(4.5);
double horizontalMargin = fromCMToPPI(0.25);
double verticalMargin = fromCMToPPI(0.1);
paper.setSize(width, height);
paper.setImageableArea(
horizontalMargin,
verticalMargin,
width,
height);
pageFormat.setOrientation(PageFormat.REVERSE_LANDSCAPE);
pageFormat.setPaper(paper);
printerJob.setPrintable(new MyPrintable(), pageFormat);
try {
printerJob.print();
} catch (PrinterException ex) {
ex.printStackTrace();
}
}
}
private static double fromCMToPPI(double cm) {
return toPPI(cm * 0.393700787);
}
private static double toPPI(double inch) {
return inch * 72d;
}
public static class MyPrintable implements Printable {
#Override
public int print(Graphics graphics, PageFormat pageFormat,
int pageIndex) {
System.out.println(pageIndex);
int result = NO_SUCH_PAGE;
if (pageIndex < 1) {
Graphics2D g2d = (Graphics2D) graphics;
double width = pageFormat.getImageableWidth();
double height = pageFormat.getImageableHeight();
double x = pageFormat.getImageableX();
double y = pageFormat.getImageableY();
System.out.println("x = " + x);
System.out.println("y = " + y);
g2d.translate((int) pageFormat.getImageableX(), (int) pageFormat.getImageableY());
g2d.draw(new Rectangle2D.Double(x, y, width - x, height - y));
FontMetrics fm = g2d.getFontMetrics();
g2d.drawString("AxB", Math.round(x), fm.getAscent());
result = PAGE_EXISTS;
}
return result;
}
}
}
If there is an SDK available that I missed, I would love to know where to find it. Otherwise, how can I get rid of this left margin so that I can actually fit everything on the label?
Thanks!

Where to/ how to call my resizeimage method

Ok so I created a method that resizes an ImageIcon my question is how/ where do I call it in order to make the ImageIcon I want to resize to that size here it is thanks, and the method should work so anyone looking for a method that does resize you should be able to use it :)
public static void resizeIcon(ImageIcon icon, int Width, int Height){
Image geticon = icon.getImage();
BufferedImage bi = new BufferedImage(geticon.getWidth(null), geticon.getHeight(null), BufferedImage.TYPE_INT_RGB);
Graphics g = bi.createGraphics();
g.drawImage(geticon, 0, 0, Width, Height, null);
ImageIcon resizedicon = new ImageIcon(bi);
icon = resizedicon;
}
you save the resized image first .Then set the imageicon by resource as the resized image.
public static Boolean resizeImage(String sourceImage, String destinationImage, Integer Width, Integer Height) {
BufferedImage origImage;
try {
origImage = ImageIO.read(new File(sourceImage));
int type = origImage.getType() == 0? BufferedImage.TYPE_INT_ARGB : origImage.getType();
//*Special* if the width or height is 0 use image src dimensions
if (Width == 0) {
Width = origImage.getWidth();
}
if (Height == 0) {
Height = origImage.getHeight();
}
int fHeight = Height;
int fWidth = Width;
//Work out the resized width/height
if (origImage.getHeight() > Height || origImage.getWidth() > Width) {
fHeight = Height;
int wid = Width;
float sum = (float)origImage.getWidth() / (float)origImage.getHeight();
fWidth = Math.round(fHeight * sum);
if (fWidth > wid) {
//rezise again for the width this time
fHeight = Math.round(wid/sum);
fWidth = wid;
}
}
BufferedImage resizedImage = new BufferedImage(fWidth, fHeight, type);
Graphics2D g = resizedImage.createGraphics();
g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(origImage, 0, 0, fWidth, fHeight, null);
g.dispose();
ImageIO.write(resizedImage, "png", new File(destinationImage));
} catch (IOException ex) {
System.out.println(""+ex);
return false;
}
return true;
}
Then call
ImageIcon ico = new ImageIcon(destinationImage);
labelforIcon.setIcon(ico);

Rotating image on top of another image

I have a method that I want to rotate an image when the user enters the number of degrees to rotate it. The method does that, but the thing is it's rotating the image so that the new image lays on top of the old one (which I don't want it to do; I just want the new image by itself). The RotateTest is just an abbreviated form of the class with all of the methods needed in the ButtonListener class that should be relevant to rotating the image.
public class RotateTest {
public Rotate() {
try {
String path = "default.jpg";
File imageFile = new File(path);
imageURL = imageFile.toURI().toURL();
image = ImageIO.read(imageURL);
this.imageLabel = new JLabel(imageLabel);
} catch (IOException e) { }
}
public void setAngle(double angle) {
this.angle = angle;
}
public void setImage(BufferedImage img) {
this.image = img;
}
private class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
boolean doAgain = true;
Artsy artsy = new Artsy();
if(event.getSource() == rotate) {
//need something for cancel!
do {
String angleString = JOptionPane.showInputDialog("Please enter your angle in degrees.");
double angle = Double.parseDouble(angleString);
if(angle < 0) {
angle = 360 + angle;
}
setAngle(getAngle() + angle);
setImage(artsy.doRotate(image, angle));
revalidate();
repaint();
System.out.println("The angle is " + getAngle());
} while(JOptionPane.OK_OPTION == 1);
}
else {
if(doAgain) {
setImage(artsy.doRotate(image, 360 - getAngle()));
doAgain = false;
setAngle(0);
}
revalidate();
repaint();
System.out.println("The angle is " + getAngle());
}
}
}
And this is the other class with the method that rotates the image:
public class Artsy {
public BufferedImage doRotate(BufferedImage src, double angle) {
angle = Math.toRadians(angle);
Graphics2D g = (Graphics2D) src.getGraphics();
int w = src.getWidth();
int h = src.getHeight();
AffineTransform trans = new AffineTransform();
trans.rotate(angle, w / 2, h / 2);
AffineTransformOp scaleOp = new AffineTransformOp(trans, AffineTransformOp.TYPE_BILINEAR);
g.drawImage(scaleOp.filter(src, null), 0, 0, null);
g.dispose();
return src;
}
}
Thank you!!
Your code seems correct to me, i can't see an obvious mistake. Nevertheless the following function is working for my to rotate images so it should also be a solution for you:
public static BufferedImage rotate(BufferedImage srcImage, double angle)
{
double sin = Math.abs(Math.sin(Math.toRadians(angle))), cos = Math.abs(Math.cos(Math.toRadians(angle)));
int originWidth = srcImage.getWidth(), originHeight = srcImage.getHeight();
int newWidth = (int) Math.floor(originWidth * cos + originHeight * sin), newHeight = (int) Math.floor(originHeight * cos + originWidth * sin);
BufferedImage newImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = newImage.createGraphics();
g.translate((newWidth - originWidth) / 2, (newHeight - originHeight) / 2);
g.rotate(Math.toRadians(angle), originWidth / 2, originHeight / 2);
g.drawImage(srcImage, 0, 0, null);
g.dispose();
return newImage;
}
A helper function:
/**
* Converts an Icon to an Image
*/
public static Image iconToImage(Icon icon) {
if (icon instanceof ImageIcon) {
return ((ImageIcon) icon).getImage();
}
else {
int w = icon.getIconWidth();
int h = icon.getIconHeight();
GraphicsEnvironment ge =
GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
BufferedImage image = gc.createCompatibleImage(w, h);
Graphics2D g = image.createGraphics();
icon.paintIcon(null, g, 0, 0);
g.dispose();
return image;
}
}
Example usage to rotate the JLabels icon for 90 degrees clockwise:
BufferedImage buImg = new BufferedImage(imageLabel.getIcon().getIconWidth(), imageLabel.getIcon().getIconHeight(), BufferedImage.TYPE_INT_ARGB);
buImg.getGraphics().drawImage(iconToImage(imageLabel.getIcon()), 0, 0, null);
imageLabel.setIcon(new ImageIcon(rotate(buImg, 90)));

BufferedImage only showing on 1/3 of JPanel

Here's my original question on SO kindly answered. The height is now set at what I think is the correct size. But I can't see the bottom 2/3s of the panel.
I have read, and asked, and mused, and experimented, but I still cannot find an answer. I don't need code, just a little help.
My JFrame class;
public Frame(String title) throws FileNotFoundException {
super(String.format("Title", title));
this.panel = new Panel();
this.panel.drawLinesAndTab();
this.panel.setSize(this.panel.getPreferredSize());
this.panel.validate();
this.scroller = new JScrollPane(this.panel);
//this.scroller.setPreferredSize(new Dimension(this.panel.getPreferredSize()));
this.scroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
this.scroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
//this.scroller.setSize(new Dimension(this.panel.getPreferredSize()));
this.scroller.getVerticalScrollBar().setUnitIncrement(20);
this.getContentPane().add(this.scroller);
//this.pack();
}
and this is the JPanel class. I know it's huge, and I do have plans to re-write this code, but I'm under time limitations and have to try and get it at least seeing all of the output.
public Panel() throws FileNotFoundException {
this.tab = new ReadTabFile("tabSource.txt");
this.image = new BufferedImage(this.width, this.height, BufferedImage.TYPE_INT_RGB);
Graphics g = this.image.createGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, this.image.getWidth(), this.image.getHeight());
setBorder(BorderFactory.createLineBorder(Color.black));
this.setFocusable(true);
}
public void drawLinesAndTab() {
Graphics g = this.image.getGraphics();
g.setColor(Color.black);
this.list = tab.readTabCode();
this.a = 20;
this.b = 100;
this.c = 60;
this.x = 40;
this.y = 100;
this.beginBarlineX = 20;
this.beginBarlineY = 100;
this.endBarY = 980;
this.endBarY = 100;
this.title = tab.getTitle();
g.drawString(this.title, 40, 20);
for (int i = 0; i < this.list.size(); i++) {
Bar theBar = (Bar) this.list.get(i);
drawBarline(a, b, a, b + 125);
ArrayList<String> stuff = theBar.getLinesInBar();
for (int j = 0; j < stuff.size(); j++) {
String line = stuff.get(j);
theFlag = line.substring(0, 1);
theNotes = line.substring(1, line.length());
if (newLine = true) {
}
try {
System.out.println(theNotes);
if (c <= (width - 40)) {
newLine = false;
String zero = theFlag;
drawFlag(zero, x + 5, y - 20);
String one = theNotes.substring(0, 1);
g.drawLine(a, b, c, b);
drawLetter(one, x, y);
String two = theNotes.substring(1, 2);
drawLetter(two, x, y += 25);
g.drawLine(a, b += 25, c, b);
String three = theNotes.substring(2, 3);
drawLetter(three, x, y += 25);
g.drawLine(a, b += 25, c, b);
String four = theNotes.substring(3, 4);
drawLetter(four, x, y += 25);
g.drawLine(a, b += 25, c, b);
String five = theNotes.substring(4, 5);
drawLetter(five, x, y += 25);
g.drawLine(a, b += 25, c, b);
String six = theNotes.substring(5, 6);
drawLetter(six, x, y += 25);
g.drawLine(a, b += 25, c, b);
this.repaint();
b -= 125;
y -= 125;
x += 40;
a += 40;
c += 40;
} else {
if (height < (b - 100)) {
height += 205;
}
newLine = true;
a = 20;
x = 20;
b += 225;
c = 60;
y += 225;
beginBarlineX = 20;
beginBarlineY += 100;
endBarX += 100;
endBarY = 100;
this.repaint();
}
} catch (Exception ex) {
System.err.println(ex + " within if drawtab/line for loop");
}
}
}
}
public void drawBarline(int xTop, int yTop, int xBot, int yBot) {
Graphics g = this.image.getGraphics();
g.setColor(Color.black);
g.drawLine(xTop, yTop, xBot, yBot);
}
public Point makeBarline(int xTop, int yTop, int xBot, int yBot) {
Graphics g = this.image.getGraphics();
g.setColor(Color.black);
g.drawLine(xTop, yTop, xBot, yBot);
return (new Point());
}
public Point drawLetter(String letter, int x, int y) throws FontFormatException, IOException {
Graphics g = this.image.getGraphics();
g.setColor(Color.black);
g.setFont(letterFont(letter).deriveFont(20.0f));
g.drawString(letter, x, y);
return (new Point());
}
public Point drawFlag(String letter, int x, int y) throws FontFormatException, IOException {
Graphics g = this.image.getGraphics();
g.setColor(Color.black);
g.setFont(flagFont(letter).deriveFont(30.0f));
g.drawString(letter, x, y);
return (new Point());
}
public Font letterFont(String fontString) throws FontFormatException, IOException {
Graphics g = this.image.getGraphics();
g.setColor(Color.black);
if (!Character.isDigit(fontString.charAt(0))) {
this.letterFont = Font.createFont(Font.TRUETYPE_FONT, new File("LeRoy.ttf"));
g.getFontMetrics(this.letterFont);
g.setFont(this.letterFont);
return this.letterFont;
} else {
return null;
}
}
public Font flagFont(String fontString) throws FontFormatException, IOException {
Graphics g = this.image.getGraphics();
g.setColor(Color.black);
if (!Character.isDigit(fontString.charAt(0))) {
this.flagFont = Font.createFont(Font.TRUETYPE_FONT, new File("LeroyLuteNotes1.ttf"));
g.getFontMetrics(this.flagFont);
g.setFont(this.flagFont);
return this.flagFont;
} else {
return null;
}
}
#Override
public Dimension getPreferredSize() {
return (new Dimension(this.width, this.height));
}
public BufferedImage getImage() {
return this.image;
}
#Override
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
Graphics g = graphics.create();
g.drawImage(this.image, 0, 0, null);
}
}
I'm not sure what you are attempting to do with that code. It looks like you might be trying to do some custom painting on top of an image. If so then I have the following suggestions:
public Dimension getPreferredSize() {
return (new Dimension(this.width, this.height));
}
This makes no sense, you are saying that the preferred size is equal to the actual size of the component. The preferred size should be the size of the image.
Your custom painting code is completely wrong. All custom painting code should be done from the paintComponent() method. So first you would paint the image as the background of your component. Then you would invoke the other painting methods to paint stuff on top of the image. You would pass the Graphics object from the paintComponent() method to all of these other painting methods, instead of using image.getGraphics().
Start with a simple custom painting example from the Swing tutorial on Custom Painting. Once you learn the basics you customize your code one step at a time. That is first paint the background. Make sure the size is correct and scrolling works. Then move to the next step and add another method to paint something else on top of the image.
I never understand why people write hundreds of lines of code without doing basic testing along the way to make sure the code is working.

BufferedImage getScaledInstance changes brightness of picture

I use this piece of code to draw a Image into a Graphics component. It should size the image to the maximum space available, if it is big enough:
// getWidth() = component width, image.getWidth() = image width
double w = getWidth() * 1.0 / image.getWidth();
double h = getHeight() * 1.0 / image.getHeight();
if (w < 1 || h < 1) {
double d = Math.min(Math.min(w, h), 1);
g.drawImage(bi.getScaledInstance((int) (d * image.getWidth()), (int) (d * image.getHeight()), Image.SCALE_REPLICATE), 0, 0, null);
} else {
g.drawImage(bi, 0, 0, null);
}
The code works, the image gets scaled correctly. But unfortunately when the image is scaled, the brightness of the images changes as well on the Graphics!
Has anyone an idea where this could come from?
I attached the scaled (first) and the not scaled version of the screen.
I hope someone can help me with that!
Cheers!
Sebastian
This seems to be an issue with Image.getScaledInstance (and may also be related to gray scaled images). I tried several other hints but had the same result.
Instead, I employed my own scaling algorithm (which I stole from the Internet), which uses a divide and conquer approach, which generally produces better results...
So, original ontop, Image#getScaledInstance on the left, custom scaled on the right
nb: This uses some of my own personal library code, so it might not be entirely suitable for you, but this presents the basics...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ImageScaleTest {
public static void main(String[] args) {
new ImageScaleTest();
}
public ImageScaleTest() {
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 static enum RenderQuality {
High,
Medium,
Low
}
public class TestPane extends JPanel {
private BufferedImage original;
private BufferedImage scaled2;
private Image scaled;
public TestPane() {
try {
original = ImageIO.read(new File("/path/to/image"));
scaled = original.getScaledInstance(original.getWidth() / 2, original.getHeight() / 2, Image.SCALE_DEFAULT);
scaled2 = getScaledInstance(original, 0.5d, RenderQuality.High);
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 600);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(original, 0, 0, this);
g2d.drawImage(scaled, 0, original.getHeight(), this);
g2d.drawImage(scaled2, scaled.getWidth(this), original.getHeight(), this);
g2d.dispose();
}
}
public static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, RenderQuality quality) {
BufferedImage imgBuffer = null;
if (quality == RenderQuality.High) {
// System.out.println("Scale high quality...");
imgBuffer = getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);
} else if (quality == RenderQuality.Medium) {
imgBuffer = getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
} else {
// System.out.println("Scale low quality...");
imgBuffer = getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR, false);
}
return imgBuffer;
}
protected static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, Object hint, boolean bHighQuality) {
BufferedImage imgScale = img;
int iImageWidth = (int) Math.round(img.getWidth() * dScaleFactor);
int iImageHeight = (int) Math.round(img.getHeight() * dScaleFactor);
if (dScaleFactor <= 1.0d) {
imgScale = getScaledDownInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);
} else {
imgScale = getScaledUpInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);
}
return imgScale;
}
protected static BufferedImage getScaledDownInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality) {
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, h;
if (higherQuality) {
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached
w = img.getWidth();
h = img.getHeight();
} else {
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && 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, hint);
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 static BufferedImage getScaledUpInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality) {
int type = BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
int w, h;
if (higherQuality) {
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached
w = img.getWidth();
h = img.getHeight();
} else {
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w < targetWidth) {
w *= 2;
if (w > targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h < targetHeight) {
h *= 2;
if (h > targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
tmp = null;
} while (w != targetWidth || h != targetHeight);
return ret;
}
}
May, also, like to take a look at The Perils of Image.getScaledInstance()
ps- I did a quick bit of searching and this seems to be a bug (or feature) in the API

Categories