From 442b82a7c60407defb51bf8092b10a3ed8b4ee8d Mon Sep 17 00:00:00 2001 From: Pierre-Luc Paour Date: Sun, 1 Sep 2002 23:43:24 +0000 Subject: [PATCH] Loading of resized images moved to ImageUtils and enabled ImageMagick mode. --- com/gallery/GalleryRemote/ImageUtils.java | 200 ++++++++++++++++++ com/gallery/GalleryRemote/PreviewFrame.java | 116 ++++------ com/gallery/GalleryRemote/ThumbnailCache.java | 77 +++---- 3 files changed, 269 insertions(+), 124 deletions(-) create mode 100644 com/gallery/GalleryRemote/ImageUtils.java diff --git a/com/gallery/GalleryRemote/ImageUtils.java b/com/gallery/GalleryRemote/ImageUtils.java new file mode 100644 index 0000000..3e91f9a --- /dev/null +++ b/com/gallery/GalleryRemote/ImageUtils.java @@ -0,0 +1,200 @@ +/* + * Gallery Remote - a File Upload Utility for Gallery + * + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2001 Bharat Mediratta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package com.gallery.GalleryRemote; + +import java.io.*; +import java.util.*; +import java.awt.*; +import javax.swing.*; + +/** + * Interface to common image manipulation routines + * + *@author paour + *@created September 1, 2002 + */ + +public class ImageUtils { + public static final String MODULE = "ImageUtils"; + + static Vector toDelete = new Vector(); + static long totalTime = 0; + static int totalIter = 0; + static boolean useIM = false; + static String imPath = null; + + public static final int THUMB = 0; + public static final int PREVIEW = 1; + + static String[] filterName = new String[2]; + static String[] format = new String[2]; + + /** + * Perform the actual icon loading + * + *@param filename path to the file + *@return Resized icon + */ + public static ImageIcon load( String filename, Dimension d, int usage ) { + ImageIcon r = null; + long start = System.currentTimeMillis(); + + if (! useIM) { + r = new ImageIcon( filename ); + + Image scaled = null; + Dimension newD = getSizeKeepRatio( + new Dimension( r.getIconWidth(), r.getIconHeight() ), + d ); + scaled = r.getImage().getScaledInstance( newD.width, newD.height, Image.SCALE_FAST ); + + r.getImage().flush(); + r.setImage( scaled ); + } else { + try { + StringBuffer cmdline = new StringBuffer(imPath); + cmdline.append(" -size "); + + cmdline.append(d.width); + cmdline.append("x"); + cmdline.append(d.height); + + if (filterName[usage] != null && filterName[usage].length() > 0) { + cmdline.append(" -filter "); + cmdline.append(filterName[usage]); + } + + cmdline.append(" \""); + cmdline.append(filename); + + cmdline.append("\" -resize "); + cmdline.append(d.width); + cmdline.append("x"); + cmdline.append(d.height); + cmdline.append(" +profile \"*\" "); + + File temp = File.createTempFile("thumb", "." + format[usage], new File("thumbs")); + toDelete.add(temp); + + cmdline.append(temp.getPath()); + + Log.log(Log.TRACE, MODULE, "Executing " + cmdline.toString()); + + Process p = Runtime.getRuntime().exec(cmdline.toString()); + p.waitFor(); + Log.log(Log.TRACE, MODULE, "Retuned with value " + p.exitValue()); + + r = new ImageIcon(temp.getPath()); + } catch (IOException e1) { + Log.logException(Log.ERROR, MODULE, e1); + } catch (InterruptedException e2) { + Log.logException(Log.ERROR, MODULE, e2); + } + } + + long time = System.currentTimeMillis() - start; + totalTime += time; + totalIter++; + Log.log(Log.TRACE, MODULE, "Time: " + time + " - Avg: " + (totalTime/totalIter) ); + + return r; + } + + static { + File f = new File("thumbs"); + + if (!f.exists()) { + f.mkdir(); + } + + try { + PropertiesFile p = new PropertiesFile("imagemagick/im"); + + useIM = p.getBooleanProperty("enabled"); + Log.log(Log.INFO, MODULE, "useIM: " + useIM); + if (useIM) { + imPath = p.getProperty("imConvertPath"); + Log.log(Log.INFO, MODULE, "imPath: " + imPath); + + if (! new File(imPath).exists()) { + Log.log(Log.CRITICAL, MODULE, "Can't find ImageMagick Convert at the above path"); + useIM = false; + } + } + + if (useIM) { + filterName[THUMB] = p.getProperty("imThumbnailResizeFilter"); + filterName[PREVIEW] = p.getProperty("imPreviewResizeFilter"); + + format[THUMB] = p.getProperty("imThumbnailResizeFormat", "gif"); + format[PREVIEW] = p.getProperty("imPreviewResizeFormat", "jpg"); + } + } catch (Exception e) { + Log.logException(Log.CRITICAL, MODULE, e); + useIM = false; + } + } + + + public static void purgeTemp() + { + Enumeration e = toDelete.elements(); + while (e.hasMoreElements()) { + ((File) e.nextElement()).delete(); + } + } + + public static Dimension getSizeKeepRatio(Dimension source, Dimension target) + { + Dimension result = new Dimension(); + + float sourceRatio = (float) source.width / source.height; + float targetRatio = (float) target.width / target.height; + + if (targetRatio > sourceRatio) + { + result.height = target.height; + result.width = (int) source.width * target.height / source.height; + } + else + { + result.width = target.width; + result.height = (int) source.height * target.width / source.width; + } + + return result; + } + + public static float getRatio(Dimension source, Dimension target) + { + float widthRatio = (float) target.width / source.width; + float heightRatio = (float) target.height / source.height; + + if (heightRatio > widthRatio) + { + return widthRatio; + } + else + { + return heightRatio; + } + } +} diff --git a/com/gallery/GalleryRemote/PreviewFrame.java b/com/gallery/GalleryRemote/PreviewFrame.java index e7667c9..39c85e5 100755 --- a/com/gallery/GalleryRemote/PreviewFrame.java +++ b/com/gallery/GalleryRemote/PreviewFrame.java @@ -37,29 +37,12 @@ public class PreviewFrame extends javax.swing.JFrame { String currentImageFile = null; PreviewLoader previewLoader = new PreviewLoader(); int previewCacheSize = 10; - + public void initComponents() { setTitle("Preview"); setBounds(GalleryRemote.getInstance().properties.getPreviewBounds()); - /*if (mPropertiesFile.getProperty("previewx") == null || mPropertiesFile.getProperty("previewy") == null) - { - setLocation(new java.awt.Point(578, 0)); - } - else - { - setLocation(new java.awt.Point(Integer.parseInt(mPropertiesFile.getProperty("previewx")), Integer.parseInt(mPropertiesFile.getProperty("previewy")))); - } - - if (mPropertiesFile.getProperty("previewwidth") == null || mPropertiesFile.getProperty("previewheight") == null) - { - setSize(new java.awt.Dimension(502, 521)); - } - else - { - setSize(new java.awt.Dimension(Integer.parseInt(mPropertiesFile.getProperty("previewwidth")), Integer.parseInt(mPropertiesFile.getProperty("previewheight")))); - }*/ addComponentListener(new ComponentAdapter() { @@ -71,25 +54,19 @@ public void componentResized(ComponentEvent e) ); previewCacheSize = GalleryRemote.getInstance().properties.getIntProperty("previewCacheSize"); - } public void paint(Graphics g) { g.clearRect(0, 0, getSize().width, getSize().height); - if (currentImage == null) - { - getSizedIcon(MainFrame.DEFAULT_IMAGE).paintIcon(getContentPane(), g, getRootPane().getLocation().x, getRootPane().getLocation().y); - } - else + if (currentImage != null) { currentImage.paintIcon(getContentPane(), g, getRootPane().getLocation().x, getRootPane().getLocation().y); } } - public void displayFile(String filename) - { + public void displayFile(String filename) { if (filename == null) { currentImage = null; @@ -100,24 +77,33 @@ public void displayFile(String filename) else if (! filename.equals(currentImageFile)) { currentImageFile = filename; - previewLoader.loadPreview(filename); + + ImageIcon r = (ImageIcon) imageIcons.get(filename); + if (r != null) { + Log.log(Log.TRACE, MODULE, "Cache hit: " + filename); + currentImage = r; + repaint(); + } else { + Log.log(Log.TRACE, MODULE, "Cache miss: " + filename); + previewLoader.loadPreview(filename); + } } } - public ImageIcon getSizedIcon(String filename) - { - if (filename == null) - { - return null; - } - + public ImageIcon getSizedIconForce(String filename) { ImageIcon r = (ImageIcon) imageIcons.get(filename); if (r == null) { - r = safeNewImageIcon(filename); + /*r = safeNewImageIcon(filename); Dimension d = getSizeKeepRatio(new Dimension(r.getIconWidth(), r.getIconHeight()), getRootPane().getSize()); - r.setImage(safeGetScaledInstance(r.getImage(), d.width, d.height, Image.SCALE_FAST)); + r.setImage(safeGetScaledInstance(r.getImage(), d.width, d.height, Image.SCALE_FAST));*/ + r = ImageUtils.load( + filename, + getRootPane().getSize(), + ImageUtils.PREVIEW ); + + Log.log(Log.TRACE, MODULE, "Adding to cache: " + filename); imageIcons.put(filename, r); } @@ -141,7 +127,7 @@ public void run() iFilename = null; } - currentImage = getSizedIcon(tmpFilename); + currentImage = getSizedIconForce(tmpFilename); } stillRunning = false; @@ -164,7 +150,7 @@ public void loadPreview(String filename) } } - public ImageIcon safeNewImageIcon(String filename) + /*public ImageIcon safeNewImageIcon(String filename) { Log.log(Log.TRACE, MODULE, "safeNewImageIcon " + filename); Log.log(Log.TRACE, MODULE, Runtime.getRuntime().freeMemory() + " - " + Runtime.getRuntime().totalMemory()); @@ -204,44 +190,9 @@ public Image safeGetScaledInstance(Image image, int width, int height, int mode) { Log.log(Log.TRACE, MODULE, Runtime.getRuntime().freeMemory() + " - " + Runtime.getRuntime().totalMemory()); } - } + }*/ - public static Dimension getSizeKeepRatio(Dimension source, Dimension target) - { - Dimension result = new Dimension(); - - float sourceRatio = (float) source.width / source.height; - float targetRatio = (float) target.width / target.height; - - if (targetRatio > sourceRatio) - { - result.height = target.height; - result.width = (int) source.width * target.height / source.height; - } - else - { - result.width = target.width; - result.height = (int) source.height * target.width / source.width; - } - return result; - } - - public static float getRatio(Dimension source, Dimension target) - { - float widthRatio = (float) target.width / source.width; - float heightRatio = (float) target.height / source.height; - - if (heightRatio > widthRatio) - { - return widthRatio; - } - else - { - return heightRatio; - } - } - public class SmartHashtable extends Hashtable { Vector touchOrder = new Vector(); @@ -252,12 +203,13 @@ public Object put(Object key, Object value) super.put(key, value); Log.log(Log.TRACE, MODULE, Runtime.getRuntime().freeMemory() + " - " + Runtime.getRuntime().totalMemory()); - if (Runtime.getRuntime().freeMemory() < 2000000) + /*if (Runtime.getRuntime().freeMemory() < 2000000) { + Log.log(Log.TRACE, MODULE, "Not enough free ram, shrinking..."); shrink(); Runtime.getRuntime().gc(); } - else if (previewCacheSize > 0 && touchOrder.size() > previewCacheSize) + else */if (previewCacheSize > 0 && touchOrder.size() > previewCacheSize) { shrink(); } @@ -299,7 +251,6 @@ public void touch(Object key) public void shrink() { - Log.log(Log.TRACE, MODULE, "shrink"); if (touchOrder.size() == 0) { Log.log(Log.ERROR, MODULE, "Empty SmartHashtable"); @@ -309,7 +260,18 @@ public void shrink() Object key = touchOrder.elementAt(0); touchOrder.remove(0); + + ImageIcon i = (ImageIcon) get(key); + if (i != null) { + i.getImage().flush(); + i = null; + } + remove(key); + + Runtime.getRuntime().gc(); + + Log.log(Log.TRACE, MODULE, "Shrunk " + key); } } } diff --git a/com/gallery/GalleryRemote/ThumbnailCache.java b/com/gallery/GalleryRemote/ThumbnailCache.java index f35f024..2599fb4 100644 --- a/com/gallery/GalleryRemote/ThumbnailCache.java +++ b/com/gallery/GalleryRemote/ThumbnailCache.java @@ -64,10 +64,16 @@ public void run() { while ( !toLoad.isEmpty() ) { String filename = (String) toLoad.pop(); - if ( thumbnails.get( filename ) == null ) { - loadThumbnail( filename ); + if ( ! thumbnails.containsKey( filename ) ) { + ImageIcon i = ImageUtils.load( + filename, + GalleryRemote.getInstance().properties.getThumbnailSize(), + ImageUtils.THUMB ); + thumbnails.put( filename, i ); loaded++; + + Log.log(Log.TRACE, MODULE, "update progress " + loaded + "/" + (loaded + toLoad.size())); mf.updateProgressValue(pId, loaded, loaded + toLoad.size()); mf.thumbnailLoadedNotify(); } @@ -86,11 +92,13 @@ public void run() { *@param filename path to the file */ public void preloadThumbnail( String filename ) { - Log.log(Log.TRACE, MODULE, "loadPreview " + filename); - - toLoad.add( 0, filename ); + Log.log(Log.TRACE, MODULE, "preloadThumbnail " + filename); + + if (!thumbnails.containsKey(filename)) { + toLoad.add( 0, filename ); - rerun(); + rerun(); + } } @@ -100,11 +108,13 @@ public void preloadThumbnail( String filename ) { *@param filename path to the file */ public void preloadThumbnailFirst( String filename ) { - Log.log(Log.TRACE, MODULE, "loadPreview " + filename); + Log.log(Log.TRACE, MODULE, "preloadThumbnail " + filename); - toLoad.push( filename ); + if (!thumbnails.containsKey(filename)) { + toLoad.push( filename ); - rerun(); + rerun(); + } } @@ -114,10 +124,14 @@ public void preloadThumbnailFirst( String filename ) { *@param files enumeration of File objects that should be loaded */ public void preloadThumbnailFiles( Enumeration files ) { - Log.log(Log.TRACE, MODULE, "loadPreview " + files); + Log.log(Log.TRACE, MODULE, "preloadThumbnail " + files); while ( files.hasMoreElements() ) { - toLoad.add( 0, ( (Picture) files.nextElement() ).getSource().getPath() ); + String filename = ( (Picture) files.nextElement() ).getSource().getPath(); + + if (!thumbnails.containsKey(filename)) { + toLoad.add( 0, filename ); + } } rerun(); @@ -130,10 +144,12 @@ public void preloadThumbnailFiles( Enumeration files ) { *@param filenames an array of File objects */ public void preloadThumbnails( File[] filenames ) { - Log.log(Log.TRACE, MODULE, "loadPreview " + filenames); + Log.log(Log.TRACE, MODULE, "preloadThumbnail " + filenames); for ( int i = 0; i < filenames.length; i++ ) { - toLoad.add( 0, ( (File) filenames[i] ).getPath() ); + if (!thumbnails.containsKey(filenames[i])) { + toLoad.add( 0, ( (File) filenames[i] ).getPath() ); + } } rerun(); @@ -155,40 +171,7 @@ void cancelLoad() { /** - * Perform the actual icon loading - * - *@param filename path to the file - *@return Resized icon - */ - public ImageIcon loadThumbnail( String filename ) { - ImageIcon r = null; - long start = System.currentTimeMillis(); - - r = new ImageIcon( filename ); - - Image scaled = null; - Dimension d = PreviewFrame.getSizeKeepRatio( - new Dimension( r.getIconWidth(), r.getIconHeight() ), - GalleryRemote.getInstance().properties.getThumbnailSize() ); - scaled = r.getImage().getScaledInstance( d.width, d.height, mf.highQualityThumbnails ? Image.SCALE_SMOOTH : Image.SCALE_FAST ); - - r.getImage().flush(); - r.setImage( scaled ); - - thumbnails.put( filename, r ); - long time = System.currentTimeMillis() - start; - totalTime += time; - totalIter++; - Log.log(Log.TRACE, MODULE, "Time: " + time + " - Avg: " + (totalTime/totalIter) ); - - return r; - } - long totalTime = 0; - int totalIter = 0; - - - /** - * Retrieves a thumbnail from the thumnail cache + * Retrieves a thumbnail from the thumbnail cache * *@param filename path to the file *@return The thumbnail object