diff --git a/.classpath b/.classpath index 673ec12..5db55ae 100644 --- a/.classpath +++ b/.classpath @@ -1,9 +1,52 @@ + - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/.cvsignore @@ -0,0 +1 @@ +build diff --git a/.project b/.project index 7936a9f..d9db025 100644 --- a/.project +++ b/.project @@ -1,17 +1,19 @@ + - album - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - + album + + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + \ No newline at end of file diff --git a/Makefile b/Makefile deleted file mode 100644 index 19940ae..0000000 --- a/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# -# Java interpreter and compiler -# -JAVA = java -JAVAC = javac - -# -# Various tools -# -RM = rm -f - -# -# Which libraries do we use? -# -CLASSPATH=$(HOME)/src:$(HOME)/src/album/freeJSX1.0.7.4.jar - -CLASSES = Photo.class Album.class Item.class Transform.class - - -# -# The file types we deal with -# -.SUFFIXES: .java .class - - -all: $(CLASSES) - @echo Done - -clean: - $(RM) *.class - $(RM) *~ - -.java.class: - $(JAVAC) -classpath $(CLASSPATH) $< - - -test: $(CLASSES) Test.class - $(JAVA) -cp $(CLASSPATH) album.config.Test /home/knut/src/album/photos - -#eof diff --git a/album.launch b/album.launch new file mode 100644 index 0000000..7a4c627 --- /dev/null +++ b/album.launch @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/conf/resin.conf b/conf/resin.conf new file mode 100644 index 0000000..6cd4ee2 --- /dev/null +++ b/conf/resin.conf @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + 2s + + + + + + + + + . + + + + + + + 1M + + + 256 + + + 65s + + + 128 + 120s + + + + + 5078 + + + + + + + + + + + + + + + + + + + + + + target/resin-tmp + target/resin-work + + + + 30 + + + + + + + + + + + + diff --git a/design.txt b/design.txt index 86aa79f..31063bb 100644 --- a/design.txt +++ b/design.txt @@ -40,7 +40,7 @@ themselves. URLs for the albums are: /album/index-num.html -There is a configuretion switch indicating how many thumbnails to +There is a configuration switch indicating how many thumbnails to show per album page. This makes "num" in index-num.html represent the associated subset of images. There are also one picture per page pages. These have the pattern: diff --git a/lib/metadata-extractor-2.3.1-src.jar b/lib/metadata-extractor-2.3.1-src.jar deleted file mode 100644 index 631f360..0000000 Binary files a/lib/metadata-extractor-2.3.1-src.jar and /dev/null differ diff --git a/lib/metadata-extractor-2.3.1.jar b/lib/metadata-extractor-2.3.1.jar deleted file mode 100644 index f5f6848..0000000 Binary files a/lib/metadata-extractor-2.3.1.jar and /dev/null differ diff --git a/photos/.cvsignore b/photos/.cvsignore new file mode 100644 index 0000000..ec109f1 --- /dev/null +++ b/photos/.cvsignore @@ -0,0 +1 @@ +cache.properties diff --git a/photos/album.properties b/photos/album.properties new file mode 100644 index 0000000..27d44bb --- /dev/null +++ b/photos/album.properties @@ -0,0 +1,2 @@ +file.l1000729.jpg.caption=Test caption! +file.l1000729.jpg.dimensions=1200x1600 diff --git a/photos/portraits/.cvsignore b/photos/portraits/.cvsignore new file mode 100644 index 0000000..ec109f1 --- /dev/null +++ b/photos/portraits/.cvsignore @@ -0,0 +1 @@ +cache.properties diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..82b6e88 --- /dev/null +++ b/project.properties @@ -0,0 +1,15 @@ + +# point to CJ's maven repository +maven.repo.remote=http://www.forkalsrud.org/maven-proxy/repository + +# warn about use of deprecated classes/methods +maven.compile.deprecation=true + +# WAR plugin +#maven.war.final.name=ROOT.war +maven.war.src=webapp + +# PMD plugin +maven.pmd.cpd.enable=true + +#maven.jblanket.enable=true diff --git a/project.xml b/project.xml new file mode 100644 index 0000000..878f07c --- /dev/null +++ b/project.xml @@ -0,0 +1,251 @@ + + + 1 + album + album + forkalsrud + 2 + + forkalsrud.org + http://www.forkalsrud.org/ + + 2008 + org.forkalsrud.album + Photo Album + http://www.forkalsrud.org/album/ + + scm:pserver:forkalsrud.org:/home/cvsroot + + + + Knut Forkalsrud + 1 + knut@forkalsrud.org + http://www.forkalsrud.org/~knut/ + PST + + + Erik Forkalsrud + 2 + erik@forkalsrud.org + http://www.forkalsrud.org/~erik/ + PST + + + + + org.springframework + spring + 2.0.6 + jar + + true + + + + commons-logging + commons-logging + 1.0.4 + jar + + true + + + + commons-digester + commons-digester + 1.7 + jar + + true + + + + commons-collections + commons-collections + 3.1 + jar + + true + + + + commons-lang + commons-lang + 2.0 + jar + + true + + + + postgresql + postgresql + 8.1-408.jdbc3 + jar + + true + + + + velocity + velocity + 1.5 + jar + + true + + + + velocity-tools + velocity-tools-view + 1.2 + jar + + true + + + + com.drew + metadata-extractor + 2.3.1 + jar + + true + + + + com.drew + metadata-extractor-source + source + metadata-extractor-2.3.1-src.jar + + false + + + + servletapi + servletapi + 2.4 + jar + + + junit + junit + 4.1 + + false + + + + + resin-3.1 + resin + 3.1.5 + jar + + false + + + + resin-3.1 + resin-util + 3.1.5 + jar + + false + + + + resin-3.1 + jta-101 + 3.1.5 + jar + + false + + + + resin-3.1 + webbeans-16 + 3.1.5 + jar + + false + + + + resin-3.1 + ejb-15 + 3.1.5 + jar + + false + + + + resin-3.1 + jpa-15 + 3.1.5 + jar + + false + + + + resin-3.1 + jsdk-15 + 3.1.5 + jar + + false + + + + resin-3.1 + hessian + 3.1.5 + jar + + false + + + + resin-3.1 + jca-15 + 3.1.5 + jar + + false + + + + resin-3.1 + jstl-11 + 3.1.5 + jar + + false + + + + resin-3.1 + resin-source + source + resin-3.1.5-src.zip + + false + + + + + src + + + maven-junit-report-plugin + maven-jcoverage-plugin + maven-pmd-plugin + maven-javadoc-plugin + maven-jdepend-plugin + + diff --git a/src/album/config/Album$1.class b/src/album/config/Album$1.class deleted file mode 100644 index 474ba24..0000000 Binary files a/src/album/config/Album$1.class and /dev/null differ diff --git a/src/album/config/Album$2.class b/src/album/config/Album$2.class deleted file mode 100644 index 934ce60..0000000 Binary files a/src/album/config/Album$2.class and /dev/null differ diff --git a/src/album/config/Album.class b/src/album/config/Album.class deleted file mode 100644 index 1bd3e55..0000000 Binary files a/src/album/config/Album.class and /dev/null differ diff --git a/src/album/config/Entry.class b/src/album/config/Entry.class deleted file mode 100644 index 3834398..0000000 Binary files a/src/album/config/Entry.class and /dev/null differ diff --git a/src/album/config/Item.class b/src/album/config/Item.class deleted file mode 100644 index e1177a3..0000000 Binary files a/src/album/config/Item.class and /dev/null differ diff --git a/src/album/config/Photo.class b/src/album/config/Photo.class deleted file mode 100644 index f4a7427..0000000 Binary files a/src/album/config/Photo.class and /dev/null differ diff --git a/src/album/config/Reference.class b/src/album/config/Reference.class deleted file mode 100644 index 0ab0338..0000000 Binary files a/src/album/config/Reference.class and /dev/null differ diff --git a/src/album/config/Test.class b/src/album/config/Test.class deleted file mode 100644 index b2e229f..0000000 Binary files a/src/album/config/Test.class and /dev/null differ diff --git a/src/album/config/Transform.class b/src/album/config/Transform.class deleted file mode 100644 index 42f3f82..0000000 Binary files a/src/album/config/Transform.class and /dev/null differ diff --git a/src/album/editor/Editor$1.class b/src/album/editor/Editor$1.class deleted file mode 100644 index 888fbfb..0000000 Binary files a/src/album/editor/Editor$1.class and /dev/null differ diff --git a/src/album/editor/Editor$2.class b/src/album/editor/Editor$2.class deleted file mode 100644 index 347ec07..0000000 Binary files a/src/album/editor/Editor$2.class and /dev/null differ diff --git a/src/album/editor/Editor$CropFrame$CropSpinnerModel.class b/src/album/editor/Editor$CropFrame$CropSpinnerModel.class deleted file mode 100644 index dc10db2..0000000 Binary files a/src/album/editor/Editor$CropFrame$CropSpinnerModel.class and /dev/null differ diff --git a/src/album/editor/Editor$CropFrame.class b/src/album/editor/Editor$CropFrame.class deleted file mode 100644 index 40c7c6d..0000000 Binary files a/src/album/editor/Editor$CropFrame.class and /dev/null differ diff --git a/src/album/editor/Editor$Renderer$1.class b/src/album/editor/Editor$Renderer$1.class deleted file mode 100644 index 9dddaf2..0000000 Binary files a/src/album/editor/Editor$Renderer$1.class and /dev/null differ diff --git a/src/album/editor/Editor$Renderer.class b/src/album/editor/Editor$Renderer.class deleted file mode 100644 index a6f7618..0000000 Binary files a/src/album/editor/Editor$Renderer.class and /dev/null differ diff --git a/src/album/editor/Editor.class b/src/album/editor/Editor.class deleted file mode 100644 index a477b77..0000000 Binary files a/src/album/editor/Editor.class and /dev/null differ diff --git a/src/album/editor/ReaderHelper$1.class b/src/album/editor/ReaderHelper$1.class deleted file mode 100644 index a7f0013..0000000 Binary files a/src/album/editor/ReaderHelper$1.class and /dev/null differ diff --git a/src/album/editor/ReaderHelper.class b/src/album/editor/ReaderHelper.class deleted file mode 100644 index 9c06ac2..0000000 Binary files a/src/album/editor/ReaderHelper.class and /dev/null differ diff --git a/src/album/editor/SelectionDemo$1.class b/src/album/editor/SelectionDemo$1.class deleted file mode 100644 index ce4ab83..0000000 Binary files a/src/album/editor/SelectionDemo$1.class and /dev/null differ diff --git a/src/album/editor/SelectionDemo$SelectionArea$MyListener.class b/src/album/editor/SelectionDemo$SelectionArea$MyListener.class deleted file mode 100644 index 1212394..0000000 Binary files a/src/album/editor/SelectionDemo$SelectionArea$MyListener.class and /dev/null differ diff --git a/src/album/editor/SelectionDemo$SelectionArea.class b/src/album/editor/SelectionDemo$SelectionArea.class deleted file mode 100644 index c88caa9..0000000 Binary files a/src/album/editor/SelectionDemo$SelectionArea.class and /dev/null differ diff --git a/src/album/editor/SelectionDemo.class b/src/album/editor/SelectionDemo.class deleted file mode 100644 index 5100961..0000000 Binary files a/src/album/editor/SelectionDemo.class and /dev/null differ diff --git a/src/album/web/AlbumServlet.java b/src/album/web/AlbumServlet.java deleted file mode 100644 index 9360c58..0000000 --- a/src/album/web/AlbumServlet.java +++ /dev/null @@ -1,125 +0,0 @@ -package album.web; - -import java.io.*; -import java.util.*; - -import javax.servlet.*; -import javax.servlet.http.*; - -public class AlbumServlet - extends HttpServlet -{ - File baseDir = new File("/home/knut"); - - @Override - public void init() - throws ServletException - { - System.out.println("in init of Album"); - } - - @Override - public void doGet(HttpServletRequest req, HttpServletResponse res) - throws ServletException, IOException - { - /* System.out.println("pathInfo: " + req.getPathInfo()); - System.out.println("pathXlat: " + req.getPathTranslated()); - System.out.println("queryString: " + req.getQueryString()); - System.out.println("requestUri: " + req.getRequestURI()); - System.out.println("servletPath: " + req.getServletPath()); - */ - res.setContentType("text/html"); - // Determine which directory to list - String directory = req.getServletPath(); - directory = directory.substring( - "/".length(), - directory.length() - ".album".length()); - - System.out.println("directory: " + directory); - - File dir = new File(baseDir, directory); - if (dir == null) { - res.setStatus(HttpServletResponse.SC_NOT_FOUND); - return; - } - - if (!dir.isDirectory()) { - res.setStatus(HttpServletResponse.SC_NOT_FOUND); - return; - } - - if (!dir.canRead()) { - res.setStatus(HttpServletResponse.SC_FORBIDDEN); - return; - } - - // Determine sort order - File[] files = dir.listFiles(new FileFilter() { - public boolean accept(File candidate) { - return candidate.isDirectory() - || candidate.getName().endsWith(".gif") - || candidate.getName().endsWith(".GIF") - || candidate.getName().endsWith(".png") - || candidate.getName().endsWith(".PNG") - || candidate.getName().endsWith(".jpg") - || candidate.getName().endsWith(".JPG") - || candidate.getName().endsWith(".jpeg") - || candidate.getName().endsWith(".JPEG"); - } - }); - - Arrays.sort(files, new Comparator() { - public int compare(File f1, File f2) { - - // Directories first - if (f1.isDirectory() && !f2.isDirectory()) - return -1; - if (f2.isDirectory() && !f1.isDirectory()) - return 1; - return f1.getName().compareTo(f2.getName()); - } - }); - - // Produce tags for a thumbnail of each image or other - // album - PrintWriter out = res.getWriter(); - out.println(""); - out.println(""); - out.println("" + directory + ""); - out.println(""); - out.println(""); - - String baseUrl = req.getContextPath() - + "/" + directory + "/"; - - for (int i = 0; i < files.length; ++i) { - File file = files[i]; - String anchorUrl = ""; - String iconUrl = ""; - if (file.isDirectory()) { - anchorUrl = baseUrl + file.getName() + ".album"; - iconUrl = req.getContextPath() + "/album.png"; - } else if (file.isFile()) { - anchorUrl = baseUrl + file.getName() + ".photo"; - iconUrl = baseUrl + file.getName() + ".bitmap?size=100"; - } else { - throw new ServletException("Unknown file: " + file); - } - - out.print(""); - out.print(""); - out.println(""); - } - out.println(""); - out.println(""); - } - - - @Override - public String getServletInfo() { - return "Display a directory as an album"; - } - -} - -// eof diff --git a/src/album/config/Album.java b/src/org/forkalsrud/album/config/Album.java similarity index 96% rename from src/album/config/Album.java rename to src/org/forkalsrud/album/config/Album.java index b4b9c0b..83b1542 100644 --- a/src/album/config/Album.java +++ b/src/org/forkalsrud/album/config/Album.java @@ -1,4 +1,4 @@ -package album.config; +package org.forkalsrud.album.config; import java.io.*; diff --git a/src/album/config/Entry.java b/src/org/forkalsrud/album/config/Entry.java similarity index 76% rename from src/album/config/Entry.java rename to src/org/forkalsrud/album/config/Entry.java index 2c5de58..d8ade68 100644 --- a/src/album/config/Entry.java +++ b/src/org/forkalsrud/album/config/Entry.java @@ -1,4 +1,4 @@ -package album.config; +package org.forkalsrud.album.config; public abstract class Entry { String name; diff --git a/src/album/config/Item.java b/src/org/forkalsrud/album/config/Item.java similarity index 84% rename from src/album/config/Item.java rename to src/org/forkalsrud/album/config/Item.java index 5e9cadc..6deb66b 100644 --- a/src/album/config/Item.java +++ b/src/org/forkalsrud/album/config/Item.java @@ -1,4 +1,4 @@ -package album.config; +package org.forkalsrud.album.config; public class Item diff --git a/src/album/config/Photo.java b/src/org/forkalsrud/album/config/Photo.java similarity index 80% rename from src/album/config/Photo.java rename to src/org/forkalsrud/album/config/Photo.java index d695f71..82a9b1f 100644 --- a/src/album/config/Photo.java +++ b/src/org/forkalsrud/album/config/Photo.java @@ -1,4 +1,4 @@ -package album.config; +package org.forkalsrud.album.config; public class Photo diff --git a/src/album/config/Reference.java b/src/org/forkalsrud/album/config/Reference.java similarity index 75% rename from src/album/config/Reference.java rename to src/org/forkalsrud/album/config/Reference.java index ffa6be8..1ec5bfc 100644 --- a/src/album/config/Reference.java +++ b/src/org/forkalsrud/album/config/Reference.java @@ -1,4 +1,4 @@ -package album.config; +package org.forkalsrud.album.config; public class Reference extends Entry diff --git a/src/album/config/Test.java b/src/org/forkalsrud/album/config/Test.java similarity index 86% rename from src/album/config/Test.java rename to src/org/forkalsrud/album/config/Test.java index 1f310f8..bdfebd7 100644 --- a/src/album/config/Test.java +++ b/src/org/forkalsrud/album/config/Test.java @@ -1,4 +1,4 @@ -package album.config; +package org.forkalsrud.album.config; import java.io.*; diff --git a/src/album/config/Transform.java b/src/org/forkalsrud/album/config/Transform.java similarity index 80% rename from src/album/config/Transform.java rename to src/org/forkalsrud/album/config/Transform.java index 2cc7d58..a586eab 100644 --- a/src/album/config/Transform.java +++ b/src/org/forkalsrud/album/config/Transform.java @@ -1,4 +1,4 @@ -package album.config; +package org.forkalsrud.album.config; import java.awt.Dimension; import java.awt.Rectangle; diff --git a/src/album/editor/Editor.java b/src/org/forkalsrud/album/editor/Editor.java similarity index 99% rename from src/album/editor/Editor.java rename to src/org/forkalsrud/album/editor/Editor.java index 51e62ee..432e0b4 100644 --- a/src/album/editor/Editor.java +++ b/src/org/forkalsrud/album/editor/Editor.java @@ -1,4 +1,4 @@ -package album.editor; +package org.forkalsrud.album.editor; import java.awt.*; import java.awt.event.*; diff --git a/src/album/editor/Makefile b/src/org/forkalsrud/album/editor/Makefile similarity index 100% rename from src/album/editor/Makefile rename to src/org/forkalsrud/album/editor/Makefile diff --git a/src/org/forkalsrud/album/exif/Dimension.java b/src/org/forkalsrud/album/exif/Dimension.java new file mode 100644 index 0000000..e4d52f0 --- /dev/null +++ b/src/org/forkalsrud/album/exif/Dimension.java @@ -0,0 +1,74 @@ +/* + * Copyright 2008 Estalea, Inc. All rights reserved. + * This software is the proprietary information of Estalea, Inc. + */ + +package org.forkalsrud.album.exif; + + +/** + * TODO (knut - Mar 16, 2008 2:23:56 PM) - add documentation + * + * @author knut + */ +public class Dimension { + + int w; + int h; + + public Dimension(int w, int h) { + this.w = w; + this.h = h; + } + + public Dimension(String s) { + String[] coords = s.split("x"); + this.w = Integer.parseInt(coords[0]); + this.h = Integer.parseInt(coords[1]); + } + + + public Dimension scaled(int max) { + + int sw, sh; + if (w > h) { + if (w > max) { + sw = max; + sh = (max * h + max / 2) / w; + } else { + sw = w; + sh = h; + } + } else { + if (h > max) { + sw = (max * w + max / 2) / h; + sh = max; + } else { + sw = w; + sh = h; + } + } + return new Dimension(sw, sh); + } + + + public Dimension flip() { + return new Dimension(h, w); + } + + + @Override + public String toString() { + return w + "x" + h; + } + + + public int getWidth() { + return w; + } + + public int getHeight() { + return h; + } + +} diff --git a/src/album/exif/DirectoryTest.java b/src/org/forkalsrud/album/exif/DirectoryTest.java similarity index 94% rename from src/album/exif/DirectoryTest.java rename to src/org/forkalsrud/album/exif/DirectoryTest.java index 6d43fcd..74899b9 100644 --- a/src/album/exif/DirectoryTest.java +++ b/src/org/forkalsrud/album/exif/DirectoryTest.java @@ -1,4 +1,4 @@ -package album.exif; +package org.forkalsrud.album.exif; import static org.junit.Assert.assertTrue; @@ -55,7 +55,7 @@ public class DirectoryTest { exifDirectory.containsTag(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT)) { int width = exifDirectory.getInt(ExifDirectory.TAG_EXIF_IMAGE_WIDTH); int height = exifDirectory.getInt(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT); - imgProps.setProperty(base + "dimensions", nf.format(width) + "x" + nf.format(height)); + imgProps.setProperty(base + "dimensions", new Dimension(width, height).toString()); } if (exifDirectory.containsTag(ExifDirectory.TAG_DATETIME_ORIGINAL)) { Date captureDate = exifDirectory.getDate(ExifDirectory.TAG_DATETIME_ORIGINAL); diff --git a/src/org/forkalsrud/album/exif/Entry.java b/src/org/forkalsrud/album/exif/Entry.java new file mode 100644 index 0000000..2745aa8 --- /dev/null +++ b/src/org/forkalsrud/album/exif/Entry.java @@ -0,0 +1,111 @@ +/* + * Copyright 2008 Estalea, Inc. All rights reserved. + * This software is the proprietary information of Estalea, Inc. + */ + +package org.forkalsrud.album.exif; + +import java.util.Date; + + +/** + * Represents one item inside the album, typically file or directory, aka photo or album + * + * @author knut + */ +public class Entry { + + String name; + Dimension size; + String caption; + Date date; + int orientation; + + + /** + * @return Returns the name. + */ + public String getName() { + return name; + } + + + /** + * @param name The name to set. + */ + public void setName(String name) { + this.name = name; + } + + + + /** + * @return Returns the size. + */ + public Dimension getSize() { + return size; + } + + + + /** + * @param size The size to set. + */ + public void setSize(Dimension size) { + this.size = size; + } + + + + /** + * @return Returns the caption. + */ + public String getCaption() { + return caption; + } + + + + /** + * @param caption The caption to set. + */ + public void setCaption(String caption) { + this.caption = caption; + } + + + + /** + * @return Returns the date. + */ + public Date getDate() { + return date; + } + + + + /** + * @param date The date to set. + */ + public void setDate(Date date) { + this.date = date; + } + + + + /** + * @return Returns the orientation. + */ + public int getOrientation() { + return orientation; + } + + + + /** + * @param orientation The orientation to set. + */ + public void setOrientation(int orientation) { + this.orientation = orientation; + } +} diff --git a/src/org/forkalsrud/album/exif/EntryDao.java b/src/org/forkalsrud/album/exif/EntryDao.java new file mode 100644 index 0000000..d2a6b2e --- /dev/null +++ b/src/org/forkalsrud/album/exif/EntryDao.java @@ -0,0 +1,154 @@ +/* + * Copyright 2008 Estalea, Inc. All rights reserved. + * This software is the proprietary information of Estalea, Inc. + */ + +package org.forkalsrud.album.exif; + +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; + +import com.drew.imaging.jpeg.JpegMetadataReader; +import com.drew.imaging.jpeg.JpegProcessingException; +import com.drew.metadata.Directory; +import com.drew.metadata.Metadata; +import com.drew.metadata.MetadataException; +import com.drew.metadata.exif.ExifDirectory; + + +/** + * Responsible for translating entries to and from file + * + * @author knut + */ +public class EntryDao { + + final static String CACHE_FILE = "cache.properties"; + final static String OVERRIDE_FILE = "album.properties"; + + public List read(File directory) throws FileNotFoundException, IOException, JpegProcessingException, MetadataException, ParseException { + + List entries = new ArrayList(); + + Properties cachedProps = new Properties(); + File cache = new File(directory, CACHE_FILE); + if (cache.exists() && cache.isFile() && cache.canRead()) { + cachedProps.load(new FileInputStream(cache)); + } else { + generateEntries(directory, cachedProps); + } + Properties overrideProps = new Properties(cachedProps); + File override = new File(directory, OVERRIDE_FILE); + if (override.exists() && override.isFile() && override.canRead()) { + overrideProps.load(new FileInputStream(override)); + } + Properties combined = new Properties(); + combined.putAll(cachedProps); + combined.putAll(overrideProps); + populate(combined, entries); + Collections.sort(entries, new Comparator() { + + public int compare(Entry e1, Entry e2) { + + Date d1 = e1.getDate(); + Date d2 = e2.getDate(); + if (d1 != null && d2 != null) { + return d1.compareTo(d2); + } else if (d1 != null) { + return -1; + } else if (d2 != null) { + return +1; + } else { + return 0; + } + } + }); + return entries; + } + + + private void populate(Properties cachedProps, List entries) throws ParseException { + + HashMap entryMap = new HashMap(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HHmmss"); + Iterator i = cachedProps.keySet().iterator(); + while (i.hasNext()) { + String key = (String)i.next(); + if (key.startsWith("file.") && key.endsWith(".dimensions")) { + String name = key.substring("file.".length(), key.length() - ".dimensions".length()); + if (!entryMap.containsKey(name)) { + Entry entry = new Entry(); + entry.setName(name); + entry.setDate(sdf.parse(cachedProps.getProperty("file." + name + ".captureDate"))); + 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"))); + entries.add(entry); + } + } + } + } + + + void generateEntries(File directory, Properties cachedProps) throws JpegProcessingException, MetadataException, FileNotFoundException, IOException { + + File[] files = directory.listFiles(new FileFilter() { + + public boolean accept(File file) { + + return !file.isHidden() && !file.isDirectory() && !CACHE_FILE.equals(file.getName()) && !OVERRIDE_FILE.equals(file.getName()); + } + + }); + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HHmmss"); + NumberFormat nf = new DecimalFormat("0"); + + for (File f : files) { + String name = f.getName(); + String base = "file." + name + "."; + + Metadata metadata = JpegMetadataReader.readMetadata(f); + Directory exifDirectory = metadata.getDirectory(ExifDirectory.class); + if (exifDirectory.containsTag(ExifDirectory.TAG_ORIENTATION)) { + int orientation = exifDirectory.getInt(ExifDirectory.TAG_ORIENTATION); + cachedProps.setProperty(base + "orientation", nf.format(orientation)); + } + if (exifDirectory.containsTag(ExifDirectory.TAG_EXIF_IMAGE_WIDTH) && + exifDirectory.containsTag(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT)) { + 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()); + } + if (exifDirectory.containsTag(ExifDirectory.TAG_DATETIME_ORIGINAL)) { + Date captureDate = exifDirectory.getDate(ExifDirectory.TAG_DATETIME_ORIGINAL); + cachedProps.setProperty(base + "captureDate", sdf.format(captureDate)); + } + if (exifDirectory.containsTag(ExifDirectory.TAG_USER_COMMENT)) { + String comment = exifDirectory.getString(ExifDirectory.TAG_USER_COMMENT); + cachedProps.setProperty(base + "comment", comment); + } + } + File dst = new File(directory, CACHE_FILE); + if (directory.canWrite()) { + cachedProps.store(new FileOutputStream(dst), "Extra Comments"); + } + } + + +} diff --git a/src/album/exif/ExifDataTest.java b/src/org/forkalsrud/album/exif/ExifDataTest.java similarity index 99% rename from src/album/exif/ExifDataTest.java rename to src/org/forkalsrud/album/exif/ExifDataTest.java index cfe67ff..87090fe 100644 --- a/src/album/exif/ExifDataTest.java +++ b/src/org/forkalsrud/album/exif/ExifDataTest.java @@ -1,4 +1,4 @@ -package album.exif; +package org.forkalsrud.album.exif; import static org.junit.Assert.assertEquals; diff --git a/src/org/forkalsrud/album/web/AlbumServlet.java b/src/org/forkalsrud/album/web/AlbumServlet.java index 0aad1e6..cce683d 100644 --- a/src/org/forkalsrud/album/web/AlbumServlet.java +++ b/src/org/forkalsrud/album/web/AlbumServlet.java @@ -3,19 +3,23 @@ package org.forkalsrud.album.web; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; -import java.io.*; +import java.io.File; +import java.io.IOException; import java.text.ParseException; -import java.util.*; +import java.util.Iterator; +import java.util.List; import javax.imageio.ImageIO; import javax.imageio.ImageReadParam; import javax.imageio.ImageReader; -import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageOutputStream; -import javax.servlet.*; -import javax.servlet.http.*; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import org.forkalsrud.album.exif.Dimension; import org.forkalsrud.album.exif.Entry; @@ -41,15 +45,16 @@ public class AlbumServlet public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { + /* System.out.println("pathInfo: " + req.getPathInfo()); System.out.println("pathXlat: " + req.getPathTranslated()); System.out.println("queryString: " + req.getQueryString()); System.out.println("requestUri: " + req.getRequestURI()); System.out.println("servletPath: " + req.getServletPath()); - +*/ String path = req.getPathTranslated(); - System.out.println("file: " + path); +// System.out.println("file: " + path); File file = new File(path); if (file == null) { diff --git a/src/album/web/BitmapServlet.java b/src/org/forkalsrud/album/web/BitmapServlet.java similarity index 98% rename from src/album/web/BitmapServlet.java rename to src/org/forkalsrud/album/web/BitmapServlet.java index f12ecc0..1f86df0 100644 --- a/src/album/web/BitmapServlet.java +++ b/src/org/forkalsrud/album/web/BitmapServlet.java @@ -1,4 +1,4 @@ -package album.web; +package org.forkalsrud.album.web; import java.io.*; import java.util.*; @@ -16,7 +16,7 @@ public class BitmapServlet implements ImageObserver { File baseDir = new File("photos"); - File cacheDir = new File("/var/album"); + File cacheDir = new File("/var/org.forkalsrud.album"); final static int BUF_SIZE = 1024; protected volatile boolean complete = false; diff --git a/src/album/web/PhotoServlet.java b/src/org/forkalsrud/album/web/PhotoServlet.java similarity index 98% rename from src/album/web/PhotoServlet.java rename to src/org/forkalsrud/album/web/PhotoServlet.java index bfbc19e..7bd48b6 100644 --- a/src/album/web/PhotoServlet.java +++ b/src/org/forkalsrud/album/web/PhotoServlet.java @@ -1,4 +1,4 @@ -package album.web; +package org.forkalsrud.album.web; import java.io.*; import java.util.*; @@ -16,7 +16,7 @@ public class PhotoServlet implements ImageObserver { File baseDir = new File("/home/knut"); - File cacheDir = new File("/var/album"); + File cacheDir = new File("/var/org.forkalsrud.album"); final static int BUF_SIZE = 1024; protected volatile boolean complete = false; diff --git a/webapp/.cvsignore b/webapp/.cvsignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/webapp/.cvsignore @@ -0,0 +1 @@ +target diff --git a/webapp/WEB-INF/velocity/directory.vm b/webapp/WEB-INF/velocity/directory.vm new file mode 100644 index 0000000..b891a70 --- /dev/null +++ b/webapp/WEB-INF/velocity/directory.vm @@ -0,0 +1,48 @@ + + + + + + $directory + + + + +

$directory

+
+#set($thmb = 150) +#foreach($entry in $entries) +#if($entry.orientation == 6) +#set($dim = $entry.size.scaled($thmb).flip()) +#else +#set($dim = $entry.size.scaled($thmb)) +#end +
+ $entry.name
+
+ $!entry.caption +
+#end + + + diff --git a/webapp/WEB-INF/web.xml b/webapp/WEB-INF/web.xml index 86bdf91..a0d6f91 100644 --- a/webapp/WEB-INF/web.xml +++ b/webapp/WEB-INF/web.xml @@ -1,10 +1,38 @@ - - - + + album + org.forkalsrud.album.web.AlbumServlet + + + + photo + org.forkalsrud.album.web.PhotoServlet + + + + bitmap + org.forkalsrud.album.web.BitmapServlet + + + + velocity + org.apache.velocity.tools.view.servlet.VelocityViewServlet + + + + resin-file + /js/* + + + + velocity + /WEB-INF/velocity/* + + + + album + /* + diff --git a/webapp/css/pxapplication.css b/webapp/css/pxapplication.css new file mode 100644 index 0000000..9f808b1 --- /dev/null +++ b/webapp/css/pxapplication.css @@ -0,0 +1,132 @@ +/* + $Id: pxapplication.css,v 1.1 2008/03/17 01:01:36 knut Exp $ + + Pixory - the personal image server + Copyright 2004-2005 Joe Panico + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + 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. +*/ + +/* predefined elements */ +html { height: 100%; text-align:center; font-family: verdana, arial, helvetica, sans-serif; } + +body { height: 100%; margin: 0px; padding: 1px; } + +hr { width: 100%; height: 1px; border: none; background-color:#7070a1; } + +/* pseudo classes */ +a:link {color:#606091;} +a:visited {color:#606091;} + +/* force vertical scrollbar in Moz */ +#force-scrollbar { position: absolute; top: 0; bottom: -1px; width: 1em; z-index: -1; } + +/* generic classes */ +/* i.e. css side orderings: top, right, bottom, left */ + +.thintable { width: 100%; border: none; border-collapse: collapse; padding: 0px; } +.error_message { font-size: medium; font-style: italic; } +/* a piece of text styled to look like a button */ +.text_button { border: 1px solid black; color: black; background-color: rgb(80%,80%,80%); text-align: center; padding: 3px 5px 3px 5px; text-decoration: none;} + +/* currently used only on ViewerHome */ +.dropShadowContent { float: left; position: relative; left: -2px; top: -2px; border: none; background: #9fc;} +.dropShadowContainer { float: left; position: relative; background: #666; margin: 4px; border: none;} + +/* PXShowMessage */ +.show_message_table { border: none; height: 35px;} +.show_message_table .success_message_cell { color: black;} +.show_message_table .running_message_cell { color: black;} +.show_message_table .error_message_cell { color: red;} +.show_message_table .warn_message_cell { color: red;} + +/* PXPageDecorator */ +#page_decorator_table { height: 100%; width: 100%; border: none; color:#606091; background-color: #fffffb; vertical-align: top; text-align: left; margin: 0px; padding: 0px;} +#page_decorator_cell { height: 90%; border:none; vertical-align: top;} +#footer_cell { border: none; text-align: right; vertical-align: bottom; font-size: small; font-style: italic; color: #666; padding: 0px 4px 4px 0px; } + +/* Message page */ +#message_table {width: 30%; height: 30%; vertical-align: middle; text-align: center; margin-left: auto; margin-right:auto; border: 1px solid orange; background-color: #ddd;} +#message_table td { padding: 10px; } + +/* all pages */ +#content_table { width: 100%; border: none; text-align: center; border-collapse: collapse; } + +/* pxtapestry:PXPropertiesTable */ +table.properties_table { border: 1px dotted #ccc; text-align: left; font-size: xx-small; margin: 0px 7px 0px 7px; } +table.properties_table caption { font-size: small; font-weight: bold; text-decoration: underline; text-align: center; } +table.properties_table tr.even { background-color: #ccb; } +table.properties_table td { padding: 0px 5px 0px 5px; } + +/* all/any viewer pages */ +.image { border: 1px solid #606091; padding: 0px;} +.caption { border: none; font-size: xx-small; padding: 0px; vertical-align: top;} +.filename { border: none; font-size: xx-small; font-style: italic; padding: 0px; vertical-align: top;} +.photo_grid_table { width: 100%; height: 100%; vertical-align: top; padding: 0px 0px 0px 0px; border: none; border-spacing: 7px; empty-cells: hide; background-color: #ddd; } +.photo_grid_cell { vertical-align: top; background-color: #fffffb; border: 1px dotted #ccc; padding: 0px 0px 0px 0px; } + +/* ViewerHome */ +#viewer_home_title_cell {border: none; text-align: left; font-size: x-large; padding: 10px 20px 10px 10px; } +#viewer_home_greeting_cell {border: none; text-align: right; font-size: xx-small; padding: 5px 20px 5px 0px; } +#viewer_home_noalbums_cell {border: none; text-align: center; padding: 60px 0px 30px 0px; } + +td.home_year { text-align: left; font-size: large; font-weight: bold; padding: 5px 5px 5px 5px; } +table.home_entry_table { width: 100%; vertical-align: top; text-align: center; font-size: xx-small; color:#606091; } +table.home_entry_table td.caption { padding: 0px 5px 5px 5px; } + +/* album/index pages */ +#album_header_table { border: none; width: 100%; padding: 0px; vertical-align: top; border-collapse: collapse; } +#album_name_cell { width: 50%; text-align: left; font-weight: bold; } +#album_control_cell { width: 50%; text-align: left; font-weight: bold; } +#album_control_cell .button { width: 15% } +#album_control_cell .control { width: 35%; text-align: right; } +#album_control_cell .label { width: 35%; text-align: center; font-size: small; color: #888; } + +/* album pages */ +.album_image_table { border: none; border-collapse: collapse; margin-left: auto; margin-right:auto; } +.album_image_table td { padding: 0px; } +.album_image_table .image_properties { height: 16px; font-size: xx-small; color: #888; } +.album_narrative_cell { padding: 0px 10px 20px 10px; white-space: normal; border: none; } + +/* index page */ +table.index_entry_table { border: none; height: 100%; width: 100%; vertical-align: middle; text-align: center; font-size: xx-small; color:#606091; } + +/* FullPhoto page */ +table.full_photo { border: none; width: 100%; height: 100%; vertical-align: middle; text-align: center; border-collapse: collapse; padding: 0px; margin-left: auto; margin-right:auto;} + +/* AboutPanel */ +#about_table { border: 1px dotted #ccc; text-align: left; font-size: small; margin: 0px 7px 0px 0px; } +#about_table .heading { text-align: center; padding: 7px; } +#about_table .properties_table { text-align: left; border-top: 1px solid #ccc;} +#about_table .author { font-weight: bold; } +#about_table .label { width: 20%; text-align: right; } +#about_table .odd { background-color: #ccb; } +#about_table .centered { text-align: center; } + +/* AlbumDownload */ +#download_table { border: 1px dotted #ccc; text-align: center; font-size: small; margin: 0px 7px 0px 7px; } + +/* Login, SendCredentials */ +.icon_table { width: 100%; border: none; text-align: right; } +.centering_table { width: 100%; height: 100%; vertical-align: middle; text-align: center; border: none; } + +#login_table { border: 2px solid orange; background-color: #ddd; margin-left: auto; margin-right:auto; text-align: left; empty-cells: show;} +#login_table .error { height: 35px; } +#login_table .label { text-align: right; } +#login_table .submit { text-align: right; } + +.submit_button { padding: 0px ; border: 1px solid black; background-color: orange; } + +.form_field { padding: 0px 0px 0px 5px; border: 1px solid #888; } +