/*
* Copyright (C) 2010 Brockmann Consult GmbH (info@brockmann-consult.de)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version.
* 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, see http://www.gnu.org/licenses/
*/
package com.bc.ceres.glayer.tools;
import com.bc.ceres.glayer.Layer;
import com.bc.ceres.glayer.support.ImageLayer;
import com.bc.ceres.glayer.swing.LayerCanvas;
import com.bc.ceres.glevel.MultiLevelSource;
import com.bc.ceres.glevel.support.FileMultiLevelSource;
import com.sun.media.jai.codec.TIFFEncodeParam;
import javax.media.jai.ImageLayout;
import javax.media.jai.ImageMIPMap;
import javax.media.jai.Interpolation;
import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;
import javax.media.jai.operator.AffineDescriptor;
import javax.media.jai.operator.FileLoadDescriptor;
import javax.media.jai.operator.FileStoreDescriptor;
import javax.media.jai.operator.FormatDescriptor;
import javax.media.jai.operator.MosaicDescriptor;
import javax.media.jai.operator.ScaleDescriptor;
import javax.media.jai.util.ImagingListener;
import javax.swing.JFrame;
import javax.swing.JSlider;
import javax.swing.JWindow;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.MouseInputAdapter;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.ColorModel;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class Tools {
public static void configureJAI() {
JAI.getDefaultInstance().setImagingListener(new ImagingListener() {
@Override
public boolean errorOccurred(String message, Throwable thrown, Object where, boolean isRetryable) throws
RuntimeException {
System.out.println("JAI error occurred: " + message);
return false;
}
});
final long memoryCapacity = 256 * (1024 * 1024);
JAI.getDefaultInstance().getTileCache().setMemoryCapacity(memoryCapacity);
JAI.getDefaultInstance().getTileCache().setMemoryThreshold(0.75f);
}
public static AffineTransform loadWorldFile(String filename) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(filename));
try {
double[] flatMatrix = new double[6];
new AffineTransform().getMatrix(flatMatrix); // init with identity
for (int i = 0; i < flatMatrix.length; i++) {
final String parameter = reader.readLine();
if (parameter == null) {
throw new IOException("Could not read world file: Missing a parameter.");
}
try {
flatMatrix[i] = Double.valueOf(parameter);
} catch (NumberFormatException e) {
IOException ioException = new IOException("Could not read world file. " + e.getMessage());
ioException.initCause(e);
throw ioException;
}
}
return new AffineTransform(flatMatrix);
} finally {
reader.close();
}
}
public static RenderedOp createMosaic(RenderedImage[] images) {
return MosaicDescriptor.create(images, MosaicDescriptor.MOSAIC_TYPE_OVERLAY,
null, null, null, new double[]{0.0}, null);
}
public static void storeTiledTiff(RenderedImage image, String filePath) {
final TIFFEncodeParam encodeParam = new TIFFEncodeParam();
encodeParam.setTileSize(image.getTileWidth(), image.getTileHeight());
encodeParam.setWriteTiled(true);
encodeParam.setCompression(TIFFEncodeParam.COMPRESSION_DEFLATE);
System.out.println("Storing tiled TIFF image to " + filePath + "...");
FileStoreDescriptor.create(image, filePath, "TIFF", encodeParam, false, null);
}
public static RenderedOp scaleImage(RenderedImage image, float scale) {
final Interpolation interpol = Interpolation.getInstance(Interpolation.INTERP_NEAREST);
return ScaleDescriptor.create(image, scale, scale, 0.0f, 0.0f, interpol, null);
}
public static RenderedOp transformImage(RenderedImage image, double x0, double y0, double theta, double scale) {
final AffineTransform transform = new AffineTransform();
transform.rotate(theta, -0.5f * image.getWidth(), -0.5f * image.getHeight());
transform.scale(scale, scale);
transform.translate(x0, y0);
return transformImage(image, transform);
}
public static RenderedOp transformImage(RenderedImage image, AffineTransform transform) {
return AffineDescriptor.create(image, transform,
Interpolation.getInstance(Interpolation.INTERP_NEAREST),
new double[]{0.0}, null);
}
public static RenderedOp createTiledImage(RenderedImage image, int tileWidth, int tileHeight) {
final int dataType = image.getSampleModel().getDataType();
final ImageLayout imageLayout = new ImageLayout();
imageLayout.setTileWidth(tileWidth);
imageLayout.setTileHeight(tileHeight);
final RenderingHints hints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, imageLayout);
return FormatDescriptor.create(image, dataType, hints);
}
public static RenderedOp loadImage(String filePath) {
System.out.println("Loading image from " + filePath);
return FileLoadDescriptor.create(filePath, null, true, null);
}
public static void displayImage(File location,
String extension,
AffineTransform imageToModelTransform,
int levelCount) {
final LayerCanvas layerCanvas = new LayerCanvas();
installLayerCanvasNavigation(layerCanvas);
final Layer collectionLayer = layerCanvas.getLayer();
final MultiLevelSource source = FileMultiLevelSource.create(location, extension, imageToModelTransform,
levelCount);
final ImageLayer layer = new ImageLayer(source);
collectionLayer.getChildren().add(layer);
final Rectangle viewportBounds = new Rectangle(0, 0, 640, 480);
layerCanvas.setPreferredSize(new Dimension(640, 480));
layerCanvas.getViewport().setViewBounds(viewportBounds);
layerCanvas.getViewport().zoom(layer.getModelBounds());
openFrame(layerCanvas, location.getPath(), viewportBounds);
}
public static void displayImage(String title,
RenderedImage image,
AffineTransform imageToModelTransform,
int levelCount) {
displayImages(title,
new RenderedImage[]{image},
new AffineTransform[]{imageToModelTransform},
levelCount);
}
public static void displayImages(String title, RenderedImage[] images,
AffineTransform[] imageToModelTransforms,
int levelCount) {
final LayerCanvas layerCanvas = new LayerCanvas();
installLayerCanvasNavigation(layerCanvas);
final Layer collectionLayer = layerCanvas.getLayer();
for (int i = 0; i < images.length; i++) {
final ImageLayer layer = new ImageLayer(images[i], imageToModelTransforms[i], levelCount);
collectionLayer.getChildren().add(layer);
}
openFrame(layerCanvas, title, new Rectangle(0, 0, 512, 512));
}
public static void dumpImageInfo(RenderedImage image) {
final SampleModel sampleModel = image.getSampleModel();
final ColorModel colorModel = image.getColorModel();
System.out.println("image: " + image);
System.out.println(" minX = " + image.getMinX());
System.out.println(" minY = " + image.getMinY());
System.out.println(" width = " + image.getWidth());
System.out.println(" height = " + image.getHeight());
System.out.println(" colorModel = " + (colorModel != null ? colorModel.getClass() : "null"));
System.out.println(" colorSpace = " + (colorModel != null ? colorModel.getColorSpace() : "null"));
System.out.println(" sampleModel = " + sampleModel.getClass());
System.out.println(" numBands = " + sampleModel.getNumBands());
System.out.println(" dataType = " + sampleModel.getDataType());
System.out.println(" transferType = " + sampleModel.getTransferType());
System.out.println(" tileGridXOffset = " + image.getTileGridXOffset());
System.out.println(" tileGridYOffset = " + image.getTileGridYOffset());
System.out.println(" minTileX = " + image.getMinTileX());
System.out.println(" minTileY = " + image.getMinTileY());
System.out.println(" tileWidth = " + image.getTileWidth());
System.out.println(" tileHeight = " + image.getTileHeight());
}
public static void storeTiffPyramid(RenderedImage sourceImage, String targetBaseName, int maxLevel) {
ImageMIPMap imageMIPMap = new ImageMIPMap(sourceImage, AffineTransform.getScaleInstance(0.5, 0.5),
Interpolation.getInstance(Interpolation.INTERP_NEAREST));
for (int level = 0; level <= maxLevel; level++) {
final RenderedImage scaledImage = imageMIPMap.getImage(level);
storeTiledTiff(scaledImage, targetBaseName + "." + level + ".tif");
}
}
private static void openFrame(LayerCanvas layerCanvas, String title, Rectangle bounds) {
final JFrame frame = new JFrame(title);
frame.getContentPane().add(layerCanvas, BorderLayout.CENTER);
frame.setBounds(bounds);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void installLayerCanvasNavigation(LayerCanvas layerCanvas) {
layerCanvas.setNavControlShown(true);
final MouseHandler mouseHandler = new MouseHandler(layerCanvas);
layerCanvas.addMouseListener(mouseHandler);
layerCanvas.addMouseMotionListener(mouseHandler);
layerCanvas.addMouseWheelListener(mouseHandler);
}
public static class MouseHandler extends MouseInputAdapter {
private LayerCanvas layerCanvas;
private SliderPopUp sliderPopUp;
private Point p0;
private MouseHandler(LayerCanvas layerCanvas) {
this.layerCanvas = layerCanvas;
this.sliderPopUp = new SliderPopUp();
}
@Override
public void mousePressed(MouseEvent e) {
p0 = e.getPoint();
}
@Override
public void mouseReleased(final MouseEvent mouseEvent) {
if (mouseEvent.isPopupTrigger()) {
final Point point = mouseEvent.getPoint();
SwingUtilities.convertPointToScreen(point, layerCanvas);
sliderPopUp.show(point);
} else {
sliderPopUp.hide();
}
}
@Override
public void mouseDragged(MouseEvent e) {
final Point p = e.getPoint();
final double dx = p.x - p0.x;
final double dy = p.y - p0.y;
layerCanvas.getViewport().moveViewDelta(dx, dy);
p0 = p;
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
final int wheelRotation = e.getWheelRotation();
final double newZoomFactor = layerCanvas.getViewport().getZoomFactor() * Math.pow(1.1, wheelRotation);
layerCanvas.getViewport().setZoomFactor(newZoomFactor);
}
private class SliderPopUp {
private JWindow window;
private JSlider slider;
public void show(Point location) {
if (window == null) {
initUI();
}
final double oldZoomFactor = layerCanvas.getViewport().getZoomFactor();
slider.setValue((int) Math.round(10.0 * Math.log(oldZoomFactor) / Math.log(2.0)));
window.setLocation(location);
window.setVisible(true);
}
public void hide() {
if (window != null) {
window.setVisible(false);
}
}
private void initUI() {
window = new JWindow();
final int min = -100;
final int max = 100;
slider = new JSlider(min, max);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
final double newZoomFactor = Math.pow(2.0, slider.getValue() / 10.0);
layerCanvas.getViewport().setZoomFactor(newZoomFactor);
if (!slider.getValueIsAdjusting()) {
hide();
}
}
});
window.requestFocus();
window.setAlwaysOnTop(true);
window.add(slider);
window.pack();
window.addFocusListener(new FocusAdapter() {
@Override
public void focusLost(FocusEvent e) {
hide();
}
});
}
}
}
}