From 0b25dad6f5507d997dd385497715a773e8a6e0af Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Mon, 7 Apr 2025 14:22:34 -0500 Subject: [PATCH 1/3] Fixed Display of Misc Award Images; Upgraded Award Image Scaling - Fixed misc image count to return misc images and not medals. - Added logging to warn if image files (ribbons, medals, misc) are missing. - Adjusted the maximum number of ribbon awards per row from 4 to 3 for better display with the new scaling tech. - Introduced `scaleImage` method in `ImageUtilities`. This is essentially a duplicate of `scaleImageIcon`, with reused components separated into a shared method. - Replaced award image scaling in `PersonViewPanel` with the new `scaleImage` method from `ImageUtilities`. --- MekHQ/src/mekhq/gui/view/PersonViewPanel.java | 48 ++++++---------- MekHQ/src/mekhq/utilities/ImageUtilities.java | 56 ++++++++++++++++++- 2 files changed, 70 insertions(+), 34 deletions(-) diff --git a/MekHQ/src/mekhq/gui/view/PersonViewPanel.java b/MekHQ/src/mekhq/gui/view/PersonViewPanel.java index 0481f0f880..fbefb7f11e 100644 --- a/MekHQ/src/mekhq/gui/view/PersonViewPanel.java +++ b/MekHQ/src/mekhq/gui/view/PersonViewPanel.java @@ -34,6 +34,7 @@ import static mekhq.campaign.personnel.Person.getLoyaltyName; import static mekhq.campaign.personnel.turnoverAndRetention.Fatigue.getEffectiveFatigue; import static mekhq.utilities.ImageUtilities.addTintToImageIcon; +import static mekhq.utilities.ImageUtilities.scaleImage; import static org.jfree.chart.ChartColor.DARK_BLUE; import static org.jfree.chart.ChartColor.DARK_RED; @@ -94,8 +95,6 @@ import mekhq.gui.utilities.MarkdownRenderer; import mekhq.gui.utilities.WrapLayout; -import static megamek.client.ui.WrapLayout.wordWrap; - /** * A custom panel that gets filled in with goodies from a Person record * @@ -104,7 +103,7 @@ public class PersonViewPanel extends JScrollablePanel { private static final MMLogger logger = MMLogger.create(PersonViewPanel.class); - private static final int MAX_NUMBER_OF_RIBBON_AWARDS_PER_ROW = 4; + private static final int MAX_NUMBER_OF_RIBBON_AWARDS_PER_ROW = 3; private final CampaignGUI gui; @@ -408,13 +407,16 @@ private Box drawRibbons() { int awardTierCount = getAwardTierCount(award, maximumTiers); String ribbonFileName = award.getRibbonFileName(awardTierCount); + String directory = award.getSet() + "/ribbons/"; - ribbon = (Image) MHQStaticDirectoryManager.getAwardIcons() - .getItem(award.getSet() + "/ribbons/", ribbonFileName); + ribbon = (Image) MHQStaticDirectoryManager.getAwardIcons().getItem(directory, ribbonFileName); if (ribbon == null) { + logger.warn("No ribbon icon found for award: {}", directory + ribbonFileName); continue; } - ribbon = ribbon.getScaledInstance(25, 8, Image.SCALE_DEFAULT); + + ribbon = scaleImage(ribbon, 8, false); + ribbonLabel.setIcon(new ImageIcon(ribbon)); ribbonLabel.setToolTipText(award.getTooltip(campaign.getCampaignOptions(), person)); rowRibbonsBox.add(ribbonLabel, 0); @@ -481,23 +483,15 @@ private JPanel drawMedals() { int awardTierCount = getAwardTierCount(award, maximumTiers); String medalFileName = award.getMedalFileName(awardTierCount); + String directory = award.getSet() + "/medals/"; - medal = (Image) MHQStaticDirectoryManager.getAwardIcons() - .getItem(award.getSet() + "/medals/", medalFileName); + medal = (Image) MHQStaticDirectoryManager.getAwardIcons().getItem(directory, medalFileName); if (medal == null) { + logger.warn("No medal icon found for award: {}", directory + medalFileName); continue; } - int width = medal.getWidth(null); - int height = medal.getHeight(null); - - if (width == height) { - medal = medal.getScaledInstance(40, 40, Image.SCALE_FAST); - } else if (width < height) { - medal = medal.getScaledInstance(20, 40, Image.SCALE_FAST); - } else { - medal = medal.getScaledInstance(40, 20, Image.SCALE_FAST); - } + medal = scaleImage(medal, 40, false); medalLabel.setIcon(new ImageIcon(medal)); medalLabel.setToolTipText(award.getTooltip(campaign.getCampaignOptions(), person)); @@ -529,27 +523,19 @@ private JPanel drawMiscAwards() { Image misc; try { - int maximumTiers = award.getNumberOfMedalFiles(); + int maximumTiers = award.getNumberOfMiscFiles(); int awardTierCount = getAwardTierCount(award, maximumTiers); String miscFileName = award.getMiscFileName(awardTierCount); + String directory = award.getSet() + "/misc/"; - misc = (Image) MHQStaticDirectoryManager.getAwardIcons() - .getItem(award.getSet() + "/misc/", miscFileName); + misc = (Image) MHQStaticDirectoryManager.getAwardIcons().getItem(directory, miscFileName); if (misc == null) { + logger.warn("No misc icon found for award: {}", directory + miscFileName); continue; } - int width = misc.getWidth(null); - int height = misc.getHeight(null); - - if (width == height) { - misc = misc.getScaledInstance(40, 40, Image.SCALE_FAST); - } else if (width < height) { - misc = misc.getScaledInstance(20, 40, Image.SCALE_FAST); - } else { - misc = misc.getScaledInstance(40, 20, Image.SCALE_FAST); - } + misc = scaleImage(misc, 40, false); miscLabel.setIcon(new ImageIcon(misc)); miscLabel.setToolTipText(award.getTooltip(campaign.getCampaignOptions(), person)); diff --git a/MekHQ/src/mekhq/utilities/ImageUtilities.java b/MekHQ/src/mekhq/utilities/ImageUtilities.java index 3640579b4b..6b8c35165f 100644 --- a/MekHQ/src/mekhq/utilities/ImageUtilities.java +++ b/MekHQ/src/mekhq/utilities/ImageUtilities.java @@ -93,6 +93,57 @@ public static ImageIcon scaleImageIcon(ImageIcon icon, int size, boolean scaleBy width = (int) Math.ceil((double) height * icon.getIconWidth() / icon.getIconHeight()); } + // Create a new BufferedImage with the desired dimensions + BufferedImage scaledImage = getBufferedImage(icon.getImage(), width, height); + + return new ImageIcon(scaledImage); + } + + /** + * Scales an {@link Image} proportionally based on either the specified width or height. + * + *

This method preserves the aspect ratio of the original image while resizing. The size to scale + * is determined by the {@code size} parameter, and whether scaling is based on width or height is controlled by the + * {@code scaleByWidth} flag.

+ * + *

If the provided {@link Image} is {@code null}, an empty {@link Image} will be returned, and + * an error will be logged.

+ * + * @param image The {@link Image} to be scaled. If {@code null}, an empty {@link Image} is returned. + * @param size The target size to scale to, either width or height depending on the {@code scaleByWidth} + * flag. This value will be scaled for the GUI using {@link UIUtil#scaleForGUI(int)}. + * @param scaleByWidth A {@code boolean} flag to determine the scaling mode: + * + * + * @return A scaled {@link Image}, resized to the specified target dimension while maintaining the aspect ratio. If + * the provided {@link Image} is {@code null}, returns an empty {@link Image}. + */ + public static Image scaleImage(Image image, int size, boolean scaleByWidth) { + if (image == null) { + logger.error(new NullPointerException(), + "Image is null in scaleImage(Image, int, boolean). Returning a placeholder image."); + return new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); + } + + int width, height; + + if (scaleByWidth) { + width = Math.max(1, UIUtil.scaleForGUI(size)); + height = (int) Math.ceil((double) width * image.getHeight(null) / image.getWidth(null)); + } else { + height = Math.max(1, UIUtil.scaleForGUI(size)); + width = (int) Math.ceil((double) height * image.getWidth(null) / image.getHeight(null)); + } + + return getBufferedImage(image, width, height); + } + + private static BufferedImage getBufferedImage(Image image, int width, int height) { // Create a new BufferedImage with the desired dimensions BufferedImage scaledImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); @@ -103,10 +154,9 @@ public static ImageIcon scaleImageIcon(ImageIcon icon, int size, boolean scaleBy g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // Draw the scaled image with high-quality rendering - g2d.drawImage(icon.getImage(), 0, 0, width, height, null); + g2d.drawImage(image, 0, 0, width, height, null); g2d.dispose(); - - return new ImageIcon(scaledImage); + return scaledImage; } /** From 0c73db8462f7d3865c3a7da935eea8d8edc9db8d Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Mon, 7 Apr 2025 14:26:57 -0500 Subject: [PATCH 2/3] - Updated documentation for `scaleImage` and `getBufferedImage` --- MekHQ/src/mekhq/utilities/ImageUtilities.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/MekHQ/src/mekhq/utilities/ImageUtilities.java b/MekHQ/src/mekhq/utilities/ImageUtilities.java index 6b8c35165f..79c8f68ccb 100644 --- a/MekHQ/src/mekhq/utilities/ImageUtilities.java +++ b/MekHQ/src/mekhq/utilities/ImageUtilities.java @@ -122,6 +122,9 @@ public static ImageIcon scaleImageIcon(ImageIcon icon, int size, boolean scaleBy * * @return A scaled {@link Image}, resized to the specified target dimension while maintaining the aspect ratio. If * the provided {@link Image} is {@code null}, returns an empty {@link Image}. + * + * @author Illiani + * @since 0.50.05 */ public static Image scaleImage(Image image, int size, boolean scaleByWidth) { if (image == null) { @@ -143,6 +146,18 @@ public static Image scaleImage(Image image, int size, boolean scaleByWidth) { return getBufferedImage(image, width, height); } + /** + * Creates a high-quality, scaled {@link BufferedImage} with the specified dimensions. + * + * @param image The source {@link Image} to be scaled. Must not be {@code null}. + * @param width The target width for the scaled image. + * @param height The target height for the scaled image. + * + * @return A {@link BufferedImage} scaled to the specified dimensions with high-quality rendering. + * + * @author Illiani + * @since 0.50.05 + */ private static BufferedImage getBufferedImage(Image image, int width, int height) { // Create a new BufferedImage with the desired dimensions BufferedImage scaledImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); From 6fb3aff35c9777459ae4ca009f161d993fb14cb3 Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Fri, 11 Apr 2025 18:14:52 -0500 Subject: [PATCH 3/3] - Removed direct `scaleImage` calls and replaced them with `ImageUtilities.scaleImageIcon`. --- MekHQ/src/mekhq/gui/view/PersonViewPanel.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/MekHQ/src/mekhq/gui/view/PersonViewPanel.java b/MekHQ/src/mekhq/gui/view/PersonViewPanel.java index 9b0fc85cf3..865eb4bc47 100644 --- a/MekHQ/src/mekhq/gui/view/PersonViewPanel.java +++ b/MekHQ/src/mekhq/gui/view/PersonViewPanel.java @@ -35,8 +35,6 @@ import static mekhq.campaign.personnel.Person.getLoyaltyName; import static mekhq.campaign.personnel.skills.SkillType.RP_ONLY_TAG; import static mekhq.campaign.personnel.turnoverAndRetention.Fatigue.getEffectiveFatigue; -import static mekhq.utilities.ImageUtilities.addTintToImageIcon; -import static mekhq.utilities.ImageUtilities.scaleImage; import static org.jfree.chart.ChartColor.DARK_BLUE; import static org.jfree.chart.ChartColor.DARK_RED; @@ -68,6 +66,7 @@ import megamek.common.icons.Portrait; import megamek.common.options.IOption; import megamek.logging.MMLogger; +import megamek.utilities.ImageUtilities; import mekhq.MHQStaticDirectoryManager; import mekhq.MekHQ; import mekhq.Utilities; @@ -417,7 +416,9 @@ private Box drawRibbons() { continue; } - ribbon = scaleImage(ribbon, 8, false); + ImageIcon ribbonAsImageIcon = new ImageIcon(ribbon); + ribbonAsImageIcon = ImageUtilities.scaleImageIcon(ribbonAsImageIcon, 8, false); + ribbon = ribbonAsImageIcon.getImage(); ribbonLabel.setIcon(new ImageIcon(ribbon)); ribbonLabel.setToolTipText(award.getTooltip(campaign.getCampaignOptions(), person)); @@ -493,7 +494,9 @@ private JPanel drawMedals() { continue; } - medal = scaleImage(medal, 40, false); + ImageIcon medalAsImageIcon = new ImageIcon(medal); + medalAsImageIcon = ImageUtilities.scaleImageIcon(medalAsImageIcon, 40, false); + medal = medalAsImageIcon.getImage(); medalLabel.setIcon(new ImageIcon(medal)); medalLabel.setToolTipText(award.getTooltip(campaign.getCampaignOptions(), person)); @@ -537,7 +540,9 @@ private JPanel drawMiscAwards() { continue; } - misc = scaleImage(misc, 40, false); + ImageIcon miscAsImageIcon = new ImageIcon(misc); + miscAsImageIcon = ImageUtilities.scaleImageIcon(miscAsImageIcon, 40, false); + misc = miscAsImageIcon.getImage(); miscLabel.setIcon(new ImageIcon(misc)); miscLabel.setToolTipText(award.getTooltip(campaign.getCampaignOptions(), person));