/* *------------------------------------------------------------------------------ * Copyright (C) 2006-2015 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.agents.metadata.rnd; import java.awt.Color; import java.awt.Dimension; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.collections.CollectionUtils; import omero.romio.PlaneDef; import org.openmicroscopy.shoola.agents.metadata.MetadataViewerAgent; import org.openmicroscopy.shoola.agents.metadata.RenderingControlShutDown; import org.openmicroscopy.shoola.agents.metadata.view.MetadataViewer; import org.openmicroscopy.shoola.agents.util.ViewerSorter; import org.openmicroscopy.shoola.env.data.OmeroImageService; import omero.gateway.SecurityContext; import omero.gateway.exception.DSOutOfServiceException; import omero.gateway.exception.RenderingServiceException; import omero.log.LogMessage; import omero.model.Length; import omero.model.LengthI; import omero.model.enums.UnitsLength; import org.openmicroscopy.shoola.env.rnd.RenderingControl; import org.openmicroscopy.shoola.env.rnd.RndProxyDef; import org.openmicroscopy.shoola.env.rnd.data.ResolutionLevel; import org.openmicroscopy.shoola.util.file.modulo.ModuloInfo; import org.openmicroscopy.shoola.util.file.modulo.ModuloParser; import org.openmicroscopy.shoola.util.image.geom.Factory; import omero.gateway.model.ChannelData; import omero.gateway.model.ImageData; import omero.gateway.model.PixelsData; import omero.gateway.model.XMLAnnotationData; /** * The Model component in the <code>Renderer</code> MVC triad. * * @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 * @since 3.0-Beta4 */ class RendererModel { /** The maximum width of the preview image. */ static final int PREVIEW_WIDTH = 256; /** The maximum height of the preview image. */ static final int PREVIEW_HEIGHT = 256; /** Identifies the minimum value of the device space. */ static final int CD_START = 0; /** Identifies the maximum value of the device space. */ static final int CD_END = 255; /** Flag to select a 1-bit depth (<i>=2^1-1</i>) output interval. */ static final int DEPTH_1BIT = RenderingControl.DEPTH_1BIT; /** Flag to select a 2-bit depth (<i>=2^2-1</i>) output interval. */ static final int DEPTH_2BIT = RenderingControl.DEPTH_2BIT; /** Flag to select a 3-bit depth (<i>=2^3-1</i>) output interval. */ static final int DEPTH_3BIT = RenderingControl.DEPTH_3BIT; /** Flag to select a 4-bit depth (<i>=2^4-1</i>) output interval. */ static final int DEPTH_4BIT = RenderingControl.DEPTH_4BIT; /** Flag to select a 5-bit depth (<i>=2^5-1</i>) output interval. */ static final int DEPTH_5BIT = RenderingControl.DEPTH_5BIT; /** Flag to select a 6-bit depth (<i>=2^6-1</i>) output interval. */ static final int DEPTH_6BIT = RenderingControl.DEPTH_6BIT; /** Flag to select a 7-bit depth (<i>=2^7-1</i>) output interval. */ static final int DEPTH_7BIT = RenderingControl.DEPTH_7BIT; /** Flag to select a 8-bit depth (<i>=2^8-1</i>) output interval. */ static final int DEPTH_8BIT = RenderingControl.DEPTH_8BIT; /** Identifies the <code>Linear</code> family. */ static final String LINEAR = RenderingControl.LINEAR; /** Identifies the <code>Exponential</code> family. */ static final String LOGARITHMIC = RenderingControl.LOGARITHMIC; /** Identifies the <code>Exponential</code> family. */ static final String EXPONENTIAL = RenderingControl.EXPONENTIAL; /** Identifies the <code>Exponential</code> family. */ static final String POLYNOMIAL = RenderingControl.POLYNOMIAL; /** Reference to the component that embeds this model. */ private Renderer component; /** Reference to the rendering control. */ private RenderingControl rndControl; /** The current state of the component. */ private int state; /** The index of the selected channel. */ private int selectedChannelIndex; /** Flag to denote if the widget is visible or not. */ private boolean visible; /** The index of the rendering. */ private int rndIndex; /** The collection of sorted channels. */ private List<ChannelData> sortedChannel; /** * The global minimum of all channels if the number of channels is * greater than {@code Renderer#MAX_CHANNELS}. */ private Double globalMinChannels; /** * The global maximum of all channels if the number of channels is * greater than {@code Renderer#MAX_CHANNELS}. */ private Double globalMaxChannels; /** The plane object to render. */ private PlaneDef plane; /** The dimension of the preview image. */ private Dimension previewSize; /** The rendering settings. */ private RndProxyDef rndDef; /** Keeps track of the changes to the rendering settings */ private RenderingDefinitionHistory history = new RenderingDefinitionHistory(); /** Reference to the image. */ private ImageData image; /** The security context.*/ private SecurityContext ctx; /** Map hosting the extra dimension if available.*/ private Map<Integer, ModuloInfo> modulo; /** he alternative rendering settings if any.*/ private RndProxyDef def; /** * Creates a new instance. * * @param ctx The security context. * @param rndControl Reference to the component that controls the * rendering settings. Mustn't be <code>null</code>. * @param rndIndex The index associated to the renderer. * @param def The alternative rendering settings if any. */ RendererModel(SecurityContext ctx, RenderingControl rndControl, int rndIndex, RndProxyDef def) { if (rndControl == null) throw new NullPointerException("No rendering control."); setRenderingControl(rndControl); this.ctx = ctx; this.rndIndex = rndIndex; visible = false; globalMaxChannels = null; globalMinChannels = null; plane = new PlaneDef(); plane.slice = omero.romio.XY.value; this.def = def; } /** * Returns the security context. * * @return See above. */ SecurityContext getSecurityContext() { return ctx; } /** * Sets the image the component is for. * * @param image The value to set. */ void setImage(ImageData image) { this.image = image; } /** * Sets the rendering control. * * @param rndControl Reference to the component that controls the * rendering settings. Mustn't be <code>null</code>. */ void setRenderingControl(RenderingControl rndControl) { this.rndControl = rndControl; if (rndControl != null) { rndDef = rndControl.getRndSettingsCopy(); history.reset(); } } /** * Returns the image the renderer is for. * * @return See above. */ ImageData getRefImage() { return image; } /** * Returns <code>true</code> if one channel is selected, * <code>false</code> otherwise. * * @return See above. */ boolean hasSelectedChannel() { return selectedChannelIndex >= 0; } /** * Returns the index of a channel or <code>-1</code>. * * @return See above. */ int createSelectedChannel() { //Set the selected channel List<Integer> active = getActiveChannels(); List<ChannelData> list = getChannelData(); Iterator<ChannelData> i = list.iterator(); ChannelData channel; int index; int setIndex = -1; while (i.hasNext()) { channel = i.next(); index = channel.getIndex(); if (active.contains(index) && setIndex < 0) { setIndex = index; break; } } return setIndex; } /** * Returns the color associated to the channel. * * @param index The index of the channel. * @return See above. */ Color getChannelColor(int index) { if (rndControl == null) return Color.white; return rndControl.getRGBA(index); } /** * Returns the status of the window. * * @return See above. */ boolean isVisible() { return visible; } /** * Called by the <code>Renderer</code> after creation to allow this * object to store a back reference to the embedding component. * * @param component The embedding component. */ void initialize(Renderer component) { this.component = component; } /** Discards component. */ void discard() { if (rndControl == null) return; RenderingControlShutDown loader = new RenderingControlShutDown(ctx, rndControl.getPixelsID()); loader.load(); rndControl = null; } /** * Returns the state of the component. * * @return See above. */ int getState() { return state; } /** * Sets the pixels intensity interval for the specified channel. * or for all channels if the number of channels is greater than * {@link Renderer#MAX_CHANNELS} * * @param index The index of the channel. * @param start The lower bound of the interval. * @param end The upper bound of the interval. * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ void setInputInterval(int index, double start, double end) throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return; if (isLifetimeImage() && getModuloT() == null) { for (int i = 0; i < getMaxC(); i++) { rndControl.setChannelWindow(i, start, end); } } else rndControl.setChannelWindow(index, start, end); } /** * Returns the upper bound of the sub-interval of the device space. * * @return See above. */ int getCodomainEnd() { if (rndControl == null) return -1; return rndControl.getCodomainEnd(); } /** * Returns the lower bound of the sub-interval of the device space. * * @return See above. */ int getCodomainStart() { if (rndControl == null) return -1; return rndControl.getCodomainStart(); } /** * Sets the sub-interval of the device space. * * @param s The lower bound of the interval. * @param e The upper bound of the interval. * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ void setCodomainInterval(int s, int e) throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return; rndControl.setCodomainInterval(s, e); } /** * Sets the quantum strategy. * * @param v The bit resolution defining the strategy. * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ void setBitResolution(int v) throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return; rndControl.setQuantumStrategy(v); } /** * Sets the selected channel. * * @param index The index of the selected channel. */ void setSelectedChannel(int index) { selectedChannelIndex = index; } /** * Sets the family used during the mapping process for the specified channel. * * @param channel The selected channel. * @param family The family to set. * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ void setFamily(int channel, String family) throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return; if (channel < 0 || channel > getMaxC()) channel = selectedChannelIndex; boolean b = rndControl.getChannelNoiseReduction(selectedChannelIndex); double k = rndControl.getChannelCurveCoefficient(selectedChannelIndex); rndControl.setQuantizationMap(channel, family, k, b); } /** * Selects one curve in the family. * * @param k The coefficient identifying a curve within a family. * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ void setCurveCoefficient(double k) throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return; boolean b = rndControl.getChannelNoiseReduction(selectedChannelIndex); String family = rndControl.getChannelFamily(selectedChannelIndex); rndControl.setQuantizationMap(selectedChannelIndex, family, k, b); } /** * Turns on and off the noise reduction algorithm mapping. * * @param b Pass <code>true</code> to turn it on, * <code>false</code> otherwise. * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ void setNoiseReduction(boolean b) throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return; String family = rndControl.getChannelFamily(selectedChannelIndex); double k = rndControl.getChannelCurveCoefficient(selectedChannelIndex); rndControl.setQuantizationMap(selectedChannelIndex, family, k, b); } /** * Updates the specified {@link CodomainMapContext context}. * * @param ctx The context to update. * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ /* void updateCodomainMap(CodomainMapContext ctx) throws RenderingServiceException, DSOutOfServiceException { rndControl.updateCodomainMap(ctx); } */ /** * Returns the codomain map context corresponding to the specified * <code>codomain</code> class. Returns <code>null</code> if there is no * context matching the class. * * @param mapType The class corresponding to the context to retrieve. * @return See above. */ /* CodomainMapContext getCodomainMap(Class mapType) { List maps = getCodomainMaps(); Iterator i = maps.iterator(); CodomainMapContext ctx; while (i.hasNext()) { ctx = (CodomainMapContext) i.next(); if (ctx.getClass().equals(mapType)) return ctx; } return null; } */ /** * Returns a read-only list of {@link CodomainMapContext}s using during * the mapping process in the device space. * * @return See above. */ List getCodomainMaps() { if (rndControl == null) return new ArrayList(); return rndControl.getCodomainMaps(); } /** * Removes the codomain map identified by the class from the chain of * codomain transformations. * * @param mapType The type to identify the codomain map. * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ /* void removeCodomainMap(Class mapType) throws RenderingServiceException, DSOutOfServiceException { CodomainMapContext ctx = getCodomainMap(mapType); if (ctx != null) rndControl.removeCodomainMap(ctx); } */ /** * Adds the codomain map identified by the class to the chain of * codomain transformations. * * @param mapType The type to identify the codomain map. * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ /* void addCodomainMap(Class mapType) throws RenderingServiceException, DSOutOfServiceException { if (mapType.equals(ReverseIntensityContext.class)) { ReverseIntensityContext riCtx = new ReverseIntensityContext(); riCtx.setReverse(Boolean.TRUE); rndControl.addCodomainMap(riCtx); } else if (mapType.equals(PlaneSlicingContext.class)) { } else if (mapType.equals(ContrastStretchingContext.class)) { } } */ /** * Returns the index of the currently selected channel. * * @return See above. */ int getSelectedChannel() { return selectedChannelIndex; } /** * Returns a list of available mapping families. * * @return See above. */ List getFamilies() { if (rndControl == null) return new ArrayList(); return rndControl.getFamilies(); } /** * Returns the mapping family used for to map the selected channel. * * @return See above. */ String getFamily() { return getFamily(selectedChannelIndex); } /** * Returns the mapping family used for to map the selected channel. * * @param channel The selected channel. * @return See above. */ String getFamily(int channel) { if (rndControl == null) return ""; return rndControl.getChannelFamily(channel); } /** * Returns the map selected in the family for the selected channel. * * @return See above. */ double getCurveCoefficient() { return getCurveCoefficient(selectedChannelIndex); } /** * Returns the map selected in the family for the selected channel. * * @param channel The selected channel. * @return See above. */ double getCurveCoefficient(int channel) { if (rndControl == null) return -1; return rndControl.getChannelCurveCoefficient(channel); } /** * Returns the bit resolution value. * * @return See above. */ int getBitResolution() { if (rndControl == null) return -1; return rndControl.getBitResolution(); } /** * Returns <code>true</code> if the noise reduction flag is turned on * for the selected channel, <code>false</code> otherwise. * * @return See above. */ boolean isNoiseReduction() { if (rndControl == null) return false; return rndControl.getChannelNoiseReduction(selectedChannelIndex); } /** * Returns a list of <code>Channel Data</code> objects. * * @return See above. */ List<ChannelData> getChannelData() { if (rndControl == null) return new ArrayList<ChannelData>(); if (sortedChannel == null) { ChannelData[] data = rndControl.getChannelData(); ViewerSorter sorter = new ViewerSorter(); sortedChannel = Collections.unmodifiableList(sorter.sort(data)); } return sortedChannel; } /** * Returns the global minimum of the currently selected channel * or of all channels if the number of channels is greater * {@link Renderer#MAX_CHANNELS}. * * @return See above. */ double getGlobalMin() { if (getMaxC() > Renderer.MAX_CHANNELS) { if (globalMinChannels == null) { double min = Double.MAX_VALUE; double value; for (int i = 0; i < getMaxC(); i++) { value = getGlobalMin(i); if (value < min) min = value; } globalMinChannels = min; } return globalMinChannels.doubleValue(); } return getGlobalMin(selectedChannelIndex); } /** * Returns the global maximum of the currently selected channel * or of all channels if the number of channels is greater * {@link Renderer#MAX_CHANNELS}. * * @return See above. */ double getGlobalMax() { if (getMaxC() > Renderer.MAX_CHANNELS) { if (globalMaxChannels == null) { double max = Double.MIN_VALUE; double value; for (int i = 0; i < getMaxC(); i++) { value = getGlobalMax(i); if (value > max) max = value; } globalMaxChannels = max; } return globalMaxChannels.doubleValue(); } return getGlobalMax(selectedChannelIndex); } /** * Returns the global maximum of the passed channel. * * @param index The index of the channel. * @return See above. */ double getGlobalMax(int index) { if (rndControl == null) return -1; return rndControl.getChannelData(index).getGlobalMax(); } /** * Returns the global minimum of the passed channel. * * @param index The index of the channel. * @return See above. */ double getGlobalMin(int index) { if (rndControl == null) return -1; return rndControl.getChannelData(index).getGlobalMin(); } /** * Returns the lowest possible value. * * @return See above. */ double getLowestValue() { return getLowestValue(selectedChannelIndex); } /** * Returns the lowest possible value for the passed channel. * * @param channel The channel to handle. * @return See above. */ double getLowestValue(int channel) { if (rndControl == null) return -1; return rndControl.getPixelsTypeLowerBound(channel); } /** * Returns the highest possible value. * * @return See above. */ double getHighestValue() { return getHighestValue(selectedChannelIndex); } /** * Returns the highest possible value. * * @param channel The channel to handle. * @return See above. */ double getHighestValue(int channel) { if (rndControl == null) return -1; return rndControl.getPixelsTypeUpperBound(channel); } /** * Returns the lower bound of the pixels intensity interval of the * specified channel. * * @param channel The index of the channel. * @return See above. */ double getWindowStart(int channel) { if (rndControl == null) return -1; return rndControl.getChannelWindowStart(channel); } /** * Returns the upper bound of the pixels intensity interval of the * specified channel. * * @param channel The index of the channel. * @return See above. */ double getWindowEnd(int channel) { if (rndControl == null) return -1; return rndControl.getChannelWindowEnd(channel); } /** * Returns the lower bound of the pixels intensity interval of the * currently selected channel. * * @return See above. */ double getWindowStart() { return getWindowStart(selectedChannelIndex); } /** * Returns the upper bound of the pixels intensity interval of the * currently selected channel. * * @return See above. */ double getWindowEnd() { return getWindowEnd(selectedChannelIndex); } /** * Returns <code>true</code> if the grey scale is selected, * <code>false</code> otherwise. * * @return See above. */ boolean isGreyScale() { if (rndControl == null) return false; return rndControl.getModel().equals(RenderingControl.GREY_SCALE); } /** * Saves the rendering settings. * * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ void saveRndSettings() throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return; rndDef = rndControl.saveCurrentSettings(); } /** * Returns <code>true</code> if the channel is mapped, <code>false</code> * otherwise. * * @param w The channel's index. * @return See above. */ boolean isChannelActive(int w) { if (rndControl == null) return false; return rndControl.isActive(w); } /** * Returns the reference to the history */ RenderingDefinitionHistory getRndDefHistory() { return history; } /** * Returns a list of active channels. * * @return See above. */ List<Integer> getActiveChannels() { List<Integer> active = new ArrayList<Integer>(); if (rndControl == null) return active; for (int i = 0; i < getMaxC(); i++) { if (rndControl.isActive(i)) active.add(Integer.valueOf(i)); } return active; } /** * Returns the number of channels. * * @return See above. */ int getMaxC() { if (rndControl == null) return -1; return rndControl.getPixelsDimensionsC(); } /** * Returns the index associated to the renderer. * * @return See above. */ int getRndIndex() { return rndIndex; } /** * Returns <code>true</code> if the renderer is for a general perspective * or for a specific view. * * @return See above. */ boolean isGeneralIndex() { return getRndIndex() == MetadataViewer.RND_GENERAL; } /** * Sets the color for the specified channel. * * @param index The channel's index. * @param color The color to set. * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ void setChannelColor(int index, Color color) throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return; rndControl.setRGBA(index, color); } /** * Returns the color model. * * @return See above. */ String getColorModel() { if (rndControl == null) return null; return rndControl.getModel(); } /** * Sets the color model. * * @param colorModel The color model to set. * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ void setColorModel(String colorModel) throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return; makeHistorySnapshot(); rndControl.setModel(colorModel); } /** * Returns the number of pixels along the X-axis. * * @return See above. */ int getMaxX() { if (rndControl == null) return -1; return rndControl.getPixelsDimensionsX(); } /** * Returns the number of pixels along the Y-axis. * * @return See above. */ int getMaxY() { if (rndControl == null) return -1; return rndControl.getPixelsDimensionsY(); } /** * Returns the maximum number of z-sections. * * @return See above. */ int getMaxZ() { if (rndControl == null) return -1; return rndControl.getPixelsDimensionsZ(); } /** * Returns the maximum number of time-points. * * @return See above. */ int getMaxT() { if (rndControl == null) return -1; return rndControl.getPixelsDimensionsT(); } /** * Returns the number of time points if modulo available. * * @return See above. */ int getRealT() { if (hasModuloT()) { int sizeBin = modulo.get(ModuloInfo.T).getSize(); return getMaxT()/sizeBin; } return getMaxT(); } /** * Returns the currently selected z-section. * * @return See above. */ int getDefaultZ() { if (rndControl == null) return -1; return rndControl.getDefaultZ(); } /** * Returns the currently selected time-point. * * @return See above. */ int getDefaultT() { if (rndControl == null) return -1; return rndControl.getDefaultT(); } /** * Returns the currently selected time-point. * * @return See above. */ int getRealSelectedT() { if (rndControl == null) return -1; if (hasModuloT()) { return rndControl.getDefaultT() / getMaxLifetimeBin(); } return rndControl.getDefaultT(); } /** * Sets the selected plane. * * @param z The z-section to set. * @param t The time-point to set. * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ void setSelectedXYPlane(int z, int t) throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return; if (t >= 0 && t != getDefaultT()) rndControl.setDefaultT(t); if (z >= 0 && z != getDefaultZ()) rndControl.setDefaultZ(z); } /** * Sets the selected z-section. * * @param z The z-section to set. * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ void setSelectedZ(int z) throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return; if (z >= 0 && z != getDefaultZ()) rndControl.setDefaultZ(z); } /** * Turns on or off the specified channel. * * @param index The index of the channel. * @param active Pass <code>true</code> to turn the channel on, * <code>false</code> to turn in off. * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ void setChannelActive(int index, boolean active) throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return; rndControl.setActive(index, active); } /** * Returns the compression level. * * @return See above. */ int getCompressionLevel() { if (rndControl == null) return -1; return rndControl.getCompressionLevel(); } /** * Returns the physical size of a pixels along the Y-axis. * * @return See above. */ Length getPixelsSizeY() { if (rndControl == null) return new LengthI(1, UnitsLength.PIXEL); return rndControl.getPixelsPhysicalSizeY(); } /** * Returns the physical size of a pixels along the X-axis. * * @return See above. */ Length getPixelsSizeX() { if (rndControl == null) return new LengthI(1, UnitsLength.PIXEL); return rndControl.getPixelsPhysicalSizeX(); } /** * Returns the physical size of a pixels along the Z-axis. * * @return See above. */ Length getPixelsSizeZ() { if (rndControl == null) return new LengthI(1, UnitsLength.PIXEL); return rndControl.getPixelsPhysicalSizeZ(); } /** * Returns a copy of the current rendering settings. * * @return See above. */ RndProxyDef getRndSettingsCopy() { if (rndControl == null) return null; return rndControl.getRndSettingsCopy(); } /** * Returns the alternative rendering settings. * * @return See above. */ RndProxyDef getAlternativeRndSettings() { return def; } /** * Returns the initial rendering settings. * * @return See above. */ RndProxyDef getInitialRndSettings() { return rndDef; } /** * Returns <code>true</code> if an active channel * is mapped to <code>Red</code> if the band is <code>0</code>, * <code>Red</code> if the band is <code>0</code>, * <code>Red</code> if the band is <code>0</code>, * <code>false</code> otherwise. * * @param band Pass <code>0</code> for <code>Red</code>, * <code>1</code> for <code>Green</code>, * <code>2</code> for <code>Blue</code>. * @return See above */ boolean hasActiveChannel(int band) { if (rndControl == null) return false; switch (band) { case 0: return rndControl.hasActiveChannelRed(); case 1: return rndControl.hasActiveChannelGreen(); case 2: return rndControl.hasActiveChannelBlue(); } return false; } /** * Returns <code>true</code> if the compression is turned on, * <code>false</code> otherwise. * * @return See above. */ boolean isCompressed() { if (rndControl == null) return false; return rndControl.isCompressed(); } /** * Returns <code>true</code> if the specified channel * is mapped to <code>Red</code> if the band is <code>0</code>, * <code>Red</code> if the band is <code>0</code>, * <code>Red</code> if the band is <code>0</code>, * <code>false</code> otherwise. * * @param band Pass <code>0</code> for <code>Red</code>, * <code>1</code> for <code>Green</code>, * <code>2</code> for <code>Blue</code>. * @param index The index of the channel. * @return See above */ boolean isColorComponent(int band, int index) { if (rndControl == null) return false; switch (band) { case 0: return rndControl.isChannelRed(index); case 1: return rndControl.isChannelGreen(index); case 2: return rndControl.isChannelBlue(index); } return false; } /** * Resets the default settings. * * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ void resetDefaults() throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return; rndControl.resetDefaults(); } /** * Resets the passed rendering settings. * * @param settings The rendering settings to reset. * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ void resetSettings(RndProxyDef settings) throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return; rndControl.resetSettings(settings); } /** * Saves the current settings. * * @return See above. * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ RndProxyDef saveCurrentSettings() throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return null; RndProxyDef def = rndControl.saveCurrentSettings(); rndDef = def; return def; } /** * Undoes the last change to the rendering settings * @throws RenderingServiceException * @throws DSOutOfServiceException */ void historyBack() throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return; RndProxyDef def; boolean canRedo = history.canRedo(); boolean isSame = rndControl.isSameSettings(history.getCurrent(), true, true); if (!canRedo && !isSame) def = history.backward(rndControl.getRndSettingsCopy()); else def = history.backward(); resetSettings(def); } /** * Redoes the previous change to the rendering settings * @throws RenderingServiceException * @throws DSOutOfServiceException */ void historyForward() throws RenderingServiceException, DSOutOfServiceException { RndProxyDef def = history.forward(); resetSettings(def); } /** * Stores the current rendering settings in the history */ void makeHistorySnapshot() { if (rndControl != null ) { if (history.getCurrent()==null || !rndControl.isSameSettings(history.getCurrent(), false)) history.add(rndControl.getRndSettingsCopy()); else history.resetPrevAction(); } } /** * Turns on or off the specified channel. * * @param index The index of the channel * @param active Pass <code>true</code> to turn the channel on, * <code>false</code> to turn it off. * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ void setActive(int index, boolean active) throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return; rndControl.setActive(index, active); } /** * Sets the compression level. * * @param compression The compression level. */ void setCompression(int compression) { if (rndControl == null) return; rndControl.setCompression(compression); } /** * Sets the original settings. * * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ void setOriginalRndSettings() throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return; rndControl.setOriginalRndSettings(); } /** * Checks if the passed set of pixels is compatible. * Returns <code>true</code> if the pixels set is compatible, * <code>false</code> otherwise. * * @param pixels The pixels to check. * @return See above. */ boolean validatePixels(PixelsData pixels) { if (rndControl == null) return false; return rndControl.validatePixels(pixels); } /** * Renders the specified plane. * * @param pDef The plane to render. * @return See above. * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ BufferedImage render(PlaneDef pDef) throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return null; return rndControl.render(pDef); } /** * Renders the specified plane. * * @param pDef The plane to render. * @param compression The compression level. * @return See above. * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ BufferedImage render(PlaneDef pDef, int compression) throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return null; return rndControl.render(pDef, compression); } /** * Returns <code>true</code> if the passed rendering settings are the same * that the current one, <code>false</code> otherwise. * * @param def The settings to check. * @param checkPlane Pass <code>true</code> to take into account the * z-section and time-point, <code>false</code> * otherwise. * @return See above. */ boolean isSameSettings(RndProxyDef def, boolean checkPlane) { if (rndControl == null) return false; return rndControl.isSameSettings(def, checkPlane); } /** * Returns <code>true</code> if the rendering settings * have been modified * * @return See above. */ boolean isModified() { if(rndControl!=null) { return !rndControl.isSameSettings(rndDef, true); } return false; } /** * Returns <code>true</code> if the image with the active channels * is an RGB image, <code>false</code> otherwise. * * @return See above. */ boolean isMappedImageRGB(List channels) { if (rndControl == null) return false; return rndControl.isMappedImageRGB(channels); } /** * Sets the overlays. * * @param tableID The id of the table. * @param overlays The overlays to set, or <code>null</code> to turn * the overlays off. */ void setOverlays(long tableID, Map<Long, Integer> overlays) throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return; rndControl.setOverlays(tableID, overlays); } /** * Renders the default plane. * * @return See above. */ BufferedImage renderImage() { plane.t = getDefaultT(); plane.z = getDefaultZ(); try { if (rndControl == null) return null; return rndControl.render(plane, RenderingControl.LOW); } catch (Exception e) { LogMessage msg = new LogMessage(); msg.append("Error while rendering the image."); msg.print(e); MetadataViewerAgent.getRegistry().getLogger().error(this, msg); } return null; } /** * Returns the dimension of the preview image. * * @return See above. */ Dimension getPreviewDimension() { if (previewSize != null) return previewSize; previewSize = Factory.computeThumbnailSize(PREVIEW_WIDTH, PREVIEW_HEIGHT, getMaxX(), getMaxY()); return previewSize; } /** * Resets the rendering settings. * * @throws RenderingServiceException If an error occurred while setting * the value. * @throws DSOutOfServiceException If the connection is broken. */ void resetRenderingSettings() throws RenderingServiceException, DSOutOfServiceException { rndControl.resetSettings(rndDef); } /** * Returns <code>true</code> if it is a large image, * <code>false</code> otherwise. * * @return See above. */ boolean isBigImage() { if (rndControl == null) return false; return rndControl.isBigImage(); } /** * Returns the number of bins per time interval. * * @return See above */ int getMaxLifetimeBin() { if (hasModuloT()) { ModuloInfo info = modulo.get(ModuloInfo.T); return info.getSize(); } if (isLifetimeImage()) return getMaxC()-1; return 0; } /** * Returns <code>true</code> if the image has extra dimension along T. * <code>false</code> otherwise. * * @return See above. */ boolean hasModuloT() { return (modulo != null && modulo.containsKey(ModuloInfo.T)); } /** * Returns the modulo info if it exists. * * @return See above. */ ModuloInfo getModuloT() { if (!hasModuloT()) return null; return modulo.get(ModuloInfo.T); } /** * Returns <code>true</code> if the image is a lifetime image, * <code>false</code> otherwise. * * @return See above. */ boolean isLifetimeImage() { if (hasModuloT()) return true; if (getMaxC() >= Renderer.MAX_CHANNELS) return true; return false; } /** * Returns the selected bin for lifetime image. * * @return See above. */ int getSelectedBin() { if (!isLifetimeImage()) return -1; if (hasModuloT()) { return getDefaultT()-getRealSelectedT()*getMaxLifetimeBin(); } List<Integer> active = getActiveChannels(); if (active == null || active.size() != 1) return 0; return active.get(0); } /** * Sets the selected lifetime bin. * * @param bin The selected bin. * @param t The selected t. */ void setSelectedBin(int bin, int t) throws RenderingServiceException, DSOutOfServiceException { if (hasModuloT()) { int binSize = getMaxLifetimeBin(); int v = bin + t * binSize; setSelectedXYPlane(getDefaultZ(), v); return; } List<ChannelData> channels = getChannelData(); ChannelData channel; Iterator<ChannelData> i = channels.iterator(); int index; while (i.hasNext()) { channel = i.next(); index = channel.getIndex(); setActive(index, index == bin); } } /** * Returns the dimension of a tile. * * @return See above. */ Dimension getTileSize() throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return new Dimension(0, 0); return rndControl.getTileSize(); } /** * Returns the possible resolution levels. This method should only be used * when dealing with large images. * * @return See above. */ int getResolutionLevels() { if (rndControl == null) return 1; return rndControl.getResolutionLevels(); } /** * Returns the currently selected resolution level. This method should only * be used when dealing with large images. * * @return See above. */ int getSelectedResolutionLevel() { if (rndControl == null) return 0; return rndControl.getSelectedResolutionLevel(); } /** * Sets resolution level. This method should only be used when dealing with * large images. * * @param level The value to set. */ void setSelectedResolutionLevel(int level) throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return; rndControl.setSelectedResolutionLevel(level); } /** * Sets the channels. * * @param channels The updated channels. */ void setChannels(List<ChannelData> channels) { ViewerSorter sorter = new ViewerSorter(); sortedChannel = Collections.unmodifiableList(sorter.sort(channels)); } /** * Returns <code>true</code> if the object can be annotated, * <code>false</code> otherwise, depending on the permission. * * @return See above. */ boolean canAnnotate() { ImageData image = getRefImage(); if (image == null) return false; return image.canAnnotate(); } /** * Returns the collection of rendering controls. This method should only * be invoked when loading tiles. * * @return See above. */ List<RenderingControl> getRenderingControls() { if (rndControl == null) return null; List<RenderingControl> list = new ArrayList<RenderingControl>(); list.add(rndControl); List<RenderingControl> slaves = rndControl.getSlaves(); if (slaves != null && slaves.size() > 0) list.addAll(slaves); return list; } /** * Returns the list of the levels. * * @return See above. */ List<ResolutionLevel> getResolutionDescriptions() throws RenderingServiceException, DSOutOfServiceException { if (rndControl == null) return null; return rndControl.getResolutionDescriptions(); } /** * Sets the annotations and parses the content. * * @param annotations The annotations to parse. */ void setXMLAnnotations(Collection<XMLAnnotationData> annotations) { modulo = new HashMap<Integer, ModuloInfo>(); if (CollectionUtils.isEmpty(annotations)) return; ModuloParser parser; Iterator<XMLAnnotationData> i = annotations.iterator(); XMLAnnotationData data; List<ModuloInfo> infos; Iterator<ModuloInfo> j; ModuloInfo info; while (i.hasNext()) { data = i.next(); parser = new ModuloParser(data.getText()); try { parser.parse(); infos = parser.getModulos(); j = infos.iterator(); while (j.hasNext()) { info = j.next(); modulo.put(info.getModuloIndex(), info); } } catch (Exception e) { LogMessage msg = new LogMessage(); msg.append("Error while reading modulo annotation."); msg.print(e); MetadataViewerAgent.getRegistry().getLogger().error(this, msg); } } } /** * Set the color mode to greyscale or RGB * * @param b <code>true</code> for switching to greyscale, RGB otherwise */ void setGreyscale(boolean b) { if(b) component.setColorModel(Renderer.GREY_SCALE_MODEL, true); else component.setColorModel(Renderer.RGB_MODEL, true); } /** * Checks if the image pixel type is integer * @return See above */ boolean isIntegerPixelData() { String t = image.getDefaultPixels().getPixelType(); return t.equals(OmeroImageService.INT_8) || t.equals(OmeroImageService.UINT_8) || t.equals(OmeroImageService.INT_16) || t.equals(OmeroImageService.UINT_16) || t.equals(OmeroImageService.INT_32) || t.equals(OmeroImageService.UINT_32); } }