Face down images and cards rework (#11873)

Face down changes:
* GUI: added visible face down type and real card name for controller/owner (opponent can see it after game ends);
* GUI: added day/night button to view real card for controller/owner (opponent can see it after game ends);
* game: fixed that faced-down card can render symbols, abilities and other hidden data from a real card;
* images: added image support for normal faced-down cards;
* images: added image support for morph and megamorph faced-down cards;
* images: added image support for foretell faced-down cards;

Other changes:
* images: fixed missing tokens from DDD set;
* images: no more client restart to apply newly downloaded images or render settings;
* images: improved backface image quality (use main menu -> symbols to download it);
This commit is contained in:
Oleg Agafonov 2024-02-29 01:14:54 +04:00 committed by GitHub
parent 4901de12c1
commit e38a79f231
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
104 changed files with 2178 additions and 1495 deletions

View file

@ -1517,7 +1517,11 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
public void setConnectButtonText(String status) {
this.btnConnect.setText(status);
changeGUISize(); // Needed to layout the tooltbar after text length change
// Needed to layout the tooltbar after text length change
// TODO: need research, is it actual?
GUISizeHelper.refreshGUIAndCards();
this.btnConnect.repaint();
this.btnConnect.revalidate();
}
@ -1741,8 +1745,13 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
}
}
public void changeGUISize() {
ImageCaches.flush();
/**
* Refresh whole GUI including cards and card images.
* Use it after new images downloaded, new fonts or theme settings selected.
*/
public void refreshGUIAndCards() {
ImageCaches.clearAll();
setGUISize();
setGUISizeTooltipContainer();

View file

@ -24,12 +24,12 @@ public class MageRoundPane extends JPanel {
private int Y_OFFSET = 30;
private final Color defaultBackgroundColor = new Color(141, 130, 112, 200); // color of the frame of the popup window
private Color backgroundColor = defaultBackgroundColor;
private static final SoftValuesLoadingCache<ShadowKey, BufferedImage> SHADOW_IMAGE_CACHE;
private static final SoftValuesLoadingCache<Key, BufferedImage> IMAGE_CACHE;
private static final SoftValuesLoadingCache<ShadowKey, BufferedImage> ROUND_PANEL_SHADOW_IMAGES_CACHE;
private static final SoftValuesLoadingCache<Key, BufferedImage> ROUND_PANEL_IMAGES_CACHE;
static {
SHADOW_IMAGE_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(MageRoundPane::createShadowImage));
IMAGE_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(MageRoundPane::createImage));
ROUND_PANEL_IMAGES_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(MageRoundPane::createImage));
ROUND_PANEL_SHADOW_IMAGES_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(MageRoundPane::createShadowImage));
}
private static final class ShadowKey {
@ -132,7 +132,7 @@ public class MageRoundPane extends JPanel {
@Override
protected void paintComponent(Graphics g) {
g.drawImage(IMAGE_CACHE.getOrThrow(new Key(getWidth(), getHeight(), X_OFFSET, Y_OFFSET, backgroundColor)), 0, 0, null);
g.drawImage(ROUND_PANEL_IMAGES_CACHE.getOrThrow(new Key(getWidth(), getHeight(), X_OFFSET, Y_OFFSET, backgroundColor)), 0, 0, null);
}
private static BufferedImage createImage(Key key) {
@ -146,7 +146,7 @@ public class MageRoundPane extends JPanel {
Graphics2D g2 = image.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
BufferedImage shadow = SHADOW_IMAGE_CACHE.getOrThrow(new ShadowKey(w, h));
BufferedImage shadow = ROUND_PANEL_SHADOW_IMAGES_CACHE.getOrThrow(new ShadowKey(w, h));
{
int xOffset = (shadow.getWidth() - w) / 2;

View file

@ -19,6 +19,7 @@ import mage.client.util.audio.AudioManager;
import mage.client.util.sets.ConstructedFormats;
import mage.components.ImagePanel;
import mage.components.ImagePanelStyle;
import mage.constants.MageObjectType;
import mage.game.command.Dungeon;
import mage.game.command.Emblem;
import mage.game.command.Plane;
@ -396,7 +397,7 @@ public class MageBook extends JComponent {
draftRating.setBounds(rectangle.x, rectangle.y + cardImg.getCardLocation().getCardHeight() + dy, cardDimensions.getFrameWidth(), 20);
draftRating.setHorizontalAlignment(SwingConstants.CENTER);
draftRating.setFont(jLayeredPane.getFont().deriveFont(jLayeredPane.getFont().getStyle() | Font.BOLD));
if (card.isOriginalACard()) {
if (card.getMageObjectType().equals(MageObjectType.CARD)) {
// card
draftRating.setText("draft rating: " + RateCard.rateCard(card, null));
} else {

View file

@ -87,8 +87,8 @@ public class MageCardComparator implements CardViewComparator {
bCom = RateCard.rateCard(b, null);
break;
case 10:
aCom = a.getColorIdentityStr();
bCom = b.getColorIdentityStr();
aCom = a.getOriginalColorIdentity();
bCom = b.getOriginalColorIdentity();
break;
default:
break;

View file

@ -255,7 +255,7 @@ public class TableModel extends AbstractTableModel implements ICardGrid {
case 9:
return RateCard.rateCard(c, null);
case 10:
return ManaSymbols.getClearManaCost(c.getColorIdentityStr());
return ManaSymbols.getClearManaCost(c.getOriginalColorIdentity());
default:
return "error";
}

View file

@ -2928,8 +2928,8 @@ public class PreferencesDialog extends javax.swing.JDialog {
save(prefs, dialog.sliderCardSizeMinBattlefield, KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.sliderCardSizeMaxBattlefield, KEY_GUI_CARD_BATTLEFIELD_MAX_SIZE, "true", "false", UPDATE_CACHE_POLICY);
// do as worker job
GUISizeHelper.changeGUISize();
// refresh full GUI with new settings
GUISizeHelper.refreshGUIAndCards();
}
private void exitButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitButtonActionPerformed

View file

@ -2,6 +2,7 @@ package mage.client.dialog;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect;
import mage.abilities.icon.*;
import mage.abilities.keyword.TransformAbility;
import mage.cards.*;
@ -184,6 +185,18 @@ public class TestCardRenderDialog extends MageDialog {
if (perm.isTransformable()) {
perm.setTransformed(true);
}
// workaround to apply face down image and other settings
if (perm.isFaceDown(game)) {
BecomesFaceDownCreatureEffect.makeFaceDownObject(
game,
null,
perm,
BecomesFaceDownCreatureEffect.findFaceDownType(game, perm),
null
);
}
PermanentView cardView = new PermanentView(perm, permCard, controllerId, game);
cardView.setInViewerOnly(false); // must false for face down
return cardView;
@ -386,9 +399,9 @@ public class TestCardRenderDialog extends MageDialog {
List<CardView> cardViews = new ArrayList<>();
/* test morphed
cardViews.add(createPermanentCard(game, playerYou.getId(), "RNA", "263", 0, 0, 0, false, null)); // mountain
cardViews.add(createPermanentCard(game, playerYou.getId(), "RNA", "185", 0, 0, 0, true, null)); // Judith, the Scourge Diva
//* test face down
cardViews.add(createPermanentCard(game, playerYou.getId(), "RNA", "263", 0, 0, 0, false, false, null)); // mountain
cardViews.add(createPermanentCard(game, playerYou.getId(), "RNA", "185", 0, 0, 0, true, false, null)); // Judith, the Scourge Diva
cardViews.add(createHandCard(game, playerYou.getId(), "DIS", "153")); // Odds // Ends (split card)
cardViews.add(createHandCard(game, playerYou.getId(), "ELD", "38")); // Animating Faerie (adventure card)
cardViews.add(createFaceDownCard(game, playerOpponent.getId(), "ELD", "38", false, false, false)); // face down
@ -414,7 +427,7 @@ public class TestCardRenderDialog extends MageDialog {
cardViews.add(createHandCard(game, playerYou.getId(), "AKH", "210")); // Dusk // Dawn
//*/
//* test adventure cards in hands
/* test adventure cards in hands
cardViews.add(createHandCard(game, playerYou.getId(), "ELD", "14")); // Giant Killer
cardViews.add(createHandCard(game, playerYou.getId(), "WOE", "222")); // Cruel Somnophage
cardViews.add(createHandCard(game, playerYou.getId(), "WOE", "227")); // Gingerbread Hunter
@ -430,7 +443,7 @@ public class TestCardRenderDialog extends MageDialog {
cardViews.add(createHandCard(game, playerYou.getId(), "MKM", "155")); // Case of the Locked Hothouse
//*/
//* test case, class and saga cards in hands
/* test case, class and saga cards in hands
cardViews.add(createHandCard(game, playerYou.getId(), "MKM", "113")); // Case of the Burning Masks
cardViews.add(createHandCard(game, playerYou.getId(), "MKM", "155")); // Case of the Locked Hothouse
cardViews.add(createHandCard(game, playerYou.getId(), "AFR", "6")); // Cleric Class
@ -504,7 +517,7 @@ public class TestCardRenderDialog extends MageDialog {
PermanentView oldPermanent = (PermanentView) main.getGameCard();
PermanentView newPermament = new PermanentView(
oldPermanent,
game.getCard(oldPermanent.getOriginalId()),
game.getCard(oldPermanent.getId()),
UUID.randomUUID(),
game
);

View file

@ -117,7 +117,7 @@ public class MageActionCallback implements ActionCallback {
}
@Override
public void mouseClicked(MouseEvent e, TransferData data, boolean doubleClick) {
public void mouseClicked(MouseEvent e, TransferData data, boolean doubleClick) {
// send mouse clicked event to the card's area and other cards list components for processing
if (e.isConsumed()) {
return;
@ -720,7 +720,7 @@ public class MageActionCallback implements ActionCallback {
switch (enlargeMode) {
case COPY:
if (cardView instanceof PermanentView) {
image = ImageCache.getImageOriginal(((PermanentView) cardView).getOriginal()).getImage();
image = ImageCache.getCardImageOriginal(((PermanentView) cardView).getOriginal()).getImage();
}
break;
case ALTERNATE:
@ -729,10 +729,14 @@ public class MageActionCallback implements ActionCallback {
&& !cardView.isFlipCard()
&& !cardView.canTransform()
&& ((PermanentView) cardView).isCopy()) {
image = ImageCache.getImageOriginal(((PermanentView) cardView).getOriginal()).getImage();
image = ImageCache.getCardImageOriginal(((PermanentView) cardView).getOriginal()).getImage();
} else {
image = ImageCache.getImageOriginalAlternateName(cardView).getImage();
image = ImageCache.getCardImageAlternate(cardView).getImage();
displayCard = displayCard.getSecondCardFace();
if (displayCard == null) {
// opponent's face down cards are hidden, so no alternative
displayCard = cardPanel.getOriginal();
}
}
}
break;
@ -745,7 +749,6 @@ public class MageActionCallback implements ActionCallback {
} else {
logger.warn("No Card preview Pane in Mage Frame defined. Card: " + cardView.getName());
}
} catch (Exception e) {
logger.warn("Problem dring display of enlarged card", e);
}
@ -786,6 +789,7 @@ public class MageActionCallback implements ActionCallback {
private void displayCardInfo(CardView card, Image image, BigCard bigCard) {
if (image instanceof BufferedImage) {
// IMAGE MODE
// XXX: scaled to fit width
bigCard.setCard(card.getId(), enlargeMode, image, card.getRules(), card.isToRotate());
// if it's an ability, show only the ability text as overlay
@ -795,6 +799,7 @@ public class MageActionCallback implements ActionCallback {
bigCard.hideTextComponent();
}
} else {
// TEXT MODE
JXPanel panel = GuiDisplayUtil.getDescription(card, bigCard.getWidth(), bigCard.getHeight());
panel.setVisible(true);
bigCard.hideTextComponent();

View file

@ -2,8 +2,9 @@ package mage.client.themes;
import mage.abilities.hint.HintUtils;
import mage.abilities.icon.CardIconColor;
import mage.client.util.GUISizeHelper;
import mage.client.util.ImageCaches;
import org.mage.card.arcane.SvgUtils;
import org.mage.plugins.card.images.ImageCache;
import java.awt.*;
@ -350,6 +351,6 @@ public enum ThemeType {
}
// reload card icons and other rendering things from cache - it can depend on current theme
ImageCache.clearCache();
GUISizeHelper.refreshGUIAndCards();
}
}

View file

@ -9,7 +9,7 @@ import java.util.List;
import java.util.Map;
/**
* @author BetaSteward_at_googlemail.com
* @author BetaSteward_at_googlemail.com, JayDi85
*/
public final class CardsViewUtil {

View file

@ -84,9 +84,11 @@ public final class GUISizeHelper {
return new Font("Arial", Font.PLAIN, 14);
}
public static void changeGUISize() {
public static void refreshGUIAndCards() {
calculateGUISizes();
MageFrame.getInstance().changeGUISize();
if (MageFrame.getInstance() != null) {
MageFrame.getInstance().refreshGUIAndCards();
}
}
public static void calculateGUISizes() {

View file

@ -1,11 +1,11 @@
package mage.client.util;
import java.util.ArrayList;
import com.google.common.cache.Cache;
import java.util.ArrayList;
/**
* GUI: collect info about all used image caches, so it can be cleared from a single place
*
* @author draxdyn
*/
@ -22,7 +22,11 @@ public final class ImageCaches {
return map;
}
public static void flush() {
/**
* Global method to clear all images cache.
* Warning, GUI must be refreshed too for card updates, so use GUISizeHelper.refreshGUIAndCards instead
*/
public static void clearAll() {
for (Cache<?, ?> map : IMAGE_CACHES) {
map.invalidateAll();
}

View file

@ -55,11 +55,10 @@ public final class TransformedImageCache {
}
}
private static final SoftValuesLoadingCache<Key, SoftValuesLoadingCache<BufferedImage, BufferedImage>> IMAGE_CACHE;
private static final SoftValuesLoadingCache<Key, SoftValuesLoadingCache<BufferedImage, BufferedImage>> TRANSFORMED_IMAGES_CACHE;
static {
// TODO: can we use a single map?
IMAGE_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(TransformedImageCache::createTransformedImageCache));
TRANSFORMED_IMAGES_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(TransformedImageCache::createTransformedImageCache));
}
private static SoftValuesLoadingCache<BufferedImage, BufferedImage> createTransformedImageCache(Key key) {
@ -139,6 +138,6 @@ public final class TransformedImageCache {
if (resHeight < 3) {
resHeight = 3;
}
return IMAGE_CACHE.getOrThrow(new Key(resWidth, resHeight, angle)).getOrThrow(image);
return TRANSFORMED_IMAGES_CACHE.getOrThrow(new Key(resWidth, resHeight, angle)).getOrThrow(image);
}
}

View file

@ -377,7 +377,7 @@ public abstract class CardPanel extends MagePermanent implements ComponentListen
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) (g.create());
// Deferr to subclasses
// Defer to subclasses
paintCard(g2d);
// Done, dispose of the context
@ -854,7 +854,7 @@ public abstract class CardPanel extends MagePermanent implements ComponentListen
// VIEW mode (user can change card side at any time by n/d button)
this.guiTransformed = !this.guiTransformed;
if (dayNightButton != null) { // if transformbable card is copied, button can be null
if (dayNightButton != null) { // if transformable card is copied, button can be null
BufferedImage image = this.isTransformed() ? ImageManagerImpl.instance.getNightImage() : ImageManagerImpl.instance.getDayImage();
dayNightButton.setIcon(new ImageIcon(image));
}

View file

@ -14,8 +14,6 @@ import mage.constants.SubType;
import mage.util.DebugUtil;
import mage.view.CardView;
import mage.view.CounterView;
import mage.view.PermanentView;
import mage.view.StackAbilityView;
import org.jdesktop.swingx.graphics.GraphicsUtilities;
import org.mage.plugins.card.images.ImageCache;
import org.mage.plugins.card.images.ImageCacheData;
@ -37,7 +35,7 @@ public class CardPanelRenderModeImage extends CardPanel {
private static final long serialVersionUID = -3272134219262184411L;
private static final SoftValuesLoadingCache<Key, BufferedImage> IMAGE_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(CardPanelRenderModeImage::createImage));
private static final SoftValuesLoadingCache<Key, BufferedImage> IMAGE_MODE_RENDERED_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(CardPanelRenderModeImage::createImage));
private static final int WIDTH_LIMIT = 90; // card width limit to create smaller counter
@ -472,11 +470,7 @@ public class CardPanelRenderModeImage extends CardPanel {
@Override
public Image getImage() {
if (this.hasImage) {
if (getGameCard().isFaceDown()) {
return getFaceDownImage().getImage();
} else {
return ImageCache.getImageOriginal(getGameCard()).getImage();
}
return ImageCache.getCardImageOriginal(getGameCard()).getImage();
}
return null;
}
@ -492,7 +486,7 @@ public class CardPanelRenderModeImage extends CardPanel {
// draw background (selected/chooseable/playable)
MageCardLocation cardLocation = getCardLocation();
g2d.drawImage(
IMAGE_CACHE.getOrThrow(
IMAGE_MODE_RENDERED_CACHE.getOrThrow(
new Key(getInsets(),
cardLocation.getCardWidth(), cardLocation.getCardHeight(),
cardLocation.getCardWidth(), cardLocation.getCardHeight(),
@ -640,14 +634,9 @@ public class CardPanelRenderModeImage extends CardPanel {
Util.threadPool.submit(() -> {
try {
final ImageCacheData data;
if (getGameCard().isFaceDown()) {
data = getFaceDownImage();
} else {
data = ImageCache.getImage(getGameCard(), getCardWidth(), getCardHeight());
}
ImageCacheData data = ImageCache.getCardImage(getGameCard(), getCardWidth(), getCardHeight());
// show path on miss image
// save missing image
if (data.getImage() == null) {
setFullPath(data.getPath());
}
@ -665,21 +654,6 @@ public class CardPanelRenderModeImage extends CardPanel {
});
}
private ImageCacheData getFaceDownImage() {
// TODO: add download default images
if (isPermanent() && getGameCard() instanceof PermanentView) {
if (((PermanentView) getGameCard()).isMorphed()) {
return ImageCache.getMorphImage();
} else {
return ImageCache.getManifestImage();
}
} else if (this.getGameCard() instanceof StackAbilityView) {
return ImageCache.getMorphImage();
} else {
return ImageCache.getCardbackImage();
}
}
private int getManaWidth(String manaCost, int symbolMarginX) {
int width = 0;
manaCost = manaCost.replace("\\", "");

View file

@ -3,46 +3,40 @@ package org.mage.card.arcane;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import mage.cards.action.ActionCallback;
import mage.client.util.ImageCaches;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.view.CardView;
import mage.view.CounterView;
import mage.view.PermanentView;
import mage.view.StackAbilityView;
import org.jdesktop.swingx.graphics.GraphicsUtilities;
import org.mage.plugins.card.images.ImageCache;
import org.mage.plugins.card.images.ImageCacheData;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
/**
* Render mode: MTGO
*
*/
public class CardPanelRenderModeMTGO extends CardPanel {
//
// https://www.mtg.onl/evolution-of-magic-token-card-frame-design/
// Map of generated images
private static final Cache<ImageKey, BufferedImage> IMAGE_CACHE = CacheBuilder
.newBuilder()
.maximumSize(3000)
.expireAfterAccess(60, TimeUnit.MINUTES)
.softValues()
.build();
private static final Cache<ImageKey, BufferedImage> MTGO_MODE_RENDERED_CACHE = ImageCaches.register(
CacheBuilder
.newBuilder()
.maximumSize(3000)
.expireAfterAccess(60, TimeUnit.MINUTES)
.softValues()
.build()
);
// The art image for the card, loaded in from the disk
private BufferedImage artImage;
// The faceart image for the card, loaded in from the disk (based on artid from mtgo)
private BufferedImage faceArtImage;
// Factory to generate card appropriate views
private final CardRendererFactory cardRendererFactory = new CardRendererFactory();
@ -161,11 +155,7 @@ public class CardPanelRenderModeMTGO extends CardPanel {
if (artImage == null) {
return null;
}
if (getGameCard().isFaceDown()) {
return getFaceDownImage().getImage();
} else {
return ImageCache.getImageOriginal(getGameCard()).getImage();
}
return ImageCache.getCardImageOriginal(getGameCard()).getImage();
}
@Override
@ -173,16 +163,21 @@ public class CardPanelRenderModeMTGO extends CardPanel {
// Render the card if we don't have an image ready to use
if (cardImage == null) {
// Try to get card image from cache based on our card characteristics
ImageKey key = new ImageKey(getGameCard(), artImage,
getCardWidth(), getCardHeight(),
isChoosable(), isSelected(), isTransformed());
ImageKey key = new ImageKey(
getGameCard(),
artImage,
getCardWidth(),
getCardHeight(),
isChoosable(),
isSelected(),
isTransformed()
);
try {
cardImage = IMAGE_CACHE.get(key, this::renderCard);
} catch (ExecutionException e) {
cardImage = MTGO_MODE_RENDERED_CACHE.get(key, this::renderCard);
} catch (Exception e) {
// TODO: research and replace with logs, message and backface image
throw new RuntimeException(e);
}
// No cached copy exists? Render one and cache it
}
// And draw the image we now have
@ -237,8 +232,6 @@ public class CardPanelRenderModeMTGO extends CardPanel {
// Use the art image and current rendered image from the card
artImage = impl.artImage;
cardRenderer.setArtImage(artImage);
faceArtImage = impl.faceArtImage;
cardRenderer.setFaceArtImage(faceArtImage);
cardImage = impl.cardImage;
}
}
@ -252,7 +245,6 @@ public class CardPanelRenderModeMTGO extends CardPanel {
cardImage = null;
cardRenderer = cardRendererFactory.create(getGameCard());
cardRenderer.setArtImage(artImage);
cardRenderer.setFaceArtImage(faceArtImage);
// Repaint
repaint();
@ -264,7 +256,6 @@ public class CardPanelRenderModeMTGO extends CardPanel {
artImage = null;
cardImage = null;
cardRenderer.setArtImage(null);
cardRenderer.setFaceArtImage(null);
// Stop animation
setTappedAngle(isTapped() ? CardPanel.TAPPED_ANGLE : 0);
@ -276,29 +267,18 @@ public class CardPanelRenderModeMTGO extends CardPanel {
// See if the image is already loaded
//artImage = ImageCache.tryGetImage(gameCard, getCardWidth(), getCardHeight());
//this.cardRenderer.setArtImage(artImage);
// Submit a task to draw with the card art when it arrives
if (artImage == null) {
final int stamp = ++updateArtImageStamp;
Util.threadPool.submit(() -> {
try {
final BufferedImage srcImage;
final BufferedImage faceArtSrcImage;
if (getGameCard().isFaceDown()) {
// Nothing to do
srcImage = null;
faceArtSrcImage = null;
} else {
srcImage = ImageCache.getImage(getGameCard(), getCardWidth(), getCardHeight()).getImage();
faceArtSrcImage = ImageCache.getFaceImage(getGameCard(), getCardWidth(), getCardHeight()).getImage();
}
srcImage = ImageCache.getCardImage(getGameCard(), getCardWidth(), getCardHeight()).getImage();
UI.invokeLater(() -> {
if (stamp == updateArtImageStamp) {
artImage = srcImage;
cardRenderer.setArtImage(srcImage);
faceArtImage = faceArtSrcImage;
cardRenderer.setFaceArtImage(faceArtSrcImage);
if (srcImage != null) {
// Invalidate and repaint
cardImage = null;
@ -317,21 +297,6 @@ public class CardPanelRenderModeMTGO extends CardPanel {
return new CardPanelAttributes(getCardWidth(), getCardHeight(), isChoosable(), isSelected(), isTransformed());
}
private ImageCacheData getFaceDownImage() {
// TODO: add download default images
if (isPermanent() && getGameCard() instanceof PermanentView) {
if (((PermanentView) getGameCard()).isMorphed()) {
return ImageCache.getMorphImage();
} else {
return ImageCache.getManifestImage();
}
} else if (this.getGameCard() instanceof StackAbilityView) {
return ImageCache.getMorphImage();
} else {
return ImageCache.getCardbackImage();
}
}
/**
* Render the card to a new BufferedImage at it's current dimensions
*

View file

@ -55,10 +55,7 @@ public abstract class CardRenderer {
protected final CardView cardView;
// The card image
protected BufferedImage artImage;
// The face card image
protected BufferedImage faceArtImage;
protected BufferedImage artImage; // TODO: make sure it changed/reset on face down/up change
///////////////////////////////////////////////////////////////////////////
// Common layout metrics between all cards
@ -206,7 +203,7 @@ public abstract class CardRenderer {
}
// The Draw Method
// The draw method takes the information caculated by the constructor
// The draw method takes the information calculated by the constructor
// and uses it to draw to a concrete size of card and graphics.
public void draw(Graphics2D g, CardPanelAttributes attribs, BufferedImage image) {
@ -313,51 +310,6 @@ public abstract class CardRenderer {
}
private boolean lessOpaqueRulesTextBox = false;
protected void drawFaceArtIntoRect(Graphics2D g, int x, int y, int w, int h, int alternate_h, Rectangle2D artRect, boolean shouldPreserveAspect) {
// Perform a process to make sure that the art is scaled uniformly to fill the frame, cutting
// off the minimum amount necessary to make it completely fill the frame without "squashing" it.
double fullCardImgWidth = faceArtImage.getWidth();
double fullCardImgHeight = faceArtImage.getHeight();
double artWidth = fullCardImgWidth;
double artHeight = fullCardImgHeight;
double targetWidth = w;
double targetHeight = h;
double targetAspect = targetWidth / targetHeight;
if (!shouldPreserveAspect) {
// No adjustment to art
} else if (targetAspect * artHeight < artWidth) {
// Trim off some width
artWidth = targetAspect * artHeight;
} else {
// Trim off some height
artHeight = artWidth / targetAspect;
}
try {
/*BufferedImage subImg
= faceArtImage.getSubimage(
(int) (artRect.getX() * fullCardImgWidth), (int) (artRect.getY() * fullCardImgHeight),
(int) artWidth, (int) artHeight);*/
RenderingHints rh = new RenderingHints(
RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g.setRenderingHints(rh);
if (fullCardImgWidth > fullCardImgHeight) {
g.drawImage(faceArtImage,
x, y,
(int) targetWidth, (int) targetHeight,
null);
} else {
g.drawImage(faceArtImage,
x, y,
(int) targetWidth, alternate_h, // alernate_h is roughly (targetWidth / 0.74)
null);
lessOpaqueRulesTextBox = true;
}
} catch (RasterFormatException e) {
// At very small card sizes we may encounter a problem with rounding error making the rect not fit
System.out.println(e);
}
}
// Draw +1/+1 and other counters
protected void drawCounters(Graphics2D g) {
@ -532,10 +484,4 @@ public abstract class CardRenderer {
public void setArtImage(Image image) {
artImage = CardRendererUtils.toBufferedImage(image);
}
// Set the card art image (CardPanel will give it to us when it
// is loaded and ready)
public void setFaceArtImage(Image image) {
faceArtImage = CardRendererUtils.toBufferedImage(image);
}
}

View file

@ -28,7 +28,7 @@ public class GlowText extends JLabel {
private Color glowColor;
private boolean wrap;
private int lineCount = 0;
private static final SoftValuesLoadingCache<Key, BufferedImage> IMAGE_CACHE;
private static final SoftValuesLoadingCache<Key, BufferedImage> GLOW_TEXT_IMAGES_CACHE;
private static final class Key {
@ -122,7 +122,7 @@ public class GlowText extends JLabel {
}
static {
IMAGE_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(GlowText::createGlowImage));
GLOW_TEXT_IMAGES_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(GlowText::createGlowImage));
}
public void setGlow(Color glowColor, int size, float intensity) {
@ -153,7 +153,7 @@ public class GlowText extends JLabel {
}
public BufferedImage getGlowImage() {
return IMAGE_CACHE.getOrThrow(new Key(getWidth(), getHeight(), getText(), getFont(), getForeground(), glowSize, glowIntensity, glowColor, wrap));
return GLOW_TEXT_IMAGES_CACHE.getOrThrow(new Key(getWidth(), getHeight(), getText(), getFont(), getForeground(), glowSize, glowIntensity, glowColor, wrap));
}
private static BufferedImage createGlowImage(Key key) {

View file

@ -8,6 +8,7 @@ import mage.client.dialog.PreferencesDialog;
import mage.constants.CardType;
import mage.constants.MageObjectType;
import mage.constants.SubType;
import mage.util.CardUtil;
import mage.util.SubTypes;
import mage.view.CardView;
import mage.view.PermanentView;
@ -26,27 +27,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/*
private void cardRendererBasedRender(Graphics2D g) {
// Prepare for draw
g.translate(cardXOffset, cardYOffset);
int cardWidth = this.cardWidth - cardXOffset;
int cardHeight = this.cardHeight - cardYOffset;
// AA on
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// Renderer
CardRenderer render = new ModernCardRenderer(gameCard, transformed);
Image img = imagePanel.getSrcImage();
if (img != null) {
render.setArtImage(img);
}
render.draw(g, cardWidth, cardHeight);
}
*/
/**
* @author stravant@gmail.com, JayDi85
* <p>
@ -285,7 +265,8 @@ public class ModernCardRenderer extends CardRenderer {
protected void drawBackground(Graphics2D g) {
// Draw background, in 3 parts
if (cardView.isFaceDown()) {
if (false && cardView.isFaceDown()) {
// TODO: delete un-used code?!
// Just draw a brown rectangle
drawCardBack(g);
} else {
@ -392,16 +373,9 @@ public class ModernCardRenderer extends CardRenderer {
@Override
protected void drawArt(Graphics2D g) {
if ((artImage != null || faceArtImage != null) && !cardView.isFaceDown()) {
boolean useFaceArt = false;
if (faceArtImage != null && !isZendikarFullArtLand()) {
useFaceArt = true;
}
if (artImage != null) {
// Invention rendering, art fills the entire frame
if (useInventionFrame()) {
useFaceArt = false;
drawArtIntoRect(g,
borderWidth, borderWidth,
cardWidth - 2 * borderWidth, cardHeight - 2 * borderWidth,
@ -412,7 +386,6 @@ public class ModernCardRenderer extends CardRenderer {
Rectangle2D sourceRect = getArtRect();
if (cardView.getMageObjectType() == MageObjectType.SPELL) {
useFaceArt = false;
ArtRect rect = cardView.getArtRect();
if (rect != ArtRect.NORMAL) {
sourceRect = rect.rect;
@ -421,14 +394,7 @@ public class ModernCardRenderer extends CardRenderer {
}
// Normal drawing of art from a source part of the card frame into the rect
if (useFaceArt) {
int alternate_height = cardHeight - boxHeight * 2 - totalContentInset;
drawFaceArtIntoRect(g,
totalContentInset + 1, totalContentInset + boxHeight,
contentWidth - 2, typeLineY - totalContentInset - boxHeight,
alternate_height,
sourceRect, shouldPreserveAspect);
} else if (cardView.getArtRect() == ArtRect.FULL_LENGTH_RIGHT) {
if (cardView.getArtRect() == ArtRect.FULL_LENGTH_RIGHT) {
drawArtIntoRect(g,
contentWidth / 2 + totalContentInset + 1, totalContentInset + boxHeight,
contentWidth / 2 - 1, typeLineY - totalContentInset - boxHeight,
@ -713,27 +679,20 @@ public class ModernCardRenderer extends CardRenderer {
public void drawZendikarCurvedFace(Graphics2D g2, BufferedImage image, int x, int y, int x2, int y2,
Color boxColor, Paint paint) {
BufferedImage artToUse = faceArtImage;
boolean hadToUseFullArt = false;
if (faceArtImage == null) {
if (artImage == null) {
return;
}
hadToUseFullArt = true;
artToUse = artImage;
if (artImage == null) {
return;
}
BufferedImage artToUse = artImage;
int srcW = artToUse.getWidth();
int srcH = artToUse.getHeight();
if (hadToUseFullArt) {
// Get a box based on the standard scan from gatherer.
// Width = 185/223 pixels (centered)
// Height = 220/310, 38 pixels from top
int subx = 19 * srcW / 223;
int suby = 38 * srcH / 310;
artToUse = artImage.getSubimage(subx, suby, 185 * srcW / 223, 220 * srcH / 310);
}
// Get a box based on the standard scan from gatherer.
// Width = 185/223 pixels (centered)
// Height = 220/310, 38 pixels from top
int subx = 19 * srcW / 223;
int suby = 38 * srcH / 310;
artToUse = artImage.getSubimage(subx, suby, 185 * srcW / 223, 220 * srcH / 310);
Path2D.Double curve = new Path2D.Double();
@ -762,26 +721,19 @@ public class ModernCardRenderer extends CardRenderer {
public void drawBFZCurvedFace(Graphics2D g2, BufferedImage image, int x, int y, int x2, int y2,
int topxdelta, int endydelta,
Color boxColor, Paint paint) {
BufferedImage artToUse = faceArtImage;
boolean hadToUseFullArt = false;
if (faceArtImage == null) {
if (artImage == null) {
return;
}
hadToUseFullArt = true;
artToUse = artImage;
if (artImage == null) {
return;
}
BufferedImage artToUse = artImage;
int srcW = artToUse.getWidth();
int srcH = artToUse.getHeight();
if (hadToUseFullArt) {
// Get a box based on the standard scan from gatherer.
// Width = 185/223 pixels (centered)
// Height = 220/310, 38 pixels from top
int subx = 19 * srcW / 223;
int suby = 38 * srcH / 310;
artToUse = artImage.getSubimage(subx, suby, 185 * srcW / 223, 220 * srcH / 310);
}
// Get a box based on the standard scan from gatherer.
// Width = 185/223 pixels (centered)
// Height = 220/310, 38 pixels from top
int subx = 19 * srcW / 223;
int suby = 38 * srcH / 310;
artToUse = artImage.getSubimage(subx, suby, 185 * srcW / 223, 220 * srcH / 310);
Path2D.Double curve = new Path2D.Double();
curve.moveTo(x + topxdelta, y);
@ -907,23 +859,13 @@ public class ModernCardRenderer extends CardRenderer {
int availableWidth = w - manaCostWidth + 2;
// Draw the name
String nameStr;
if (cardView.isFaceDown()) {
if (cardView instanceof PermanentView && ((PermanentView) cardView).isManifested()) {
nameStr = "Manifest: " + cardView.getName();
} else {
nameStr = "Morph: " + cardView.getName();
}
} else {
nameStr = baseName;
}
if (!nameStr.isEmpty()) {
AttributedString str = new AttributedString(nameStr);
if (!baseName.isEmpty()) {
AttributedString str = new AttributedString(baseName);
str.addAttribute(TextAttribute.FONT, boxTextFont);
TextMeasurer measure = new TextMeasurer(str.getIterator(), g.getFontRenderContext());
int breakIndex = measure.getLineBreakIndex(0, availableWidth);
if (breakIndex < nameStr.length()) {
str = new AttributedString(nameStr);
if (breakIndex < baseName.length()) {
str = new AttributedString(baseName);
str.addAttribute(TextAttribute.FONT, boxTextFontNarrow);
measure = new TextMeasurer(str.getIterator(), g.getFontRenderContext());
breakIndex = measure.getLineBreakIndex(0, availableWidth);

View file

@ -157,7 +157,8 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
@Override
protected void drawBackground(Graphics2D g) {
if (cardView.isFaceDown()) {
if (false && cardView.isFaceDown()) {
// TODO: delete un-used code?!
drawCardBack(g);
} if (isAdventure()) {
super.drawBackground(g);
@ -206,7 +207,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
protected void drawArt(Graphics2D g) {
if (isAdventure) {
super.drawArt(g);
} else if (artImage != null && !cardView.isFaceDown()) {
} else if (artImage != null) {
if (isAftermath()) {
Rectangle2D topRect = ArtRect.AFTERMATH_TOP.rect;
int topLineY = (int) (leftHalf.ch * TYPE_LINE_Y_FRAC);

View file

@ -4,6 +4,7 @@ import mage.cards.MageCard;
import mage.cards.MagePermanent;
import mage.cards.action.ActionCallback;
import mage.client.util.GUISizeHelper;
import mage.client.util.ImageCaches;
import mage.interfaces.plugin.CardPlugin;
import mage.view.CardView;
import mage.view.CounterView;
@ -667,7 +668,7 @@ public class CardPluginImpl implements CardPlugin {
LOGGER.info("Symbols download finished");
dialog.dispose();
ManaSymbols.loadImages();
ImageCache.clearCache();
GUISizeHelper.refreshGUIAndCards();
}
}
}
@ -710,6 +711,6 @@ public class CardPluginImpl implements CardPlugin {
@Override
public BufferedImage getOriginalImage(CardView card) {
return ImageCache.getImageOriginal(card).getImage();
return ImageCache.getCardImageOriginal(card).getImage();
}
}

View file

@ -24,15 +24,17 @@ public class DownloadJob extends AbstractLaternaBean {
private final String name;
private Source source;
private final Destination destination;
private final boolean forceToDownload; // download image everytime, do not keep old image
private final Property<State> state = properties.property("state", State.NEW);
private final Property<String> message = properties.property("message");
private final Property<Exception> error = properties.property("error");
private final BoundedRangeModel progress = new DefaultBoundedRangeModel();
public DownloadJob(String name, Source source, Destination destination) {
public DownloadJob(String name, Source source, Destination destination, boolean forceToDownload) {
this.name = name;
this.source = source;
this.destination = destination;
this.forceToDownload = forceToDownload;
}
/**
@ -155,6 +157,10 @@ public class DownloadJob extends AbstractLaternaBean {
return destination;
}
public boolean isForceToDownload() {
return forceToDownload;
}
public static Source fromURL(final String url) {
return fromURL(CardImageUtils.getProxyFromPreferences(), url);
}

View file

@ -146,7 +146,7 @@ public class Downloader extends AbstractLaternaBean {
Destination dst = job.getDestination();
BoundedRangeModel progress = job.getProgress();
if (dst.isValid()) {
if (dst.isValid() && !job.isForceToDownload()) {
// already done
progress.setMaximum(1);
progress.setValue(1);

View file

@ -1,76 +0,0 @@
package org.mage.plugins.card.dl.sources;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.mage.plugins.card.dl.DownloadJob;
import static org.mage.plugins.card.dl.DownloadJob.fromURL;
import static org.mage.plugins.card.dl.DownloadJob.toFile;
/**
*
* @author LevelX2
*/
public class CardFrames implements Iterable<DownloadJob> {
private static final String FRAMES_PATH = File.separator + "frames";
private static final File DEFAULT_OUT_DIR = new File("plugins" + File.separator + "images" + FRAMES_PATH);
private static File outDir = DEFAULT_OUT_DIR;
static final String BASE_DOWNLOAD_URL = "http://ct-magefree.rhcloud.com/resources/img/";
static final String TEXTURES_FOLDER = "textures";
static final String PT_BOXES_FOLDER = "pt";
private static final String[] TEXTURES = {"U", "R", "G", "B", "W", "A",
"BG_LAND", "BR_LAND", "WU_LAND", "WB_LAND", "UB_LAND", "GW_LAND", "RW_LAND",
"RG_LAND", "GU_LAND", "UR_LAND"
// NOT => "BW_LAND","BU_LAND","WG_LAND","WR_LAND",
};
private static final String[] PT_BOXES = {"U", "R", "G", "B", "W", "A"};
public CardFrames(String path) {
if (path == null) {
useDefaultDir();
} else {
changeOutDir(path);
}
}
@Override
public Iterator<DownloadJob> iterator() {
List<DownloadJob> jobs = new ArrayList<>();
for (String texture : TEXTURES) {
jobs.add(generateDownloadJob(TEXTURES_FOLDER, texture));
}
for (String pt_box : PT_BOXES) {
jobs.add(generateDownloadJob(PT_BOXES_FOLDER, pt_box));
}
return jobs.iterator();
}
private DownloadJob generateDownloadJob(String dirName, String name) {
File dst = new File(outDir, name + ".png");
String url = BASE_DOWNLOAD_URL + dirName + '/' + name + ".png";
return new DownloadJob("frames-" + dirName + '-' + name, fromURL(url), toFile(dst));
}
private void useDefaultDir() {
outDir = DEFAULT_OUT_DIR;
}
private void changeOutDir(String path) {
File file = new File(path + FRAMES_PATH);
if (file.exists()) {
outDir = file;
} else {
file.mkdirs();
if (file.exists()) {
outDir = file;
}
}
}
}

View file

@ -11,6 +11,7 @@ import static org.mage.plugins.card.dl.DownloadJob.toFile;
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
/**
* TODO: outdated, delete and use xmage tokens instead ?!
* Used when we need to point to direct links to download resources from.
*
* @author noxx
@ -20,11 +21,9 @@ public class DirectLinksForDownload implements Iterable<DownloadJob> {
private static final Map<String, String> directLinks = new LinkedHashMap<>();
public static final String cardbackFilename = "cardback.jpg";
public static final String foretellFilename = "foretell.jpg";
static {
directLinks.put(cardbackFilename, "https://upload.wikimedia.org/wikipedia/en/a/aa/Magic_the_gathering-card_back.jpg");
directLinks.put(foretellFilename, "https://api.scryfall.com/cards/tkhm/23/en?format=image");
}
private final File outDir;
@ -42,7 +41,8 @@ public class DirectLinksForDownload implements Iterable<DownloadJob> {
for (Map.Entry<String, String> url : directLinks.entrySet()) {
File dst = new File(outDir, url.getKey());
jobs.add(new DownloadJob(url.getKey(), fromURL(url.getValue()), toFile(dst)));
// download images every time (need to update low quality image)
jobs.add(new DownloadJob(url.getKey(), fromURL(url.getValue()), toFile(dst), true));
}
return jobs.iterator();
}

View file

@ -337,6 +337,6 @@ public class GathererSets implements Iterable<DownloadJob> {
set = codeReplacements.get(set);
}
String url = "https://gatherer.wizards.com/Handlers/Image.ashx?type=symbol&set=" + set + "&size=small&rarity=" + urlRarity;
return new DownloadJob(set + '-' + rarity, fromURL(url), toFile(dst));
return new DownloadJob(set + '-' + rarity, fromURL(url), toFile(dst), false);
}
}

View file

@ -125,7 +125,7 @@ public class GathererSymbols implements Iterable<DownloadJob> {
String url = format(urlFmt, sizes[modSizeIndex], symbol);
return new DownloadJob(sym, fromURL(url), toFile(dst));
return new DownloadJob(sym, fromURL(url), toFile(dst), false);
}
}
};

View file

@ -96,15 +96,13 @@ public enum ScryfallImageSource implements CardImageSource {
}
// double faced cards (modal double faces cards too)
if (card.isTwoFacedCard()) {
if (card.isSecondSide()) {
// back face - must be prepared before
logger.warn("Can't find back face info in prepared list "
+ card.getName() + " (" + card.getSet() + ") #" + card.getCollectorId());
return new CardImageUrls(null, null);
} else {
// front face - can be downloaded normally as basic card
}
if (card.isSecondSide()) {
// back face - must be prepared before
logger.warn("Can't find back face info in prepared list "
+ card.getName() + " (" + card.getSet() + ") #" + card.getCollectorId());
return new CardImageUrls(null, null);
} else {
// front face - can be downloaded normally as basic card
}
// basic cards by api call (redirect to img link)
@ -219,7 +217,7 @@ public enum ScryfallImageSource implements CardImageSource {
int needPrepareCount = 0;
int currentPrepareCount = 0;
for (CardDownloadData card : downloadList) {
if (card.isTwoFacedCard() && card.isSecondSide()) {
if (card.isSecondSide()) {
needPrepareCount++;
}
}
@ -232,7 +230,7 @@ public enum ScryfallImageSource implements CardImageSource {
}
// prepare the back face URL
if (card.isTwoFacedCard() && card.isSecondSide()) {
if (card.isSecondSide()) {
currentPrepareCount++;
try {
String url = getFaceImageUrl(proxy, card, card.isToken());

View file

@ -1275,9 +1275,9 @@ public class ScryfallImageSupportTokens {
put("DDE/Saproling", "https://api.scryfall.com/cards/tdde/3/en?format=image");
// DDD
put("DDD/Beast/1", "https://api.scryfall.com/cards/tddd/1/en?format=image");
put("DDD/Beast/2", "https://api.scryfall.com/cards/tddd/2/en?format=image");
put("DDD/Elephant", "https://api.scryfall.com/cards/tddd/3/en?format=image");
put("DDD/Beast/1", "https://api.scryfall.com/cards/tddd/T1/en?format=image");
put("DDD/Beast/2", "https://api.scryfall.com/cards/tddd/T2/en?format=image");
put("DDD/Elephant", "https://api.scryfall.com/cards/tddd/T3/en?format=image");
// SOM
put("SOM/Cat", "https://api.scryfall.com/cards/tsom/1/en?format=image");

View file

@ -1,18 +1,19 @@
package org.mage.plugins.card.dl.sources;
import org.mage.plugins.card.dl.DownloadJob;
import org.mage.plugins.card.utils.CardImageUtils;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.mage.plugins.card.dl.DownloadJob;
import org.mage.plugins.card.utils.CardImageUtils;
import static org.mage.card.arcane.ManaSymbols.getSymbolFileNameAsSVG;
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
@ -105,7 +106,7 @@ public class ScryfallSymbolsSource implements Iterable<DownloadJob> {
if (destFile.exists() && (destFile.length() > 0)) {
continue;
}
try(FileOutputStream stream = new FileOutputStream(destFile)) {
try (FileOutputStream stream = new FileOutputStream(destFile)) {
// base64 transform
String data64 = foundedData.get(searchCode);
Base64.Decoder dec = Base64.getDecoder();
@ -166,16 +167,14 @@ public class ScryfallSymbolsSource implements Iterable<DownloadJob> {
}
}
private String destFile = "";
public ScryfallSymbolsDownloadJob() {
// download init
super("Scryfall symbols source", fromURL(""), toFile(DOWNLOAD_TEMP_FILE)); // url setup on preparing stage
this.destFile = DOWNLOAD_TEMP_FILE;
this.addPropertyChangeListener(STATE_PROP_NAME, new ScryfallDownloadOnFinishedListener(this.destFile));
super("Scryfall symbols source", fromURL(""), toFile(DOWNLOAD_TEMP_FILE), true); // url setup on preparing stage
String destFile = DOWNLOAD_TEMP_FILE;
this.addPropertyChangeListener(STATE_PROP_NAME, new ScryfallDownloadOnFinishedListener(destFile));
// clear dest file (always download new data)
File file = new File(this.destFile);
// duplicate a forceToDownload param above, but it's ok to clear temp file anyway
File file = new File(destFile);
if (file.exists()) {
file.delete();
}

View file

@ -14,37 +14,18 @@ public class CardDownloadData {
private String set;
private final String collectorId;
private final Integer imageNumber;
private boolean token;
private final boolean twoFacedCard;
private final boolean secondSide;
private boolean flipCard;
private boolean flippedSide;
private boolean splitCard;
private final boolean usesVariousArt;
private String tokenClassName;
private boolean isToken;
private boolean isSecondSide;
private boolean isFlippedSide;
private boolean isSplitCard;
private final boolean isUsesVariousArt;
public CardDownloadData(String name, String setCode, String collectorId, boolean usesVariousArt, Integer imageNumber) {
this(name, setCode, collectorId, usesVariousArt, imageNumber, false);
}
public CardDownloadData(String name, String setCode, String collectorId, boolean usesVariousArt, Integer imageNumber, boolean token) {
this(name, setCode, collectorId, usesVariousArt, imageNumber, token, false, false, "");
}
public CardDownloadData(String name, String setCode, String collectorId, boolean usesVariousArt, Integer imageNumber, boolean token, boolean twoFacedCard, boolean secondSide) {
this(name, setCode, collectorId, usesVariousArt, imageNumber, token, twoFacedCard, secondSide, "");
}
public CardDownloadData(String name, String setCode, String collectorId, boolean usesVariousArt, Integer imageNumber, boolean token, boolean twoFacedCard, boolean secondSide, String tokenClassName) {
public CardDownloadData(String name, String setCode, String collectorId, boolean isUsesVariousArt, Integer imageNumber) {
this.name = name;
this.set = setCode;
this.collectorId = collectorId;
this.usesVariousArt = usesVariousArt;
this.isUsesVariousArt = isUsesVariousArt;
this.imageNumber = imageNumber;
this.token = token;
this.twoFacedCard = twoFacedCard;
this.secondSide = secondSide;
this.tokenClassName = tokenClassName;
}
public CardDownloadData(final CardDownloadData card) {
@ -53,14 +34,11 @@ public class CardDownloadData {
this.set = card.set;
this.collectorId = card.collectorId;
this.imageNumber = card.imageNumber;
this.token = card.token;
this.twoFacedCard = card.twoFacedCard;
this.secondSide = card.secondSide;
this.flipCard = card.flipCard;
this.flippedSide = card.flippedSide;
this.splitCard = card.splitCard;
this.usesVariousArt = card.usesVariousArt;
this.tokenClassName = card.tokenClassName;
this.isToken = card.isToken;
this.isSecondSide = card.isSecondSide;
this.isFlippedSide = card.isFlippedSide;
this.isSplitCard = card.isSplitCard;
this.isUsesVariousArt = card.isUsesVariousArt;
}
@Override
@ -81,14 +59,11 @@ public class CardDownloadData {
if (!Objects.equals(this.collectorId, other.collectorId)) {
return false;
}
if (this.token != other.token) {
return false;
}
if (this.twoFacedCard != other.twoFacedCard) {
if (this.isToken != other.isToken) {
return false;
}
return this.secondSide == other.secondSide;
return this.isSecondSide == other.isSecondSide;
}
@Override
@ -98,9 +73,8 @@ public class CardDownloadData {
hash = 47 * hash + (this.set != null ? this.set.hashCode() : 0);
hash = 47 * hash + (this.collectorId != null ? this.collectorId.hashCode() : 0);
hash = 47 * hash + (this.imageNumber != null ? this.imageNumber.hashCode() : 0);
hash = 47 * hash + (this.token ? 1 : 0);
hash = 47 * hash + (this.twoFacedCard ? 1 : 0);
hash = 47 * hash + (this.secondSide ? 1 : 0);
hash = 47 * hash + (this.isToken ? 1 : 0);
hash = 47 * hash + (this.isSecondSide ? 1 : 0);
return hash;
}
@ -149,28 +123,20 @@ public class CardDownloadData {
this.set = set;
}
public void setTokenClassName(String tokenClassName) {
this.tokenClassName = tokenClassName;
}
public String getAffectedClassName() {
return tokenClassName.isEmpty() ? name.replaceAll("[^a-zA-Z0-9]", "") : tokenClassName;
}
public boolean isToken() {
return token;
return isToken;
}
public void setToken(boolean token) {
this.token = token;
}
public boolean isTwoFacedCard() {
return twoFacedCard;
this.isToken = token;
}
public boolean isSecondSide() {
return secondSide;
return isSecondSide;
}
public void setSecondSide(boolean isSecondSide) {
this.isSecondSide = isSecondSide;
}
public String getDownloadName() {
@ -181,20 +147,12 @@ public class CardDownloadData {
this.downloadName = downloadName;
}
public boolean isFlipCard() {
return flipCard;
}
public void setFlipCard(boolean flipCard) {
this.flipCard = flipCard;
}
public boolean isSplitCard() {
return splitCard;
return isSplitCard;
}
public void setSplitCard(boolean splitCard) {
this.splitCard = splitCard;
this.isSplitCard = splitCard;
}
public Integer getImageNumber() {
@ -202,14 +160,14 @@ public class CardDownloadData {
}
public boolean getUsesVariousArt() {
return usesVariousArt;
return isUsesVariousArt;
}
public boolean isFlippedSide() {
return flippedSide;
return isFlippedSide;
}
public void setFlippedSide(boolean flippedSide) {
this.flippedSide = flippedSide;
this.isFlippedSide = flippedSide;
}
}

View file

@ -10,6 +10,8 @@ import mage.client.MageFrame;
import mage.client.dialog.DownloadImagesDialog;
import mage.client.dialog.PreferencesDialog;
import mage.client.util.CardLanguage;
import mage.client.util.GUISizeHelper;
import mage.client.util.ImageCaches;
import mage.client.util.sets.ConstructedFormats;
import mage.remote.Connection;
import net.java.truevfs.access.TFile;
@ -437,14 +439,19 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
&& !"0".equals(card.getCardNumber())
&& !card.getSetCode().isEmpty()) {
String cardName = card.getName();
CardDownloadData url = new CardDownloadData(cardName, card.getSetCode(), card.getCardNumber(), card.usesVariousArt(), 0, false, card.isDoubleFaced(), card.isNightCard());
CardDownloadData url = new CardDownloadData(
cardName,
card.getSetCode(),
card.getCardNumber(),
card.usesVariousArt(),
0);
url.setSecondSide(card.isNightCard());
// variations must have diff file names with additional postfix
if (url.getUsesVariousArt()) {
url.setDownloadName(createDownloadName(card));
}
url.setFlipCard(card.isFlipCard());
url.setSplitCard(card.isSplitCard());
// main side
@ -467,7 +474,9 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
card.getSetCode(),
secondSideCard.getCardNumber(),
card.usesVariousArt(),
0, false, card.isDoubleFaced(), true);
0
);
url.setSecondSide(true);
allCardsUrls.add(url);
}
if (card.isFlipCard()) {
@ -479,9 +488,10 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
card.getSetCode(),
card.getCardNumber(),
card.usesVariousArt(),
0, false, card.isDoubleFaced(), card.isNightCard());
cardDownloadData.setFlipCard(true);
0
);
cardDownloadData.setFlippedSide(true);
cardDownloadData.setSecondSide(card.isNightCard());
allCardsUrls.add(cardDownloadData);
}
if (card.getMeldsToCardName() != null) {
@ -500,7 +510,8 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
card.getSetCode(),
meldsToCard.getCardNumber(),
card.usesVariousArt(),
0, false, false, false);
0
);
allCardsUrls.add(url);
}
if (card.isModalDoubleFacedCard()) {
@ -512,7 +523,9 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
card.getSetCode(),
card.getCardNumber(),
card.usesVariousArt(),
0, false, true, true);
0
);
cardDownloadData.setSecondSide(true);
allCardsUrls.add(cardDownloadData);
}
} else if (card.getCardNumber().isEmpty() || "0".equals(card.getCardNumber())) {
@ -531,9 +544,8 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
token.getSetCode(),
"0",
false,
token.getImageNumber(),
true
);
token.getImageNumber());
card.setToken(true);
allCardsUrls.add(card);
});
} catch (Exception e) {
@ -674,8 +686,8 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
reloadCardsToDownload(uiDialog.getSetsCombo().getSelectedItem().toString());
enableDialogButtons();
// reset images cache
ImageCache.clearCache();
// reset GUI and cards to use new images
GUISizeHelper.refreshGUIAndCards();
}
static String convertStreamToString(InputStream is) {

View file

@ -1,14 +1,15 @@
package org.mage.plugins.card.images;
import com.google.common.collect.ComputationException;
import mage.abilities.icon.CardIconColor;
import mage.client.constants.Constants;
import mage.client.util.ImageCaches;
import mage.client.util.SoftValuesLoadingCache;
import mage.client.util.TransformedImageCache;
import mage.view.CardView;
import net.java.truevfs.access.TFile;
import net.java.truevfs.access.TFileInputStream;
import org.apache.log4j.Logger;
import org.mage.card.arcane.CardPanelRenderModeImage;
import org.mage.plugins.card.dl.sources.DirectLinksForDownload;
import org.mage.plugins.card.utils.CardImageUtils;
import org.mage.plugins.card.utils.impl.ImageManagerImpl;
@ -21,17 +22,9 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* This class stores ALL card images in a cache with soft values. this means
* This class stores ALL card images in a cache with soft values. This means
* that the images may be garbage collected when they are not needed any more,
* but will be kept as long as possible.
* <p>
* Key format: "[cardname]#[setname]#[type]#[collectorID]#[image size]#[additional data]"
*
* <li>#Normal: request for unrotated image</li>
* <li>#Tapped: request for rotated image</li>
* <li>#Cropped: request for cropped image that is used for Shandalar like card
* look</li>
* </ul>
*
* @author JayDi85
*/
@ -39,195 +32,105 @@ public final class ImageCache {
private static final Logger LOGGER = Logger.getLogger(ImageCache.class);
private static final SoftValuesLoadingCache<String, ImageCacheData> IMAGE_CACHE; // cards and tokens
private static final SoftValuesLoadingCache<String, ImageCacheData> FACE_IMAGE_CACHE;
private static final SoftValuesLoadingCache<String, ImageCacheData> CARD_ICONS_CACHE;
// global cache for both mtgo and image render modes
private static final SoftValuesLoadingCache<String, ImageCacheData> SHARED_CARD_IMAGES_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(ImageCache::createCardOrTokenImage));
private static final SoftValuesLoadingCache<String, ImageCacheData> SHARED_CARD_ICONS_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(ImageCache::createIcon));
/**
* Common pattern for keys. See ImageCache.getKey for structure info
*/
private static final Pattern KEY_PATTERN = Pattern.compile("(.*)#(.*)#(.*)#(.*)#(.*)");
// format: name #setcode #imagenumber #cardnumber #size #usesVariousArt
private static final Pattern CARD_IMAGE_KEY_PATTERN = Pattern.compile("(.*)#(.*)#(.*)#(.*)#(.*)");
// format: size #icon #color
private static final Pattern CARD_ICON_KEY_PATTERN = Pattern.compile("(.*)#(.*)#(.*)");
static {
// softValues() = Specifies that each value (not key) stored in the map should be wrapped in a SoftReference
// (by default, strong references are used). Softly-referenced objects will be garbage-collected in a
// globally least-recently-used manner, in response to memory demand.
IMAGE_CACHE = SoftValuesLoadingCache.from(key -> {
try {
boolean usesVariousArt = false;
if (key.matches(".*#usesVariousArt.*")) {
usesVariousArt = true;
key = key.replace("#usesVariousArt", "");
}
Matcher m = KEY_PATTERN.matcher(key);
if (m.matches()) {
String name = m.group(1);
String setCode = m.group(2);
Integer type = Integer.parseInt(m.group(3));
String collectorId = m.group(4);
if (collectorId.equals("null")) {
collectorId = "0";
}
CardDownloadData info = new CardDownloadData(name, setCode, collectorId, usesVariousArt, type);
boolean cardback = false;
String path;
if (collectorId.isEmpty() || "0".equals(collectorId)) {
// TOKEN
// can be a normal token or a token from card (see embalm ability)
info.setToken(true);
TFile tokenFile;
// try normal token
path = CardImageUtils.buildImagePathToCardOrToken(info);
tokenFile = getTFile(path);
// try token from card
// TODO: return image from another set on empty image?
if (tokenFile == null || !tokenFile.exists()) {
CardDownloadData tempInfo = new CardDownloadData(info);
tempInfo.setToken(false);
path = CardImageUtils.buildImagePathToCardOrToken(info);
tokenFile = getTFile(path);
}
// try unknown token image
if (tokenFile == null || !tokenFile.exists()) {
// TODO: replace empty token by other default card, not cardback
cardback = true;
path = CardImageUtils.buildImagePathToDefault(DirectLinksForDownload.cardbackFilename);
}
} else {
// CARD
path = CardImageUtils.buildImagePathToCardOrToken(info);
}
TFile file = getTFile(path);
if (file == null) {
return new ImageCacheData(path, null);
}
if (cardback) {
// TODO: is there any different in images styles? Cardback must be from scryfall, not wizards
// need cardback image
BufferedImage image = loadImage(file);
image = getRoundCorner(image);
return new ImageCacheData(path, image);
} else {
// need normal card image
BufferedImage image = loadImage(file);
image = getWizardsCard(image);
image = getRoundCorner(image);
return new ImageCacheData(path, image);
}
} else {
throw new RuntimeException(
"Requested image doesn't fit the requirement for key (<cardname>#<setname>#<collectorID>): " + key);
}
} catch (Exception ex) {
if (ex instanceof ComputationException) {
throw (ComputationException) ex;
} else {
throw new ComputationException(ex);
}
}
});
FACE_IMAGE_CACHE = SoftValuesLoadingCache.from(key -> {
try {
Matcher m = KEY_PATTERN.matcher(key);
if (m.matches()) {
String name = m.group(1);
String setCode = m.group(2);
// skip type
// skip collectorId
String path = CardImageUtils.generateFaceImagePath(name, setCode);
TFile file = getTFile(path);
if (file == null) {
return new ImageCacheData(path, null);
}
BufferedImage image = loadImage(file);
return new ImageCacheData(path, image);
} else {
throw new RuntimeException(
"Requested face image doesn't fit the requirement for key (<cardname>#<artid>#: " + key);
}
} catch (Exception ex) {
if (ex instanceof ComputationException) {
throw (ComputationException) ex;
} else {
throw new ComputationException(ex);
}
}
});
CARD_ICONS_CACHE = SoftValuesLoadingCache.from(key -> {
try {
Matcher m = CARD_ICON_KEY_PATTERN.matcher(key);
if (m.matches()) {
int cardSize = Integer.parseInt(m.group(1));
String resourceName = m.group(2);
CardIconColor cardIconColor = CardIconColor.valueOf(m.group(3));
BufferedImage image = ImageManagerImpl.instance.getCardIcon(resourceName, cardSize, cardIconColor);
return new ImageCacheData(resourceName, image);
} else {
throw new RuntimeException("Wrong card icons image key format: " + key);
}
} catch (Exception ex) {
if (ex instanceof ComputationException) {
throw (ComputationException) ex;
} else {
throw new ComputationException(ex);
}
}
});
}
public static void clearCache() {
IMAGE_CACHE.invalidateAll();
FACE_IMAGE_CACHE.invalidateAll();
CARD_ICONS_CACHE.invalidateAll();
}
private ImageCache() {
}
public static ImageCacheData getCardbackImage() {
String path = CardImageUtils.buildImagePathToDefault(DirectLinksForDownload.cardbackFilename);
BufferedImage image = ImageCache.loadImage(getTFile(path));
image = getRoundCorner(image);
return new ImageCacheData(path, image);
private static ImageCacheData createCardOrTokenImage(String key) {
boolean usesVariousArt = false;
if (key.matches(".*#usesVariousArt.*")) {
usesVariousArt = true;
key = key.replace("#usesVariousArt", "");
}
Matcher m = CARD_IMAGE_KEY_PATTERN.matcher(key);
if (m.matches()) {
String name = m.group(1);
String setCode = m.group(2);
Integer imageNumber = Integer.parseInt(m.group(3));
String collectorId = m.group(4);
if (collectorId.equals("null")) {
collectorId = "0";
}
CardDownloadData info = new CardDownloadData(name, setCode, collectorId, usesVariousArt, imageNumber);
boolean cardback = false;
String path;
if (collectorId.isEmpty() || "0".equals(collectorId)) {
// TOKEN
// can be a normal token or a token from card (see embalm ability)
info.setToken(true);
TFile tokenFile;
// try normal token
path = CardImageUtils.buildImagePathToCardOrToken(info);
tokenFile = getTFile(path);
// try token from card
// TODO: unused code?
// TODO: return image from another set on empty image?
if (tokenFile == null || !tokenFile.exists()) {
CardDownloadData tempInfo = new CardDownloadData(info);
tempInfo.setToken(false);
path = CardImageUtils.buildImagePathToCardOrToken(info);
tokenFile = getTFile(path);
}
// try unknown token image
if (tokenFile == null || !tokenFile.exists()) {
// TODO: replace empty token by other default card, not cardback
cardback = true;
path = CardImageUtils.buildImagePathToDefault(DirectLinksForDownload.cardbackFilename);
}
} else {
// CARD
path = CardImageUtils.buildImagePathToCardOrToken(info);
}
TFile file = getTFile(path);
if (file == null) {
return new ImageCacheData(path, null);
}
if (cardback) {
// TODO: is there any different in images styles? Cardback must be from scryfall, not wizards
// need cardback image
BufferedImage image = loadImage(file);
image = getRoundCorner(image);
return new ImageCacheData(path, image);
} else {
// need normal card image
BufferedImage image = loadImage(file);
image = getWizardsCard(image);
image = getRoundCorner(image);
return new ImageCacheData(path, image);
}
} else {
throw new IllegalArgumentException("Unknown card image's key format: " + key);
}
}
public static ImageCacheData getMorphImage() {
// TODO: replace by downloadable morth image
CardDownloadData info = new CardDownloadData("Morph", "KTK", "0", false, 0);
info.setToken(true);
String path = CardImageUtils.buildImagePathToCardOrToken(info);
TFile file = getTFile(path);
BufferedImage image = loadImage(file);
image = getRoundCorner(image);
return new ImageCacheData(path, image);
}
public static ImageCacheData getManifestImage() {
// TODO: replace by downloadable manifestest image
CardDownloadData info = new CardDownloadData("Manifest", "FRF", "0", false, 0);
info.setToken(true);
String path = CardImageUtils.buildImagePathToCardOrToken(info);
TFile file = getTFile(path);
BufferedImage image = loadImage(file);
image = getRoundCorner(image);
return new ImageCacheData(path, image);
private static ImageCacheData createIcon(String key) {
Matcher m = CARD_ICON_KEY_PATTERN.matcher(key);
if (m.matches()) {
int cardSize = Integer.parseInt(m.group(1));
String resourceName = m.group(2);
CardIconColor cardIconColor = CardIconColor.valueOf(m.group(3));
BufferedImage image = ImageManagerImpl.instance.getCardIcon(resourceName, cardSize, cardIconColor);
return new ImageCacheData(resourceName, image);
} else {
throw new IllegalArgumentException("Unknown card icon's key format: " + key);
}
}
public static BufferedImage getRoundCorner(BufferedImage image) {
@ -269,61 +172,52 @@ public final class ImageCache {
}
}
public static ImageCacheData getImageOriginal(CardView card) {
return getImage(getKey(card, card.getName(), 0));
/** Find image for current side
*/
public static ImageCacheData getCardImageOriginal(CardView card) {
return getCardImage(getKey(card, card.getName(), 0));
}
public static ImageCacheData getImageOriginalAlternateName(CardView card) {
return getImage(getKey(card, card.getAlternateName(), 0));
/**
* Find image for other side
*/
public static ImageCacheData getCardImageAlternate(CardView card) {
return getCardImage(getKey(card, card.getAlternateName(), 0));
}
public static ImageCacheData getCardIconImage(String resourceName, int iconSize, String cardColorName) {
return getCardIconImage(getCardIconKey(resourceName, iconSize, cardColorName));
}
/**
* Returns the Image corresponding to the key
*/
private static ImageCacheData getImage(String key) {
private static ImageCacheData getCardImage(String key) {
try {
ImageCacheData data = IMAGE_CACHE.getOrNull(key);
ImageCacheData data = SHARED_CARD_IMAGES_CACHE.getOrNull(key);
return data != null ? data : new ImageCacheData("ERROR: key - " + key, null);
} catch (ComputationException ex) {
// too low memory
if (ex.getCause() instanceof NullPointerException) {
return new ImageCacheData("ERROR: low memory?", null);
} catch (Exception e) {
if (e.getCause() instanceof NullPointerException) {
// low memory error???
return new ImageCacheData("ERROR: possible low memory", null);
} else {
// other error
LOGGER.error("Error while loading card image: " + e, e);
return new ImageCacheData("ERROR: see client logs for details", null);
}
LOGGER.error(ex, ex);
return new ImageCacheData("ERROR: see logs", null);
}
}
/**
* Returns the Image corresponding to the key
*/
private static ImageCacheData getFaceImage(String key) {
try {
ImageCacheData data = FACE_IMAGE_CACHE.getOrNull(key);
return data != null ? data : new ImageCacheData("ERROR: key " + key, null);
} catch (ComputationException ex) {
if (ex.getCause() instanceof NullPointerException) {
return new ImageCacheData("ERROR: low memory?", null);
}
LOGGER.error(ex, ex);
return new ImageCacheData("ERROR: see logs", null);
}
}
private static ImageCacheData getCardIconImage(String key) {
try {
ImageCacheData data = CARD_ICONS_CACHE.getOrNull(key);
ImageCacheData data = SHARED_CARD_ICONS_CACHE.getOrNull(key);
return data != null ? data : new ImageCacheData("ERROR: key - " + key, null);
} catch (ComputationException ex) {
if (ex.getCause() instanceof NullPointerException) {
return new ImageCacheData("ERROR: low memory?", null);
} catch (Exception e) {
if (e.getCause() instanceof NullPointerException) {
// low memory error???
return new ImageCacheData("ERROR: possible low memory", null);
} else {
// other error
LOGGER.error("Error while loading card icon: " + e, e);
return new ImageCacheData("ERROR: see client logs for details", null);
}
LOGGER.error(ex, ex);
return new ImageCacheData("ERROR: see logs", null);
}
}
@ -332,7 +226,7 @@ public final class ImageCache {
* the cache.
*/
private static ImageCacheData tryGetImage(String key) {
return IMAGE_CACHE.peekIfPresent(key);
return SHARED_CARD_IMAGES_CACHE.peekIfPresent(key);
}
/**
@ -343,7 +237,11 @@ public final class ImageCache {
* @param imageSize - size info, 0 to use original image (with max size)
*/
private static String getKey(CardView card, String cardName, int imageSize) {
return (card.isToken() ? cardName.replace(" Token", "") : cardName)
String imageFileName = card.getImageFileName();
if (imageFileName.isEmpty()) {
imageFileName = cardName;
}
return imageFileName.replace(" Token", "")
+ '#' + card.getExpansionSetCode()
+ '#' + card.getImageNumber()
+ '#' + card.getCardNumber()
@ -420,9 +318,9 @@ public final class ImageCache {
* @param height
* @return
*/
public static ImageCacheData getImage(CardView card, int width, int height) {
public static ImageCacheData getCardImage(CardView card, int width, int height) {
String key = getKey(card, card.getName(), width);
ImageCacheData data = getImage(key);
ImageCacheData data = getCardImage(key);
if (data.getImage() == null) {
LOGGER.debug("Image doesn't exists in the cache: " + key);
return data;
@ -438,23 +336,6 @@ public final class ImageCache {
return data;
}
/**
* Returns the image appropriate to display the card in the picture panel
*
* @param card
* @param width
* @param height
* @return
*/
public static ImageCacheData getFaceImage(CardView card, int width, int height) {
String key = getFaceKey(card, card.getName(), card.getExpansionSetCode());
ImageCacheData data = getFaceImage(key);
if (data.getImage() == null) {
LOGGER.debug(key + " (faceimage) not found");
}
return data;
}
/**
* Returns the image appropriate to display for a card in a picture panel,
* but only it was ALREADY LOADED. That is, the call is immediate and will

View file

@ -146,37 +146,47 @@ public final class CardImageUtils {
*/
public static String buildImagePathToCardView(CardView card) {
String imageFile;
if (card.getMageObjectType().isUseTokensRepository()) {
// token images
String imageFileName = card.getImageFileName();
if (imageFileName.isEmpty()) {
imageFileName = card.getName();
}
if (imageFileName.isEmpty()) {
return "ERROR: empty image file name, object type - " + card.getMageObjectType();
}
if (card.getMageObjectType().isUseTokensRepository()
|| card.getExpansionSetCode().equals(TokenRepository.XMAGE_TOKENS_SET_CODE)) {
// token images or inner cards like face down
CardDownloadData cardData = new CardDownloadData(
card.getName().replace(" Token", ""),
imageFileName.replace(" Token", ""),
card.getExpansionSetCode(),
"0",
false,
card.getImageNumber(),
true);
card.getCardNumber(),
card.getUsesVariousArt(),
card.getImageNumber());
cardData.setToken(true);
imageFile = CardImageUtils.buildImagePathToCardOrToken(cardData);
} else {
TokenRepository.instance.getAll();
// card images
// workaround to find various art settings first
// TODO: no needs in workaround?! ?!
boolean usesVariousArt = false;
CardInfo cardInfo = CardRepository.instance.findCardWithPreferredSetAndNumber(
card.getName(),
card.getExpansionSetCode(),
card.getCardNumber()
);
if (cardInfo != null) {
CardDownloadData cardData = new CardDownloadData(
cardInfo.getName(),
cardInfo.getSetCode(),
cardInfo.getCardNumber(),
cardInfo.usesVariousArt(),
card.getImageNumber()
);
imageFile = CardImageUtils.buildImagePathToCardOrToken(cardData);
} else {
imageFile = "ERROR: can't find card info in repository - " + card.getName();
usesVariousArt = cardInfo.usesVariousArt();
}
CardDownloadData cardData = new CardDownloadData(
imageFileName,
card.getExpansionSetCode(),
card.getCardNumber(),
card.getUsesVariousArt(), // TODO: need to use usesVariousArt instead card?
card.getImageNumber()
);
imageFile = CardImageUtils.buildImagePathToCardOrToken(cardData);
}
return imageFile;
}