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; }
+