forked from External/mage
Merge pull request #2030 from draxdyn/performance
Improve GUI performance
This commit is contained in:
commit
d220c739a8
19 changed files with 673 additions and 376 deletions
|
|
@ -119,6 +119,7 @@ import mage.client.table.TablesPane;
|
|||
import mage.client.tournament.TournamentPane;
|
||||
import mage.client.util.EDTExceptionHandler;
|
||||
import mage.client.util.GUISizeHelper;
|
||||
import mage.client.util.ImageCaches;
|
||||
import mage.client.util.SettingsManager;
|
||||
import mage.client.util.SystemUtil;
|
||||
import mage.client.util.audio.MusicPlayer;
|
||||
|
|
@ -1470,6 +1471,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
|
|||
}
|
||||
|
||||
public void changeGUISize() {
|
||||
ImageCaches.flush();
|
||||
setGUISize();
|
||||
Plugins.getInstance().changeGUISize();
|
||||
CountryUtil.changeGUISize();
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ import mage.client.plugins.impl.Plugins;
|
|||
import mage.client.util.ImageHelper;
|
||||
import mage.constants.EnlargeMode;
|
||||
import org.jdesktop.swingx.JXPanel;
|
||||
import mage.client.util.TransformedImageCache;
|
||||
|
||||
/**
|
||||
* Class for displaying big image of the card
|
||||
|
|
@ -103,7 +104,13 @@ public class BigCard extends JComponent {
|
|||
|
||||
}
|
||||
|
||||
public void setCard(UUID cardId, EnlargeMode enlargeMode, Image image, List<String> strings) {
|
||||
public void setCard(UUID cardId, EnlargeMode enlargeMode, Image image, List<String> strings, boolean rotate) {
|
||||
if (rotate && getWidth() > getHeight()) {
|
||||
image = TransformedImageCache.getRotatedResizedImage((BufferedImage)image, getHeight(), getWidth(), Math.toRadians(90.0));
|
||||
} else {
|
||||
image = TransformedImageCache.getResizedImage((BufferedImage)image, getWidth(), getHeight());
|
||||
}
|
||||
|
||||
if (this.cardId == null || !enlargeMode.equals(this.enlargeMode) || !this.cardId.equals(cardId)) {
|
||||
if (this.panel != null) {
|
||||
remove(this.panel);
|
||||
|
|
|
|||
|
|
@ -374,7 +374,7 @@ public class Card extends MagePermanent implements MouseMotionListener, MouseLis
|
|||
@Override
|
||||
public void mouseMoved(MouseEvent arg0) {
|
||||
this.bigCard.showTextComponent();
|
||||
this.bigCard.setCard(card.getId(), EnlargeMode.NORMAL, image, getRules());
|
||||
this.bigCard.setCard(card.getId(), EnlargeMode.NORMAL, image, getRules(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@ import mage.client.util.ImageHelper;
|
|||
import mage.constants.CardType;
|
||||
import mage.view.CounterView;
|
||||
import mage.view.PermanentView;
|
||||
import org.mage.plugins.card.images.ImageCache;
|
||||
import mage.client.util.TransformedImageCache;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -215,7 +217,7 @@ public class Permanent extends Card {
|
|||
Graphics2D g = (Graphics2D) tappedImage.getGraphics();
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
g.drawImage(this.createImage(ImageHelper.rotate(small, dimension)), 0, 0, this);
|
||||
g.drawImage(TransformedImageCache.getRotatedResizedImage(small, dimension.frameWidth, dimension.frameHeight, Math.toRadians(90.0)), 0, 0, this);
|
||||
|
||||
g.dispose();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,9 +139,7 @@ public class ColorPane extends JEditorPane {
|
|||
if (hyperlinkEnabled) {
|
||||
text = text.replaceAll("(<font color=[^>]*>([^<]*)) (\\[[0-9a-fA-F]*\\])</font>", "<a href=\"#$2\">$1</a> $3");
|
||||
}
|
||||
setEditable(true);
|
||||
kit.insertHTML(doc, doc.getLength(), text, 0, 0, null);
|
||||
setEditable(false);
|
||||
int len = getDocument().getLength();
|
||||
setCaretPosition(len);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,18 @@
|
|||
package mage.client.components;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import javax.swing.JPanel;
|
||||
import mage.client.util.ImageCaches;
|
||||
import org.jdesktop.swingx.graphics.GraphicsUtilities;
|
||||
import org.jdesktop.swingx.graphics.ShadowRenderer;
|
||||
|
||||
|
|
@ -21,23 +27,145 @@ public class MageRoundPane extends JPanel {
|
|||
|
||||
private int X_OFFSET = 30;
|
||||
private int Y_OFFSET = 30;
|
||||
private BufferedImage shadow = null;
|
||||
private final Color defaultBackgroundColor = new Color(255, 255, 255, 200);
|
||||
private Color backgroundColor = defaultBackgroundColor;
|
||||
private final int alpha = 0;
|
||||
private static Map<ShadowKey, BufferedImage> SHADOW_IMAGE_CACHE;
|
||||
private static Map<Key, BufferedImage> IMAGE_CACHE;
|
||||
|
||||
static {
|
||||
SHADOW_IMAGE_CACHE = ImageCaches.register(new MapMaker().softValues().makeComputingMap(new Function<ShadowKey, BufferedImage>() {
|
||||
@Override
|
||||
public BufferedImage apply(ShadowKey key) {
|
||||
return createShadowImage(key);
|
||||
}
|
||||
}));
|
||||
|
||||
IMAGE_CACHE = ImageCaches.register(new MapMaker().softValues().makeComputingMap(new Function<Key, BufferedImage>() {
|
||||
@Override
|
||||
public BufferedImage apply(Key key) {
|
||||
return createImage(key);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private final static class ShadowKey
|
||||
{
|
||||
final int width;
|
||||
final int height;
|
||||
|
||||
public ShadowKey(int width, int height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
hash = 97 * hash + this.width;
|
||||
hash = 97 * hash + this.height;
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final ShadowKey other = (ShadowKey) obj;
|
||||
if (this.width != other.width) {
|
||||
return false;
|
||||
}
|
||||
if (this.height != other.height) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private final static class Key
|
||||
{
|
||||
final int width;
|
||||
final int height;
|
||||
final int xOffset;
|
||||
final int yOffset;
|
||||
final Color backgroundColor;
|
||||
|
||||
public Key(int width, int height, int xOffset, int yOffset, Color backgroundColor) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.xOffset = xOffset;
|
||||
this.yOffset = yOffset;
|
||||
this.backgroundColor = backgroundColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 5;
|
||||
hash = 59 * hash + this.width;
|
||||
hash = 59 * hash + this.height;
|
||||
hash = 59 * hash + this.xOffset;
|
||||
hash = 59 * hash + this.yOffset;
|
||||
hash = 59 * hash + Objects.hashCode(this.backgroundColor);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final Key other = (Key) obj;
|
||||
if (this.width != other.width) {
|
||||
return false;
|
||||
}
|
||||
if (this.height != other.height) {
|
||||
return false;
|
||||
}
|
||||
if (this.xOffset != other.xOffset) {
|
||||
return false;
|
||||
}
|
||||
if (this.yOffset != other.yOffset) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.backgroundColor, other.backgroundColor)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
int x = X_OFFSET;
|
||||
int y = Y_OFFSET;
|
||||
int w = getWidth() - 2 * X_OFFSET;
|
||||
int h = getHeight() - 2 * Y_OFFSET;
|
||||
g.drawImage(IMAGE_CACHE.get(new Key(getWidth(), getHeight(), X_OFFSET, Y_OFFSET, backgroundColor)), 0, 0, null);
|
||||
}
|
||||
|
||||
private static BufferedImage createImage(Key key) {
|
||||
int x = key.xOffset;
|
||||
int y = key.yOffset;
|
||||
int w = key.width - 2 * key.xOffset;
|
||||
int h = key.height - 2 * key.yOffset;
|
||||
int arc = 10;
|
||||
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
BufferedImage image = GraphicsUtilities.createCompatibleTranslucentImage(key.width, key.height);
|
||||
Graphics2D g2 = image.createGraphics();
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
if (shadow != null) {
|
||||
BufferedImage shadow = SHADOW_IMAGE_CACHE.get(new ShadowKey(w, h));
|
||||
|
||||
{
|
||||
int xOffset = (shadow.getWidth() - w) / 2;
|
||||
int yOffset = (shadow.getHeight() - h) / 2;
|
||||
g2.drawImage(shadow, x - xOffset, y - yOffset, null);
|
||||
|
|
@ -54,7 +182,7 @@ public class MageRoundPane extends JPanel {
|
|||
g2.fillRoundRect(x, y, w, h, arc, arc);
|
||||
}*/
|
||||
|
||||
g2.setColor(backgroundColor);
|
||||
g2.setColor(key.backgroundColor);
|
||||
g2.fillRoundRect(x, y, w, h, arc, arc);
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
@ -66,6 +194,7 @@ public class MageRoundPane extends JPanel {
|
|||
// ////////////////////////////////////////////////////////////////
|
||||
|
||||
g2.dispose();
|
||||
return image;
|
||||
}
|
||||
|
||||
public void setXOffset(int x_offset) {
|
||||
|
|
@ -76,24 +205,21 @@ public class MageRoundPane extends JPanel {
|
|||
Y_OFFSET = y_offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBounds(int x, int y, int width, int height) {
|
||||
super.setBounds(x, y, width, height);
|
||||
|
||||
int w = getWidth() - 2 * X_OFFSET;
|
||||
int h = getHeight() - 2 * Y_OFFSET;
|
||||
private static BufferedImage createShadowImage(ShadowKey key) {
|
||||
int w = key.width;
|
||||
int h = key.height;
|
||||
int arc = 10;
|
||||
int shadowSize = 50;
|
||||
|
||||
shadow = GraphicsUtilities.createCompatibleTranslucentImage(w, h);
|
||||
Graphics2D g2 = shadow.createGraphics();
|
||||
BufferedImage base = GraphicsUtilities.createCompatibleTranslucentImage(w, h);
|
||||
Graphics2D g2 = base.createGraphics();
|
||||
g2.setColor(Color.WHITE);
|
||||
g2.fillRoundRect(0, 0, w, h, arc, arc);
|
||||
g2.dispose();
|
||||
|
||||
ShadowRenderer renderer = new ShadowRenderer(shadowSize, 0.5f,
|
||||
Color.GRAY);
|
||||
shadow = renderer.createShadow(shadow);
|
||||
return renderer.createShadow(base);
|
||||
}
|
||||
|
||||
public void showDialog(boolean bShow) {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import org.mage.card.arcane.UI;
|
|||
* @author nantuko
|
||||
*/
|
||||
public class MageTextArea extends JEditorPane {
|
||||
private String currentText;
|
||||
private int currentPanelWidth;
|
||||
|
||||
public MageTextArea() {
|
||||
UI.setHTMLEditorKit(this);
|
||||
|
|
@ -31,6 +33,12 @@ public class MageTextArea extends JEditorPane {
|
|||
return;
|
||||
}
|
||||
|
||||
if(text.equals(currentText) && panelWidth == currentPanelWidth)
|
||||
return;
|
||||
|
||||
currentText = text;
|
||||
currentPanelWidth = panelWidth;
|
||||
|
||||
final StringBuilder buffer = new StringBuilder(512);
|
||||
// Dialog is a java logical font family, so it should work on all systems
|
||||
buffer.append("<html><body style='font-family:Dialog;font-size:");
|
||||
|
|
|
|||
|
|
@ -409,8 +409,7 @@ public class TableModel extends AbstractTableModel implements ICardGrid {
|
|||
Image image = Plugins.getInstance().getOriginalImage(card);
|
||||
if (image != null && image instanceof BufferedImage) {
|
||||
// XXX: scaled to fit width
|
||||
image = ImageHelper.getResizedImage((BufferedImage) image, bigCard.getWidth());
|
||||
bigCard.setCard(card.getId(), EnlargeMode.NORMAL, image, new ArrayList<String>());
|
||||
bigCard.setCard(card.getId(), EnlargeMode.NORMAL, image, new ArrayList<String>(), false);
|
||||
} else {
|
||||
drawCardText(card);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ public class DraftPanel extends javax.swing.JPanel {
|
|||
int height = left * 18;
|
||||
lblTableImage.setSize(new Dimension(lblTableImage.getWidth(), height));
|
||||
Image tableImage = ImageHelper.getImageFromResources(draftView.getBoosterNum() == 2 ? "/draft/table_left.png" : "/draft/table_right.png");
|
||||
BufferedImage resizedTable = ImageHelper.getResizedImage(BufferedImageBuilder.bufferImage(tableImage, BufferedImage.TYPE_INT_ARGB), lblTableImage.getWidth());
|
||||
BufferedImage resizedTable = ImageHelper.getResizedImage(BufferedImageBuilder.bufferImage(tableImage, BufferedImage.TYPE_INT_ARGB), lblTableImage.getWidth(), lblTableImage.getHeight());
|
||||
lblTableImage.setIcon(new ImageIcon(resizedTable));
|
||||
|
||||
int count = 0;
|
||||
|
|
|
|||
|
|
@ -155,6 +155,7 @@ public class MageActionCallback implements ActionCallback {
|
|||
}
|
||||
data.locationOnScreen = data.component.getLocationOnScreen();
|
||||
}
|
||||
data.popupText.updateText();
|
||||
tooltipPopup = factory.getPopup(data.component, data.popupText, (int) data.locationOnScreen.getX() + data.popupOffsetX, (int) data.locationOnScreen.getY() + data.popupOffsetY + 40);
|
||||
tooltipPopup.show();
|
||||
// hack to get popup to resize to fit text
|
||||
|
|
@ -597,13 +598,7 @@ public class MageActionCallback implements ActionCallback {
|
|||
private void displayCardInfo(MageCard mageCard, Image image, BigCard bigCard) {
|
||||
if (image != null && image instanceof BufferedImage) {
|
||||
// XXX: scaled to fit width
|
||||
if (mageCard.getOriginal().isToRotate() && bigCard.getWidth() > bigCard.getHeight()) {
|
||||
image = ImageHelper.getResizedImage((BufferedImage) image, bigCard.getHeight());
|
||||
image = ImageHelper.rotate((BufferedImage) image, Math.toRadians(90));
|
||||
} else {
|
||||
image = ImageHelper.getResizedImage((BufferedImage) image, bigCard.getWidth());
|
||||
}
|
||||
bigCard.setCard(mageCard.getOriginal().getId(), enlargeMode, image, mageCard.getOriginal().getRules());
|
||||
bigCard.setCard(mageCard.getOriginal().getId(), enlargeMode, image, mageCard.getOriginal().getRules(), mageCard.getOriginal().isToRotate());
|
||||
// if it's an ability, show only the ability text as overlay
|
||||
if (mageCard.getOriginal().isAbility() && enlargeMode.equals(EnlargeMode.NORMAL)) {
|
||||
bigCard.showTextComponent();
|
||||
|
|
|
|||
34
Mage.Client/src/main/java/mage/client/util/ImageCaches.java
Normal file
34
Mage.Client/src/main/java/mage/client/util/ImageCaches.java
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.client.util;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author user
|
||||
*/
|
||||
public class ImageCaches {
|
||||
private static Vector<Map> IMAGE_CACHES;
|
||||
|
||||
static {
|
||||
IMAGE_CACHES = new Vector<Map>();
|
||||
}
|
||||
|
||||
public static Map register(Map map)
|
||||
{
|
||||
IMAGE_CACHES.add(map);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static void flush()
|
||||
{
|
||||
for (Map map : IMAGE_CACHES) {
|
||||
map.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -52,6 +52,7 @@ import static mage.client.constants.Constants.FRAME_MAX_WIDTH;
|
|||
import static mage.client.constants.Constants.SYMBOL_MAX_SPACE;
|
||||
import mage.view.CardView;
|
||||
import org.mage.card.arcane.UI;
|
||||
import org.mage.plugins.card.images.ImageCache;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -70,21 +71,6 @@ public class ImageHelper {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param ref - image name
|
||||
* @param height - height after scaling
|
||||
* @return a scaled image that preserves the original aspect ratio, with a
|
||||
* specified height
|
||||
*/
|
||||
public static BufferedImage loadImage(String ref, int height) {
|
||||
BufferedImage image = loadImage(ref);
|
||||
if (image != null) {
|
||||
return scaleImage(image, height);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static BufferedImage loadImage(String ref) {
|
||||
if (!images.containsKey(ref)) {
|
||||
try {
|
||||
|
|
@ -107,67 +93,7 @@ public class ImageHelper {
|
|||
}
|
||||
|
||||
public static BufferedImage scaleImage(BufferedImage image, int width, int height) {
|
||||
BufferedImage scaledImage = image;
|
||||
int w = image.getWidth();
|
||||
int h = image.getHeight();
|
||||
do {
|
||||
w /= 2;
|
||||
h /= 2;
|
||||
if (w < width || h < height) {
|
||||
w = width;
|
||||
h = height;
|
||||
}
|
||||
BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D graphics2D = newImage.createGraphics();
|
||||
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
graphics2D.drawImage(scaledImage, 0, 0, w, h, null);
|
||||
graphics2D.dispose();
|
||||
scaledImage = newImage;
|
||||
} while (w != width || h != height);
|
||||
return scaledImage;
|
||||
}
|
||||
|
||||
public static BufferedImage scaleImage(BufferedImage image, int height) {
|
||||
double ratio = height / (double) image.getHeight();
|
||||
int width = (int) (image.getWidth() * ratio);
|
||||
return scaleImage(image, width, height);
|
||||
}
|
||||
|
||||
public static MemoryImageSource rotate(Image image, CardDimensions dimensions) {
|
||||
int buffer[] = new int[dimensions.frameWidth * dimensions.frameHeight];
|
||||
int rotate[] = new int[dimensions.frameHeight * dimensions.frameWidth];
|
||||
PixelGrabber grabber = new PixelGrabber(image, 0, 0, dimensions.frameWidth, dimensions.frameHeight, buffer, 0, dimensions.frameWidth);
|
||||
try {
|
||||
grabber.grabPixels();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
for (int y = 0; y < dimensions.frameHeight; y++) {
|
||||
for (int x = 0; x < dimensions.frameWidth; x++) {
|
||||
rotate[((dimensions.frameWidth - x - 1) * dimensions.frameHeight) + y] = buffer[(y * dimensions.frameWidth) + x];
|
||||
}
|
||||
}
|
||||
|
||||
return new MemoryImageSource(dimensions.frameHeight, dimensions.frameWidth, rotate, 0, dimensions.frameHeight);
|
||||
|
||||
}
|
||||
|
||||
public static BufferedImage rotate(BufferedImage image, double angle) {
|
||||
double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle));
|
||||
int w = image.getWidth(), h = image.getHeight();
|
||||
int neww = (int) Math.floor(w * cos + h * sin), newh = (int) Math.floor(h * cos + w * sin);
|
||||
|
||||
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
GraphicsDevice gs = ge.getDefaultScreenDevice();
|
||||
GraphicsConfiguration gc = gs.getDefaultConfiguration();
|
||||
|
||||
BufferedImage result = gc.createCompatibleImage(neww, newh, Transparency.TRANSLUCENT);
|
||||
Graphics2D g = result.createGraphics();
|
||||
g.translate((neww - w) / 2, (newh - h) / 2);
|
||||
g.rotate(angle, w / 2, h / 2);
|
||||
g.drawRenderedImage(image, null);
|
||||
g.dispose();
|
||||
return result;
|
||||
return TransformedImageCache.getResizedImage(image, width, height);
|
||||
}
|
||||
|
||||
public static void drawCosts(List<String> costs, Graphics2D g, int xOffset, int yOffset, ImageObserver o) {
|
||||
|
|
@ -191,26 +117,7 @@ public class ImageHelper {
|
|||
* @return
|
||||
*/
|
||||
public static BufferedImage getResizedImage(BufferedImage original, int width, int height) {
|
||||
ResampleOp resampleOp = new ResampleOp(width, height);
|
||||
BufferedImage image = resampleOp.filter(original, null);
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an image scaled to fit width panel
|
||||
*
|
||||
* @param original
|
||||
* @param width
|
||||
* @return
|
||||
*/
|
||||
public static BufferedImage getResizedImage(BufferedImage original, int width) {
|
||||
if (width != original.getWidth()) {
|
||||
double ratio = width / (double) original.getWidth();
|
||||
int height = (int) (original.getHeight() * ratio);
|
||||
return getResizedImage(original, width, height);
|
||||
} else {
|
||||
return original;
|
||||
}
|
||||
return TransformedImageCache.getResizedImage(original, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -223,17 +130,7 @@ public class ImageHelper {
|
|||
* @return scaled image
|
||||
*/
|
||||
public static BufferedImage scale(BufferedImage sbi, int imageType, int dWidth, int dHeight) {
|
||||
BufferedImage dbi = null;
|
||||
if (sbi != null) {
|
||||
double fWidth = dWidth / sbi.getWidth();
|
||||
double fHeight = dHeight / sbi.getHeight();
|
||||
dbi = new BufferedImage(dWidth, dHeight, imageType);
|
||||
Graphics2D g = dbi.createGraphics();
|
||||
AffineTransform at = AffineTransform.getScaleInstance(fWidth, fHeight);
|
||||
g.drawRenderedImage(sbi, at);
|
||||
g.dispose();
|
||||
}
|
||||
return dbi;
|
||||
return TransformedImageCache.getResizedImage(sbi, dWidth, dHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -244,9 +141,7 @@ public class ImageHelper {
|
|||
* @return
|
||||
*/
|
||||
public static BufferedImage getResizedImage(BufferedImage original, Rectangle sizeNeed) {
|
||||
ResampleOp resampleOp = new ResampleOp(sizeNeed.width, sizeNeed.height);
|
||||
BufferedImage image = resampleOp.filter(original, null);
|
||||
return image;
|
||||
return TransformedImageCache.getResizedImage(original, sizeNeed.width, sizeNeed.height);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.client.util;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.mortennobel.imagescaling.ResampleOp;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Transparency;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Map;
|
||||
import mage.client.util.ImageHelper;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author user
|
||||
*/
|
||||
public class TransformedImageCache {
|
||||
private final static class Key
|
||||
{
|
||||
final int width;
|
||||
final int height;
|
||||
final double angle;
|
||||
|
||||
public Key(int width, int height, double angle) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.angle = angle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 3;
|
||||
hash = 53 * hash + this.width;
|
||||
hash = 53 * hash + this.height;
|
||||
hash = 53 * hash + (int) (Double.doubleToLongBits(this.angle) ^ (Double.doubleToLongBits(this.angle) >>> 32));
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final Key other = (Key) obj;
|
||||
if (this.width != other.width) {
|
||||
return false;
|
||||
}
|
||||
if (this.height != other.height) {
|
||||
return false;
|
||||
}
|
||||
if (Double.doubleToLongBits(this.angle) != Double.doubleToLongBits(other.angle)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static Map<Key, Map<BufferedImage, BufferedImage>> IMAGE_CACHE;
|
||||
|
||||
static
|
||||
{
|
||||
// TODO: can we use a single map?
|
||||
IMAGE_CACHE = ImageCaches.register(new MapMaker().softValues().makeComputingMap(new Function<Key, Map<BufferedImage, BufferedImage>>() {
|
||||
@Override
|
||||
public Map<BufferedImage, BufferedImage> apply(final Key key) {
|
||||
return new MapMaker().weakKeys().softValues().makeComputingMap(new Function<BufferedImage, BufferedImage>() {
|
||||
@Override
|
||||
public BufferedImage apply(BufferedImage image) {
|
||||
if(key.width != image.getWidth() || key.height != image.getHeight())
|
||||
image = resizeImage(image, key.width, key.height);
|
||||
if(key.angle != 0.0)
|
||||
image = rotateImage(image, key.angle);
|
||||
return image;
|
||||
}
|
||||
});
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private static BufferedImage rotateImage(BufferedImage image, double angle) {
|
||||
double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle));
|
||||
int w = image.getWidth(), h = image.getHeight();
|
||||
int neww = (int) Math.floor(w * cos + h * sin), newh = (int) Math.floor(h * cos + w * sin);
|
||||
|
||||
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
GraphicsDevice gs = ge.getDefaultScreenDevice();
|
||||
GraphicsConfiguration gc = gs.getDefaultConfiguration();
|
||||
|
||||
BufferedImage result = gc.createCompatibleImage(neww, newh, Transparency.TRANSLUCENT);
|
||||
Graphics2D g = result.createGraphics();
|
||||
g.translate((neww - w) / 2, (newh - h) / 2);
|
||||
g.rotate(angle, w / 2, h / 2);
|
||||
g.drawRenderedImage(image, null);
|
||||
g.dispose();
|
||||
return result;
|
||||
}
|
||||
|
||||
private static BufferedImage resizeImage(BufferedImage original, int width, int height) {
|
||||
ResampleOp resampleOp = new ResampleOp(width, height);
|
||||
BufferedImage image = resampleOp.filter(original, null);
|
||||
return image;
|
||||
}
|
||||
|
||||
public static BufferedImage getResizedImage(BufferedImage image, int width, int height)
|
||||
{
|
||||
return getRotatedResizedImage(image, width, height, 0.0);
|
||||
}
|
||||
|
||||
public static BufferedImage getRotatedImage(BufferedImage image, double angle)
|
||||
{
|
||||
return getRotatedResizedImage(image, -1, -1, angle);
|
||||
}
|
||||
|
||||
public static BufferedImage getRotatedResizedImage(BufferedImage image, int width, int height, double angle)
|
||||
{
|
||||
int imageWidth = image.getWidth();
|
||||
int imageHeight = image.getHeight();
|
||||
|
||||
if(angle == 0.0 && (width < 0 || imageWidth == width) && (height < 0 || imageHeight == height))
|
||||
return image;
|
||||
|
||||
int resWidth;
|
||||
int resHeight;
|
||||
if(width < 0 && height < 0) {
|
||||
resWidth = imageWidth;
|
||||
resHeight = imageHeight;
|
||||
} else if((height < 0) || (width >= 0 && imageHeight * width <= imageWidth * height)) {
|
||||
resWidth = width;
|
||||
resHeight = imageHeight * width / imageWidth;
|
||||
} else {
|
||||
resWidth = imageWidth * height / imageHeight;
|
||||
resHeight = height;
|
||||
}
|
||||
|
||||
if(angle == 0.0 && imageWidth == resWidth && imageHeight == resHeight)
|
||||
return image;
|
||||
|
||||
return IMAGE_CACHE.get(new Key(resWidth, resHeight, angle)).get(image);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue