/*
* omeis.providers.re.Renderer
*
* Copyright 2006 University of Dundee. All rights reserved.
* Use is subject to license terms supplied in LICENSE.txt
*/
package omeis.providers.re;
import java.awt.Dimension;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ome.conditions.ResourceError;
import ome.io.nio.PixelBuffer;
import ome.model.core.Pixels;
import ome.model.display.ChannelBinding;
import ome.model.display.QuantumDef;
import ome.model.display.RenderingDef;
import ome.model.enums.Family;
import ome.model.enums.PixelsType;
import ome.model.enums.RenderingModel;
import omeis.providers.re.codomain.CodomainChain;
import omeis.providers.re.data.PlaneDef;
import omeis.providers.re.data.PlaneFactory;
import omeis.providers.re.data.RegionDef;
import omeis.providers.re.quantum.QuantizationException;
import omeis.providers.re.quantum.QuantumFactory;
import omeis.providers.re.quantum.QuantumStrategy;
/**
* Transforms raw image data into an <i>RGB</i> image that can be displayed on
* screen.
* <p>
* Every instance of this class works against a given pixels set within an
* <i>OME</i> Image (recall that an Image can have more than one pixels set)
* and holds the rendering environment for that pixels set. Said environment is
* composed of:
* </p>
* <ul>
* <li>Resources to access pixels raw data and metadata.</li>
* <li>Cached pixels metadata (statistic measurements).</li>
* <li>Settings that define the transformation context that is, a
* specification of how raw data is to be transformed into an image that can be
* displayed on screen.</li>
* <li>Resources to apply the transformations defined by the transformation
* context to raw pixels.</li>
* </ul>
* <p>
* This class delegates the actual rendering to a {@link RenderingStrategy},
* which is selected depending on how transformed data is to be mapped into a
* color space.
* </p>
*
* @see RenderingDef
* @see QuantumManager
* @see CodomainChain
* @see RenderingStrategy
* @author Jean-Marie Burel <a
* href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a>
* @author <br>
* Andrea Falconi <a
* href="mailto:a.falconi@dundee.ac.uk"> a.falconi@dundee.ac.uk</a>
* @version 2.2 <small> (<b>Internal version:</b> $Revision$ $Date:
* 2005/07/05 16:13:52 $) </small>
* @since OME2.2
*/
public class Renderer {
/** The logger for this particular class */
private static Logger log = LoggerFactory.getLogger(Renderer.class);
/** The maximum number of channels. */
public static final int MAX_CHANNELS = 8;
/** Identifies the type used to store model values. */
public static final String MODEL_GREYSCALE = "greyscale";
/** Identifies the type used to store model values. */
public static final String MODEL_RGB = "rgb";
/** Identifies the type used to store model values. */
public static final String MODEL_HSB = MODEL_RGB;
/** Identifies the type used to store photometric interpretation values. */
public static final String PHOTOMETRIC_MONOCHROME = "Monochrome";
//static final String RGB_COLOR_DOMAIN = "RGB";
/**
* The {@link Pixels} object to access the metadata of the pixels set bound
* to this <code>Renderer</code>.
*/
private Pixels metadata;
/** The settings that define the transformation context. */
private RenderingDef rndDef;
/** The object that allows access the raw pixel data. */
private PixelBuffer buffer;
/**
* Manages and allows to retrieve the objects that are used to quantize
* wavelength data.
*/
private QuantumManager quantumManager;
/**
* Defines the sequence of spatial transformations to apply to quantized
* data.
*/
private CodomainChain codomainChain;
/**
* Takes care of the actual rendering, using this <code>Renderer</code> as
* a rendering context.
*/
private RenderingStrategy renderingStrategy;
/**
* Collects performance measurements during each invocation of the
* {@link #render(PlaneDef) render} method.
*/
private RenderingStats stats;
/** Renderer optimizations. */
private Optimizations optimizations = new Optimizations();
/** Map of overlays we've currently been told to render. */
private Map<byte[], Integer> overlays;
/**
* Returns a copy of a list of channel bindings with one element removed;
* the so called "other" channel bindings for the image.
*
* @param bindings The original bindings.
* @param toRemove The bindings to remove.
* @throws IllegalArgumentException if the <code>toRemove</code> channel
* binding is not present in the list.
* @return See above.
*/
private List<ChannelBinding> getOtherBindings(
List<ChannelBinding> bindings, ChannelBinding toRemove)
{
if (!bindings.contains(toRemove))
throw new IllegalArgumentException(
"Channel binding not found in list.");
List<ChannelBinding> otherBindings =
new ArrayList<ChannelBinding>(bindings.size() - 1);
for (ChannelBinding binding : bindings)
{
if (binding != toRemove)
otherBindings.add(binding);
}
return otherBindings;
}
/**
* Returns <code>true</code> if the color is black or white,
* <code>false</code> otherwise.
*
* @param color The array representing an RGB color.
* @return See above.
*/
private boolean isEndColor(int[] color)
{
if (color[0] == 255 && color[1] == 255 && color[2] == 255)
return true;
if (color[0] == 0 && color[1] == 0 && color[2] == 0) return true;
return false;
}
/**
* Checks to see if we can enable specific optimizations for "primary" color
* rendering and alphaless rendering.
*
* Alphaless rendering is only enabled when each of the active channels has
* no alpha blending (alpha of 0xFF [255]).
*
* Primary color rendering optimizations are only enabled when the
* number of active channels < 4, each of the active channels is mapped
* to a primary color (0xFF0000 [Red], 0x00FF00 [Green], 0x0000FF [Blue])
* and there are no duplicate mappings (two channels mapped to Green for
* example). It is also dependent on alphaless rendering being enabled.
*/
private void checkOptimizations()
{
List<ChannelBinding> channelBindings = getChannelBindingsAsList();
for (ChannelBinding channelBinding : channelBindings)
{
boolean isActive = channelBinding.getActive();
if (isActive && channelBinding.getAlpha() != 255)
{
log.info("Disabling alphaless rendering and " +
"PriColor rendering.");
optimizations.setAlphalessRendering(false);
return;
}
}
log.info("Enabling alphaless rendering.");
optimizations.setAlphalessRendering(true);
int channelsActive = 0;
for (ChannelBinding channelBinding : channelBindings)
{
// First lets check and see if we have more than 3 channels active.
if (channelBinding.getActive() == false)
continue;
channelsActive++;
if (overlays != null && overlays.size() > 0)
{
log.info("Disabling PriColor rendering, have overlays.");
optimizations.setPrimaryColorEnabled(false);
return;
}
if (channelsActive > 3)
{
log.info("Disabling PriColor rendering, active channels > 3");
optimizations.setPrimaryColorEnabled(false);
return;
}
// Now we ensure the color is "primary" (Red, Green or Blue).
boolean isPrimary = false;
int[] colorArray = getColorArray(channelBinding);
if (isEndColor(colorArray)) {
optimizations.setPrimaryColorEnabled(false);
return;
}
for (int value : colorArray)
{
if (value != 0 && value != 255)
{
log.info("Disabling PriColor rendering, " +
"channel color not primary.");
optimizations.setPrimaryColorEnabled(false);
return;
}
if (value == 255)
{
if (isPrimary == true)
{
log.info("Disabling PriColor rendering, " +
"duplicate channel color component.");
optimizations.setPrimaryColorEnabled(false);
return;
}
isPrimary = true;
}
}
// Finally we check to make sure that the color is different from
// all other channels that are active.
List<ChannelBinding> otherBindings =
getOtherBindings(channelBindings, channelBinding);
for (ChannelBinding otherChannelBinding : otherBindings)
{
if (otherChannelBinding.getActive() == false)
continue;
int[] otherColorArray =
getColorArray(otherChannelBinding);
for (int i = 0; i < colorArray.length; i++)
{
if (colorArray[i] == otherColorArray[i]
&& colorArray[i] != 0)
{
log.info("Disabling PriColor rendering, " +
"duplicate channel color.");
optimizations.setPrimaryColorEnabled(false);
return;
}
}
}
}
// All checks have passed, enable "primary" color rendering.
log.info("Enabling primary color rendering.");
optimizations.setPrimaryColorEnabled(true);
}
/**
* Checks the region definition to ensure that the requested tile width
* and height are valid with respect to the current resolution level.
* @param rd Requested region definition.
*/
private void checkRegionDef(RegionDef rd)
{
if (rd == null)
{
return;
}
// We're using the buffer X and Y size because of the
// possibility that we're on a resolution level where
// Pixels.Size[X,Y] != PixelBuffer.Size[X,Y].
int sizeX = buffer.getSizeX();
int sizeY = buffer.getSizeY();
int x = rd.getX();
int y = rd.getY();
if ((rd.getWidth() + x) > sizeX)
{
rd.setWidth(sizeX - x);
}
if ((rd.getHeight() + y) > sizeY)
{
rd.setHeight(sizeY - y);
}
}
/**
* Creates a new instance to render the specified pixels set and get this
* new instance ready for rendering.
*
* @param quantumFactory a populated quantum factory.
* @param renderingModels an enumerated list of all rendering models.
* @param pixelsObj Pixels object.
* @param renderingDefObj Rendering definition object.
* @param bufferObj PixelBuffer object.
* @throws NullPointerException If <code>null</code> parameters are passed.
*/
public Renderer(QuantumFactory quantumFactory,
List<RenderingModel> renderingModels, Pixels pixelsObj,
RenderingDef renderingDefObj, PixelBuffer bufferObj) {
metadata = pixelsObj;
rndDef = renderingDefObj;
buffer = bufferObj;
if (metadata == null) {
throw new NullPointerException("Expecting not null metadata");
} else if (rndDef == null) {
throw new NullPointerException("Expecting not null rndDef");
} else if (buffer == null) {
throw new NullPointerException("Expecting not null buffer");
}
// Create and configure the quantum strategies.
QuantumDef qd = rndDef.getQuantization();
quantumManager = new QuantumManager(metadata, quantumFactory);
ChannelBinding[] cBindings = getChannelBindings();
quantumManager.initStrategies(qd, cBindings);
// Create and configure the codomain chain.
codomainChain = new CodomainChain(qd.getCdStart().intValue(), qd
.getCdEnd().intValue(), rndDef.<ome.model.display.CodomainMapContext>
collectSpatialDomainEnhancement(null));
// Create an appropriate rendering strategy.
renderingStrategy = RenderingStrategy.makeNew(rndDef.getModel());
// Examine the metadata we've been given and enable optimizations.
checkOptimizations();
}
/**
* Specifies the model that dictates how transformed raw data has to be
* mapped onto a color space. This class delegates the actual rendering to a
* {@link RenderingStrategy}, which is selected depending on that model. So
* setting the model also results in changing the rendering strategy.
*
* @param model
* Identifies the color space model.
*/
public void setModel(RenderingModel model)
{
rndDef.setModel(model);
renderingStrategy = RenderingStrategy.makeNew(model);
}
/**
* Sets the index of the default focal section. This index is used to define
* a default plane.
*
* @param z
* The stack index.
* @see #setDefaultT(int)
*/
public void setDefaultZ(int z)
{
rndDef.setDefaultZ(Integer.valueOf(z));
}
/**
* Sets the default timepoint index. This index is used to define a default
* plane.
*
* @param t
* The timepoint index.
* @see #setDefaultZ(int)
*/
public void setDefaultT(int t) {
rndDef.setDefaultT(Integer.valueOf(t));
}
/**
* Sets a map of overlays to be rendered.
* @param overlays Overlay to color map.
*/
public void setOverlays(Map<byte[], Integer> overlays) {
this.overlays = overlays;
checkOptimizations();
}
/**
* Returns the current set of overlays to be rendered.
* @return Overlay to color map.
*/
public Map<byte[], Integer> getOverlays() {
return overlays;
}
/**
* Updates the {@link QuantumManager} and configures it according to the
* current quantum definition.
*/
public void updateQuantumManager() {
QuantumDef qd = rndDef.getQuantization();
ChannelBinding[] cb = getChannelBindings();
quantumManager.initStrategies(qd, cb);
}
/**
* Renders the data selected by <code>pd</code> according to the current
* rendering settings. The passed argument selects a plane orthogonal to one
* of the <i>X</i>, <i>Y</i>, or <i>Z</i> axes. How many wavelengths are
* rendered and what color model is used depends on the current rendering
* settings.
*
* @param pd
* Selects a plane orthogonal to one of the <i>X</i>, <i>Y</i>,
* or <i>Z</i> axes.
* @return An <i>RGB</i> image ready to be displayed on screen.
* @throws IOException
* If an error occurred while trying to pull out data from the
* pixels data repository.
* @throws QuantizationException
* If an error occurred while quantizing the pixels raw data.
* @throws NullPointerException
* If <code>pd</code> is <code>null</code>.
*/
public RGBBuffer render(PlaneDef pd) throws IOException,
QuantizationException {
if (pd == null) {
throw new NullPointerException("No plane definition.");
}
checkRegionDef(pd.getRegion());
stats = new RenderingStats(this, pd);
log.info("Using: '" + renderingStrategy.getClass().getName()
+ "' rendering strategy.");
RGBBuffer img = renderingStrategy.render(this, pd);
stats.stop();
// TODO: Commenting this out for now. -- callan
//log.info(stats.getStats());
return img;
}
/**
* Renders the data selected by <code>pd</code> according to the current
* rendering settings. The passed argument selects a plane orthogonal to one
* of the <i>X</i>, <i>Y</i>, or <i>Z</i> axes. How many wavelengths are
* rendered and what color model is used depends on the current rendering
* settings.
*
* @param pd
* Selects a plane orthogonal to one of the <i>X</i>, <i>Y</i>,
* or <i>Z</i> axes.
* @param newBuffer
* The pixel buffer to use in place of the one currently
* defined in the renderer. This will not change the state
* of the Renderer. If <code>null</code> is passed the existing
* pixel buffer will be used.
* @return An <i>RGB</i> image ready to be displayed on screen.
* @throws IOException
* If an error occurred while trying to pull out data from the
* pixels data repository.
* @throws QuantizationException
* If an error occurred while quantizing the pixels raw data.
* @throws NullPointerException
* If <code>pd</code> is <code>null</code>.
*/
public int[] renderAsPackedInt(PlaneDef pd, PixelBuffer newBuffer)
throws IOException, QuantizationException
{
if (pd == null) {
throw new NullPointerException("No plane definition.");
}
checkRegionDef(pd.getRegion());
stats = new RenderingStats(this, pd);
log.info("Using: '" + renderingStrategy.getClass().getName()
+ "' rendering strategy.");
PixelBuffer oldBuffer = buffer;
try
{
if (newBuffer != null)
{
buffer = newBuffer;
}
RGBIntBuffer img = renderingStrategy.renderAsPackedInt(this, pd);
stats.stop();
// TODO: Commenting this out for now. -- callan
//log.info(stats.getStats());
return img.getDataBuffer();
}
finally
{
buffer = oldBuffer;
}
}
/**
* Returns the size, in bytes, of the {@link RGBBuffer} that would be
* rendered from the plane selected by <code>pd</code>. Note that the
* returned value also depends on the current rendering strategy which is
* selected by the {@link #setModel(RenderingModel) setModel} method. So a
* subsequent invocation of this method may return a different value if the
* {@link #setModel(RenderingModel) setModel} method has been called since
* the first call to this method.
*
* @param pd
* Selects a plane orthogonal to one of the <i>X</i>, <i>Y</i>,
* or <i>Z</i> axes.
* @return See above.
* @throws NullPointerException
* If <code>pd</code> is <code>null</code>.
*/
public int getImageSize(PlaneDef pd) {
if (pd == null) {
throw new NullPointerException("No plane definition.");
}
return renderingStrategy.getImageSize(pd, metadata);
}
/**
* Returns a string with the dimensions of the specified plane. The returned
* string has the format <code>AxB</code>, where <code>A</code> is the
* number of pixels on the <i>X1</i>-axis and <code>B</code> the the
* number of pixels on the the <i>X2</i>-axis. The <i>X1</i>-axis is the
* <i>X</i>-axis in the case of an <i>XY</i> or <i>XZ</i> plane.
* Otherwise it is the <i>Z</i>-axis <i>ZY</i> plane. The <i>X2</i>-axis
* is the <i>Y</i>-axis in the case of an <i>XY</i> or <i>ZY</i> plane.
* Otherwise it is the <i>Z</i>-axis <i>XZ</i> plane.
*
* @param pd
* Selects a plane orthogonal to one of the <i>X</i>, <i>Y</i>,
* or <i>Z</i> axes.
* @return See above.
* @throws NullPointerException
* If <code>pd</code> is <code>null</code>.
*/
public String getPlaneDimsAsString(PlaneDef pd) {
if (pd == null) {
throw new NullPointerException("No plane definition.");
}
return renderingStrategy.getPlaneDimsAsString(pd, metadata);
}
/**
* Returns an array containing the channel bindings. The dimension of the
* array equals the number of channels.
*
* @return See above.
*/
public ChannelBinding[] getChannelBindings() {
List<ChannelBinding> bindings = rndDef.collectWaveRendering(null);
return (ChannelBinding[]) bindings.toArray(new ChannelBinding[bindings
.size()]);
}
/**
* Returns a list containing the channel bindings. The dimension of the
* array equals the number of channels.
*
* @return See above.
*/
public List<ChannelBinding> getChannelBindingsAsList() {
return rndDef.collectWaveRendering(null);
}
/**
* Returns the settings that define the transformation context. That is, a
* specification of how raw data is to be transformed into an image that can
* be displayed on screen.
*
* @return See above.
*/
public RenderingDef getRenderingDef() {
return rndDef;
}
/**
* Returns the object that manages and allows to retrieve the objects that
* are used to quantize wavelength data.
*
* @return See above.
*/
public QuantumManager getQuantumManager() {
return quantumManager;
}
/**
* Returns the object that allows to access the pixels raw data.
*
* @return See above.
*/
public PixelBuffer getPixels() {
return buffer;
}
/**
* Returns the {@link Pixels} set the rendering engine is for.
*
* @return See above.
*/
public Pixels getMetadata() {
return metadata;
}
/**
* Returns the pixels type.
*
* @return A pixels type enumeration object.
*/
public PixelsType getPixelsType() {
return metadata.getPixelsType();
}
/**
* Returns the object that defines the sequence of spatial transformations
* to be applied to quantized data.
*
* @return See above.
*/
public CodomainChain getCodomainChain() {
return codomainChain;
}
/**
* Returns a {@link RenderingStats} object that the rendering strategy can
* use to track performance. A new stats object is created upon each
* invocation of the {@link #render(PlaneDef) render} method.
*
* @return The stats object.
*/
public RenderingStats getStats() {
return stats;
}
//
// Methods pushed down from RenderingBean
//
/**
* Sets the bit resolution.
*
* @param bitResolution
* The value to set.
*/
public void setQuantumStrategy(int bitResolution) {
/*
* RenderingDef rd = getRenderingDef();
*
* QuantumDef qd = rd.getQuantization(), newQd; newQd = new
* QuantumDef(); newQd.setBitResolution(Integer.valueOf(bitResolution));
* newQd.setCdStart(qd.getCdStart()); newQd.setCdEnd(qd.getCdEnd());
* rd.setQuantization(newQd); updateQuantumManager();
*/
RenderingDef rd = getRenderingDef();
QuantumDef qd = rd.getQuantization();
qd.setBitResolution(Integer.valueOf(bitResolution));
updateQuantumManager();
}
/**
* Sets the codomain interval i.e. a sub-interval of [0, 255].
*
* @param start
* The lower bound of the interval.
* @param end
* The upper bound of the interval.
*/
public void setCodomainInterval(int start, int end) {
CodomainChain chain = getCodomainChain();
chain.setInterval(start, end);
/*
* RenderingDef rd = getRenderingDef(); QuantumDef qd =
* rd.getQuantization(), newQd; newQd = new QuantumDef();
* newQd.setBitResolution(qd.getBitResolution());
* newQd.setCdStart(Integer.valueOf(start));
* newQd.setCdEnd(Integer.valueOf(end)); rd.setQuantization(newQd);
*/
RenderingDef rd = getRenderingDef();
QuantumDef qd = rd.getQuantization();
qd.setCdStart(Integer.valueOf(start));
qd.setCdEnd(Integer.valueOf(end));
ome.model.display.CodomainMapContext mapCtx;
Iterator<ome.model.display.CodomainMapContext> i = rd.iterateSpatialDomainEnhancement();
while (i.hasNext()) {
mapCtx = i.next();
throw new UnsupportedOperationException("BROKEN");
// XXX What is supposed to happen here? mapCtx.setCodomain(start, end);
}
//need to rebuild the look up table
updateQuantumManager();
}
/**
* Sets the pixels intensity interval for the specified channel.
*
* @param w
* The channel index.
* @param start
* The lower bound of the interval.
* @param end
* The upper bound of the interval.
*/
public void setChannelWindow(int w, double start, double end) {
QuantumStrategy qs = getQuantumManager().getStrategyFor(w);
qs.setWindow(start, end);
ChannelBinding[] cb = getChannelBindings();
cb[w].setInputStart(new Double(start));
cb[w].setInputEnd(new Double(end));
}
/**
* Sets the mapping strategy for the specified channel.
*
* @param w
* The channel index.
* @param family
* The mapping family.
* @param coefficient
* The coefficient identifying a curve in the family.
* @param noiseReduction
* Pass <code>true</code> to select the noiseReduction
* algorithm, <code>false</code> otherwise.
*/
public void setQuantizationMap(int w, Family family, double coefficient,
boolean noiseReduction) {
QuantumStrategy qs = getQuantumManager().getStrategyFor(w);
qs.setQuantizationMap(family, coefficient, noiseReduction);
ChannelBinding[] cb = getChannelBindings();
cb[w].setFamily(family);
cb[w].setCoefficient(coefficient);
cb[w].setNoiseReduction(noiseReduction);
}
/**
* Sets the color associated to the specified channel.
*
* @param w
* The channel index.
* @param red
* The red component of the color.
* @param green
* The green component of the color.
* @param blue
* The blue component of the color.
* @param alpha
* The alpha component of the color.
*/
public void setRGBA(int w, int red, int green, int blue, int alpha) {
ChannelBinding[] cb = getChannelBindings();
cb[w].setRed(Integer.valueOf(red));
cb[w].setGreen(Integer.valueOf(green));
cb[w].setBlue(Integer.valueOf(blue));
cb[w].setAlpha(Integer.valueOf(alpha));
checkOptimizations();
}
/**
* Makes a particular channel active or inactive.
* @param w the wavelength index to toggle.
* @param active <code>true</code> to set the channel active or
* <code>false</code> to set the channel inactive.
*/
public void setActive(int w, boolean active) {
ChannelBinding[] cb = getChannelBindings();
cb[w].setActive(Boolean.valueOf(active));
checkOptimizations();
}
/**
* Returns the optimizations that the renderer currently has enabled.
* @return See above.
*/
public Optimizations getOptimizations()
{
return optimizations;
}
/**
* Closes the buffer, cleaning up file state.
*
* @throws IOException if an I/O error occurs.
*/
public void close() {
try
{
if (buffer != null)
buffer.close();
}
catch (IOException e)
{
log.error("Buffer did not close successfully.", e);
throw new ResourceError(
e.getMessage() + " Please check server log.");
}
}
/**
* Returns an array whose ascending indices represent the color
* components Red, Green and Blue.
*
* @param channel the color to decompose into an array.
* @return See above.
*/
public static int[] getColorArray(ChannelBinding channel)
{
int[] colors = new int[3];
colors[0] = channel.getRed();
colors[1] = channel.getGreen();
colors[2] = channel.getBlue();
return colors;
}
/**
* Returns <code>true</code> if the pixels type is signed,
* <code>false</code> otherwise.
*
* @return See above.
*/
public boolean isPixelsTypeSigned()
{
if (metadata == null) return false;
return PlaneFactory.isTypeSigned(metadata.getPixelsType());
}
/**
* Returns the minimum value for that channels depending on the pixels
* type and the original range (globalmax, globalmin)
*
* @param w The channel index.
* @return See above.
*/
public double getPixelsTypeLowerBound(int w)
{
QuantumStrategy qs = getQuantumManager().getStrategyFor(w);
return qs.getPixelsTypeMin();
}
/**
* Returns the maximum value for that channels depending on the pixels
* type and the original range (globalmax, globalmin)
*
* @param w The channel index.
* @return See above.
*/
public double getPixelsTypeUpperBound(int w)
{
QuantumStrategy qs = getQuantumManager().getStrategyFor(w);
return qs.getPixelsTypeMax();
}
/**
* Sets the active resolution level.
* @param resolutionLevel The resolution level to be used by the renderer.
**/
public void setResolutionLevel(int resolutionLevel)
{
buffer.setResolutionLevel(resolutionLevel);
}
/**
* Retrieves the active resolution level.
* @return The active resolution level.
**/
public int getResolutionLevel()
{
return buffer.getResolutionLevel();
}
/**
* Retrieves the number of resolution levels that the backing
* pixels pyramid contains.
* @return The number of resolution levels. This value does not
* necessarily indicate either the presence or absence of a
* pixels pyramid.
**/
public int getResolutionLevels()
{
return buffer.getResolutionLevels();
}
/**
* Returns the image's size information per resolution level.
*
* @return See above.
*/
public List<List<Integer>> getResolutionDescriptions()
{
return buffer.getResolutionDescriptions();
}
/**
* Retrieves the tile size for the pixel store.
* @return The dimension of the tile or <code>null</code> if the pixel
* buffer is not tiled.
**/
public Dimension getTileSize()
{
return buffer.getTileSize();
}
}