NIHVIVO-1208 Cleaned things up a bit - ready to give up, for now at least. Still works for JPEG, but not for GIF.
This commit is contained in:
parent
d0846f2348
commit
5a2af2f97d
3 changed files with 154 additions and 16 deletions
|
@ -393,7 +393,7 @@ public class ImageUploadHelper {
|
|||
* is written as a simple log message.
|
||||
* </p>
|
||||
*/
|
||||
private static class NonNoisyImagingListener implements ImagingListener {
|
||||
static class NonNoisyImagingListener implements ImagingListener {
|
||||
@Override
|
||||
public boolean errorOccurred(String message, Throwable thrown,
|
||||
Object where, boolean isRetryable) throws RuntimeException {
|
||||
|
|
|
@ -7,7 +7,6 @@ import java.io.ByteArrayInputStream;
|
|||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.media.jai.InterpolationBilinear;
|
||||
import javax.media.jai.RenderedOp;
|
||||
|
@ -28,8 +27,15 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadControl
|
|||
/**
|
||||
* Crop the main image as specified, and scale it to the correct size for a
|
||||
* thumbnail.
|
||||
*
|
||||
* The JAI library has a problem when writing a JPEG from a source image with an
|
||||
* alpha channel (transparency). The colors come out inverted. We throw in a
|
||||
* step that will remove transparency from a PNG, but it won't touch a GIF.
|
||||
*/
|
||||
public class ImageUploadThumbnailer {
|
||||
/** If an image has 3 color bands and 1 alpha band, we want these. */
|
||||
private static final int[] COLOR_BAND_INDEXES = new int[] { 0, 1, 2 };
|
||||
|
||||
private static final Log log = LogFactory
|
||||
.getLog(ImageUploadThumbnailer.class);
|
||||
|
||||
|
@ -69,11 +75,20 @@ public class ImageUploadThumbnailer {
|
|||
|
||||
private RenderedOp makeImageOpaque(RenderedOp image) {
|
||||
ColorModel colorModel = image.getColorModel();
|
||||
|
||||
if (!colorModel.hasAlpha()) {
|
||||
// The image is already opaque.
|
||||
return image;
|
||||
}
|
||||
return BandSelectDescriptor.create(image, figureBandIndices(image),
|
||||
null);
|
||||
|
||||
if (image.getNumBands() == 4) {
|
||||
// The image has a separate alpha channel. Drop the alpha channel.
|
||||
return BandSelectDescriptor.create(image, COLOR_BAND_INDEXES, null);
|
||||
}
|
||||
|
||||
// Don't know how to handle it. Probably a GIF with a transparent
|
||||
// background. Give up.
|
||||
return image;
|
||||
}
|
||||
|
||||
private RenderedOp cropImage(RenderedOp image, CropRectangle crop) {
|
||||
|
@ -104,18 +119,6 @@ public class ImageUploadThumbnailer {
|
|||
return bytes.toByteArray();
|
||||
}
|
||||
|
||||
/** Build an array holding the indexes of the color bands in this image. */
|
||||
private int[] figureBandIndices(RenderedOp image) {
|
||||
int howMany = Math.min(image.getColorModel().getNumColorComponents(),
|
||||
image.getNumBands());
|
||||
int[] bandIndices = new int[howMany];
|
||||
for (int i = 0; i < bandIndices.length; i++) {
|
||||
bandIndices[i] = i;
|
||||
}
|
||||
log.debug("Selecting these bands: " + Arrays.toString(bandIndices));
|
||||
return bandIndices;
|
||||
}
|
||||
|
||||
private CropRectangle limitCropRectangleToImageBounds(RenderedOp image,
|
||||
CropRectangle crop) {
|
||||
log.debug("Generating a thumbnail, initial crop info: " + crop);
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
|
||||
|
||||
import static edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.THUMBNAIL_HEIGHT;
|
||||
import static edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.THUMBNAIL_WIDTH;
|
||||
|
||||
import java.awt.Frame;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.media.jai.JAI;
|
||||
import javax.media.jai.RenderedOp;
|
||||
import javax.media.jai.operator.StreamDescriptor;
|
||||
import javax.media.jai.widget.ImageCanvas;
|
||||
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.sun.media.jai.codec.MemoryCacheSeekableStream;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadHelper.NonNoisyImagingListener;
|
||||
|
||||
/**
|
||||
* This is not a unit test, so it is not named BlahBlahTest.
|
||||
*
|
||||
* Instead, it's a test harness that creates thumbnails and writes them to
|
||||
* files, while also displaying them in a window on the screen. It takes human
|
||||
* intervention to evaluate.
|
||||
*
|
||||
* This is especially true because the images on the screen look color-correct,
|
||||
* but when viewed in the browser, they might not be.
|
||||
*/
|
||||
public class ImageUploaderThumbnailerTester extends Frame {
|
||||
static {
|
||||
JAI.getDefaultInstance().setImagingListener(
|
||||
new NonNoisyImagingListener());
|
||||
}
|
||||
|
||||
/** Big enough to hold the JPEG file, certainly. */
|
||||
private final static int BUFFER_SIZE = 200 * 200 * 4;
|
||||
|
||||
private final static ImageCropData[] THUMBNAIL_DATA = new ImageCropData[] {
|
||||
new ImageCropData("/Users/jeb228/Pictures/JimBlake_20010915.jpg",
|
||||
50, 50, 115),
|
||||
new ImageCropData("/Users/jeb228/Pictures/brazil_collab.png", 600,
|
||||
250, 400),
|
||||
new ImageCropData("/Users/jeb228/Pictures/wheel.png", 0, 0, 195),
|
||||
new ImageCropData("/Users/jeb228/Pictures/DSC04203w-trans.gif",
|
||||
400, 1200, 800) };
|
||||
|
||||
private final ImageUploadThumbnailer thumbnailer = new ImageUploadThumbnailer(
|
||||
THUMBNAIL_HEIGHT, THUMBNAIL_WIDTH);
|
||||
|
||||
private ImageUploaderThumbnailerTester() {
|
||||
setTitle("Alpha Killer Test");
|
||||
addWindowListener(new CloseWindowListener());
|
||||
setLayout(createLayout());
|
||||
for (ImageCropData icd : THUMBNAIL_DATA) {
|
||||
try {
|
||||
InputStream mainStream = new FileInputStream(icd.filename);
|
||||
File thumbFile = writeToTempFile(thumbnailer.cropAndScale(
|
||||
mainStream, icd.crop));
|
||||
System.out.println(thumbFile.getAbsolutePath());
|
||||
|
||||
MemoryCacheSeekableStream thumbFileStream = new MemoryCacheSeekableStream(
|
||||
new FileInputStream(thumbFile));
|
||||
RenderedOp thumbImage = StreamDescriptor.create(
|
||||
thumbFileStream, null, null);
|
||||
add(new ImageCanvas(thumbImage));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
pack();
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param thumbStream
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
private File writeToTempFile(InputStream thumbStream) throws IOException,
|
||||
FileNotFoundException {
|
||||
File thumbFile = File.createTempFile("ImageUploaderThumbnailerTester",
|
||||
"");
|
||||
OutputStream imageOutputStream = new FileOutputStream(thumbFile);
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
int howMany = thumbStream.read(buffer);
|
||||
imageOutputStream.write(buffer, 0, howMany);
|
||||
imageOutputStream.close();
|
||||
return thumbFile;
|
||||
}
|
||||
|
||||
private GridLayout createLayout() {
|
||||
GridLayout layout = new GridLayout(1, THUMBNAIL_DATA.length);
|
||||
layout.setHgap(10);
|
||||
return layout;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Logger.getLogger(ImageUploadThumbnailer.class).setLevel(Level.DEBUG);
|
||||
new ImageUploaderThumbnailerTester();
|
||||
}
|
||||
|
||||
private static class ImageCropData {
|
||||
final String filename;
|
||||
final ImageUploadController.CropRectangle crop;
|
||||
|
||||
ImageCropData(String filename, int x, int y, int size) {
|
||||
this.filename = filename;
|
||||
this.crop = new ImageUploadController.CropRectangle(x, y, size,
|
||||
size);
|
||||
}
|
||||
}
|
||||
|
||||
private class CloseWindowListener extends WindowAdapter {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
setVisible(false);
|
||||
dispose();
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue