Initial checkin
7
.classpath
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="var" path="MAVEN_REPO/servletapi/jars/servletapi-2.4.jar"/>
|
||||
<classpathentry kind="output" path="target"/>
|
||||
</classpath>
|
||||
17
.project
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>album</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
40
Makefile
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#
|
||||
# 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
|
||||
BIN
album.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
60
design.txt
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
A (hidden) file exists in each album directory, holding information
|
||||
about each image and each sub-album. For both images and albums the key is the
|
||||
filename and the order in which each is listed determines the ordering
|
||||
in the album. Common to both we have the following attributes:
|
||||
|
||||
- Caption, a text fragment explaining what's in the picture/album.
|
||||
|
||||
Special to images additional attributes stored are:
|
||||
|
||||
- Rotation (floating point number)
|
||||
|
||||
- Mask, represented by the four border sizes; top, left, bottom,
|
||||
right. All floating point.
|
||||
|
||||
- Thumbnail mask. Same as above, but applies to thumbnail images.
|
||||
As these are very small there may be a need to focus on a detail
|
||||
of the original image to have a visual cue about the subject of
|
||||
the photo.
|
||||
|
||||
For albums the additional attributes are:
|
||||
|
||||
- Cover picture, the picture (or album) representing the album as a
|
||||
whole for the purpose of a thumbnail.
|
||||
|
||||
|
||||
Web Interface
|
||||
=============
|
||||
|
||||
The theory of operation is that the directory holding all the
|
||||
subdirectories with albums maps to a webapp. The URLs accepted by the
|
||||
webapp reflect the directory structure of the photo directories, but
|
||||
adds some twists to make it possible to represent thumbnails, medium
|
||||
sized images and large images in addition to the album pages
|
||||
themselves. URLs for the albums are:
|
||||
|
||||
/album/index-num.html
|
||||
|
||||
There is a configuretion 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:
|
||||
|
||||
/album/filename.html
|
||||
|
||||
The individual pictures are accessed with URLs like the following:
|
||||
|
||||
/album/.../size/filename.ext
|
||||
|
||||
In this URL size has to be one of the following: "thumb", "medium",
|
||||
"large". The (global?) configuration determines the actual size
|
||||
constraints for each of the sizes. Only certain file extentions are
|
||||
supported. Notably "jpeg" and "png". "html" can not be allowed as it
|
||||
would destroy the page per picture setup.
|
||||
|
||||
|
||||
BIN
photos/forkalsrud-ca-1951.jpg
Executable file
|
After Width: | Height: | Size: 90 KiB |
BIN
photos/fra_jakt.jpg
Executable file
|
After Width: | Height: | Size: 73 KiB |
BIN
photos/l1000729.jpg
Normal file
|
After Width: | Height: | Size: 327 KiB |
BIN
photos/l1000802.jpg
Normal file
|
After Width: | Height: | Size: 814 KiB |
BIN
photos/portraits/anton-rudi.jpg
Executable file
|
After Width: | Height: | Size: 5 KiB |
BIN
photos/portraits/otto-kaurstad.jpg
Executable file
|
After Width: | Height: | Size: 6 KiB |
BIN
photos/portraits/valdemar-dahl.jpg
Executable file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
src/album/config/Album$1.class
Normal file
BIN
src/album/config/Album$2.class
Normal file
BIN
src/album/config/Album.class
Normal file
49
src/album/config/Album.java
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
package album.config;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class Album
|
||||
extends Item
|
||||
{
|
||||
String frontPic;
|
||||
|
||||
Entry[] contents;
|
||||
|
||||
public Album(String name) {
|
||||
super(name);
|
||||
frontPic = null;
|
||||
contents = null;
|
||||
}
|
||||
|
||||
|
||||
public void scan(File dir)
|
||||
{
|
||||
File[] dirs = dir.listFiles(new FileFilter() {
|
||||
public boolean accept(File f) {
|
||||
return f.isDirectory();
|
||||
}
|
||||
});
|
||||
|
||||
File[] files = dir.listFiles(new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.endsWith(".JPEG")
|
||||
|| name.endsWith(".jpeg")
|
||||
|| name.endsWith(".JPG")
|
||||
|| name.endsWith(".jpg");
|
||||
}
|
||||
});
|
||||
|
||||
contents = new Entry[dirs.length + files.length];
|
||||
int idx = 0;
|
||||
|
||||
for (File d : dirs) {
|
||||
contents[idx++] = new Reference(d.getName());
|
||||
}
|
||||
|
||||
for (File f : files) {
|
||||
contents[idx++] = new Photo(f.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// eof
|
||||
BIN
src/album/config/Entry.class
Normal file
11
src/album/config/Entry.java
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package album.config;
|
||||
|
||||
public abstract class Entry {
|
||||
String name;
|
||||
|
||||
public Entry(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
// eof
|
||||
BIN
src/album/config/Item.class
Normal file
19
src/album/config/Item.java
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
package album.config;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
public class Item
|
||||
extends Entry
|
||||
{
|
||||
String caption;
|
||||
boolean hidden;
|
||||
|
||||
public Item(String name) {
|
||||
super(name);
|
||||
caption = null;
|
||||
hidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
// eof
|
||||
BIN
src/album/config/Photo.class
Normal file
21
src/album/config/Photo.java
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
package album.config;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import javax.imageio.*;
|
||||
import java.awt.image.*;
|
||||
import java.awt.geom.*;
|
||||
|
||||
public class Photo
|
||||
extends Item
|
||||
{
|
||||
Transform xform;
|
||||
|
||||
public Photo(String name) {
|
||||
super(name);
|
||||
xform = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// eof
|
||||
BIN
src/album/config/Reference.class
Normal file
11
src/album/config/Reference.java
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package album.config;
|
||||
|
||||
public class Reference
|
||||
extends Entry
|
||||
{
|
||||
public Reference(String name) {
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
|
||||
// eof
|
||||
BIN
src/album/config/Test.class
Normal file
20
src/album/config/Test.java
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
package album.config;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class Test
|
||||
{
|
||||
|
||||
public static void main(String args[])
|
||||
throws Exception
|
||||
{
|
||||
File dir = new File(args[0]);
|
||||
|
||||
Album a = new Album(dir.getName());
|
||||
|
||||
a.scan(dir);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// eof
|
||||
BIN
src/album/config/Transform.class
Normal file
12
src/album/config/Transform.java
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package album.config;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.*;
|
||||
|
||||
public class Transform {
|
||||
Dimension size;
|
||||
float rotation;
|
||||
Rectangle region;
|
||||
}
|
||||
|
||||
// eof
|
||||
BIN
src/album/editor/Editor$1.class
Normal file
BIN
src/album/editor/Editor$2.class
Normal file
BIN
src/album/editor/Editor$CropFrame$CropSpinnerModel.class
Normal file
BIN
src/album/editor/Editor$CropFrame.class
Normal file
BIN
src/album/editor/Editor$Renderer$1.class
Normal file
BIN
src/album/editor/Editor$Renderer.class
Normal file
BIN
src/album/editor/Editor.class
Normal file
473
src/album/editor/Editor.java
Normal file
|
|
@ -0,0 +1,473 @@
|
|||
package album.editor;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.awt.geom.*;
|
||||
import java.awt.image.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import javax.imageio.*;
|
||||
import javax.imageio.stream.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.border.*;
|
||||
|
||||
/**
|
||||
* Editor
|
||||
*
|
||||
* @author knut@forkalsrud.org
|
||||
*/
|
||||
public class Editor
|
||||
extends JComponent
|
||||
{
|
||||
BufferedImage img;
|
||||
double rotation;
|
||||
double scale;
|
||||
Rectangle region;
|
||||
Dimension displaySize;
|
||||
AffineTransform t;
|
||||
|
||||
CropFrame mask;
|
||||
|
||||
Rectangle currentRect = null;
|
||||
|
||||
Rectangle rectToDraw = null;
|
||||
|
||||
Rectangle previousRectDrawn = new Rectangle();
|
||||
|
||||
public Editor(BufferedImage img) {
|
||||
this.img = img;
|
||||
|
||||
rotation = 0; // 135.0;
|
||||
displaySize = new Dimension(480, 300);
|
||||
int w = img.getWidth();
|
||||
int h = img.getHeight();
|
||||
|
||||
scale = Math.min(displaySize.width, displaySize.height)
|
||||
/ Math.sqrt(w * w + h * h);
|
||||
|
||||
t = new AffineTransform();
|
||||
t.translate(displaySize.width/2.0, displaySize.height/2.0);
|
||||
t.scale(scale, scale);
|
||||
t.translate(-w/2.0, -h/2.0);
|
||||
Point topLeft = new Point(0, 0);
|
||||
Point topLeft1 = new Point();
|
||||
Point bottomRight = new Point(w, h);
|
||||
Point bottomRight2 = new Point();
|
||||
t.transform(topLeft, topLeft1);
|
||||
t.transform(bottomRight, bottomRight2);
|
||||
Dimension d = new Dimension((int)Math.round(bottomRight2.getX() - topLeft1.getX() + 1),
|
||||
(int)Math.round(bottomRight2.getY() - topLeft1.getY() + 1));
|
||||
Rectangle imgRec = new Rectangle(topLeft1, d);
|
||||
|
||||
log("rect: " + imgRec);
|
||||
|
||||
mask = new CropFrame();
|
||||
add(mask);
|
||||
mask.setBounds(imgRec);
|
||||
mask.setVisible(true);
|
||||
|
||||
setPreferredSize(displaySize);
|
||||
MyListener ml = new MyListener();
|
||||
addMouseListener(ml);
|
||||
addMouseMotionListener(ml);
|
||||
|
||||
|
||||
mask.addMouseListener(mask);
|
||||
mask.addMouseMotionListener(mask);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
AffineTransform render() {
|
||||
int w = img.getWidth();
|
||||
int h = img.getHeight();
|
||||
|
||||
scale = Math.min(displaySize.width, displaySize.height)
|
||||
/ Math.sqrt(w * w + h * h);
|
||||
|
||||
t = new AffineTransform();
|
||||
|
||||
t.translate(displaySize.width/2.0, displaySize.height/2.0);
|
||||
t.scale(scale, scale);
|
||||
t.rotate(rotation * Math.PI / 180);
|
||||
t.translate(-w/2.0, -h/2.0);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
VolatileImage dst;
|
||||
|
||||
protected void paintComponent(Graphics g1) {
|
||||
super.paintComponent(g1);
|
||||
|
||||
if (getWidth() != displaySize.width
|
||||
|| getHeight() != displaySize.height
|
||||
|| t == null || dst == null)
|
||||
{
|
||||
displaySize.width = getWidth();
|
||||
displaySize.height = getHeight();
|
||||
AffineTransform dxf = render();
|
||||
|
||||
|
||||
dst = createVolatileImage(getWidth(), getHeight());
|
||||
Graphics2D g = dst.createGraphics();
|
||||
g.drawRenderedImage(img, dxf);
|
||||
}
|
||||
g1.drawImage(dst, 0, 0, dst.getWidth(), dst.getHeight(), this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void drawWireframe(Graphics2D g, int w, int h) {
|
||||
double delta = Math.round(Math.sqrt(w * w + h * h) / 20);
|
||||
//
|
||||
// 0------------4------------1
|
||||
// | /|\ |
|
||||
// | 6 | 7 |
|
||||
// | | |
|
||||
// | 5 |
|
||||
// | 8 |
|
||||
// | | |
|
||||
// | 10-+-11 |
|
||||
// | | |
|
||||
// | 9 |
|
||||
// | |
|
||||
// | |
|
||||
// | |
|
||||
// | |
|
||||
// 3-------------------------2
|
||||
double[] wireFramePoints = new double[] {
|
||||
0, 0,
|
||||
w, 0,
|
||||
w, h,
|
||||
0, h,
|
||||
w/2, 0,
|
||||
w/2, 3 * delta,
|
||||
w/2 - delta, delta,
|
||||
w/2 + delta, delta,
|
||||
w/2, h/2 - delta,
|
||||
w/2, h/2 + delta,
|
||||
w/2 - delta, h/2,
|
||||
w/2 + delta, h/2
|
||||
};
|
||||
|
||||
float[] screen = new float[wireFramePoints.length];
|
||||
int[] x = new int[wireFramePoints.length / 2];
|
||||
int[] y = new int[wireFramePoints.length / 2];
|
||||
|
||||
t.transform(wireFramePoints, 0, screen, 0, x.length);
|
||||
|
||||
for (int i = 0; i < x.length; ++i) {
|
||||
x[i] = Math.round(screen[2*i]);
|
||||
y[i] = Math.round(screen[2*i + 1]);
|
||||
}
|
||||
g.setColor(Color.BLUE);
|
||||
|
||||
g.drawPolygon(x, y, 4);
|
||||
g.drawLine(x[4], y[4], x[5], y[5]);
|
||||
g.drawLine(x[4], y[4], x[6], y[6]);
|
||||
g.drawLine(x[4], y[4], x[7], y[7]);
|
||||
g.drawLine(x[8], y[8], x[9], y[9]);
|
||||
g.drawLine(x[10], y[10], x[11], y[11]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private class MyListener extends MouseInputAdapter {
|
||||
|
||||
public void mousePressed(MouseEvent e) {
|
||||
int x = e.getX();
|
||||
int y = e.getY();
|
||||
mask.setLocation(x, y);
|
||||
mask.setSize(1, 1);
|
||||
mask.repaint();
|
||||
}
|
||||
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
mask.updateFrame(e.getX(), e.getY());
|
||||
}
|
||||
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
mask.updateFrame(e.getX(), e.getY());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
JComponent createControlPanel() {
|
||||
BevelBorder border = new BevelBorder(BevelBorder.LOWERED);
|
||||
JPanel hp = new JPanel();
|
||||
hp.setLayout(new BoxLayout(hp, BoxLayout.Y_AXIS));
|
||||
hp.setBorder(
|
||||
new TitledBorder(border, "Controls", TitledBorder.LEFT,
|
||||
TitledBorder.ABOVE_TOP));
|
||||
hp.add(new JLabel("Rotation"));
|
||||
final JSlider rotationSlider = new JSlider(-180, 180, 0);
|
||||
rotationSlider.setPaintTicks(true);
|
||||
rotationSlider.setMajorTickSpacing(15);
|
||||
rotationSlider.addChangeListener(new ChangeListener() {
|
||||
int previousValue = 0;
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
int value = rotationSlider.getValue();
|
||||
if (value != previousValue) {
|
||||
previousValue = value;
|
||||
rotation = value;
|
||||
t = null;
|
||||
// render();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
});
|
||||
hp.add(rotationSlider);
|
||||
|
||||
|
||||
final JCheckBox renderQualityControl = new JCheckBox("Render Quality", false);
|
||||
renderQualityControl.addChangeListener(new ChangeListener() {
|
||||
boolean previousValue = false;
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
boolean value = renderQualityControl.isSelected();
|
||||
if (value != previousValue) {
|
||||
previousValue = value;
|
||||
render();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
});
|
||||
hp.add(renderQualityControl);
|
||||
|
||||
|
||||
hp.add(new JPanel());
|
||||
|
||||
return hp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static void main(String args[])
|
||||
throws Exception
|
||||
{
|
||||
Iterator readers = ImageIO.getImageReadersByFormatName("jpg");
|
||||
ImageReader reader = (ImageReader)readers.next();
|
||||
ImageInputStream iis = ImageIO.createImageInputStream(
|
||||
new File(args[0]));
|
||||
reader.setInput(iis, true);
|
||||
ImageReadParam param = reader.getDefaultReadParam();
|
||||
// param.setSourceSubsampling(8, 8, 0, 0);
|
||||
BufferedImage raw = reader.read(0, param);
|
||||
|
||||
Editor x = new Editor(raw);
|
||||
|
||||
JFrame frame = new JFrame("Editor");
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
|
||||
Container c = frame.getContentPane();
|
||||
c.setLayout(new BorderLayout());
|
||||
c.add(x.createControlPanel(), BorderLayout.EAST);
|
||||
c.add(x, BorderLayout.CENTER);
|
||||
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static class CropFrame extends JComponent implements MouseListener, MouseMotionListener {
|
||||
|
||||
/**
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int resizeBand = 6;
|
||||
|
||||
Stroke stroke = new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1f, new float[] { 5f, 5f }, 0);
|
||||
|
||||
public CropFrame()
|
||||
{
|
||||
setOpaque(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// 1------(5)-------2
|
||||
// | |
|
||||
// | |
|
||||
// (8) (6)
|
||||
// | |
|
||||
// | |
|
||||
// 4------(7)-------3
|
||||
//
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g); //paints the background and image
|
||||
|
||||
// Draw a rectangle on top of the image.
|
||||
// g.setColor(Color.WHITE);
|
||||
g.setXORMode(Color.white); //Color of line varies
|
||||
((Graphics2D)g).setStroke(stroke);
|
||||
//depending on image colors
|
||||
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void mouseExited(MouseEvent e) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void mousePressed(MouseEvent e) {
|
||||
int r = findRegion(e.getX(), e.getY());
|
||||
if (r < 8) {
|
||||
edge = r;
|
||||
}
|
||||
}
|
||||
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
updateFrame(e.getX() + getX(), e.getY() + getY());
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
updateFrame(e.getX() + getX(), e.getY() + getY());
|
||||
}
|
||||
|
||||
|
||||
|
||||
boolean is(int who, int alt0, int alt1, int alt2) {
|
||||
return who == alt0 || who == alt1 || who == alt2;
|
||||
}
|
||||
int[] oppositeX = new int[] { NE, N, NW, W, SW, S, SE, E };
|
||||
int[] oppositeY = new int[] { SW, S, SE, E, NE, N, NW, W };
|
||||
Cursor[] cursors = new Cursor[] {
|
||||
Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR),
|
||||
};
|
||||
String[] edgeName = new String[] { "NW", "N", "NE", "E", "SE", "S", "SW", "W" };
|
||||
static final int NW = 0;
|
||||
static final int N = 1;
|
||||
static final int NE = 2;
|
||||
static final int E = 3;
|
||||
static final int SE = 4;
|
||||
static final int S = 5;
|
||||
static final int SW = 6;
|
||||
static final int W = 7;
|
||||
int edge = SE;
|
||||
Rectangle frame = new Rectangle();
|
||||
|
||||
void updateFrame(int x, int y) {
|
||||
getBounds(frame);
|
||||
if (is(edge, NW, W, SW)) {
|
||||
frame.width += frame.x - x;
|
||||
frame.x = x;
|
||||
}
|
||||
if (is(edge, NE, E, SE)) {
|
||||
frame.width = x - frame.x;
|
||||
}
|
||||
if (is(edge, NW, N, NE)) {
|
||||
frame.height += frame.y - y;
|
||||
frame.y = y;
|
||||
}
|
||||
if (is(edge, SW, S, SE)) {
|
||||
frame.height = y - frame.y;
|
||||
}
|
||||
if (frame.width < 0) {
|
||||
frame.x += frame.width;
|
||||
frame.width = -frame.width;
|
||||
edge = oppositeX[edge];
|
||||
}
|
||||
if (frame.height < 0) {
|
||||
frame.y += frame.height;
|
||||
frame.height = -frame.height;
|
||||
edge = oppositeY[edge];
|
||||
}
|
||||
setBounds(frame);
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int findRegion(int ex, int ey) {
|
||||
int w = getWidth();
|
||||
int h = getHeight();
|
||||
int c = 8;
|
||||
|
||||
if (ex > (w - resizeBand)) {
|
||||
if (ey > (h - resizeBand)) {
|
||||
c = SE;
|
||||
} else if (ey < resizeBand) {
|
||||
c = NE;
|
||||
} else {
|
||||
c = E;
|
||||
}
|
||||
} else if (ex < resizeBand) {
|
||||
if (ey > (h - resizeBand)) {
|
||||
c = SW;
|
||||
} else if (ey < resizeBand) {
|
||||
c = NW;
|
||||
} else {
|
||||
c = W;
|
||||
}
|
||||
} else {
|
||||
if (ey > (h - resizeBand)) {
|
||||
c = S;
|
||||
} else if (ey < resizeBand) {
|
||||
c = N;
|
||||
} else {
|
||||
c = 8;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
setCursor(cursors[findRegion(e.getX(), e.getY())]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void log(String x) {
|
||||
System.out.println(x);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// eof
|
||||
44
src/album/editor/Makefile
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#
|
||||
# Java interpreter and compiler
|
||||
#
|
||||
JAVA = java
|
||||
JAVAC = javac
|
||||
|
||||
#
|
||||
# Various tools
|
||||
#
|
||||
RM = rm -f
|
||||
|
||||
#
|
||||
# Which libraries do we use?
|
||||
#
|
||||
CLASSPATH=$(HOME)/src/album
|
||||
|
||||
CLASSES = Editor.class
|
||||
|
||||
|
||||
#
|
||||
# The file types we deal with
|
||||
#
|
||||
.SUFFIXES: .java .class
|
||||
|
||||
|
||||
all: $(CLASSES)
|
||||
@echo Done
|
||||
|
||||
clean:
|
||||
$(RM) *.class
|
||||
$(RM) *~
|
||||
|
||||
.java.class:
|
||||
$(JAVAC) -classpath $(CLASSPATH) $<
|
||||
|
||||
|
||||
editor: Editor.class
|
||||
$(JAVA) -cp $(CLASSPATH) editor.Editor /home/knut/src/album/photos/l1000802.jpg
|
||||
|
||||
reader: ReaderHelper.class
|
||||
$(JAVA) -cp $(CLASSPATH) editor.ReaderHelper /home/knut/src/album/photos
|
||||
|
||||
|
||||
#eof
|
||||
BIN
src/album/editor/ReaderHelper$1.class
Normal file
BIN
src/album/editor/ReaderHelper.class
Normal file
BIN
src/album/editor/SelectionDemo$1.class
Normal file
BIN
src/album/editor/SelectionDemo$SelectionArea$MyListener.class
Normal file
BIN
src/album/editor/SelectionDemo$SelectionArea.class
Normal file
BIN
src/album/editor/SelectionDemo.class
Normal file
209
src/album/editor/SelectionDemo.java
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
/* From http://java.sun.com/docs/books/tutorial/index.html */
|
||||
/*
|
||||
* SelectionDemo.java is a 1.4 application that requires one other file:
|
||||
* images/starfield.gif
|
||||
*/
|
||||
|
||||
package album.editor;
|
||||
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.event.MouseInputAdapter;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
/*
|
||||
* This displays an image. When the user drags within the image, this program
|
||||
* displays a rectangle and a string indicating the bounds of the rectangle.
|
||||
*/
|
||||
public class SelectionDemo {
|
||||
JLabel label;
|
||||
|
||||
static String starFile = "/home/knut/src/album/photos/forkalsrud-ca-1951.jpg";
|
||||
|
||||
private void buildUI(Container container, ImageIcon image) {
|
||||
container.setLayout(new BoxLayout(container, BoxLayout.PAGE_AXIS));
|
||||
|
||||
SelectionArea area = new SelectionArea(image, this);
|
||||
container.add(area);
|
||||
|
||||
label = new JLabel("Drag within the image.");
|
||||
label.setLabelFor(area);
|
||||
container.add(label);
|
||||
|
||||
//Align the left edges of the components.
|
||||
area.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
label.setAlignmentX(Component.LEFT_ALIGNMENT); //redundant
|
||||
}
|
||||
|
||||
public void updateLabel(Rectangle rect) {
|
||||
int width = rect.width;
|
||||
int height = rect.height;
|
||||
|
||||
//Make the coordinates look OK if a dimension is 0.
|
||||
if (width == 0) {
|
||||
width = 1;
|
||||
}
|
||||
if (height == 0) {
|
||||
height = 1;
|
||||
}
|
||||
|
||||
label.setText("Rectangle goes from (" + rect.x + ", " + rect.y
|
||||
+ ") to (" + (rect.x + width - 1) + ", "
|
||||
+ (rect.y + height - 1) + ").");
|
||||
}
|
||||
|
||||
/** Returns an ImageIcon, or null if the path was invalid. */
|
||||
protected static ImageIcon createImageIcon(String path) {
|
||||
return new ImageIcon(path, "description");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the GUI and show it. For thread safety, this method should be
|
||||
* invoked from the event-dispatching thread.
|
||||
*/
|
||||
private static void createAndShowGUI() {
|
||||
//Make sure we have nice window decorations.
|
||||
JFrame.setDefaultLookAndFeelDecorated(true);
|
||||
|
||||
//Create and set up the window.
|
||||
JFrame frame = new JFrame("SelectionDemo");
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
|
||||
//Set up the content pane.
|
||||
SelectionDemo controller = new SelectionDemo();
|
||||
controller.buildUI(frame.getContentPane(), createImageIcon(starFile));
|
||||
|
||||
//Display the window.
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
//Schedule a job for the event-dispatching thread:
|
||||
//creating and showing this application's GUI.
|
||||
javax.swing.SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
createAndShowGUI();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class SelectionArea extends JLabel {
|
||||
Rectangle currentRect = null;
|
||||
|
||||
Rectangle rectToDraw = null;
|
||||
|
||||
Rectangle previousRectDrawn = new Rectangle();
|
||||
|
||||
SelectionDemo controller;
|
||||
|
||||
public SelectionArea(ImageIcon image, SelectionDemo controller) {
|
||||
super(image); //This component displays an image.
|
||||
this.controller = controller;
|
||||
setOpaque(true);
|
||||
setMinimumSize(new Dimension(10, 10)); //don't hog space
|
||||
|
||||
MyListener myListener = new MyListener();
|
||||
addMouseListener(myListener);
|
||||
addMouseMotionListener(myListener);
|
||||
}
|
||||
|
||||
private class MyListener extends MouseInputAdapter {
|
||||
public void mousePressed(MouseEvent e) {
|
||||
int x = e.getX();
|
||||
int y = e.getY();
|
||||
currentRect = new Rectangle(x, y, 0, 0);
|
||||
updateDrawableRect(getWidth(), getHeight());
|
||||
repaint();
|
||||
}
|
||||
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
updateSize(e);
|
||||
}
|
||||
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
updateSize(e);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the size of the current rectangle and call repaint.
|
||||
* Because currentRect always has the same origin, translate it if
|
||||
* the width or height is negative.
|
||||
*
|
||||
* For efficiency (though that isn't an issue for this program),
|
||||
* specify the painting region using arguments to the repaint()
|
||||
* call.
|
||||
*
|
||||
*/
|
||||
void updateSize(MouseEvent e) {
|
||||
int x = e.getX();
|
||||
int y = e.getY();
|
||||
currentRect.setSize(x - currentRect.x, y - currentRect.y);
|
||||
updateDrawableRect(getWidth(), getHeight());
|
||||
Rectangle totalRepaint = rectToDraw.union(previousRectDrawn);
|
||||
repaint(totalRepaint.x, totalRepaint.y, totalRepaint.width,
|
||||
totalRepaint.height);
|
||||
}
|
||||
}
|
||||
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g); //paints the background and image
|
||||
|
||||
//If currentRect exists, paint a box on top.
|
||||
if (currentRect != null) {
|
||||
//Draw a rectangle on top of the image.
|
||||
g.setXORMode(Color.white); //Color of line varies
|
||||
//depending on image colors
|
||||
g.drawRect(rectToDraw.x, rectToDraw.y, rectToDraw.width - 1,
|
||||
rectToDraw.height - 1);
|
||||
|
||||
controller.updateLabel(rectToDraw);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDrawableRect(int compWidth, int compHeight) {
|
||||
int x = currentRect.x;
|
||||
int y = currentRect.y;
|
||||
int width = currentRect.width;
|
||||
int height = currentRect.height;
|
||||
|
||||
//Make the width and height positive, if necessary.
|
||||
if (width < 0) {
|
||||
width = 0 - width;
|
||||
x = x - width + 1;
|
||||
if (x < 0) {
|
||||
width += x;
|
||||
x = 0;
|
||||
}
|
||||
}
|
||||
if (height < 0) {
|
||||
height = 0 - height;
|
||||
y = y - height + 1;
|
||||
if (y < 0) {
|
||||
height += y;
|
||||
y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//The rectangle shouldn't extend past the drawing area.
|
||||
if ((x + width) > compWidth) {
|
||||
width = compWidth - x;
|
||||
}
|
||||
if ((y + height) > compHeight) {
|
||||
height = compHeight - y;
|
||||
}
|
||||
|
||||
//Update rectToDraw after saving old value.
|
||||
if (rectToDraw != null) {
|
||||
previousRectDrawn.setBounds(rectToDraw.x, rectToDraw.y,
|
||||
rectToDraw.width, rectToDraw.height);
|
||||
rectToDraw.setBounds(x, y, width, height);
|
||||
} else {
|
||||
rectToDraw = new Rectangle(x, y, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
122
src/album/web/AlbumServlet.java
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
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");
|
||||
|
||||
public void init()
|
||||
throws ServletException
|
||||
{
|
||||
System.out.println("in init of Album");
|
||||
}
|
||||
|
||||
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<File>() {
|
||||
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 <img> tags for a thumbnail of each image or other
|
||||
// album
|
||||
PrintWriter out = res.getWriter();
|
||||
out.println("<html>");
|
||||
out.println("<head>");
|
||||
out.println("<title>" + directory + "</title>");
|
||||
out.println("</head>");
|
||||
out.println("<body>");
|
||||
|
||||
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("<a href=\"" + anchorUrl + "\">");
|
||||
out.print("<img hspace=5 vspace=5 src=\"" + iconUrl + "\">");
|
||||
out.println("</a>");
|
||||
}
|
||||
out.println("</body>");
|
||||
out.println("</html>");
|
||||
}
|
||||
|
||||
|
||||
public String getServletInfo() {
|
||||
return "Display a directory as an album";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// eof
|
||||
223
src/album/web/BitmapServlet.java
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
package album.web;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
|
||||
import javax.imageio.*;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.*;
|
||||
|
||||
public class BitmapServlet
|
||||
extends HttpServlet
|
||||
implements ImageObserver
|
||||
{
|
||||
File baseDir = new File("/home/knut");
|
||||
File cacheDir = new File("/var/album");
|
||||
|
||||
final static int BUF_SIZE = 1024;
|
||||
protected volatile boolean complete = false;
|
||||
protected int size;
|
||||
|
||||
|
||||
public void init()
|
||||
throws ServletException
|
||||
{
|
||||
System.out.println("in init of Bitmap");
|
||||
}
|
||||
|
||||
|
||||
File cacheFile(String filename, int size) {
|
||||
return new File(cacheDir, filename + "-" + size + ".png");
|
||||
}
|
||||
|
||||
|
||||
public void doGet(HttpServletRequest req, HttpServletResponse res)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
res.setContentType("image/png");
|
||||
|
||||
// Determine which file to show
|
||||
String filename = req.getServletPath();
|
||||
filename = filename.substring(
|
||||
"/".length(),
|
||||
filename.length() - ".bitmap".length());
|
||||
|
||||
System.out.println("file: " + filename);
|
||||
|
||||
File file = new File(baseDir, filename);
|
||||
if (file == null) {
|
||||
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file.isFile()) {
|
||||
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file.canRead()) {
|
||||
res.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
||||
return;
|
||||
}
|
||||
|
||||
int size = Integer.parseInt(req.getParameter("size"));
|
||||
|
||||
File cacheFile = cacheFile(filename, size);
|
||||
|
||||
if (!cacheFile.exists()) {
|
||||
writeJpegImage(file, size, cacheFile);
|
||||
}
|
||||
|
||||
try {
|
||||
OutputStream out = res.getOutputStream();
|
||||
FileInputStream infile = new FileInputStream(cacheFile);
|
||||
byte[] buf = new byte[BUF_SIZE];
|
||||
int chunksize;
|
||||
do {
|
||||
chunksize = infile.read(buf);
|
||||
if (chunksize > 0)
|
||||
out.write(buf, 0, chunksize);
|
||||
} while (!(chunksize < 0));
|
||||
infile.close();
|
||||
} catch (FileNotFoundException e1) {
|
||||
System.err.println("File creation error! " + e1.getMessage());
|
||||
} catch (IOException e2) {
|
||||
System.err.println("IO error! " + e2.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
static int DONE = (ABORT | ALLBITS | ERROR | FRAMEBITS);
|
||||
|
||||
int previousInfoFlags = 0;
|
||||
// HEIGHT PROPERTIES SOMEBITS WIDTH
|
||||
public boolean imageUpdate(Image img, int infoflags,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
if (infoflags != previousInfoFlags) {
|
||||
/* StringBuffer b = new StringBuffer("Flags:");
|
||||
if ((infoflags & ABORT) != 0)
|
||||
b.append(" ABORT");
|
||||
if ((infoflags & ALLBITS) != 0)
|
||||
b.append(" ALLBITS");
|
||||
if ((infoflags & ERROR) != 0)
|
||||
b.append(" ERROR");
|
||||
if ((infoflags & FRAMEBITS) != 0)
|
||||
b.append(" FRAMEBITS");
|
||||
if ((infoflags & HEIGHT) != 0)
|
||||
b.append(" HEIGHT");
|
||||
if ((infoflags & WIDTH) != 0)
|
||||
b.append(" WIDTH");
|
||||
if ((infoflags & PROPERTIES) != 0)
|
||||
b.append(" PROPERTIES");
|
||||
if ((infoflags & SOMEBITS) != 0)
|
||||
b.append(" SOMEBITS");
|
||||
System.err.println(b.toString());
|
||||
*/
|
||||
previousInfoFlags = infoflags;
|
||||
}
|
||||
|
||||
if ((infoflags & DONE) != 0) {
|
||||
synchronized (this) {
|
||||
this.complete = true;
|
||||
// new Throwable().printStackTrace(System.err);
|
||||
notify();
|
||||
// System.err.println("Wakeup! " + this.complete + " " + this);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected Dimension scaleMaxExtent(int extent, Dimension in)
|
||||
{
|
||||
Dimension original = new Dimension(in);
|
||||
if (extent > 0) {
|
||||
if (original.width > original.height && original.width > extent) {
|
||||
original.height *= extent;
|
||||
original.height /= original.width;
|
||||
original.width = extent;
|
||||
} else if (original.height > extent) {
|
||||
original.width *= extent;
|
||||
original.width /= original.height;
|
||||
original.height = extent;
|
||||
}
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
|
||||
protected void writeJpegImage(File source, int size, File destination)
|
||||
throws IOException
|
||||
{
|
||||
BufferedImage img = ImageIO.read(source);
|
||||
Dimension dim = scaleMaxExtent(size, new Dimension(
|
||||
img.getWidth(), img.getHeight()));
|
||||
|
||||
Toolkit tk = Toolkit.getDefaultToolkit();
|
||||
|
||||
synchronized (this) {
|
||||
complete = false;
|
||||
boolean alreadyDone = tk.prepareImage(img, -1, -1, this);
|
||||
complete = complete || alreadyDone;
|
||||
|
||||
// Suspend until the image is rendered completely
|
||||
for (int i = 0; !this.complete && i < 10; ++i)
|
||||
try {
|
||||
// System.err.println("Waiting 1: " + this.complete + " " + this);
|
||||
wait(2000);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
BufferedImage buff = new BufferedImage(
|
||||
dim.width, dim.height, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics g = buff.createGraphics();
|
||||
|
||||
synchronized (this) {
|
||||
complete = false;
|
||||
|
||||
boolean alreadyDone = g.drawImage(img, 0, 0, dim.width, dim.height, this);
|
||||
|
||||
complete = complete || alreadyDone;
|
||||
|
||||
// Suspend until the image is rendered completely
|
||||
for (int i = 0; !complete && i < 10; ++i)
|
||||
try {
|
||||
// System.err.println("Waiting 2: " + this.complete);
|
||||
wait(2000);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
if (size > 120 || size == 0) {
|
||||
g.setColor(Color.cyan);
|
||||
int lineHeight = g.getFontMetrics().getHeight();
|
||||
int year = Calendar.getInstance().get(Calendar.YEAR);
|
||||
g.drawString("<EFBFBD> " + year + " forkalsrud.org", 5, 5 + lineHeight);
|
||||
}
|
||||
|
||||
try {
|
||||
destination.getParentFile().mkdirs();
|
||||
FileOutputStream out = new FileOutputStream(destination);
|
||||
ImageIO.write(buff, "png", out);
|
||||
out.close();
|
||||
/* System.err.println("OK: " + ok
|
||||
+ " Writers : "
|
||||
+ Arrays.asList(ImageIO.getWriterFormatNames()));
|
||||
*/
|
||||
} catch (FileNotFoundException e1) {
|
||||
System.err.println("File creation error! " + e1.getMessage());
|
||||
} catch (IOException e2) {
|
||||
System.err.println("IO error! " + e2.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// eof
|
||||
171
src/album/web/PhotoServlet.java
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
package album.web;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
|
||||
import javax.imageio.*;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.*;
|
||||
|
||||
public class PhotoServlet
|
||||
extends HttpServlet
|
||||
implements ImageObserver
|
||||
{
|
||||
File baseDir = new File("/home/knut");
|
||||
File cacheDir = new File("/var/album");
|
||||
|
||||
final static int BUF_SIZE = 1024;
|
||||
protected volatile boolean complete = false;
|
||||
protected int size;
|
||||
|
||||
|
||||
public void init()
|
||||
throws ServletException
|
||||
{
|
||||
System.out.println("in init of Bitmap");
|
||||
}
|
||||
|
||||
|
||||
File cacheFile(String filename, int size) {
|
||||
return new File(cacheDir, filename + "-" + size + ".jpeg");
|
||||
}
|
||||
|
||||
|
||||
public void doGet(HttpServletRequest req, HttpServletResponse res)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
res.setContentType("text/plain");
|
||||
|
||||
// Determine which file to show
|
||||
String filename = req.getServletPath();
|
||||
filename = filename.substring(
|
||||
"/".length(),
|
||||
filename.length() - ".photo".length());
|
||||
|
||||
System.out.println("file: " + filename);
|
||||
|
||||
File file = new File(baseDir, filename);
|
||||
if (file == null) {
|
||||
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file.isFile()) {
|
||||
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file.canRead()) {
|
||||
res.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
||||
return;
|
||||
}
|
||||
|
||||
PrintWriter out = res.getWriter();
|
||||
|
||||
|
||||
String[] formats = ImageIO.getReaderFormatNames();
|
||||
out.println(Arrays.asList(formats).toString());
|
||||
|
||||
Iterator ii = ImageIO.getImageReadersByFormatName("jpeg");
|
||||
while (ii.hasNext()) {
|
||||
ImageReader ir = (ImageReader)ii.next();
|
||||
|
||||
Class[] inputs = ir.getOriginatingProvider().getInputTypes();
|
||||
out.println(" inputs: " + Arrays.asList(inputs).toString());
|
||||
|
||||
ir.setInput(ImageIO.createImageInputStream(file));
|
||||
|
||||
int cnt = ir.getNumImages(true);
|
||||
|
||||
int thCnt = ir.getNumThumbnails(0);
|
||||
|
||||
out.println("Num images: " + cnt + " thumbnails: " + thCnt);
|
||||
|
||||
// BufferedImage th = ir.readThumbnail(0, 0);
|
||||
|
||||
// out.println(" Thumbnail size: " + th.getWidth() + "x" + th.getWidth());
|
||||
ir.dispose();
|
||||
}
|
||||
/*
|
||||
EXIFInfo info = new EXIFInfo(file);
|
||||
Map props = info.getEXIFMetaData();
|
||||
|
||||
Set s = props.entrySet();
|
||||
Iterator i = s.iterator();
|
||||
|
||||
while (i.hasNext()) {
|
||||
Map.Entry e = (Map.Entry)i.next();
|
||||
out.println(e.getKey() + ": " + e.getValue());
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
static int DONE = (ABORT | ALLBITS | ERROR | FRAMEBITS);
|
||||
|
||||
int previousInfoFlags = 0;
|
||||
// HEIGHT PROPERTIES SOMEBITS WIDTH
|
||||
public boolean imageUpdate(Image img, int infoflags,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
if (infoflags != previousInfoFlags) {
|
||||
/* StringBuffer b = new StringBuffer("Flags:");
|
||||
if ((infoflags & ABORT) != 0)
|
||||
b.append(" ABORT");
|
||||
if ((infoflags & ALLBITS) != 0)
|
||||
b.append(" ALLBITS");
|
||||
if ((infoflags & ERROR) != 0)
|
||||
b.append(" ERROR");
|
||||
if ((infoflags & FRAMEBITS) != 0)
|
||||
b.append(" FRAMEBITS");
|
||||
if ((infoflags & HEIGHT) != 0)
|
||||
b.append(" HEIGHT");
|
||||
if ((infoflags & WIDTH) != 0)
|
||||
b.append(" WIDTH");
|
||||
if ((infoflags & PROPERTIES) != 0)
|
||||
b.append(" PROPERTIES");
|
||||
if ((infoflags & SOMEBITS) != 0)
|
||||
b.append(" SOMEBITS");
|
||||
System.err.println(b.toString());
|
||||
*/
|
||||
previousInfoFlags = infoflags;
|
||||
}
|
||||
|
||||
if ((infoflags & DONE) != 0) {
|
||||
synchronized (this) {
|
||||
this.complete = true;
|
||||
// new Throwable().printStackTrace(System.err);
|
||||
notify();
|
||||
// System.err.println("Wakeup! " + this.complete + " " + this);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected Dimension scaleMaxExtent(int extent, Dimension in)
|
||||
{
|
||||
Dimension original = new Dimension(in);
|
||||
if (extent > 0) {
|
||||
if (original.width > original.height && original.width > extent) {
|
||||
original.height *= extent;
|
||||
original.height /= original.width;
|
||||
original.width = extent;
|
||||
} else if (original.height > extent) {
|
||||
original.width *= extent;
|
||||
original.width /= original.height;
|
||||
original.height = extent;
|
||||
}
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// eof
|
||||
10
webapp/WEB-INF/web.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<web-app>
|
||||
|
||||
<servlet-mapping url-pattern="*.album"
|
||||
servlet-name="album.AlbumServlet" />
|
||||
<servlet-mapping url-pattern="*.photo"
|
||||
servlet-name="album.PhotoServlet" />
|
||||
<servlet-mapping url-pattern="*.bitmap"
|
||||
servlet-name="album.BitmapServlet" />
|
||||
|
||||
</web-app>
|
||||