小编典典
这是一个棘手的问题。你强调了一个事实,即你正在使用a JLabel来显示图像,这是标准的处理方式,但是却JLabel是一个复杂的小野兽,具有文本,图标以及文本的对齐和定位。
如果你不需要所有这些额外的功能,我将为你自己创建一个能够绘制缩放图像的自定义组件…
下一个问题是,你如何缩放图像?你是否要保持图像的长宽比?是否要将图像“适合”或“填充”到可用空间。
@大卫是正确的。你应该尽可能避免Image#getScaledInstance使用它,因为它不是最快的,但是更重要的是,通常它也不提供最高的质量。
适合与填充
以下示例非常简单(并且从我的代码库中借来了很多代码,因此可能还有些复杂;)。可以从后台缩放线程使用它,但是我将根据原始图像的潜在大小来做出决定。
public class ResizableImage {
public static void main(String[] args) {
new ResizableImage();
}
public ResizableImage() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
try {
BufferedImage image = ImageIO.read(new File("/path/to/your/image"));
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new ScalablePane(image));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (Exception exp) {
exp.printStackTrace();
}
}
});
}
public class ScalablePane extends JPanel {
private Image master;
private boolean toFit;
private Image scaled;
public ScalablePane(Image master) {
this(master, true);
}
public ScalablePane(Image master, boolean toFit) {
this.master = master;
setToFit(toFit);
}
@Override
public Dimension getPreferredSize() {
return master == null ? super.getPreferredSize() : new Dimension(master.getWidth(this), master.getHeight(this));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Image toDraw = null;
if (scaled != null) {
toDraw = scaled;
} else if (master != null) {
toDraw = master;
}
if (toDraw != null) {
int x = (getWidth() - toDraw.getWidth(this)) / 2;
int y = (getHeight() - toDraw.getHeight(this)) / 2;
g.drawImage(toDraw, x, y, this);
}
}
@Override
public void invalidate() {
generateScaledInstance();
super.invalidate();
}
public boolean isToFit() {
return toFit;
}
public void setToFit(boolean value) {
if (value != toFit) {
toFit = value;
invalidate();
}
}
protected void generateScaledInstance() {
scaled = null;
if (isToFit()) {
scaled = getScaledInstanceToFit(master, getSize());
} else {
scaled = getScaledInstanceToFill(master, getSize());
}
}
protected BufferedImage toBufferedImage(Image master) {
Dimension masterSize = new Dimension(master.getWidth(this), master.getHeight(this));
BufferedImage image = createCompatibleImage(masterSize);
Graphics2D g2d = image.createGraphics();
g2d.drawImage(master, 0, 0, this);
g2d.dispose();
return image;
}
public Image getScaledInstanceToFit(Image master, Dimension size) {
Dimension masterSize = new Dimension(master.getWidth(this), master.getHeight(this));
return getScaledInstance(
toBufferedImage(master),
getScaleFactorToFit(masterSize, size),
RenderingHints.VALUE_INTERPOLATION_BILINEAR,
true);
}
public Image getScaledInstanceToFill(Image master, Dimension size) {
Dimension masterSize = new Dimension(master.getWidth(this), master.getHeight(this));
return getScaledInstance(
toBufferedImage(master),
getScaleFactorToFill(masterSize, size),
RenderingHints.VALUE_INTERPOLATION_BILINEAR,
true);
}
public Dimension getSizeToFit(Dimension original, Dimension toFit) {
double factor = getScaleFactorToFit(original, toFit);
Dimension size = new Dimension(original);
size.width *= factor;
size.height *= factor;
return size;
}
public Dimension getSizeToFill(Dimension original, Dimension toFit) {
double factor = getScaleFactorToFill(original, toFit);
Dimension size = new Dimension(original);
size.width *= factor;
size.height *= factor;
return size;
}
public double getScaleFactor(int iMasterSize, int iTargetSize) {
return (double) iTargetSize / (double) iMasterSize;
}
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;
}
public double getScaleFactorToFill(Dimension masterSize, Dimension targetSize) {
double dScaleWidth = getScaleFactor(masterSize.width, targetSize.width);
double dScaleHeight = getScaleFactor(masterSize.height, targetSize.height);
return Math.max(dScaleHeight, dScaleWidth);
}
public BufferedImage createCompatibleImage(Dimension size) {
return createCompatibleImage(size.width, size.height);
}
public BufferedImage createCompatibleImage(int width, int height) {
GraphicsConfiguration gc = getGraphicsConfiguration();
if (gc == null) {
gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
}
BufferedImage image = gc.createCompatibleImage(width, height, Transparency.TRANSLUCENT);
image.coerceData(true);
return image;
}
protected 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 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 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;
}
}
}
2020-03-05