我使用这段代码将图像绘制到图形组件中。如果图像足够大,则应将图像调整为最大可用空间:
// 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);
}
代码有效,图像正确缩放。但是不幸的是,当缩放图像时,图像的亮度在图形卡上也会改变!
有谁知道这可能来自哪里?
我附上了屏幕的缩放比例(第一)和未缩放的版本。
我希望有人可以帮助我!
干杯!
塞巴斯蒂安
最佳答案
这似乎是Image.getScaledInstance
的问题(并且也可能与灰度图像有关)。我尝试了其他一些提示,但结果相同。
相反,我采用了自己的缩放算法(从互联网上窃取),该算法使用分而治之的方法,通常可以产生更好的结果...
因此,原始的在顶部,Image#getScaledInstance
在左侧,自定义在右侧缩放
nb:这使用了我自己的一些个人图书馆代码,因此它可能不完全适合您,但这提供了基础知识...
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;
}
}
也可以看一看The Perils of Image.getScaledInstance()
ps-我做了一下快速搜索,这似乎是API中的错误(或功能)