Added prev/next and etag for caching of images

This commit is contained in:
knut 2008-11-30 05:40:02 +00:00
parent c4b1a3ee5f
commit 68c297603a
5 changed files with 108 additions and 10 deletions

BIN
photos/irony.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View file

@ -20,6 +20,9 @@ public class Entry {
String caption;
Date date;
int orientation;
Entry next;
Entry prev;
String etag;
/**
@ -108,4 +111,25 @@ public class Entry {
public void setOrientation(int orientation) {
this.orientation = orientation;
}
public Entry prev() {
return prev;
}
public Entry next() {
return next;
}
public String getEtag() {
return etag;
}
public void setEtag(String etag) {
this.etag = etag;
}
}

View file

@ -5,6 +5,7 @@
package org.forkalsrud.album.exif;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
@ -24,6 +25,11 @@ import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.metadata.Directory;
@ -43,13 +49,18 @@ public class EntryDao {
final static String CACHE_FILE = "cache.properties";
final static String OVERRIDE_FILE = "album.properties";
boolean isCurrent(File directory) {
return directory.lastModified() <= new File(directory, CACHE_FILE).lastModified();
}
public List<Entry> read(File directory) throws FileNotFoundException, IOException, JpegProcessingException, MetadataException, ParseException {
List<Entry> entries = new ArrayList<Entry>();
Properties cachedProps = new Properties();
File cache = new File(directory, CACHE_FILE);
if (cache.exists() && cache.isFile() && cache.canRead()) {
if (cache.exists() && cache.isFile() && cache.canRead() && isCurrent(directory)) {
cachedProps.load(new FileInputStream(cache));
} else {
generateEntries(directory, cachedProps);
@ -80,9 +91,25 @@ public class EntryDao {
}
}
});
fillLinkedList(entries);
return entries;
}
void fillLinkedList(List<Entry> entries) {
Entry prev = null;
for (Entry e : entries) {
e.prev = prev;
if (prev != null) {
prev.next = e;
}
prev = e;
}
if (prev != null) {
prev.next = null;
}
}
private void populate(Properties cachedProps, List<Entry> entries) throws ParseException {
@ -100,6 +127,7 @@ public class EntryDao {
entry.setSize(new Dimension(cachedProps.getProperty("file." + name + ".dimensions")));
entry.setCaption(cachedProps.getProperty("file." + name + ".caption"));
entry.setOrientation(Integer.parseInt(cachedProps.getProperty("file." + name + ".orientation")));
entry.setEtag(cachedProps.getProperty("file." + name + ".etag"));
entries.add(entry);
}
}
@ -137,6 +165,7 @@ public class EntryDao {
String base = "file." + name + ".";
boolean hasDate = false;
boolean hasOrientation = false;
boolean hasDim = false;
Metadata metadata = JpegMetadataReader.readMetadata(f);
Directory exifDirectory = metadata.getDirectory(ExifDirectory.class);
@ -150,6 +179,7 @@ public class EntryDao {
int width = exifDirectory.getInt(ExifDirectory.TAG_EXIF_IMAGE_WIDTH);
int height = exifDirectory.getInt(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT);
cachedProps.setProperty(base + "dimensions", new Dimension(width, height).toString());
hasDim = true;
}
if (exifDirectory.containsTag(ExifDirectory.TAG_DATETIME_ORIGINAL)) {
Date captureDate = exifDirectory.getDate(ExifDirectory.TAG_DATETIME_ORIGINAL);
@ -166,13 +196,22 @@ public class EntryDao {
int width = jpegDirectory.getInt(JpegDirectory.TAG_JPEG_IMAGE_WIDTH);
int height = jpegDirectory.getInt(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT);
cachedProps.setProperty(base + "dimensions", new Dimension(width, height).toString());
hasDim = true;
}
cachedProps.setProperty(base + "etag", Integer.toHexString(name.hashCode() + Long.valueOf(f.lastModified()).hashCode()));
if (!hasDate) {
cachedProps.setProperty(base + "captureDate", sdf.format(new Date(f.lastModified())));
}
if (!hasOrientation) {
cachedProps.setProperty(base + "orientation", "1");
}
if (!hasDim) {
Dimension dim = decodeImageForDimensions(f);
if (dim != null) {
cachedProps.setProperty(base + "dimensions", dim.toString());
hasDim = true;
}
}
}
File dst = new File(directory, CACHE_FILE);
if (directory.canWrite()) {
@ -180,5 +219,24 @@ public class EntryDao {
}
}
Dimension decodeImageForDimensions(File file) throws IOException {
String suffix = null;
String name = file.getName();
if (name.indexOf('.') > 0) {
suffix = name.substring(name.lastIndexOf('.') + 1);
}
Iterator<ImageReader> readers = ImageIO.getImageReadersBySuffix(suffix);
if (!readers.hasNext()) {
return null;
}
ImageReader reader = readers.next();
ImageInputStream iis = ImageIO.createImageInputStream(file);
reader.setInput(iis, true);
ImageReadParam param = reader.getDefaultReadParam();
BufferedImage img = reader.read(0, param);
return new Dimension(img.getWidth(), img.getHeight());
}
}

View file

@ -94,6 +94,8 @@ public class AlbumServlet
try {
Entry e = dao.readFile(file);
req.setAttribute("entry", e);
req.setAttribute("prev", e.prev());
req.setAttribute("next", e.next());
RequestDispatcher rd = req.getRequestDispatcher("/WEB-INF/velocity/photo.vm");
rd.forward(req, res);
} catch (Exception e) {
@ -104,17 +106,22 @@ public class AlbumServlet
}
}
boolean etagMatches(HttpServletRequest req, HttpServletResponse res, Entry entry, String size) {
String reqEtag = req.getHeader("If-None-Match");
String fileEtag = entry.getEtag() + "-" + size;
if (reqEtag != null) {
return reqEtag.equals(fileEtag);
}
res.setHeader("ETag", fileEtag);
return false;
}
void scaleImage(HttpServletRequest req, HttpServletResponse res, File file, String size) throws IOException, JpegProcessingException, MetadataException, ParseException {
List<Entry> entries = dao.read(file.getParentFile());
Entry entry = null;
String myName = file.getName();
for (Entry e : entries) {
if (myName.equals(e.getName())) {
entry = e;
break;
}
Entry entry = dao.readFile(file);
if (etagMatches(req, res, entry, size)) {
res.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
Dimension orig = entry.getSize();
Dimension outd;
@ -134,7 +141,7 @@ public class AlbumServlet
ImageInputStream iis = ImageIO.createImageInputStream(file);
reader.setInput(iis, true);
ImageReadParam param = reader.getDefaultReadParam();
if (true /* subsampling */) {
if (false /* subsampling */) {
double subSampleScale = (double)outd.getWidth() / orig.getWidth();
int subSampling = (int)Math.floor(0.25d/subSampleScale);
if (subSampling > 1) {

View file

@ -34,6 +34,15 @@
</head>
<body>
<center>
#if($prev)
<a href="${prev.name}.photo">&lt;--</a>
#end
#if($next)
<a href="${next.name}.photo">--&gt;</a>
#end
</center>
#set($thmb = 480)
#set($dim = $entry.size.scaled($thmb))
<div class="photo">