From 568fb95ee6077b7465130a95dd98bafdf94d259a Mon Sep 17 00:00:00 2001 From: nathan Date: Mon, 24 Oct 2016 02:39:40 +0200 Subject: [PATCH] Cleaned up caching - now is based on file hash, instead of cache names, which could lead to heisenbugs. Everything always caches now based on hash of input --- src/dorkbox/systemTray/MenuItem.java | 81 ++---- src/dorkbox/systemTray/SystemTray.java | 82 ++---- .../swingUI/SwingMenuItemCheckbox.java | 2 +- src/dorkbox/systemTray/util/ImageUtils.java | 273 +++++++----------- 4 files changed, 156 insertions(+), 282 deletions(-) diff --git a/src/dorkbox/systemTray/MenuItem.java b/src/dorkbox/systemTray/MenuItem.java index eacdd79..4280f32 100644 --- a/src/dorkbox/systemTray/MenuItem.java +++ b/src/dorkbox/systemTray/MenuItem.java @@ -21,6 +21,8 @@ import java.io.File; import java.io.InputStream; import java.net.URL; +import javax.imageio.stream.ImageInputStream; + import dorkbox.systemTray.peer.MenuItemPeer; import dorkbox.systemTray.util.ImageUtils; @@ -80,27 +82,32 @@ class MenuItem extends Entry { public MenuItem(final String text, final String imagePath, final ActionListener callback) { - this(text, ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imagePath, true), callback, false); + this(text, ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imagePath), callback, false); } public MenuItem(final String text, final File imageFile, final ActionListener callback) { - this(text, ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageFile, true), callback, false); + this(text, ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageFile), callback, false); } public MenuItem(final String text, final URL imageUrl, final ActionListener callback) { - this(text, ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageUrl, true), callback, false); + this(text, ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageUrl), callback, false); } public MenuItem(final String text, final InputStream imageStream, final ActionListener callback) { - this(text, ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageStream, true), callback, false); + this(text, ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageStream), callback, false); } public MenuItem(final String text, final Image image, final ActionListener callback) { - this(text, ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, image, true), callback, false); + this(text, ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, image), callback, false); + } + + public + MenuItem(final String text, final ImageInputStream imageStream, final ActionListener callback) { + this(text, ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageStream), callback, false); } // the last parameter (unused) is there so the signature is different @@ -205,18 +212,7 @@ class MenuItem extends Entry { */ public void setImage(final File imageFile) { - setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageFile, true)); - } - - /** - * Specifies the new image to set for a menu entry, NULL to delete the image. - * - * @param imageFile the file of the image to use or null - * @param cacheImage true to cache the image (only if the image is resized as necessary) - */ - public - void setImage(final File imageFile, final boolean cacheImage) { - setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageFile, cacheImage)); + setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageFile)); } /** @@ -228,18 +224,7 @@ class MenuItem extends Entry { */ public void setImage(final String imagePath) { - setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imagePath, true)); - } - - /** - * Specifies the new image to set for a menu entry, NULL to delete the image - * - * @param imagePath the full path of the image to use or null - * @param cacheImage true to cache the image (only if the image is resized as necessary) - */ - public - void setImage(final String imagePath, final boolean cacheImage) { - setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imagePath, cacheImage)); + setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imagePath)); } /** @@ -251,18 +236,7 @@ class MenuItem extends Entry { */ public void setImage(final URL imageUrl) { - setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageUrl, true)); - } - - /** - * Specifies the new image to set for a menu entry, NULL to delete the image - * - * @param imageUrl the URL of the image to use or null - * @param cacheImage true to cache the image (only if the image is resized as necessary) - */ - public - void setImage(final URL imageUrl, final boolean cacheImage) { - setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageUrl, cacheImage)); + setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageUrl)); } /** @@ -274,18 +248,7 @@ class MenuItem extends Entry { */ public void setImage(final InputStream imageStream) { - setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageStream, true)); - } - - /** - * Specifies the new image to set for a menu entry, NULL to delete the image - * - * @param imageStream the InputStream of the image to use - * @param cacheImage true to cache the image (only if the image is resized as necessary) - */ - public - void setImage(final InputStream imageStream, final boolean cacheImage) { - setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageStream, cacheImage)); + setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageStream)); } /** @@ -297,20 +260,22 @@ class MenuItem extends Entry { */ public void setImage(final Image image) { - setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, image, true)); + setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, image)); } /** * Specifies the new image to set for a menu entry, NULL to delete the image + *

+ * This method will cache the image if it needs to be resized to fit. * - * @param image the image of the image to use - * @param cacheImage true to cache the image (only if the image is resized as necessary) + * @param imageStream the ImageInputStream of the image to use */ public - void setImage(final Image image, final boolean cacheImage) { - setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, image, cacheImage)); + void setImage(final ImageInputStream imageStream) { + setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageStream)); } + /** * @return true if this menu entry has an image assigned to it, or is just text. */ diff --git a/src/dorkbox/systemTray/SystemTray.java b/src/dorkbox/systemTray/SystemTray.java index c03ffe8..a6efc50 100644 --- a/src/dorkbox/systemTray/SystemTray.java +++ b/src/dorkbox/systemTray/SystemTray.java @@ -27,6 +27,7 @@ import java.io.PrintStream; import java.net.URL; import java.util.concurrent.atomic.AtomicReference; +import javax.imageio.stream.ImageInputStream; import javax.swing.SwingUtilities; import org.slf4j.Logger; @@ -748,24 +749,13 @@ class SystemTray { */ public void setImage(final File imageFile) { - setImage(imageFile, true); - } - - /** - * Specifies the new image to set for a menu entry, NULL to delete the image - * - * @param imageFile the file of the image to use or null - * @param cacheImage true to cache the image (only if the image is resized as necessary) - */ - public - void setImage(final File imageFile, final boolean cacheImage) { if (imageFile == null) { throw new NullPointerException("imageFile cannot be null!"); } final Menu menu = systemTrayMenu; if (menu != null) { - menu.setImage(imageFile, cacheImage); + menu.setImage(imageFile); } } @@ -778,24 +768,13 @@ class SystemTray { */ public void setImage(final String imagePath) { - setImage(imagePath, true); - } - - /** - * Specifies the new image to set for a menu entry, NULL to delete the image - * - * @param imagePath the full path of the image to use or null - * @param cacheImage true to cache the image (only if the image is resized as necessary) - */ - public - void setImage(final String imagePath, final boolean cacheImage) { if (imagePath == null) { throw new NullPointerException("imagePath cannot be null!"); } final Menu menu = systemTrayMenu; if (menu != null) { - menu.setImage(imagePath, cacheImage); + menu.setImage(imagePath); } } @@ -808,17 +787,6 @@ class SystemTray { */ public void setImage(final URL imageUrl) { - setImage(imageUrl, true); - } - - /** - * Specifies the new image to set for a menu entry, NULL to delete the image - * - * @param imageUrl the URL of the image to use or null - * @param cacheImage true to cache the image (only if the image is resized as necessary) - */ - public - void setImage(final URL imageUrl, final boolean cacheImage) { if (imageUrl == null) { throw new NullPointerException("imageUrl cannot be null!"); } @@ -838,17 +806,6 @@ class SystemTray { */ public void setImage(final InputStream imageStream) { - setImage(imageStream, true); - } - - /** - * Specifies the new image to set for a menu entry, NULL to delete the image - * - * @param imageStream the InputStream of the image to use - * @param cacheImage true to cache the image (only if the image is resized as necessary) - */ - public - void setImage(final InputStream imageStream, final boolean cacheImage) { if (imageStream == null) { throw new NullPointerException("imageStream cannot be null!"); } @@ -868,25 +825,32 @@ class SystemTray { */ public void setImage(final Image image) { - setImage(image, true); - } - - /** - * Specifies the new image to set for a menu entry, NULL to delete the image - * - * @param image the image of the image to use - * @param cacheImage true to cache the image (only if the image is resized as necessary) - * - */ - public - void setImage(final Image image, final boolean cacheImage) { if (image == null) { throw new NullPointerException("image cannot be null!"); } final Menu menu = systemTrayMenu; if (menu != null) { - menu.setImage(image, cacheImage); + menu.setImage(image); + } + } + + /** + * Specifies the new image to set for a menu entry, NULL to delete the image + *

+ * This method will cache the image if it needs to be resized to fit. + * + *@param imageStream the ImageInputStream of the image to use + */ + public + void setImage(final ImageInputStream imageStream) { + if (imageStream == null) { + throw new NullPointerException("image cannot be null!"); + } + + final Menu menu = systemTrayMenu; + if (menu != null) { + menu.setImage(imageStream); } } } diff --git a/src/dorkbox/systemTray/swingUI/SwingMenuItemCheckbox.java b/src/dorkbox/systemTray/swingUI/SwingMenuItemCheckbox.java index 0274407..98145c4 100644 --- a/src/dorkbox/systemTray/swingUI/SwingMenuItemCheckbox.java +++ b/src/dorkbox/systemTray/swingUI/SwingMenuItemCheckbox.java @@ -48,7 +48,7 @@ class SwingMenuItemCheckbox implements CheckboxPeer { if (checkedIcon == null) { // from Brankic1979, public domain - File checkedFile = ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, ImageUtils.class.getResource("checked_32.png"), true); + File checkedFile = ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, ImageUtils.class.getResource("checked_32.png")); checkedIcon = new ImageIcon(checkedFile.getAbsolutePath()); File uncheckedFile = ImageUtils.getTransparentImage(ImageUtils.ENTRY_SIZE); diff --git a/src/dorkbox/systemTray/util/ImageUtils.java b/src/dorkbox/systemTray/util/ImageUtils.java index 584d58a..99933f2 100644 --- a/src/dorkbox/systemTray/util/ImageUtils.java +++ b/src/dorkbox/systemTray/util/ImageUtils.java @@ -63,7 +63,8 @@ class ImageUtils { public static void determineIconSize() { - int scalingFactor = 0; + int trayScalingFactor = 0; + int menuScalingFactor = 0; if (SystemTray.AUTO_TRAY_SIZE) { if (OS.isWindows()) { @@ -109,57 +110,71 @@ class ImageUtils { if (windowsVersion.startsWith("5.1")) { // Windows XP 5.1.2600 - scalingFactor = 1; + trayScalingFactor = 1; } else if (windowsVersion.startsWith("5.1")) { // Windows Server 2003 5.2.3790.1218 - scalingFactor = 1; + trayScalingFactor = 1; } else if (windowsVersion.startsWith("6.0")) { // Windows Vista 6.0.6000 // Windows Server 2008 SP1 6.0.6001 // Windows Server 2008 SP2 6.0.6002 - scalingFactor = 1; + trayScalingFactor = 1; } else if (windowsVersion.startsWith("6.1")) { // Windows 7 // Windows Server 2008 R2 6.1.7600 // Windows Server 2008 R2 SP1 6.1.7601 - scalingFactor = 2; + trayScalingFactor = 2; } else if (windowsVersion.startsWith("6.2")) { // Windows 8 // Windows Server 2012 6.2.9200 - scalingFactor = 2; + trayScalingFactor = 2; } else if (windowsVersion.startsWith("6.3")) { // Windows 8.1 // Windows Server 2012 6.3.9200 - scalingFactor = 4; + trayScalingFactor = 4; } else if (windowsVersion.startsWith("6.4")) { // Windows 10 Technical Preview 1 6.4.9841 - scalingFactor = 4; + trayScalingFactor = 4; } else if (windowsVersion.startsWith("10.0")) { // Windows 10 Technical Preview 4 10.0.9926 // Windows 10 Insider Preview 10.0.14915 - scalingFactor = 4; + trayScalingFactor = 4; } else { // dunnno, but i'm going to assume HiDPI for this... - scalingFactor = 8; + trayScalingFactor = 8; } Pointer screen = User32.GetDC(null); int dpiX = GetDeviceCaps (screen, LOGPIXELSX); User32.ReleaseDC(null, screen); - System.err.println("DPI : " + dpiX); + // 96 DPI = 100% scaling + // 120 DPI = 125% scaling + // 144 DPI = 150% scaling + // 192 DPI = 200% scaling + + // just a note on scaling... + // We want to scale the image as best we can beforehand, so there is an attempt to have it look good + if (dpiX != 96) { + // so there are additional scaling settings... + // casting around for rounding/math stuff + // *2 because we want a 2x scale to be 64, not 32. + trayScalingFactor = (int) (((double) dpiX) / ((double) 96)) * 2; + menuScalingFactor = trayScalingFactor; + } if (SystemTray.DEBUG) { SystemTray.logger.debug("Windows version (partial): '{}'", windowsVersion); + SystemTray.logger.debug("Windows DPI settings: '{}'", dpiX); } } else if (OS.isLinux()) { // GtkStatusIcon will USUALLY automatically scale the icon @@ -197,12 +212,12 @@ class ImageUtils { // 4 = 64 // 8 = 128 if (value.startsWith("4")) { - scalingFactor = 2; + trayScalingFactor = 2; } else if (value.startsWith("5")) { - scalingFactor = 8; // it is insane how large the icon is + trayScalingFactor = 8; // it is insane how large the icon is } else { // assume very low version of plasmashell, default 32 - scalingFactor = 2; + trayScalingFactor = 2; } } } @@ -237,7 +252,7 @@ class ImageUtils { // should be: uint32 0 or something if (output.contains("uint32")) { String value = output.substring(output.indexOf("uint")+7, output.length()-1); - scalingFactor = Integer.parseInt(value); + trayScalingFactor = Integer.parseInt(value); // 0 is disabled (no scaling) // 1 is enabled (default scale) @@ -265,16 +280,16 @@ class ImageUtils { if (height < 32) { // lock in at 32 - scalingFactor = 2; + trayScalingFactor = 2; } else if ((height & (height - 1)) == 0) { // is this a power of 2 number? If so, we can use it - scalingFactor = height/SystemTray.DEFAULT_TRAY_SIZE; + trayScalingFactor = height/SystemTray.DEFAULT_TRAY_SIZE; } else { // don't know how exactly to determine this, but we are going to assume very high "HiDPI" for this... // the OS should go up/down as needed. - scalingFactor = 8; + trayScalingFactor = 8; } } } @@ -284,16 +299,20 @@ class ImageUtils { // we want to make sure our "scaled" size is appropriate for the OS. // the DEFAULT scale is 16 - if (scalingFactor > 1) { - TRAY_SIZE = SystemTray.DEFAULT_TRAY_SIZE * scalingFactor; - ENTRY_SIZE = SystemTray.DEFAULT_MENU_SIZE; - - if (SystemTray.DEBUG) { - SystemTray.logger.debug("Scaling Factor factor is '{}', tray size is '{}'.", scalingFactor, TRAY_SIZE); - } + if (trayScalingFactor > 1) { + TRAY_SIZE = SystemTray.DEFAULT_TRAY_SIZE * trayScalingFactor; } else { TRAY_SIZE = SystemTray.DEFAULT_TRAY_SIZE; - ENTRY_SIZE = SystemTray.DEFAULT_MENU_SIZE; + } + + if (menuScalingFactor > 1) { + ENTRY_SIZE = SystemTray.DEFAULT_MENU_SIZE * menuScalingFactor; + } + ENTRY_SIZE = SystemTray.DEFAULT_MENU_SIZE; + + if (SystemTray.DEBUG) { + SystemTray.logger.debug("Scaling Factor factor is '{}', tray size is '{}'.", trayScalingFactor, TRAY_SIZE); + SystemTray.logger.debug("Scaling Factor factor is '{}', tray size is '{}'.", menuScalingFactor, ENTRY_SIZE); } } @@ -359,189 +378,112 @@ class ImageUtils { } public static synchronized - File resizeAndCache(final int size, final File file, final boolean cacheResult) { - return resizeAndCache(size, file.getAbsolutePath(), cacheResult); + File resizeAndCache(final int size, final File file) { + return resizeAndCache(size, file.getAbsolutePath()); } public static synchronized - File resizeAndCache(final int size, final String fileName, final boolean cacheResult) { + File resizeAndCache(final int size, final String fileName) { if (fileName == null) { return null; } - // check if we already have this file information saved to disk, based on size - final String cacheName = size + "_" + fileName; - - // if we already have this fileName, reuse it - File check = getIfCachedOrError(cacheName); - if (check != null) { - return check; - } - - // no cached file, so we resize then save the new one. - String newFileOnDisk; try { - newFileOnDisk = resizeFile(size, fileName); + FileInputStream fileInputStream = new FileInputStream(fileName); + File file = resizeAndCache(size, fileInputStream); + fileInputStream.close(); + + return file; } catch (IOException e) { // have to serve up the error image instead. - SystemTray.logger.error("Error resizing image. Using error icon instead", e); - return getErrorImage(cacheName); - } - - try { - return CacheUtil.save(cacheName, newFileOnDisk); - } catch (IOException e) { - // have to serve up the error image instead. - SystemTray.logger.error("Error caching image. Using error icon instead", e); - return getErrorImage(cacheName); + SystemTray.logger.error("Error reading image. Using error icon instead", e); + return getErrorImage(size + "default"); } } @SuppressWarnings("Duplicates") public static synchronized - File resizeAndCache(final int size, final URL imageUrl, final boolean cacheResult) { + File resizeAndCache(final int size, final URL imageUrl) { if (imageUrl == null) { return null; } - final String cacheName = size + "_" + imageUrl.getPath(); - - // if we already have this fileName, reuse it - final File check = getIfCachedOrError(cacheName); - if (check != null) { - return check; - } - - // no cached file, so we resize then save the new one. - boolean needsResize = true; try { InputStream inputStream = imageUrl.openStream(); - Dimension imageSize = getImageSize(inputStream); - //noinspection NumericCastThatLosesPrecision - if (size == ((int) imageSize.getWidth()) && size == ((int) imageSize.getHeight())) { - // we can reuse this URL (it's the correct size). - needsResize = false; - } + File file = resizeAndCache(size, inputStream); + inputStream.close(); + + return file; } catch (IOException e) { // have to serve up the error image instead. - SystemTray.logger.error("Error resizing image. Using error icon instead", e); - return getErrorImage(cacheName); - } - - if (needsResize) { - // we have to hop through hoops. - try { - File resizedFile = resizeFileNoCheck(size, imageUrl); - - // now cache that file - try { - return CacheUtil.save(cacheName, resizedFile); - } catch (IOException e) { - // have to serve up the error image instead. - SystemTray.logger.error("Error caching image. Using error icon instead", e); - return getErrorImage(cacheName); - } - - } catch (IOException e) { - // have to serve up the error image instead. - SystemTray.logger.error("Error resizing image. Using error icon instead", e); - return getErrorImage(cacheName); - } - - } else { - // no resize necessary, just cache as is. - try { - return CacheUtil.save(cacheName, imageUrl); - } catch (IOException e) { - // have to serve up the error image instead. - SystemTray.logger.error("Error caching image. Using error icon instead", e); - return getErrorImage(cacheName); - } + SystemTray.logger.error("Error reading image. Using error icon instead", e); + return getErrorImage(size + "default"); } } @SuppressWarnings("Duplicates") public static synchronized - File resizeAndCache(final int size, final Image image, final boolean cacheResult) { + File resizeAndCache(final int size, final Image image) { if (image == null) { return null; } + // stupid java won't scale it right away, so we have to do this twice to get the correct size + final Image trayImage = new ImageIcon(image).getImage(); + trayImage.flush(); -// final String cacheName = size + "_" + imageUrl.getPath(); -// -// // if we already have this fileName, reuse it -// final File check = getIfCachedOrError(cacheName); -// if (check != null) { -// return check; -// } -// -// // no cached file, so we resize then save the new one. -// boolean needsResize = true; -// try { -// InputStream inputStream = imageUrl.openStream(); -// Dimension imageSize = getImageSize(inputStream); -// //noinspection NumericCastThatLosesPrecision -// if (size == ((int) imageSize.getWidth()) && size == ((int) imageSize.getHeight())) { -// // we can reuse this URL (it's the correct size). -// needsResize = false; -// } -// } catch (IOException e) { -// // have to serve up the error image instead. -// SystemTray.logger.error("Error resizing image. Using error icon instead", e); -// return getErrorImage(cacheName); -// } -// -// if (needsResize) { -// // we have to hop through hoops. -// try { -// File resizedFile = resizeFileNoCheck(size, imageUrl); -// -// // now cache that file -// try { -// return CacheUtil.save(cacheName, resizedFile); -// } catch (IOException e) { -// // have to serve up the error image instead. -// SystemTray.logger.error("Error caching image. Using error icon instead", e); -// return getErrorImage(cacheName); -// } -// -// } catch (IOException e) { -// // have to serve up the error image instead. -// SystemTray.logger.error("Error resizing image. Using error icon instead", e); -// return getErrorImage(cacheName); -// } -// -// } else { -// // no resize necessary, just cache as is. -// try { -// return CacheUtil.save(cacheName, imageUrl); -// } catch (IOException e) { -// // have to serve up the error image instead. -// SystemTray.logger.error("Error caching image. Using error icon instead", e); -// return getErrorImage(cacheName); -// } -// } - return null; + try { + ImageInputStream imageInputStream = ImageIO.createImageInputStream(image); + File file = resizeAndCache(size, imageInputStream); + imageInputStream.close(); + + return file; + } catch (IOException e) { + // have to serve up the error image instead. + SystemTray.logger.error("Error reading image. Using error icon instead", e); + return getErrorImage(size + "default"); + } } @SuppressWarnings("Duplicates") public static synchronized - File resizeAndCache(final int size, InputStream imageStream, final boolean cacheResult) { + File resizeAndCache(final int size, final ImageInputStream imageStream) { if (imageStream == null) { return null; } - // have to make a copy of the inputStream. try { ByteArrayOutputStream byteArrayOutputStream = IO.copyStream(imageStream); - imageStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); + return resizeAndCache(size, new ByteArrayInputStream(byteArrayOutputStream.toByteArray())); } catch (IOException e) { - throw new RuntimeException("Unable to read from inputStream.", e); + // have to serve up the error image instead. + SystemTray.logger.error("Error reading image. Using error icon instead", e); + return getErrorImage(size + "default"); + } + } + + @SuppressWarnings("Duplicates") + public static synchronized + File resizeAndCache(final int size, InputStream imageStream) { + if (imageStream == null) { + return null; } - // check if we already have this file information saved to disk, based on size + if (!(imageStream instanceof ByteArrayInputStream)) { + // have to make a copy of the inputStream, but only if necessary + try { + ByteArrayOutputStream byteArrayOutputStream = IO.copyStream(imageStream); + imageStream.close(); + + imageStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); + } catch (IOException e) { + throw new RuntimeException("Unable to read from inputStream.", e); + } + } + imageStream.mark(0); + + // check if we already have this file information saved to disk, based on size + hash of data final String cacheName = size + "_" + CacheUtil.createNameAsHash(imageStream); - ((ByteArrayInputStream) imageStream).reset(); + ((ByteArrayInputStream) imageStream).reset(); // casting to avoid unnecessary try/catch for IOException // if we already have this fileName, reuse it @@ -553,6 +495,7 @@ class ImageUtils { // no cached file, so we resize then save the new one. boolean needsResize = true; try { + imageStream.mark(0); Dimension imageSize = getImageSize(imageStream); //noinspection NumericCastThatLosesPrecision if (size == ((int) imageSize.getWidth()) && size == ((int) imageSize.getHeight())) { @@ -563,6 +506,8 @@ class ImageUtils { // have to serve up the error image instead. SystemTray.logger.error("Error resizing image. Using error icon instead", e); return getErrorImage(cacheName); + } finally { + ((ByteArrayInputStream) imageStream).reset(); // casting to avoid unnecessary try/catch for IOException } if (needsResize) { @@ -641,7 +586,7 @@ class ImageUtils { } /** - * Resizes the given URL to the specified size. No checks are performed if it's the correct size to begin with. + * Resizes the given InputStream to the specified size. No checks are performed if it's the correct size to begin with. * * @return the file on disk that is the resized icon */