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
This commit is contained in:
nathan 2016-10-24 02:39:40 +02:00
parent 146afbf949
commit 568fb95ee6
4 changed files with 156 additions and 282 deletions

View File

@ -21,6 +21,8 @@ import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL; import java.net.URL;
import javax.imageio.stream.ImageInputStream;
import dorkbox.systemTray.peer.MenuItemPeer; import dorkbox.systemTray.peer.MenuItemPeer;
import dorkbox.systemTray.util.ImageUtils; import dorkbox.systemTray.util.ImageUtils;
@ -80,27 +82,32 @@ class MenuItem extends Entry {
public public
MenuItem(final String text, final String imagePath, final ActionListener callback) { 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 public
MenuItem(final String text, final File imageFile, final ActionListener callback) { 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 public
MenuItem(final String text, final URL imageUrl, final ActionListener callback) { 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 public
MenuItem(final String text, final InputStream imageStream, final ActionListener callback) { 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 public
MenuItem(final String text, final Image image, final ActionListener callback) { 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 // the last parameter (unused) is there so the signature is different
@ -205,18 +212,7 @@ class MenuItem extends Entry {
*/ */
public public
void setImage(final File imageFile) { void setImage(final File imageFile) {
setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageFile, true)); setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageFile));
}
/**
* 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));
} }
/** /**
@ -228,18 +224,7 @@ class MenuItem extends Entry {
*/ */
public public
void setImage(final String imagePath) { void setImage(final String imagePath) {
setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imagePath, true)); setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imagePath));
}
/**
* 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));
} }
/** /**
@ -251,18 +236,7 @@ class MenuItem extends Entry {
*/ */
public public
void setImage(final URL imageUrl) { void setImage(final URL imageUrl) {
setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageUrl, true)); setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageUrl));
}
/**
* 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));
} }
/** /**
@ -274,18 +248,7 @@ class MenuItem extends Entry {
*/ */
public public
void setImage(final InputStream imageStream) { void setImage(final InputStream imageStream) {
setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageStream, true)); setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageStream));
}
/**
* 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));
} }
/** /**
@ -297,20 +260,22 @@ class MenuItem extends Entry {
*/ */
public public
void setImage(final Image image) { 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 * Specifies the new image to set for a menu entry, NULL to delete the image
* <p>
* This method will cache the image if it needs to be resized to fit.
* *
* @param image the image of the image to use * @param imageStream the ImageInputStream of the image to use
* @param cacheImage true to cache the image (only if the image is resized as necessary)
*/ */
public public
void setImage(final Image image, final boolean cacheImage) { void setImage(final ImageInputStream imageStream) {
setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, image, cacheImage)); setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageStream));
} }
/** /**
* @return true if this menu entry has an image assigned to it, or is just text. * @return true if this menu entry has an image assigned to it, or is just text.
*/ */

View File

@ -27,6 +27,7 @@ import java.io.PrintStream;
import java.net.URL; import java.net.URL;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import javax.imageio.stream.ImageInputStream;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -748,24 +749,13 @@ class SystemTray {
*/ */
public public
void setImage(final File imageFile) { 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) { if (imageFile == null) {
throw new NullPointerException("imageFile cannot be null!"); throw new NullPointerException("imageFile cannot be null!");
} }
final Menu menu = systemTrayMenu; final Menu menu = systemTrayMenu;
if (menu != null) { if (menu != null) {
menu.setImage(imageFile, cacheImage); menu.setImage(imageFile);
} }
} }
@ -778,24 +768,13 @@ class SystemTray {
*/ */
public public
void setImage(final String imagePath) { 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) { if (imagePath == null) {
throw new NullPointerException("imagePath cannot be null!"); throw new NullPointerException("imagePath cannot be null!");
} }
final Menu menu = systemTrayMenu; final Menu menu = systemTrayMenu;
if (menu != null) { if (menu != null) {
menu.setImage(imagePath, cacheImage); menu.setImage(imagePath);
} }
} }
@ -808,17 +787,6 @@ class SystemTray {
*/ */
public public
void setImage(final URL imageUrl) { 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) { if (imageUrl == null) {
throw new NullPointerException("imageUrl cannot be null!"); throw new NullPointerException("imageUrl cannot be null!");
} }
@ -838,17 +806,6 @@ class SystemTray {
*/ */
public public
void setImage(final InputStream imageStream) { 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) { if (imageStream == null) {
throw new NullPointerException("imageStream cannot be null!"); throw new NullPointerException("imageStream cannot be null!");
} }
@ -868,25 +825,32 @@ class SystemTray {
*/ */
public public
void setImage(final Image image) { 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) { if (image == null) {
throw new NullPointerException("image cannot be null!"); throw new NullPointerException("image cannot be null!");
} }
final Menu menu = systemTrayMenu; final Menu menu = systemTrayMenu;
if (menu != null) { 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
* <p>
* 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);
} }
} }
} }

View File

@ -48,7 +48,7 @@ class SwingMenuItemCheckbox implements CheckboxPeer {
if (checkedIcon == null) { if (checkedIcon == null) {
// from Brankic1979, public domain // 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()); checkedIcon = new ImageIcon(checkedFile.getAbsolutePath());
File uncheckedFile = ImageUtils.getTransparentImage(ImageUtils.ENTRY_SIZE); File uncheckedFile = ImageUtils.getTransparentImage(ImageUtils.ENTRY_SIZE);

View File

@ -63,7 +63,8 @@ class ImageUtils {
public static public static
void determineIconSize() { void determineIconSize() {
int scalingFactor = 0; int trayScalingFactor = 0;
int menuScalingFactor = 0;
if (SystemTray.AUTO_TRAY_SIZE) { if (SystemTray.AUTO_TRAY_SIZE) {
if (OS.isWindows()) { if (OS.isWindows()) {
@ -109,57 +110,71 @@ class ImageUtils {
if (windowsVersion.startsWith("5.1")) { if (windowsVersion.startsWith("5.1")) {
// Windows XP 5.1.2600 // Windows XP 5.1.2600
scalingFactor = 1; trayScalingFactor = 1;
} else if (windowsVersion.startsWith("5.1")) { } else if (windowsVersion.startsWith("5.1")) {
// Windows Server 2003 5.2.3790.1218 // Windows Server 2003 5.2.3790.1218
scalingFactor = 1; trayScalingFactor = 1;
} else if (windowsVersion.startsWith("6.0")) { } else if (windowsVersion.startsWith("6.0")) {
// Windows Vista 6.0.6000 // Windows Vista 6.0.6000
// Windows Server 2008 SP1 6.0.6001 // Windows Server 2008 SP1 6.0.6001
// Windows Server 2008 SP2 6.0.6002 // Windows Server 2008 SP2 6.0.6002
scalingFactor = 1; trayScalingFactor = 1;
} else if (windowsVersion.startsWith("6.1")) { } else if (windowsVersion.startsWith("6.1")) {
// Windows 7 // Windows 7
// Windows Server 2008 R2 6.1.7600 // Windows Server 2008 R2 6.1.7600
// Windows Server 2008 R2 SP1 6.1.7601 // Windows Server 2008 R2 SP1 6.1.7601
scalingFactor = 2; trayScalingFactor = 2;
} else if (windowsVersion.startsWith("6.2")) { } else if (windowsVersion.startsWith("6.2")) {
// Windows 8 // Windows 8
// Windows Server 2012 6.2.9200 // Windows Server 2012 6.2.9200
scalingFactor = 2; trayScalingFactor = 2;
} else if (windowsVersion.startsWith("6.3")) { } else if (windowsVersion.startsWith("6.3")) {
// Windows 8.1 // Windows 8.1
// Windows Server 2012 6.3.9200 // Windows Server 2012 6.3.9200
scalingFactor = 4; trayScalingFactor = 4;
} else if (windowsVersion.startsWith("6.4")) { } else if (windowsVersion.startsWith("6.4")) {
// Windows 10 Technical Preview 1 6.4.9841 // Windows 10 Technical Preview 1 6.4.9841
scalingFactor = 4; trayScalingFactor = 4;
} else if (windowsVersion.startsWith("10.0")) { } else if (windowsVersion.startsWith("10.0")) {
// Windows 10 Technical Preview 4 10.0.9926 // Windows 10 Technical Preview 4 10.0.9926
// Windows 10 Insider Preview 10.0.14915 // Windows 10 Insider Preview 10.0.14915
scalingFactor = 4; trayScalingFactor = 4;
} else { } else {
// dunnno, but i'm going to assume HiDPI for this... // dunnno, but i'm going to assume HiDPI for this...
scalingFactor = 8; trayScalingFactor = 8;
} }
Pointer screen = User32.GetDC(null); Pointer screen = User32.GetDC(null);
int dpiX = GetDeviceCaps (screen, LOGPIXELSX); int dpiX = GetDeviceCaps (screen, LOGPIXELSX);
User32.ReleaseDC(null, screen); 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) { if (SystemTray.DEBUG) {
SystemTray.logger.debug("Windows version (partial): '{}'", windowsVersion); SystemTray.logger.debug("Windows version (partial): '{}'", windowsVersion);
SystemTray.logger.debug("Windows DPI settings: '{}'", dpiX);
} }
} else if (OS.isLinux()) { } else if (OS.isLinux()) {
// GtkStatusIcon will USUALLY automatically scale the icon // GtkStatusIcon will USUALLY automatically scale the icon
@ -197,12 +212,12 @@ class ImageUtils {
// 4 = 64 // 4 = 64
// 8 = 128 // 8 = 128
if (value.startsWith("4")) { if (value.startsWith("4")) {
scalingFactor = 2; trayScalingFactor = 2;
} else if (value.startsWith("5")) { } 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 { } else {
// assume very low version of plasmashell, default 32 // assume very low version of plasmashell, default 32
scalingFactor = 2; trayScalingFactor = 2;
} }
} }
} }
@ -237,7 +252,7 @@ class ImageUtils {
// should be: uint32 0 or something // should be: uint32 0 or something
if (output.contains("uint32")) { if (output.contains("uint32")) {
String value = output.substring(output.indexOf("uint")+7, output.length()-1); String value = output.substring(output.indexOf("uint")+7, output.length()-1);
scalingFactor = Integer.parseInt(value); trayScalingFactor = Integer.parseInt(value);
// 0 is disabled (no scaling) // 0 is disabled (no scaling)
// 1 is enabled (default scale) // 1 is enabled (default scale)
@ -265,16 +280,16 @@ class ImageUtils {
if (height < 32) { if (height < 32) {
// lock in at 32 // lock in at 32
scalingFactor = 2; trayScalingFactor = 2;
} }
else if ((height & (height - 1)) == 0) { else if ((height & (height - 1)) == 0) {
// is this a power of 2 number? If so, we can use it // 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 { else {
// don't know how exactly to determine this, but we are going to assume very high "HiDPI" for this... // 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. // 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. // we want to make sure our "scaled" size is appropriate for the OS.
// the DEFAULT scale is 16 // the DEFAULT scale is 16
if (scalingFactor > 1) { if (trayScalingFactor > 1) {
TRAY_SIZE = SystemTray.DEFAULT_TRAY_SIZE * scalingFactor; TRAY_SIZE = SystemTray.DEFAULT_TRAY_SIZE * trayScalingFactor;
ENTRY_SIZE = SystemTray.DEFAULT_MENU_SIZE;
if (SystemTray.DEBUG) {
SystemTray.logger.debug("Scaling Factor factor is '{}', tray size is '{}'.", scalingFactor, TRAY_SIZE);
}
} else { } else {
TRAY_SIZE = SystemTray.DEFAULT_TRAY_SIZE; 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 public static synchronized
File resizeAndCache(final int size, final File file, final boolean cacheResult) { File resizeAndCache(final int size, final File file) {
return resizeAndCache(size, file.getAbsolutePath(), cacheResult); return resizeAndCache(size, file.getAbsolutePath());
} }
public static synchronized 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) { if (fileName == null) {
return 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 { try {
newFileOnDisk = resizeFile(size, fileName); FileInputStream fileInputStream = new FileInputStream(fileName);
File file = resizeAndCache(size, fileInputStream);
fileInputStream.close();
return file;
} catch (IOException e) { } catch (IOException e) {
// have to serve up the error image instead. // have to serve up the error image instead.
SystemTray.logger.error("Error resizing image. Using error icon instead", e); SystemTray.logger.error("Error reading image. Using error icon instead", e);
return getErrorImage(cacheName); return getErrorImage(size + "default");
}
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);
} }
} }
@SuppressWarnings("Duplicates") @SuppressWarnings("Duplicates")
public static synchronized 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) { if (imageUrl == null) {
return 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 { try {
InputStream inputStream = imageUrl.openStream(); InputStream inputStream = imageUrl.openStream();
Dimension imageSize = getImageSize(inputStream); File file = resizeAndCache(size, inputStream);
//noinspection NumericCastThatLosesPrecision inputStream.close();
if (size == ((int) imageSize.getWidth()) && size == ((int) imageSize.getHeight())) {
// we can reuse this URL (it's the correct size). return file;
needsResize = false;
}
} catch (IOException e) { } catch (IOException e) {
// have to serve up the error image instead. // have to serve up the error image instead.
SystemTray.logger.error("Error resizing image. Using error icon instead", e); SystemTray.logger.error("Error reading image. Using error icon instead", e);
return getErrorImage(cacheName); return getErrorImage(size + "default");
}
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);
}
} }
} }
@SuppressWarnings("Duplicates") @SuppressWarnings("Duplicates")
public static synchronized 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) { if (image == null) {
return 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(); try {
// ImageInputStream imageInputStream = ImageIO.createImageInputStream(image);
// // if we already have this fileName, reuse it File file = resizeAndCache(size, imageInputStream);
// final File check = getIfCachedOrError(cacheName); imageInputStream.close();
// if (check != null) {
// return check; return file;
// } } catch (IOException e) {
// // have to serve up the error image instead.
// // no cached file, so we resize then save the new one. SystemTray.logger.error("Error reading image. Using error icon instead", e);
// boolean needsResize = true; return getErrorImage(size + "default");
// 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;
} }
@SuppressWarnings("Duplicates") @SuppressWarnings("Duplicates")
public static synchronized public static synchronized
File resizeAndCache(final int size, InputStream imageStream, final boolean cacheResult) { File resizeAndCache(final int size, final ImageInputStream imageStream) {
if (imageStream == null) { if (imageStream == null) {
return null; return null;
} }
// have to make a copy of the inputStream.
try { try {
ByteArrayOutputStream byteArrayOutputStream = IO.copyStream(imageStream); ByteArrayOutputStream byteArrayOutputStream = IO.copyStream(imageStream);
imageStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); return resizeAndCache(size, new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
} catch (IOException e) { } 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); 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 // 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. // no cached file, so we resize then save the new one.
boolean needsResize = true; boolean needsResize = true;
try { try {
imageStream.mark(0);
Dimension imageSize = getImageSize(imageStream); Dimension imageSize = getImageSize(imageStream);
//noinspection NumericCastThatLosesPrecision //noinspection NumericCastThatLosesPrecision
if (size == ((int) imageSize.getWidth()) && size == ((int) imageSize.getHeight())) { if (size == ((int) imageSize.getWidth()) && size == ((int) imageSize.getHeight())) {
@ -563,6 +506,8 @@ class ImageUtils {
// have to serve up the error image instead. // have to serve up the error image instead.
SystemTray.logger.error("Error resizing image. Using error icon instead", e); SystemTray.logger.error("Error resizing image. Using error icon instead", e);
return getErrorImage(cacheName); return getErrorImage(cacheName);
} finally {
((ByteArrayInputStream) imageStream).reset(); // casting to avoid unnecessary try/catch for IOException
} }
if (needsResize) { 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 * @return the file on disk that is the resized icon
*/ */