/* * org.openmicroscopy.shoola.util.ui.lens.LensModel.java * *------------------------------------------------------------------------------ * Copyright (C) 2006 University of Dundee. All rights reserved. * * * 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 2 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, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * *------------------------------------------------------------------------------ */ package org.openmicroscopy.shoola.util.ui.lens; //Java imports import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.image.DataBufferInt; import java.awt.image.Raster; import java.awt.image.SampleModel; import java.awt.image.WritableRaster; import org.openmicroscopy.shoola.util.ui.UIUtilities; /** * The Lens model controls the manipulation of the lens, creating the zoomed * version of the image to be displayed in the zoomPanel. * * @author Jean-Marie Burel      * <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a> * @author Donald MacDonald      * <a href="mailto:donald@lifesci.dundee.ac.uk">donald@lifesci.dundee.ac.uk</a> * @version 3.0 * <small> * (<b>Internal version:</b> $Revision: $Date: $) * </small> * @since OME2.2 */ class LensModel { /** Dark lens color, when the background of the image is light. */ static final Color LENS_DARK_COLOUR = new Color(96, 96, 96, 255); /** Light lens color, when the background of the image is Dark. */ static final Color LENS_LIGHT_COLOUR = new Color(196, 196, 196, 255); /** The default color of the background. */ static final Color DEFAULT_BACKGROUND = new Color(200, 200, 200); /** Minimum zoom allowed. */ final static int MINIMUM_ZOOM = 1; /** Maximum zoom allowed. */ final static int MAXIMUM_ZOOM = 10; /** * The default size of the pre-allocated buffer used to store the * zoomed image. */ final static int DEFAULT_SIZE = 562500; /** The minimum size of heapspace for the lens to still work. */ final static long MINHEAPSIZE = UIUtilities.MEGABYTE*8; /** X-coordinate of the lens. */ private int x; /** Y-coordinate of the lens. */ private int y; /** Width of the lens. */ private int width; /** Height of the lens. */ private int height; /** * ZoomFactor which will be used to convert the original image * represented by the viewport of the lens component to the image * shown by the zoomWindow. */ private float zoomFactor; /** The amount of zooming in the original image. */ private float imageZoomFactor; /** plane image. */ private BufferedImage planeImage; /** Pre-allocated buffer storing image data */ private DataBuffer zoomedDataBuffer; /** * Size of the zoomedDatabuffer, used to see if a new Buffer * will exceed the size of the current buffer. */ private int zoomedDataBufferSize; /** The background color. */ private Color background; /** The name of the image.*/ private String imageName; /** Flushes the data buffer. */ private void flushDataBuffer() { //System.gc(); zoomedDataBuffer = null; } /** * Returns a writable raster to the {@link #scaleBufferedImage} method. * This method will allocate a new databuffer only if the new raster is * larger than the pre-allocated one. * * @param dataBufferType The type of the data buffer. * @param colorModel The color model. * @param w The width of new image. * @param h The height of new image * @return See above. */ private WritableRaster getZoomedRaster(int dataBufferType, ColorModel colorModel, int w, int h) { double f = zoomFactor*zoomFactor; //reset dataBuffer switch (dataBufferType) { case DataBuffer.TYPE_INT: if (zoomedDataBuffer instanceof DataBufferByte) flushDataBuffer(); break; case DataBuffer.TYPE_BYTE: if (zoomedDataBuffer instanceof DataBufferInt) flushDataBuffer(); } if (zoomedDataBufferSize < height*width*f) { flushDataBuffer(); switch (dataBufferType) { case DataBuffer.TYPE_INT: zoomedDataBuffer = new DataBufferInt((int)(150*150*f), 1); break; case DataBuffer.TYPE_BYTE: zoomedDataBuffer = new DataBufferByte((int)(150*150*f), 1); break; } } else { if (zoomedDataBuffer != null && zoomedDataBuffer.getSize() != DEFAULT_SIZE) flushDataBuffer(); } if (zoomedDataBuffer == null) { switch (dataBufferType) { case DataBuffer.TYPE_INT: zoomedDataBuffer = new DataBufferInt(DEFAULT_SIZE, 1); break; case DataBuffer.TYPE_BYTE: zoomedDataBuffer = new DataBufferByte(DEFAULT_SIZE, 1); break; } } if (dataBufferType == DataBuffer.TYPE_BYTE && zoomedDataBuffer.getSize() < (w * h * 3)) // if type==byte (i.e. compressed images) the buffer size has to be // w * h * 3 at least zoomedDataBuffer = new DataBufferByte((w * h * 3), 1); SampleModel sm = colorModel.createCompatibleSampleModel(w, h); return Raster.createWritableRaster(sm, zoomedDataBuffer, null); } /** * Scales the image to the new size xScale, yScale. * * @param image Buffered Image to be scaled. * @param xScale x scale factor for image, as a percent. * @param yScale y scale factor for image, as a percent. * @return thumbImage scaled image. */ private BufferedImage scaleBufferedImage(BufferedImage image, float xScale, float yScale) { int thumbHeight = (int) (image.getHeight()*yScale); int thumbWidth = (int) (image.getWidth()*xScale); // Create the required compatible (thumbnail) buffered image to // avoid potential errors from Java's ImagingLib. ColorModel cm = image.getColorModel(); int type = image.getData().getDataBuffer().getDataType(); WritableRaster r = getZoomedRaster(type, cm, thumbWidth, thumbHeight); BufferedImage thumbImage = new BufferedImage(cm, r, false, null); // Do the actual scaling and return the result Graphics2D graphics2D = thumbImage.createGraphics(); graphics2D.drawImage(image, 0, 0, thumbWidth, thumbHeight, null); graphics2D.dispose(); //System.gc(); return thumbImage; } /** * Creates a new instance. * * @param planeImage The image to handle. */ LensModel(BufferedImage planeImage) { this.planeImage = planeImage; x = 0; y = 0; width = LensComponent.LENS_DEFAULT_WIDTH; height = LensComponent.LENS_DEFAULT_WIDTH; setBackgroundColor(DEFAULT_BACKGROUND); zoomedDataBufferSize = DEFAULT_SIZE; } /** * Sets the plane image to a new image. * * @param img new PlaneImage. */ void setPlaneImage(BufferedImage img) { planeImage = img; } /** * Returns the width of the plane Image. * * @return See above. */ int getImageWidth() { if (planeImage != null) return planeImage.getWidth(); return 0; } /** * Returns the width of the plane Image. * * @return See above. */ int getImageScaledWidth() { return (int) (getImageWidth()*imageZoomFactor); } /** * Returns the height of the plane Image. * * @return See above. */ int getImageScaledHeight() { return (int) (getImageHeight()*imageZoomFactor); } /** * Returns the height of the plane Image. * * @return See above. */ int getImageHeight() { if (planeImage != null) return planeImage.getHeight(); return 0; } /** * Returns the zoomedImage from the model. * * @return See above. */ BufferedImage getZoomedImage() { /* if (UIUtilities.getFreeMemory() < MINHEAPSIZE) { Runtime.getRuntime().gc(); return null; } */ try { if (planeImage == null) return null; ColorModel cm = planeImage.getColorModel(); Raster raster = planeImage.getData(); Raster r = raster.createChild(getX(), getY(), getWidth(), getHeight(), 0, 0, null); BufferedImage img = new BufferedImage(cm, (WritableRaster) r, false, null); return scaleBufferedImage(img, zoomFactor, zoomFactor); } catch (Exception e) { } return null; } /** * Creates a zoomed version of the passed image. * * @param image The image to zoom. * @return See above. */ BufferedImage createZoomedImage(BufferedImage image) { if (image == null) return null; ColorModel cm = image.getColorModel(); Raster r = image.getData().createChild(getX(), getY(), getWidth(), getHeight(), 0, 0, null); BufferedImage img = new BufferedImage(cm, (WritableRaster) r, false, null); int thumbHeight = (int) (img.getHeight()*zoomFactor); int thumbWidth = (int) (img.getWidth()*zoomFactor); // Create the required compatible (thumbnail) buffered image to // avoid potential errors from Java's ImagingLib. int type = image.getData().getDataBuffer().getDataType(); WritableRaster wr = getZoomedRaster(type, cm, thumbWidth, thumbHeight); BufferedImage thumbImage = new BufferedImage(img.getColorModel(), wr, false, null); //Do the actual scaling and return the result Graphics2D graphics2D = thumbImage.createGraphics(); graphics2D.drawImage(img, 0, 0, thumbWidth, thumbHeight, null); graphics2D.dispose(); //System.gc(); return thumbImage; } /** * Returns the height of the lens. * * @return See above. */ int getHeight() { return height; } /** * Returns the width of the lens. * * @return See above. */ int getWidth() { return width; } /** * Returns the height of the lens. * * @return See above. */ int getScaledHeight() { return (int) Math.ceil(height*imageZoomFactor); } /** * Returns the width of the lens. * * @return See above. */ int getScaledWidth() { return (int) Math.ceil(width*imageZoomFactor); } /** * Returns the x-coordinate of the lens. * * @return See above. */ int getX() { return x; } /** * Returns the y-coordinate of the lens. * @return See above. */ int getY() { return y; } /** * Returns the x-coordinate of the lens multiplied by the magnification * factor. * * @return See above. */ int getScaledX() { return (int) (x*imageZoomFactor); } /** * Returns the y-coordinate of the lens multiplied by the magnification * factor. * * @return See above. */ int getScaledY() { return (int) (y*imageZoomFactor); } /** * Sets the height of the lens. * * @param height The height to set. */ void setHeight(int height) { this.height = height; } /** * Sets the width of the lens. * * @param width The width to set. */ void setWidth(int width) { this.width = width; } /** * Sets the location of the lens. * * @param x The x-coordinate to set. * @param y The y-coordinate to set. */ void setLensLocation(int x, int y) { this.x = x; this.y = y; } /** * Returns the current magnification factor of the lens. * * @return See above. */ float getZoomFactor() { return zoomFactor; } /** * Sets the zoom factor. * * @param zoomFactor The zoomFactor to set. */ void setZoomFactor(float zoomFactor) { this.zoomFactor = zoomFactor; } /** * Sets the image zoom factor. The image in the viewer has been zoomed by * this number. * * @param imageZoomFactor The amount of zooming that has occurred on the * image. */ void setImageZoomFactor(float imageZoomFactor) { this.imageZoomFactor = imageZoomFactor; } /** * Returns the image zoom factor. The image in the viewer has been zoomed by * this number. * * @return See above. */ float getImageZoomFactor() { return imageZoomFactor; } /** * Returns the scaled size of the lens, scaled by the imageZoomFactor. * * @return See above. */ Dimension getLensScaledSize() { return new Dimension(getScaledWidth(), getScaledHeight()); } /** * Returns the scaled location of the lens, scaled by the * imageZoomFactor. * * @return See above. */ Point getLensScaledLocation() { return new Point(getScaledX(), getScaledY()); } /** * Returns the location of the lens. * * @return See above. */ Point getLensLocation() { return new Point(getX(), getY()); } /** * Returns the bounds of the scaled image size, takes into account the zoom * factor of the image viewer. * * @return See above. */ Rectangle getLensScaledBounds() { Point p = getLensScaledLocation(); Dimension d = getLensScaledSize(); return new Rectangle(p.x, p.y, d.width, d.height); } /** * Depending on the sampled colour of the image; if the image is * predominantly dark returns a light lens else returns a dark lens * colour. Returns <code>null</code> if the image is <code>null</code>. * * @return See above. */ Color getLensPreferredColour() { /* if (planeImage != null) { long r = 0, g = 0, b = 0; long cnt = 0, total = 0; for (int i = 0 ; i < planeImage.getWidth() ; i+=10) for (int j = 0 ; j < planeImage.getHeight() ; j+= 10) { cnt++; Color c = new Color(planeImage.getRGB(i, j)); r = c.getRed(); g = c.getGreen(); b = c.getBlue(); total += (r+g+b)/3; } if ((total)/(cnt) > 128) return LENS_DARK_COLOUR; return LENS_LIGHT_COLOUR; } */ return LENS_LIGHT_COLOUR; } /** Resets the data buffer. */ void resetDataBuffer() { zoomedDataBuffer = null; zoomedDataBufferSize = DEFAULT_SIZE; } /** * Returns the background. * * @return See above. */ Color getBackgroundColor() { return background; } /** * Sets the background color. * * @param color The value to set. */ void setBackgroundColor(Color color) { if (color == null) background = DEFAULT_BACKGROUND; background = color; } /** * Sets the name of the image. * * @param imageName The name of the image. */ void setImageName(String imageName) { this.imageName = imageName;} /** * Returns the name of the image. * * @return See above. */ String getImageName() { return imageName; } }