Java tutorial
/* * ome.io.nio.PixelBuffer * * Copyright 2007 Glencoe Software Inc. All rights reserved. * Use is subject to license terms supplied in LICENSE.txt */ package ome.io.nio; import java.awt.Dimension; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.BufferOverflowException; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.List; import ome.conditions.ApiUsageException; import ome.model.core.Pixels; import ome.util.PixelData; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Class implementation of the PixelBuffer interface for standard "proprietary" * ROMIO/OMEIS data format. * * @author Chris Allan <a * href="mailto:chris@glencoesoftware.com">chris@glencoesoftware.com</a> * @version $Revision$ * @since 3.0 * @see PixelBuffer */ public class RomioPixelBuffer extends AbstractBuffer implements PixelBuffer { /** The logger for this particular class */ private static Log log = LogFactory.getLog(RomioPixelBuffer.class); /** Default maximum buffer size for planar data transfer. (1MB) */ public static final int MAXIMUM_BUFFER_SIZE = 1048576; /** Reference to the pixels. */ private Pixels pixels; private RandomAccessFile file; private FileChannel channel; /** The size of a row. */ private Integer rowSize; /** The size of a column. */ private Integer colSize; /** The size of a plane. */ private Integer planeSize; /** The size of a stack. */ private Integer stackSize; /** The size of a timepoint. */ private Integer timepointSize; /** The total size. */ private Integer totalSize; /** * Whether or not any of the mutators to write data can be called. * If not, an internal exception will be raised since it represents * a programming error. */ private final boolean permitModification; /** * Creates a new instance. {@link #permitModification} defaults to false. * * @param path The path to the file. * @param pixels The pixels object to handle. */ public RomioPixelBuffer(String path, Pixels pixels) { this(path, pixels, false); } /** * Creates a new instance, with manual setting of {@link #permitModification}. * * @param path The path to the file. * @param pixels The pixels object to handle. */ public RomioPixelBuffer(String path, Pixels pixels, boolean permitModification) { super(path); if (pixels == null) { throw new NullPointerException("Expecting a not-null pixels element."); } this.pixels = pixels; this.permitModification = permitModification; } private void throwIfReadOnly() { if (!permitModification) { throw new ApiUsageException("Write-method not permitted."); } } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#checkBounds(Integer, Integer, Integer, Integer, Integer) */ public void checkBounds(Integer x, Integer y, Integer z, Integer c, Integer t) throws DimensionsOutOfBoundsException { if (x != null && (x > getSizeX() - 1 || x < 0)) { throw new DimensionsOutOfBoundsException("X '" + x + "' greater than sizeX '" + getSizeX() + "'."); } if (y != null && (y > getSizeY() - 1 || y < 0)) { throw new DimensionsOutOfBoundsException("Y '" + y + "' greater than sizeY '" + getSizeY() + "'."); } if (z != null && (z > getSizeZ() - 1 || z < 0)) { throw new DimensionsOutOfBoundsException("Z '" + z + "' greater than sizeZ '" + getSizeZ() + "'."); } if (c != null && (c > getSizeC() - 1 || c < 0)) { throw new DimensionsOutOfBoundsException("C '" + c + "' greater than sizeC '" + getSizeC() + "'."); } if (t != null && (t > getSizeT() - 1 || t < 0)) { throw new DimensionsOutOfBoundsException("T '" + t + "' greater than sizeT '" + getSizeT() + "'."); } } private FileChannel getFileChannel() throws FileNotFoundException { if (channel == null) { file = new RandomAccessFile(getPath(), "rw"); channel = file.getChannel(); } return channel; } /** * Closes the buffer, cleaning up file state. * * @throws IOException * if an I/O error occurs. */ public void close() throws IOException { if (channel != null) { try { channel.close(); } catch (Exception e) { log.error("Error closing channel", e); } finally { channel = null; } } if (file != null) { try { file.close(); } catch (Exception e) { log.error("Error closing file", e); } finally { file = null; } } } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getPlaneSize() */ public Integer getPlaneSize() { if (planeSize == null) { planeSize = getSizeX() * getSizeY() * getByteWidth(); } return planeSize; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getRowSize() */ public Integer getRowSize() { if (rowSize == null) { rowSize = getSizeX() * getByteWidth(); } return rowSize; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getColSize() */ public Integer getColSize() { if (colSize == null) { colSize = getSizeY() * getByteWidth(); } return colSize; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getStackSize() */ public Integer getStackSize() { if (stackSize == null) { stackSize = getPlaneSize() * getSizeZ(); } return stackSize; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getTimepointSize() */ public Integer getTimepointSize() { if (timepointSize == null) { timepointSize = getStackSize() * getSizeC(); } return timepointSize; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getTotalSize() */ public Integer getTotalSize() { if (totalSize == null) { totalSize = getTimepointSize() * getSizeT(); } return totalSize; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getRowOffset(Integer, Integer, Integer, Integer) */ public Long getRowOffset(Integer y, Integer z, Integer c, Integer t) throws DimensionsOutOfBoundsException { checkBounds(null, y, z, c, t); Integer rowSize = getRowSize(); Integer timepointSize = getTimepointSize(); Integer stackSize = getStackSize(); Integer planeSize = getPlaneSize(); return (long) rowSize * y + (long) timepointSize * t + (long) stackSize * c + (long) planeSize * z; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getPlaneOffset(Integer, Integer, Integer) */ public Long getPlaneOffset(Integer z, Integer c, Integer t) throws DimensionsOutOfBoundsException { checkBounds(null, null, z, c, t); Integer timepointSize = getTimepointSize(); Integer stackSize = getStackSize(); Integer planeSize = getPlaneSize(); return (long) timepointSize * t + (long) stackSize * c + (long) planeSize * z; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getStackOffset(Integer, Integer) */ public Long getStackOffset(Integer c, Integer t) throws DimensionsOutOfBoundsException { checkBounds(null, null, null, c, t); Integer timepointSize = getTimepointSize(); Integer stackSize = getStackSize(); return (long) timepointSize * t + (long) stackSize * c; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getTimepointOffset(Integer) */ public Long getTimepointOffset(Integer t) throws DimensionsOutOfBoundsException { checkBounds(null, null, null, null, t); Integer timepointSize = getTimepointSize(); return (long) timepointSize * t; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getRegion(Integer, Long) */ public PixelData getRegion(Integer size, Long offset) throws IOException { FileChannel fileChannel = getFileChannel(); /* * fileChannel should not be "null" as it will throw an exception if * there happens to be an error. */ MappedByteBuffer b = fileChannel.map(MapMode.READ_ONLY, offset, size); return new PixelData(pixels.getPixelsType().getValue(), b); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getRegionDirect(Integer, Long, byte[]) */ public byte[] getRegionDirect(Integer size, Long offset, byte[] buffer) throws IOException { if (buffer.length != size) throw new ApiUsageException("Buffer size incorrect."); ByteBuffer b = getRegion(size, offset).getData(); b.get(buffer); return buffer; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getRow(Integer, Integer, Integer, Integer) */ public PixelData getRow(Integer y, Integer z, Integer c, Integer t) throws IOException, DimensionsOutOfBoundsException { //dimension check getRowOffset Long offset = getRowOffset(y, z, c, t); Integer size = getRowSize(); return getRegion(size, offset); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getCol(Integer, Integer, Integer, Integer) */ public PixelData getCol(Integer x, Integer z, Integer c, Integer t) throws IOException, DimensionsOutOfBoundsException { //Dimension check in plane. PixelData plane = getPlane(z, c, t); Integer sizeY = getSizeY(); Integer sizeX = getSizeX(); Integer colSize = getColSize(); ByteBuffer buf = ByteBuffer.wrap(new byte[colSize]); PixelData column = new PixelData(pixels.getPixelsType().getValue(), buf); int offset; double value; for (int i = 0; i < sizeY; i++) { offset = (i * sizeX) + x; value = plane.getPixelValue(offset); column.setPixelValue(i, value); } return column; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getRowDirect(Integer, Integer, Integer, Integer, byte[]) */ public byte[] getRowDirect(Integer y, Integer z, Integer c, Integer t, byte[] buffer) throws IOException, DimensionsOutOfBoundsException { if (buffer.length != getRowSize()) throw new ApiUsageException("Buffer size incorrect."); ByteBuffer b = getRow(y, z, c, t).getData(); b.get(buffer); return buffer; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getColDirect(Integer, Integer, Integer, Integer, byte[]) */ public byte[] getColDirect(Integer x, Integer z, Integer c, Integer t, byte[] buffer) throws IOException, DimensionsOutOfBoundsException { PixelData plane = getPlane(z, c, t); Integer sizeY = getSizeY(); Integer sizeX = getSizeX(); ByteBuffer buf = ByteBuffer.wrap(buffer); PixelData column = new PixelData(pixels.getPixelsType().getValue(), buf); int offset; double value; for (int i = 0; i < sizeY; i++) { offset = (i * sizeX) + x; value = plane.getPixelValue(offset); column.setPixelValue(i, value); } return buffer; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getHypercube(List<Integer>, IList<Integer>, List<Integer>) */ public PixelData getHypercube(List<Integer> offset, List<Integer> size, List<Integer> step) throws IOException, DimensionsOutOfBoundsException { PixelData d; byte[] buffer = new byte[getHypercubeSize(offset, size, step)]; getHypercubeDirect(offset, size, step, buffer); d = new PixelData(pixels.getPixelsType().getValue(), ByteBuffer.wrap(buffer)); return d; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getHypercubeDirect(List<Integer>, IList<Integer>, List<Integer>, byte[]) */ public byte[] getHypercubeDirect(List<Integer> offset, List<Integer> size, List<Integer> step, byte[] buffer) throws IOException, DimensionsOutOfBoundsException { if (buffer.length != getHypercubeSize(offset, size, step)) throw new RuntimeException("Buffer size incorrect."); getWholeHypercube(offset, size, step, buffer); return buffer; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getPlaneRegionDirect(Integer, Integer, Integer, Integer, * Integer, byte[]) */ public byte[] getPlaneRegionDirect(Integer z, Integer c, Integer t, Integer count, Integer offset, byte[] buffer) throws IOException, DimensionsOutOfBoundsException { ByteBuffer b = getPlane(z, c, t).getData(); b.position(offset * getByteWidth()); b.get(buffer, 0, count * getByteWidth()); return buffer; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getPlane(Integer, Integer, Integer) */ public PixelData getPlane(Integer z, Integer c, Integer t) throws IOException, DimensionsOutOfBoundsException { log.info("Retrieving plane: " + z + "x" + c + "x" + t); Long offset = getPlaneOffset(z, c, t); Integer size = getPlaneSize(); PixelData region = getRegion(size, offset); byte[] nullPlane = PixelsService.nullPlane; for (int i = 0; i < PixelsService.NULL_PLANE_SIZE; i++) { if (region.getData().get(i) != nullPlane[i]) { return region; } } return null; // All of the nullPlane bytes match, non-filled plane } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getPlaneRegion(Integer, Integer, Integer, Integer, * Integer, Integer, Integer, Integer) */ public PixelData getPlaneRegion(Integer x, Integer y, Integer width, Integer height, Integer z, Integer c, Integer t, Integer stride) throws IOException, DimensionsOutOfBoundsException { if (stride == null || stride < 0) stride = 0; checkBounds(x, y, z, c, t); checkBounds(x + width - 1, y + height - 1, null, null, null); PixelData plane = getPlane(z, c, t); Integer size; ByteBuffer buf; PixelData region = null; int offset; if (stride == 0) { size = width * height * getByteWidth(); buf = ByteBuffer.wrap(new byte[size]); region = new PixelData(pixels.getPixelsType().getValue(), buf); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { offset = (i + y) * getSizeX() + x + j; region.setPixelValue(i * width + j, plane.getPixelValue(offset)); } } return region; } stride++; int w = width / stride; size = width * height * getByteWidth() / (stride * stride); buf = ByteBuffer.wrap(new byte[size]); region = new PixelData(pixels.getPixelsType().getValue(), buf); int k = 0; int l = 0; for (int i = 0; i < height; i = i + stride) { l = 0; for (int j = 0; j < width; j = j + stride) { offset = (i + y) * getSizeX() + x + j; region.setPixelValue(k * w + l, plane.getPixelValue(offset)); l++; } k++; } return region; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getPlaneDirect(Integer, Integer, Integer, byte[]) */ public byte[] getPlaneDirect(Integer z, Integer c, Integer t, byte[] buffer) throws IOException, DimensionsOutOfBoundsException { if (buffer.length != getPlaneSize()) throw new ApiUsageException("Buffer size incorrect."); ByteBuffer b = getPlane(z, c, t).getData(); b.get(buffer); return buffer; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getStack(Integer, Integer) */ public PixelData getStack(Integer c, Integer t) throws IOException, DimensionsOutOfBoundsException { Long offset = getStackOffset(c, t); Integer size = getStackSize(); return getRegion(size, offset); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getStackDirect(Integer, Integer, byte[]) */ public byte[] getStackDirect(Integer c, Integer t, byte[] buffer) throws IOException, DimensionsOutOfBoundsException { if (buffer.length != getStackSize()) throw new ApiUsageException("Buffer size incorrect."); ByteBuffer b = getStack(c, t).getData(); b.get(buffer); return buffer; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getTimepoint(Integer) */ public PixelData getTimepoint(Integer t) throws IOException, DimensionsOutOfBoundsException { Long offset = getTimepointOffset(t); Integer size = getTimepointSize(); return getRegion(size, offset); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getTimepointDirect(Integer, byte[]) */ public byte[] getTimepointDirect(Integer t, byte[] buffer) throws IOException, DimensionsOutOfBoundsException { if (buffer.length != getTimepointSize()) throw new ApiUsageException("Buffer size incorrect."); ByteBuffer b = getTimepoint(t).getData(); b.get(buffer); return buffer; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#setRegion(Integer, Long, byte[]) */ public void setRegion(Integer size, Long offset, byte[] buffer) throws IOException { throwIfReadOnly(); ByteBuffer buf = MappedByteBuffer.wrap(buffer); buf.limit(size); setRegion(size, offset, buf); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#setRegion(Integer, Long, ByteBuffer) */ public void setRegion(Integer size, Long offset, ByteBuffer buffer) throws IOException { throwIfReadOnly(); FileChannel fileChannel = getFileChannel(); /* * fileChannel should not be "null" as it will throw an exception if * there happens to be an error. */ fileChannel.write(buffer, offset); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#setRow(ByteBuffer, Integer, Integer, Integer, Integer) */ public void setRow(ByteBuffer buffer, Integer y, Integer z, Integer c, Integer t) throws IOException, DimensionsOutOfBoundsException { throwIfReadOnly(); Long offset = getRowOffset(y, z, c, t); Integer size = getRowSize(); setRegion(size, offset, buffer); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#setPlane(ByteBuffer, Integer, Integer, Integer) */ public void setPlane(ByteBuffer buffer, Integer z, Integer c, Integer t) throws IOException, DimensionsOutOfBoundsException { throwIfReadOnly(); Long offset = getPlaneOffset(z, c, t); Integer size = getPlaneSize(); if (buffer.limit() != size) { // Handle the size mismatch. if (buffer.limit() < size) throw new BufferUnderflowException(); throw new BufferOverflowException(); } setRegion(size, offset, buffer); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#setPlane(byte[], Integer, Integer, Integer) */ public void setPlane(byte[] buffer, Integer z, Integer c, Integer t) throws IOException, DimensionsOutOfBoundsException { throwIfReadOnly(); setPlane(ByteBuffer.wrap(buffer), z, c, t); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#setStack(ByteBuffer, Integer, Integer, Integer) */ public void setStack(ByteBuffer buffer, Integer z, Integer c, Integer t) throws IOException, DimensionsOutOfBoundsException { throwIfReadOnly(); Long offset = getStackOffset(c, t); Integer size = getStackSize(); if (buffer.limit() != size) { // Handle the size mismatch. if (buffer.limit() < size) throw new BufferUnderflowException(); throw new BufferOverflowException(); } setRegion(size, offset, buffer); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#setStack(byte[], Integer, Integer, Integer) */ public void setStack(byte[] buffer, Integer z, Integer c, Integer t) throws IOException, DimensionsOutOfBoundsException { throwIfReadOnly(); setStack(MappedByteBuffer.wrap(buffer), z, c, t); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#setTimepoint(ByteBuffer, Integer) */ public void setTimepoint(ByteBuffer buffer, Integer t) throws IOException, DimensionsOutOfBoundsException { throwIfReadOnly(); Long offset = getTimepointOffset(t); Integer size = getTimepointSize(); if (buffer.limit() != size) { // Handle the size mismatch. if (buffer.limit() < size) throw new BufferUnderflowException(); throw new BufferOverflowException(); } setRegion(size, offset, buffer); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#setTimepoint(ByteBuffer, Integer) */ public void setTimepoint(byte[] buffer, Integer t) throws IOException, DimensionsOutOfBoundsException { throwIfReadOnly(); setTimepoint(MappedByteBuffer.wrap(buffer), t); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#calculateMessageDigest() */ public byte[] calculateMessageDigest() throws IOException { MessageDigest md; try { md = MessageDigest.getInstance("SHA-1"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("Required SHA-1 message digest algorithm unavailable."); } for (int t = 0; t < getSizeT(); t++) { try { ByteBuffer buffer = getTimepoint(t).getData(); md.update(buffer); } catch (DimensionsOutOfBoundsException e) { // This better not happen. :) throw new RuntimeException(e); } } return md.digest(); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getByteWidth() */ public int getByteWidth() { return PixelData.getBitDepth(pixels.getPixelsType().getValue()) / 8; } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#isSigned() */ public boolean isSigned() { PixelData d = new PixelData(pixels.getPixelsType().getValue(), null); return d.isSigned(); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#isFloat() */ public boolean isFloat() { PixelData d = new PixelData(pixels.getPixelsType().getValue(), null); return d.isFloat(); } // // Delegate methods to ease work with pixels // /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getSizeC() */ public int getSizeC() { return pixels.getSizeC(); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getSizeT() */ public int getSizeT() { return pixels.getSizeT(); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getSizeX() */ public int getSizeX() { return pixels.getSizeX(); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getSizeY() */ public int getSizeY() { return pixels.getSizeY(); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getSizeZ() */ public int getSizeZ() { return pixels.getSizeZ(); } /** * Implemented as specified by {@link PixelBuffer} I/F. * @see PixelBuffer#getId() */ public long getId() { return pixels.getId(); } public String getSha1() { return pixels.getSha1(); } /* (non-Javadoc) * @see ome.io.nio.PixelBuffer#getTile(java.lang.Integer, java.lang.Integer, java.lang.Integer, java.lang.Integer, java.lang.Integer, java.lang.Integer, java.lang.Integer) */ public PixelData getTile(Integer z, Integer c, Integer t, Integer x, Integer y, Integer w, Integer h) throws IOException { return getPlaneRegion(x, y, w, h, z, c, t, 0); } /* (non-Javadoc) * @see ome.io.nio.PixelBuffer#getTileDirect(java.lang.Integer, java.lang.Integer, java.lang.Integer, java.lang.Integer, java.lang.Integer, java.lang.Integer, java.lang.Integer, byte[]) */ public byte[] getTileDirect(Integer z, Integer c, Integer t, Integer x, Integer y, Integer w, Integer h, byte[] buffer) throws IOException { List<Integer> offset = Arrays.asList(new Integer[] { x, y, z, c, t }); List<Integer> size = Arrays.asList(new Integer[] { w, h, 1, 1, 1 }); List<Integer> step = Arrays.asList(new Integer[] { 1, 1, 1, 1, 1 }); return getHypercubeDirect(offset, size, step, buffer); } /* (non-Javadoc) * @see ome.io.nio.PixelBuffer#setTile(byte[], java.lang.Integer, java.lang.Integer, java.lang.Integer, java.lang.Integer, java.lang.Integer, java.lang.Integer, java.lang.Integer) */ public void setTile(byte[] buffer, Integer z, Integer c, Integer t, Integer x, Integer y, Integer w, Integer h) throws IOException, BufferOverflowException { if (x != 0) { throw new UnsupportedOperationException("ROMIO pixel buffer only supports 0 offseted tile writes."); } if (w != getSizeX()) { throw new UnsupportedOperationException("ROMIO pixel buffer only supports full row writes."); } try { long offset = getPlaneOffset(z, c, t); offset += getByteWidth() * getSizeX() * y; setRegion(buffer.length, offset, buffer); } catch (DimensionsOutOfBoundsException e) { throw new RuntimeException(e); } } /* (non-Javadoc) * @see ome.io.nio.PixelBuffer#getResolutionLevel() */ public int getResolutionLevel() { return 0; } /* (non-Javadoc) * @see ome.io.nio.PixelBuffer#getResolutionLevels() */ public int getResolutionLevels() { return 1; } /* (non-Javadoc) * @see ome.io.nio.PixelBuffer#getTileSize() */ public Dimension getTileSize() { int width = getSizeX(); int height = Math.min(getSizeY(), (MAXIMUM_BUFFER_SIZE / getByteWidth()) / getSizeX()); return new Dimension(width, height); } /* (non-Javadoc) * @see ome.io.nio.PixelBuffer#setResolutionLevel(int) */ public void setResolutionLevel(int resolutionLevel) { throw new UnsupportedOperationException("Cannot set resolution levels on a ROMIO pixel buffer."); } public Integer getHypercubeSize(List<Integer> offset, List<Integer> size, List<Integer> step) throws DimensionsOutOfBoundsException { // only works for 5d at present checkCubeBounds(offset, size, step); int tStripes = (size.get(4) + step.get(4) - 1) / step.get(4); int cStripes = (size.get(3) + step.get(3) - 1) / step.get(3); int zStripes = (size.get(2) + step.get(2) - 1) / step.get(2); int yStripes = (size.get(1) + step.get(1) - 1) / step.get(1); int xStripes = (size.get(0) + step.get(0) - 1) / step.get(0); int tileRowSize = getByteWidth() * xStripes; int cubeSize = tileRowSize * yStripes * zStripes * cStripes * tStripes; return cubeSize; } /* * Temporary helpers. May be factored out. * This code is repeated in bfPixelWrapper and so needs refactoring. */ private byte[] getWholeHypercube(List<Integer> offset, List<Integer> size, List<Integer> step, byte[] cube) throws IOException { int cubeOffset = 0; int xStripes = (size.get(0) + step.get(0) - 1) / step.get(0); int pixelSize = getByteWidth(); int tileRowSize = pixelSize * xStripes; byte[] plane = new byte[getPlaneSize()]; for (int t = offset.get(4); t < size.get(4) + offset.get(4); t += step.get(4)) { for (int c = offset.get(3); c < size.get(3) + offset.get(3); c += step.get(3)) { for (int z = offset.get(2); z < size.get(2) + offset.get(2); z += step.get(2)) { getPlaneDirect(z, c, t, plane); int rowOffset = offset.get(1) * getRowSize(); if (step.get(0) == 1) { int byteOffset = rowOffset + offset.get(0) * pixelSize; for (int y = offset.get(1); y < size.get(1) + offset.get(1); y += step.get(1)) { System.arraycopy(plane, byteOffset, cube, cubeOffset, tileRowSize); cubeOffset += tileRowSize; byteOffset += getRowSize() * step.get(1); } } else { for (int y = offset.get(1); y < size.get(1) + offset.get(1); y += step.get(1)) { int byteOffset = offset.get(0) * pixelSize; for (int x = offset.get(0); x < size.get(0) + offset.get(0); x += step.get(0)) { System.arraycopy(plane, rowOffset + byteOffset, cube, cubeOffset, pixelSize); cubeOffset += pixelSize; byteOffset += step.get(0) * pixelSize; } rowOffset += getRowSize() * step.get(1); } } } } } return cube; } private void checkCubeBounds(List<Integer> offset, List<Integer> size, List<Integer> step) throws DimensionsOutOfBoundsException { // At the moment the array must contain 5 values if (offset.size() != 5 || size.size() != 5 || step.size() != 5) { throw new DimensionsOutOfBoundsException( "Invalid List length: each list must contain 5 elements XYZCT"); } checkBounds(offset.get(0), offset.get(1), offset.get(2), offset.get(3), offset.get(4)); checkBounds(offset.get(0) + size.get(0) - 1, offset.get(1) + size.get(1) - 1, offset.get(2) + size.get(2) - 1, offset.get(3) + size.get(3) - 1, offset.get(4) + size.get(4) - 1); if (step.get(0) < 1 || step.get(1) < 1 || step.get(2) < 1 || step.get(3) < 1 || step.get(4) < 1) { throw new DimensionsOutOfBoundsException("Invalid step size: steps sizes must be 1 or greater"); } } }