use of loci.common.ByteArrayHandle in project bioformats by openmicroscopy.
the class TiffSaver method writeIFD.
public void writeIFD(IFD ifd, long nextOffset) throws FormatException, IOException {
TreeSet<Integer> keys = new TreeSet<Integer>(ifd.keySet());
int keyCount = keys.size();
if (ifd.containsKey(new Integer(IFD.LITTLE_ENDIAN)))
keyCount--;
if (ifd.containsKey(new Integer(IFD.BIG_TIFF)))
keyCount--;
if (ifd.containsKey(new Integer(IFD.REUSE)))
keyCount--;
long fp = out.getFilePointer();
int bytesPerEntry = bigTiff ? TiffConstants.BIG_TIFF_BYTES_PER_ENTRY : TiffConstants.BYTES_PER_ENTRY;
int ifdBytes = (bigTiff ? 16 : 6) + bytesPerEntry * keyCount;
if (bigTiff)
out.writeLong(keyCount);
else
out.writeShort(keyCount);
ByteArrayHandle extra = new ByteArrayHandle();
RandomAccessOutputStream extraStream = new RandomAccessOutputStream(extra);
for (Integer key : keys) {
if (key.equals(IFD.LITTLE_ENDIAN) || key.equals(IFD.BIG_TIFF) || key.equals(IFD.REUSE))
continue;
Object value = ifd.get(key);
writeIFDValue(extraStream, ifdBytes + fp, key.intValue(), value);
}
if (bigTiff)
out.seek(out.getFilePointer());
writeIntValue(out, nextOffset);
out.write(extra.getBytes(), 0, (int) extra.length());
extraStream.close();
}
use of loci.common.ByteArrayHandle in project bioformats by openmicroscopy.
the class NativeND2Reader method initFile.
/* @see loci.formats.FormatReader#initFile(String) */
@Override
protected void initFile(String id) throws FormatException, IOException {
super.initFile(id);
// using a 32KB buffer instead of the default 1MB gives
// better performance with the seek/skip pattern used here
in = new RandomAccessInputStream(id, BUFFER_SIZE);
boolean useChunkMap = useChunkMap();
LOGGER.debug("Attempting to use chunk map = {}", useChunkMap);
channelColors = new HashMap<String, Integer>();
if (in.read() == -38 && in.read() == -50) {
// newer version of ND2 - doesn't use JPEG2000
LOGGER.info("Searching for blocks");
isJPEG = false;
in.seek(0);
in.order(true);
// assemble offsets to each block
ArrayList<String> imageNames = new ArrayList<String>();
ArrayList<Long> imageOffsets = new ArrayList<Long>();
ArrayList<int[]> imageLengths = new ArrayList<int[]>();
ArrayList<Long> customDataOffsets = new ArrayList<Long>();
ArrayList<int[]> customDataLengths = new ArrayList<int[]>();
// order matters when working with the text blocks, which is
// why two ArrayLists are used instead of a HashMap
ArrayList<String> textStrings = new ArrayList<String>();
ArrayList<Boolean> validDimensions = new ArrayList<Boolean>();
ByteArrayHandle xml = new ByteArrayHandle();
final StringBuilder name = new StringBuilder();
int extraZDataCount = 0;
boolean foundMetadata = false;
boolean foundAttributes = false;
boolean useLastText = false;
int blockCount = 0;
TreeMap<Long, ChunkMapEntry> allChunkPositions = new TreeMap<Long, ChunkMapEntry>();
if (useChunkMap) {
/* In modern ND2 files, the chunk map is stored near the end, and contains
* a list of blocks and their offsets. By using these offsets instead of
* scanning through the whole file, an enormous speed up can be achieved.
*
* Implementation: Read the chunk map beforehand, process the file as normally,
* once the first ImageDataSeq block is reached, add all images and skip past the
* image data to process remaining metadata.
* I haven't read through all of NativeND2Reader, but I hope to have the least
* chance of inadvertedly breaking something by this approach.
*/
String chunkMapSignature = "ND2 CHUNK MAP SIGNATURE 0000001";
in.seek(in.length() - 40);
if (!in.readString(chunkMapSignature.length()).equals(chunkMapSignature)) {
useChunkMap = false;
LOGGER.info("ND2 Warning: No chunk map found!");
} else {
in.skipBytes(1);
long chunkMapPosition = in.readLong();
in.seek(chunkMapPosition);
int tmpLenOne = in.readInt();
int tmpLenTwo = in.readInt();
long chunkMapLength = in.readLong();
chunkMapPosition += 16 + tmpLenTwo;
in.seek(chunkMapPosition);
long chunkMapEnd = chunkMapPosition + chunkMapLength;
int imageDataCount = 0;
int maxImageIndex = -1;
while (in.getFilePointer() + 1 + 16 < chunkMapEnd) {
char b = (char) in.readByte();
while (b != '!') {
name.append(b);
b = (char) in.readByte();
}
ChunkMapEntry entry = new ChunkMapEntry();
entry.name = name.toString();
name.delete(0, name.length());
if (entry.name.equals(chunkMapSignature))
break;
entry.position = in.readLong();
entry.length = in.readLong();
if (entry.name.startsWith("ImageDataSeq|")) {
imageDataCount++;
int imageIndex = -1;
try {
imageIndex = Integer.parseInt(entry.name.substring("ImageDataSeq|".length()));
if (imageIndex > maxImageIndex) {
maxImageIndex = imageIndex;
}
} catch (NumberFormatException e) {
LOGGER.trace(entry.name, e);
}
}
allChunkPositions.put(entry.position, entry);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("ND2 {}", entry.toString());
}
}
if (imageDataCount != maxImageIndex + 1) {
LOGGER.warn("Discarding chunk map; image data count = {}, max index = {}", imageDataCount, maxImageIndex);
useChunkMap = false;
}
}
in.seek(0);
}
// search for blocks
// 0xDACEBE0A
byte[] sigBytes = { -38, -50, -66, 10 };
byte[] buf = new byte[BUFFER_SIZE];
if (useChunkMap) {
long checkEvery = in.length() / 10;
long nextCheck = 0;
for (ChunkMapEntry entry : allChunkPositions.values()) {
if (!entry.name.startsWith("ImageDataSeq")) {
continue;
}
if (entry.position > nextCheck) {
in.seek(entry.position);
in.read(buf, 0, sigBytes.length);
if (!(buf[0] == sigBytes[0] && buf[1] == sigBytes[1] && buf[2] == sigBytes[2] && buf[3] == sigBytes[3])) {
LOGGER.warn("Broken ND2 File detected! Disabling chunk map processing.");
useChunkMap = false;
break;
}
nextCheck = entry.position + checkEvery;
}
}
}
int chunkmapSkips = 0;
in.seek(0);
while (in.getFilePointer() < in.length() - 1 && in.getFilePointer() >= 0) {
int foundIndex = -1;
in.read(buf, 0, sigBytes.length);
while (foundIndex == -1 && in.getFilePointer() < in.length()) {
int n = in.read(buf, sigBytes.length, buf.length - sigBytes.length);
for (int i = 0; i < buf.length - sigBytes.length; i++) {
for (int j = 0; j < sigBytes.length; j++) {
if (buf[i + j] != sigBytes[j])
break;
if (j == sigBytes.length - 1)
foundIndex = i;
}
if (foundIndex != -1)
break;
}
if (foundIndex == -1) {
// likely faster than System.arraycopy
buf[0] = buf[buf.length - 4];
buf[1] = buf[buf.length - 3];
buf[2] = buf[buf.length - 2];
buf[3] = buf[buf.length - 1];
} else if (in.getFilePointer() - n + foundIndex < in.length()) {
in.seek(in.getFilePointer() - n + foundIndex);
}
}
if (in.getFilePointer() > in.length() - 24 || foundIndex == -1) {
break;
}
// Remember starting position
Long helper = in.getFilePointer();
// Length of the block name
int nameLength = in.readInt();
// Length of the data
long dataLength = in.readLong();
// Read the name
String nameAttri = in.readString(nameLength).trim();
// Where this block ends
Long stop = helper + (dataLength + nameLength);
// Only 1 MetadataSeq is needed
boolean seq = false;
// (we are interested only in xxxxLV - LV = light variant)
if (nameAttri.contains("MetadataLV") || nameAttri.contains("CalibrationLV") || (nameAttri.contains("MetadataSeqLV") && !seq)) {
// prevent position count from being doubled
if (nameAttri.equals("ImageMetadataLV!")) {
positionCount = 0;
}
iterateIn(in, stop);
}
// (others should be same, and time is saved elsewhere)
if (nameAttri.contains("MetadataSeqLV")) {
seq = true;
}
// Return to starting position
in.seek(helper + 12);
int len = (int) (nameLength + dataLength);
long fp = in.getFilePointer();
String blockType = in.readString(12);
int percent = (int) (100 * fp / in.length());
LOGGER.info("Parsing block '{}' {}%", blockType, percent);
blockCount++;
int skip = len - 12 - nameLength * 2;
if (skip <= 0)
skip += nameLength * 2;
if (blockType.endsWith("Calibra")) {
long veryStart = in.getFilePointer();
// ImageCalibra|tionLV
in.skipBytes(12);
long endFP = in.getFilePointer() + len - 24;
while (in.read() == 0) ;
while (in.getFilePointer() < endFP) {
int nameLen = in.read();
if (nameLen == 0) {
in.seek(in.getFilePointer() - 3);
nameLen = in.read();
}
if (nameLen < 0) {
break;
}
// Get data
String attributeName = DataTools.stripString(in.readString(nameLen * 2));
double valueOrLength = in.readDouble();
if (attributeName.equals("dCalibration")) {
if (valueOrLength > 0) {
addGlobalMeta(attributeName, valueOrLength);
if (trueSizeX == 0) {
trueSizeX = valueOrLength;
} else if (trueSizeY == 0) {
trueSizeY = valueOrLength;
}
}
// Done with calibration
break;
}
}
// For old nd2 files
in.seek(veryStart);
}
if (blockType.startsWith("ImageDataSeq")) {
if (foundMetadata && foundAttributes) {
imageOffsets.clear();
imageNames.clear();
imageLengths.clear();
customDataOffsets.clear();
customDataLengths.clear();
foundMetadata = false;
foundAttributes = false;
extraZDataCount = 0;
useLastText = true;
}
if (useChunkMap && chunkmapSkips == 0) {
ChunkMapEntry lastImage = null;
// sanity check: see if the chunk we just found is actually in the chunkmap ...
long lookupPosition = in.getFilePointer() - 28;
Long lookupResult = allChunkPositions.floorKey(lookupPosition);
if (lookupResult == null || lookupResult != lookupPosition) {
// if not, deactivate chunkmap processing and try classic
useChunkMap = false;
in.seek(lookupPosition);
continue;
}
for (ChunkMapEntry entry : allChunkPositions.values()) {
if ((entry.position + 28) < in.getFilePointer()) {
continue;
}
if (!entry.name.startsWith("ImageDataSeq")) {
break;
}
if (lastImage != null) {
chunkmapSkips = (int) (((entry.position - lastImage.position) / entry.length) - 1);
if (chunkmapSkips > 0) {
break;
}
}
lastImage = entry;
imageOffsets.add(new Long(entry.position + 16));
int realLength = (int) Math.max(entry.name.length() + 1, nameLength);
imageLengths.add(new int[] { realLength, (int) (entry.length - nameLength - 16), getSizeX() * getSizeY() });
imageNames.add(entry.name.substring(12));
blockCount++;
percent = (int) (100 * entry.position / in.length());
LOGGER.info("Parsing block '{}' {}%", "ImageDataSeq", percent);
}
// one was already added by the outer blockCount ++;
blockCount--;
if (lastImage.position + lastImage.length >= in.length()) {
in.seek(lastImage.position + 16);
} else {
in.seek(lastImage.position + lastImage.length);
}
continue;
}
if (chunkmapSkips > 0) {
chunkmapSkips -= 1;
}
dataLength -= 31;
LOGGER.debug("Adding non-chunkmap offset {}, nameLength = {}, dataLength = {}", fp, nameLength, dataLength);
imageOffsets.add(fp);
imageLengths.add(new int[] { nameLength, (int) dataLength, getSizeX() * getSizeY() });
char b = (char) in.readByte();
while (b != '!') {
name.append(b);
b = (char) in.readByte();
}
imageNames.add(name.toString());
name.setLength(0);
} else if (blockType.startsWith("ImageText")) {
foundMetadata = true;
in.skipBytes(6);
while (in.read() == 0) ;
long startFP = in.getFilePointer();
in.seek(startFP - 1);
String textString = DataTools.stripString(in.readString((int) dataLength));
textStrings.add(textString);
validDimensions.add(blockCount > 2);
if (!textString.startsWith("<")) {
skip = 0;
}
} else if (blockType.startsWith("Image") || blockType.startsWith("CustomDataVa")) {
if (blockType.equals("ImageAttribu")) {
foundAttributes = true;
in.skipBytes(6);
long endFP = in.getFilePointer() + len - 18;
while (in.read() == 0) ;
boolean canBeLossless = true;
while (in.getFilePointer() < endFP) {
int nameLen = in.read();
if (nameLen == 0) {
in.seek(in.getFilePointer() - 3);
nameLen = in.read();
}
if (nameLen < 0) {
break;
}
long start = in.getFilePointer();
String attributeName = DataTools.stripString(in.readString(nameLen * 2));
if (attributeName.startsWith("xml ") || attributeName.startsWith("ml version") || attributeName.startsWith("l version") || attributeName.startsWith("version")) {
if (attributeName.startsWith("xml ")) {
in.seek(start - 2);
} else if (attributeName.startsWith("ml version")) {
in.seek(start - 3);
} else if (attributeName.startsWith("l version")) {
in.seek(start - 4);
} else {
in.seek(start - 6);
}
attributeName = in.readCString();
String xmlString = XMLTools.sanitizeXML(attributeName.trim());
xmlString = xmlString.substring(0, xmlString.lastIndexOf(">") + 1);
if (xmlString.startsWith("<?xml")) {
xmlString = xmlString.substring(xmlString.indexOf('>') + 1);
}
if (!xmlString.endsWith("</variant>")) {
xmlString += "</variant>";
}
if (getDimensionOrder() == null) {
core.get(0).dimensionOrder = "";
}
try {
ND2Handler handler = new ND2Handler(core, imageOffsets.size());
XMLTools.parseXML(xmlString, handler);
xmlString = null;
core = handler.getCoreMetadataList();
if (backupHandler == null) {
backupHandler = handler;
}
} catch (IOException e) {
LOGGER.debug("Could not parse XML", e);
}
in.seek(in.getFilePointer() - 8);
break;
}
int valueOrLength = in.readInt();
addGlobalMeta(attributeName, valueOrLength);
if (attributeName.equals("uiWidth")) {
core.get(0).sizeX = valueOrLength;
} else if (attributeName.equals("uiHeight")) {
core.get(0).sizeY = valueOrLength;
} else if (attributeName.equals("uiComp")) {
core.get(0).sizeC = valueOrLength;
} else if (attributeName.equals("uiBpcInMemory")) {
core.get(0).pixelType = FormatTools.pixelTypeFromBytes(valueOrLength / 8, false, false);
} else if (attributeName.equals("uiBpcSignificant")) {
core.get(0).bitsPerPixel = valueOrLength;
} else if (attributeName.equals("dCompressionParam")) {
isLossless = valueOrLength >= 0;
} else if (attributeName.equals("eCompression")) {
canBeLossless = valueOrLength <= 0;
} else if (attributeName.equals("SLxImageAttributes")) {
int toSkip = valueOrLength - 5;
if ((toSkip % 2) == 1) {
toSkip++;
}
in.skipBytes(toSkip);
} else if (attributeName.endsWith("Desc")) {
in.seek(in.getFilePointer() - 2);
} else if (attributeName.equals("SLxExperiment")) {
in.skipBytes(8);
} else if (attributeName.equals("wsCameraName")) {
in.seek(in.getFilePointer() - 4);
byte[] b = new byte[2];
in.read(b);
StringBuilder value = new StringBuilder();
while (b[0] != 0) {
value.append(b[0]);
in.read(b);
}
addGlobalMeta(attributeName, value.toString());
} else if (attributeName.equals("uLoopPars")) {
int v2 = in.readInt();
int v3 = in.readInt();
addGlobalMeta(attributeName, valueOrLength + ", " + v2 + ", " + v3);
} else if (attributeName.equals("pPeriod")) {
in.skipBytes(22);
} else if (attributeName.equals("dPeriod") || attributeName.equals("dDuration")) {
in.skipBytes(4);
} else if (attributeName.equals("bDurationPref")) {
in.seek(in.getFilePointer() - 3);
}
in.skipBytes(1);
}
if (in.getFilePointer() > endFP) {
in.seek(endFP);
}
isLossless = isLossless && canBeLossless;
} else {
if (blockType.startsWith("ImageMetadat")) {
foundMetadata = true;
}
int length = len - 12;
byte[] b = new byte[length];
in.read(b);
// strip out invalid characters
int off = 0;
for (int j = 0; j < length; j++) {
char c = (char) b[j];
if ((off == 0 && c == '!') || c == 0)
off = j + 1;
if (Character.isISOControl(c) || !Character.isDefined(c)) {
b[j] = (byte) ' ';
}
}
if (length - off >= 5 && b[off] == '<' && b[off + 1] == '?' && b[off + 2] == 'x' && b[off + 3] == 'm' && b[off + 4] == 'l') {
boolean endBracketFound = false;
while (!endBracketFound) {
if (b[off++] == '>') {
endBracketFound = true;
}
}
xml.write(b, off, b.length - off);
}
}
skip = 0;
} else if (getMetadataOptions().getMetadataLevel() != MetadataLevel.MINIMUM) {
int nDoubles = len / 8;
int nInts = len / 4;
long doubleOffset = fp + 8 * (nDoubles - imageOffsets.size());
long intOffset = fp + 4 * (nInts - imageOffsets.size());
if (blockType.startsWith("CustomData|A")) {
customDataOffsets.add(fp);
customDataLengths.add(new int[] { nameLength, (int) dataLength });
} else if (blockType.startsWith("CustomData|Z")) {
if (zOffset == 0) {
zOffset = doubleOffset;
}
extraZDataCount++;
} else if (blockType.startsWith("CustomData|X")) {
xOffset = doubleOffset;
} else if (blockType.startsWith("CustomData|Y")) {
yOffset = doubleOffset;
} else if (blockType.startsWith("CustomData|P")) {
if (pfsOffset == 0) {
pfsOffset = intOffset;
} else if (pfsStateOffset == 0) {
pfsStateOffset = intOffset;
}
}
}
if (skip > 0 && skip + in.getFilePointer() <= in.length()) {
in.skipBytes(skip);
}
}
// parse text blocks
int nChannelNames = textChannelNames.size();
for (int i = 0; i < textStrings.size(); i++) {
parseText(textStrings.get(i), imageOffsets.size(), validDimensions.get(i));
}
if (textChannelNames.size() > nChannelNames) {
int diff = textChannelNames.size() - nChannelNames;
while (textChannelNames.size() > diff) {
textChannelNames.remove(0);
}
}
// parse XML blocks
String xmlString = new String(xml.getBytes(), 0, (int) xml.length(), Constants.ENCODING);
xml = null;
xmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ND2>" + xmlString + "</ND2>";
xmlString = XMLTools.sanitizeXML(xmlString);
core.get(0).dimensionOrder = "";
ND2Handler handler = new ND2Handler(core, getSizeX() == 0, imageOffsets.size());
XMLTools.parseXML(xmlString, handler);
xmlString = null;
if (handler.getChannelColors().size() > 0) {
channelColors = handler.getChannelColors();
}
if (!isLossless) {
isLossless = handler.isLossless();
}
fieldIndex = handler.getFieldIndex();
core = handler.getCoreMetadataList();
final Map<String, Object> globalMetadata = handler.getMetadata();
nXFields = handler.getXFields();
if (nXFields > 6) {
nXFields = 0;
}
for (String key : globalMetadata.keySet()) {
addGlobalMeta(key, globalMetadata.get(key));
if (key.equals("ChannelCount")) {
for (int i = 0; i < getSeriesCount(); i++) {
CoreMetadata ms = core.get(i);
if (ms.sizeC == 0) {
ms.sizeC = Integer.parseInt(globalMetadata.get(key).toString());
if (ms.sizeC > 1) {
ms.rgb = true;
}
}
}
} else if (key.equals("uiBpcInMemory")) {
int bpc = Integer.parseInt(globalMetadata.get(key).toString());
core.get(0).pixelType = FormatTools.pixelTypeFromBytes(bpc / 8, false, false);
}
}
int planeCount = core.size() * getSizeZ() * getSizeT();
if (!textData && planeCount < imageOffsets.size() && planeCount > 0 && (imageOffsets.size() % (planeCount / core.size())) == 0) {
int seriesCount = imageOffsets.size() / (planeCount / core.size());
core = new ArrayList<CoreMetadata>();
for (int i = 0; i < seriesCount; i++) {
core.add(handler.getCoreMetadataList().get(0));
}
}
int numSeries = core.size();
if (numSeries == 0)
numSeries = 1;
else if (numSeries == 1 && positionCount > 1) {
for (int i = 1; i < positionCount; i++) {
core.add(core.get(0));
}
numSeries = core.size();
}
if (getSizeZ() == 0) {
for (int i = 0; i < getSeriesCount(); i++) {
core.get(i).sizeZ = 1;
}
if (getSizeT() == 0) {
for (int i = 0; i < getSeriesCount(); i++) {
core.get(i).sizeT = imageOffsets.size() / getSeriesCount();
}
}
}
if (getSizeT() == 0) {
for (int i = 0; i < getSeriesCount(); i++) {
core.get(i).sizeT = 1;
}
}
if (getSizeC() == 0) {
for (int i = 0; i < getSeriesCount(); i++) {
core.get(i).sizeC = 1;
}
}
if (getSizeZ() * getSizeT() == imageOffsets.size() && core.size() > 1) {
CoreMetadata ms0 = core.get(0);
core = new ArrayList<CoreMetadata>();
core.add(ms0);
}
if (positionCount != getSeriesCount() && (getSizeZ() == imageOffsets.size() || (extraZDataCount > 1 && getSizeZ() == 1 && (extraZDataCount == getSizeC())) || (handler.getXPositions().size() == 0 && (xOffset == 0 && getSizeZ() != getSeriesCount()))) && getSeriesCount() > 1) {
CoreMetadata ms0 = core.get(0);
if (getSeriesCount() > ms0.sizeZ) {
ms0.sizeZ = getSeriesCount();
}
core = new ArrayList<CoreMetadata>();
core.add(ms0);
}
// make sure the channel count is reasonable
// sometimes the XML will indicate that there are multiple channels,
// when in fact there is only one channel
long firstOffset = imageOffsets.get(0);
long secondOffset = imageOffsets.size() > 1 ? imageOffsets.get(1) : in.length();
long availableBytes = secondOffset - firstOffset;
// make sure that we have the compression setting correct
// it's not always easy to tell from the metadata
isLossless = true;
long fp = in.getFilePointer();
int[] firstLengths = imageLengths.get(0);
in.seek(firstOffset + firstLengths[0] + 8);
if (codec == null)
codec = createCodec(false);
try {
CodecOptions options = new CodecOptions();
options.littleEndian = isLittleEndian();
options.interleaved = true;
options.maxBytes = (int) secondOffset;
byte[] t = codec.decompress(in, options);
if (t.length == 2 * getSizeX() * getSizeY() && getPixelType() == FormatTools.INT8) {
core.get(0).pixelType = FormatTools.UINT16;
}
availableBytes = t.length;
} catch (IOException e) {
isLossless = false;
}
boolean allEqual = true;
long offsetDiff = imageOffsets.get(0) - imageLengths.get(0)[1];
for (int i = 1; i < imageOffsets.size(); i++) {
long nextOffsetDiff = imageOffsets.get(i) - imageLengths.get(i)[1];
if (imageLengths.get(i)[1] != imageLengths.get(0)[1] && offsetDiff != nextOffsetDiff) {
allEqual = false;
break;
}
}
if (!allEqual && !isLossless && imageOffsets.size() > 1) {
int plane = (getSizeX() + getScanlinePad()) * getSizeY();
boolean fixByteCounts = false;
if (plane > 0) {
for (int i = 0; i < imageOffsets.size(); i++) {
int check = imageLengths.get(i)[2];
int length = imageLengths.get(i)[1] - 8;
if ((length % plane != 0 && length % (getSizeX() * getSizeY()) != 0) || (check > 0 && plane != check)) {
if (imageOffsets.get(i) - length != offsetDiff + 8) {
if (i == 0) {
fixByteCounts = true;
}
imageOffsets.remove(i);
imageLengths.remove(i);
i--;
}
}
}
}
if (fixByteCounts) {
firstOffset = imageOffsets.get(0);
secondOffset = imageOffsets.size() > 1 ? imageOffsets.get(1) : in.length();
availableBytes = secondOffset - firstOffset;
if (isLossless) {
firstLengths = imageLengths.get(0);
in.seek(firstOffset + firstLengths[0] + 8);
CodecOptions options = new CodecOptions();
options.littleEndian = isLittleEndian();
options.interleaved = true;
options.maxBytes = (int) secondOffset;
byte[] t = codec.decompress(in, options);
availableBytes = t.length;
}
}
}
in.seek(fp);
long planeSize = getSizeX() * getSizeY() * getSizeC() * FormatTools.getBytesPerPixel(getPixelType());
if (availableBytes < planeSize) {
LOGGER.debug("Correcting SizeC: was {}", getSizeC());
LOGGER.debug("plane size = {}", planeSize);
LOGGER.debug("available bytes = {}", availableBytes);
core.get(0).sizeC = (int) (availableBytes / (planeSize / getSizeC()));
if (getSizeC() == 0) {
core.get(0).sizeC = 1;
}
planeSize = getSizeX() * getSizeY() * getSizeC() * FormatTools.getBytesPerPixel(getPixelType());
}
if (planeSize > 0 && availableBytes % planeSize != 0) {
// an extra 4K block of zeros may have been appended
if ((availableBytes - 4096) % planeSize == 0) {
availableBytes -= 4096;
}
}
if (planeSize > 0 && imageOffsets.size() > 1 && availableBytes > DataTools.safeMultiply64(planeSize, 3)) {
if (availableBytes < DataTools.safeMultiply64(planeSize, 6)) {
core.get(0).sizeC = 3;
core.get(0).rgb = true;
if (getPixelType() == FormatTools.INT8) {
core.get(0).pixelType = availableBytes > planeSize * 5 ? FormatTools.UINT16 : FormatTools.UINT8;
}
}
} else if (((planeSize > 0 && availableBytes >= DataTools.safeMultiply64(planeSize, 2)) || getSizeC() > 3) && getPixelType() == FormatTools.INT8) {
core.get(0).pixelType = FormatTools.UINT16;
planeSize *= 2;
if (getSizeC() > 3 && availableBytes % planeSize != 0 && planeSize > availableBytes) {
core.get(0).sizeC = 3;
core.get(0).rgb = true;
}
} else if (getSizeC() == 2 && getPixelType() == FormatTools.INT8 && availableBytes >= planeSize * 2) {
core.get(0).pixelType = FormatTools.UINT16;
} else if (getPixelType() == FormatTools.INT8) {
core.get(0).pixelType = FormatTools.UINT8;
}
if (getSizeX() == 0) {
core.get(0).sizeX = (int) Math.sqrt(availableBytes / (getSizeC() * FormatTools.getBytesPerPixel(getPixelType())));
core.get(0).sizeY = getSizeX();
}
int rowSize = getSizeX() * FormatTools.getBytesPerPixel(getPixelType()) * getSizeC();
long sizeY = availableBytes / rowSize;
if (sizeY < getSizeY()) {
core.get(0).sizeY = (int) sizeY;
}
if (getSizeT() == imageOffsets.size() && getSeriesCount() > 1) {
CoreMetadata firstCore = core.get(0);
core = new ArrayList<CoreMetadata>();
core.add(firstCore);
}
// calculate the image count
for (int i = 0; i < getSeriesCount(); i++) {
CoreMetadata ms = core.get(i);
ms.imageCount = getSizeZ() * getSizeT() * getSizeC();
if (imageOffsets.size() / getSeriesCount() < ms.imageCount) {
ms.imageCount /= getSizeC();
}
if (ms.imageCount > imageOffsets.size() / getSeriesCount()) {
int diff = imageOffsets.size() - ms.imageCount;
if (diff >= 0 && diff < ms.sizeZ && diff < ms.sizeT) {
CoreMetadata ms0 = core.get(0);
core = new ArrayList<CoreMetadata>();
core.add(ms0);
numSeries = 1;
break;
} else if (imageOffsets.size() % ms.sizeT == 0) {
ms.imageCount = imageOffsets.size() / getSeriesCount();
ms.sizeZ = ms.imageCount / ms.sizeT;
ms.dimensionOrder = "CZT";
} else {
ms.imageCount = imageOffsets.size() / getSeriesCount();
ms.sizeZ = 1;
ms.sizeT = ms.imageCount;
}
}
}
if (numSeries * getImageCount() == 1 && imageOffsets.size() > 1) {
for (int i = 0; i < getSeriesCount(); i++) {
core.get(i).imageCount = imageOffsets.size() / getSeriesCount();
core.get(i).sizeZ = getImageCount();
core.get(i).sizeT = 1;
}
}
if (getSizeZ() * getSizeT() * (split ? 1 : getSizeC()) < imageOffsets.size() / getSeriesCount()) {
split = getSizeC() > 1;
int count = imageOffsets.size() / getSeriesCount();
if (!split && count >= getSizeC()) {
count /= getSizeC();
}
int diff = count - getSizeZ() * getSizeT();
if (diff == getSizeZ()) {
core.get(0).sizeT++;
} else if (getSizeT() > getSizeZ()) {
core.get(0).sizeZ = 1;
core.get(0).sizeT = count;
} else {
core.get(0).sizeT = 1;
core.get(0).sizeZ = count;
}
if (useZ != null && !useZ) {
CoreMetadata original = core.get(0);
int nSeries = imageOffsets.size() / (getSizeZ() * getSizeT());
for (int i = 1; i < nSeries; i++) {
core.add(original);
}
numSeries = core.size();
}
if (getSizeZ() * getSizeT() * (split ? 1 : getSizeC()) < imageOffsets.size() / getSeriesCount() && getSizeC() > 4) {
core.get(0).sizeZ = 1;
core.get(0).sizeT = imageOffsets.size() / getSeriesCount();
}
core.get(0).imageCount = getSizeZ() * getSizeT() * getSizeC();
}
if (getDimensionOrder().equals("T")) {
fieldIndex = 0;
} else if (getDimensionOrder().equals("ZT") && fieldIndex == 2) {
fieldIndex--;
}
if (getSizeC() > 1 && getDimensionOrder().indexOf('C') == -1) {
core.get(0).dimensionOrder = "C" + getDimensionOrder();
fieldIndex++;
}
core.get(0).dimensionOrder = "XY" + getDimensionOrder();
if (getDimensionOrder().indexOf('Z') == -1)
core.get(0).dimensionOrder += 'Z';
if (getDimensionOrder().indexOf('C') == -1)
core.get(0).dimensionOrder += 'C';
if (getDimensionOrder().indexOf('T') == -1)
core.get(0).dimensionOrder += 'T';
if (getSizeZ() == 0) {
core.get(0).sizeZ = 1;
}
if (getSizeT() == 0) {
core.get(0).sizeT = 1;
}
if (getSizeC() == 0) {
core.get(0).sizeC = 1;
}
core.get(0).imageCount = getSizeZ() * getSizeT();
if (!isRGB()) {
core.get(0).imageCount *= getSizeC();
}
posX = handler.getXPositions();
posY = handler.getYPositions();
posZ = handler.getZPositions();
int uniqueX = 0, uniqueY = 0, uniqueZ = 0;
if (posX.size() == 0 && xOffset != 0) {
in.seek(xOffset);
for (int i = 0; i < imageOffsets.size(); i++) {
final Double number = Double.valueOf(in.readDouble());
final Length x = new Length(number, UNITS.REFERENCEFRAME);
if (!posX.contains(x)) {
uniqueX++;
}
posX.add(x);
}
}
if (posY.size() == 0 && yOffset != 0) {
in.seek(yOffset);
for (int i = 0; i < imageOffsets.size(); i++) {
final Double number = Double.valueOf(in.readDouble());
final Length y = new Length(number, UNITS.REFERENCEFRAME);
if (!posY.contains(y)) {
uniqueY++;
}
posY.add(y);
}
}
if (posZ.size() == 0 && zOffset != 0) {
in.seek(zOffset);
for (int i = 0; i < imageOffsets.size(); i++) {
final Double number = Double.valueOf(in.readDouble());
final Length z = new Length(number, UNITS.REFERENCEFRAME);
if (!posZ.contains(z)) {
boolean unique = true;
for (int q = 0; q < posZ.size(); q++) {
// account for potential stage drift
final double z1 = z.value(UNITS.REFERENCEFRAME).doubleValue();
final double z2 = posZ.get(q).value(UNITS.REFERENCEFRAME).doubleValue();
if (Math.abs(z1 - z2) <= 0.05) {
unique = false;
break;
}
}
if (unique) {
uniqueZ++;
}
}
posZ.add(z);
}
}
if (pfsOffset != 0) {
in.seek(pfsOffset);
for (int i = 0; i < imageOffsets.size(); i++) {
addGlobalMetaList("PFS Offset", in.readInt());
}
}
if (pfsStateOffset != 0) {
in.seek(pfsStateOffset);
for (int i = 0; i < imageOffsets.size(); i++) {
addGlobalMetaList("PFS Status", in.readInt());
}
}
if (core.size() == 1 && ((uniqueX == getSizeT() && uniqueY == getSizeT()) || uniqueZ == getSizeT())) {
int count = getSizeT();
core.get(0).imageCount /= count;
core.get(0).sizeT = 1;
for (int i = 1; i < count; i++) {
core.add(core.get(0));
}
numSeries = core.size();
}
// when the offsets array is allocated
if (getImageCount() == imageOffsets.size() && numSeries > 1 && getSizeC() == 1) {
CoreMetadata first = core.get(0);
core.clear();
core.add(first);
numSeries = 1;
}
offsets = new long[numSeries][getImageCount()];
int[] lengths = new int[4];
int nextChar = 2;
for (int i = 0; i < lengths.length; i++) {
if (i == fieldIndex)
lengths[i] = core.size();
else {
char axis = getDimensionOrder().charAt(nextChar++);
if (axis == 'Z')
lengths[i] = getSizeZ();
else if (axis == 'C')
lengths[i] = 1;
else if (axis == 'T')
lengths[i] = getSizeT();
}
}
int[] zctLengths = new int[4];
System.arraycopy(lengths, 0, zctLengths, 0, lengths.length);
zctLengths[fieldIndex] = 1;
boolean oneIndexed = false;
for (int i = 0; i < imageOffsets.size(); i++) {
long offset = imageOffsets.get(i).longValue();
int[] p = imageLengths.get(i);
int length = p[0] + p[1];
if (getSizeC() == 0) {
int sizeC = length / (getSizeX() * getSizeY() * FormatTools.getBytesPerPixel(getPixelType()));
for (int q = 0; q < getSeriesCount(); q++) {
core.get(q).sizeC = sizeC;
}
}
String imageName = imageNames.get(i);
int ndx = Integer.parseInt(imageName.replaceAll("\\D", ""));
if (ndx == 1 && i == 0) {
oneIndexed = true;
}
if (oneIndexed) {
ndx--;
}
int[] pos = FormatTools.rasterToPosition(lengths, ndx);
int seriesIndex = pos[fieldIndex];
pos[fieldIndex] = 0;
int plane = FormatTools.positionToRaster(zctLengths, pos);
if (seriesIndex < offsets.length && plane < offsets[seriesIndex].length) {
offsets[seriesIndex][plane] = offset + p[0] + 8;
}
}
ArrayList<long[]> tmpOffsets = new ArrayList<long[]>();
for (int i = 0; i < offsets.length; i++) {
if (offsets[i].length > 0 && offsets[i][0] > 0) {
tmpOffsets.add(offsets[i]);
}
}
offsets = new long[tmpOffsets.size()][];
for (int i = 0; i < tmpOffsets.size(); i++) {
offsets[i] = tmpOffsets.get(i);
}
if (offsets.length != getSeriesCount()) {
int x = getSizeX();
int y = getSizeY();
int c = getSizeC();
int pixelType = getPixelType();
int bitsPerPixel = getBitsPerPixel();
boolean rgb = isRGB();
String order = getDimensionOrder();
core = new ArrayList<CoreMetadata>();
for (int i = 0; i < offsets.length; i++) {
CoreMetadata ms = new CoreMetadata();
core.add(ms);
ms.sizeX = x;
ms.sizeY = y;
ms.sizeC = c == 0 ? 1 : c;
ms.pixelType = pixelType;
ms.bitsPerPixel = bitsPerPixel;
ms.rgb = rgb;
ms.sizeZ = 1;
ms.dimensionOrder = order;
int invalid = 0;
for (int q = 0; q < offsets[i].length; q++) {
if (offsets[i][q] == 0)
invalid++;
}
ms.imageCount = offsets[i].length - invalid;
ms.sizeT = ms.imageCount / (rgb ? 1 : ms.sizeC);
if (ms.sizeT == 0)
ms.sizeT = 1;
}
} else {
for (int i = 0; i < getSeriesCount(); i++) {
CoreMetadata ms = core.get(i);
ms.sizeX = getSizeX();
ms.sizeY = getSizeY();
ms.sizeC = getSizeC() == 0 ? 1 : getSizeC();
ms.sizeZ = getSizeZ() == 0 ? 1 : getSizeZ();
ms.sizeT = getSizeT() == 0 ? 1 : getSizeT();
ms.imageCount = getImageCount();
ms.pixelType = getPixelType();
ms.bitsPerPixel = getBitsPerPixel();
ms.dimensionOrder = getDimensionOrder();
}
}
boolean hasColor = false;
for (String ch : channelColors.keySet()) {
Integer color = channelColors.get(ch);
// look for a color that is neither black nor white
if (color != 0xffffff && color != 0) {
hasColor = true;
break;
}
}
split = getSizeC() > 1;
for (int i = 0; i < getSeriesCount(); i++) {
CoreMetadata ms = core.get(i);
ms.rgb = false;
ms.littleEndian = true;
ms.interleaved = false;
ms.indexed = channelColors.size() > 0 && hasColor;
ms.falseColor = true;
ms.metadataComplete = true;
ms.imageCount = ms.sizeZ * ms.sizeT * ms.sizeC;
}
if (getMetadataOptions().getMetadataLevel() != MetadataLevel.MINIMUM) {
if (customDataOffsets.size() > 0) {
in.seek(customDataOffsets.get(0).longValue());
int[] p = customDataLengths.get(0);
int len = p[0] + p[1];
int timestampBytes = imageOffsets.size() * 8;
in.skipBytes(len - timestampBytes);
for (int series = 0; series < getSeriesCount(); series++) {
setSeries(series);
int count = split ? getImageCount() / getSizeC() : getImageCount();
for (int plane = 0; plane < count; plane++) {
// timestamps are stored in ms; we want them in seconds
double time = in.readDouble() / 1000;
tsT.add(time);
addSeriesMetaList("timestamp", time);
}
}
setSeries(0);
}
}
populateMetadataStore(handler);
return;
} else
in.seek(0);
// older version of ND2 - uses JPEG 2000 compression
isJPEG = true;
LOGGER.info("Calculating image offsets");
ArrayList<Long> vs = new ArrayList<Long>();
long pos = in.getFilePointer();
boolean lastBoxFound = false;
int length = 0;
int box = 0;
// assemble offsets to each plane
int x = 0, y = 0, c = 0, type = 0;
while (!lastBoxFound) {
pos = in.getFilePointer();
length = in.readInt();
long nextPos = pos + length;
if (nextPos < 0 || nextPos >= in.length() || length == 0) {
lastBoxFound = true;
}
box = in.readInt();
pos = in.getFilePointer();
length -= 8;
if (box == 0x6a703263) {
vs.add(pos);
} else if (box == 0x6a703268) {
in.skipBytes(4);
String s = in.readString(4);
if (s.equals("ihdr")) {
y = in.readInt();
x = in.readInt();
c = in.readShort();
type = in.readInt();
if (type == 0xf070100 || type == 0xf070000)
type = FormatTools.UINT16;
else
type = FormatTools.UINT8;
}
}
if (!lastBoxFound && box != 0x6a703268)
in.skipBytes(length);
}
LOGGER.info("Finding XML metadata");
// read XML metadata from the end of the file
in.seek(vs.get(vs.size() - 1).longValue());
boolean found = false;
long off = -1;
byte[] buf = new byte[8192];
while (!found && in.getFilePointer() < in.length()) {
int read = 0;
if (in.getFilePointer() == vs.get(vs.size() - 1).longValue()) {
read = in.read(buf);
} else {
System.arraycopy(buf, buf.length - 10, buf, 0, 10);
read = in.read(buf, 10, buf.length - 10);
}
if (read == buf.length)
read -= 10;
for (int i = 0; i < read + 9; i++) {
if (buf[i] == (byte) 0xff && buf[i + 1] == (byte) 0xd9) {
found = true;
off = in.getFilePointer() - (read + 10) + i;
i = buf.length;
break;
}
}
}
buf = null;
LOGGER.info("Parsing XML");
ArrayList<Long> zs = new ArrayList<Long>();
ArrayList<Long> ts = new ArrayList<Long>();
int numSeries = 0;
ND2Handler handler = null;
if (off > 0 && off < in.length() - 5 && (in.length() - off - 5) > 14) {
in.seek(off + 4);
StringBuilder sb = new StringBuilder();
// stored XML doesn't have a root node - add one, so that we can parse
// using SAX
sb.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><NIKON>");
String s = null;
int blockLength = 0;
while (in.getFilePointer() < in.length()) {
blockLength = in.readShort();
if (blockLength < 2)
break;
blockLength -= 2;
if (blockLength + in.getFilePointer() >= in.length()) {
blockLength = (int) (in.length() - in.getFilePointer());
}
s = in.readString(blockLength);
// remove comments
s = s.replaceAll("<!--.+?>", "");
int openBracket = s.indexOf('<');
if (openBracket == -1)
continue;
int closedBracket = s.lastIndexOf(">") + 1;
if (closedBracket < openBracket)
continue;
s = s.substring(openBracket, closedBracket).trim();
if (s.indexOf("CalibrationSeq") == -1 && s.indexOf("VCAL") == -1 && s.indexOf("jp2cLUNK") == -1) {
sb.append(s);
}
}
s = null;
sb.append("</NIKON>");
LOGGER.info("Finished assembling XML string");
// strip out invalid characters
int offset = 0;
int len = sb.length();
for (int i = 0; i < len; i++) {
char ch = sb.charAt(i);
if (offset == 0 && ch == '!')
offset = i + 1;
if (Character.isISOControl(ch) || !Character.isDefined(ch)) {
sb.setCharAt(i, ' ');
}
}
core.get(0).dimensionOrder = "";
if (len - offset < offset) {
offset = 0;
}
String xml = sb.substring(offset, len);
sb = null;
handler = new ND2Handler(core, vs.size());
try {
xml = XMLTools.sanitizeXML(xml);
XMLTools.parseXML(xml, handler);
} catch (IOException e) {
}
xml = null;
isLossless = handler.isLossless();
fieldIndex = handler.getFieldIndex();
zs = handler.getZSections();
ts = handler.getTimepoints();
numSeries = handler.getSeriesCount();
core = handler.getCoreMetadataList();
final Map<String, Object> globalMetadata = handler.getMetadata();
for (final Map.Entry<String, Object> entry : globalMetadata.entrySet()) {
addGlobalMeta(entry.getKey(), entry.getValue());
}
}
LOGGER.info("Populating metadata");
core.get(0).pixelType = FormatTools.UINT8;
offsets = new long[1][2];
offsets[0][0] = vs.get(0).longValue();
if (offsets[0].length > 1 && vs.size() > 1) {
offsets[0][1] = vs.get(1).longValue();
}
in.seek(offsets[0][0]);
if (getSizeC() == 0)
core.get(0).sizeC = 1;
int numBands = c;
c = numBands > 1 ? numBands : getSizeC();
if (numBands == 1 && getImageCount() == 1)
c = 1;
for (int i = 0; i < getSeriesCount(); i++) {
CoreMetadata ms = core.get(i);
ms.sizeC = c;
ms.rgb = numBands > 1;
ms.pixelType = type;
}
if (getDimensionOrder() == null)
core.get(0).dimensionOrder = "";
if (getSizeC() > 1) {
core.get(0).dimensionOrder = getDimensionOrder().replaceAll("C", "");
core.get(0).dimensionOrder = "C" + getDimensionOrder();
fieldIndex++;
}
if (getDimensionOrder().indexOf('Z') == -1)
core.get(0).dimensionOrder += 'Z';
if (getDimensionOrder().indexOf('C') == -1)
core.get(0).dimensionOrder += 'C';
if (getDimensionOrder().indexOf('T') == -1)
core.get(0).dimensionOrder += 'T';
core.get(0).dimensionOrder = "XY" + getDimensionOrder();
if (getImageCount() == 0) {
core.get(0).imageCount = vs.size();
core.get(0).sizeZ = (int) Math.max(zs.size(), 1);
core.get(0).sizeT = (int) Math.max(ts.size(), 1);
int channels = isRGB() ? 1 : getSizeC();
if (channels * getSizeZ() * getSizeT() != getImageCount()) {
core.get(0).sizeZ = 1;
core.get(0).sizeT = getImageCount() / channels;
core.get(0).imageCount = getSizeZ() * getSizeT() * channels;
}
}
if (getSizeZ() == 0)
core.get(0).sizeZ = 1;
if (getSizeT() == 0)
core.get(0).sizeT = 1;
for (int i = 0; i < getSeriesCount(); i++) {
CoreMetadata ms = core.get(i);
ms.sizeZ = getSizeZ();
ms.sizeT = getSizeT();
ms.imageCount = getSizeZ() * getSizeT() * (isRGB() ? 1 : getSizeC());
ms.dimensionOrder = getDimensionOrder();
ms.sizeX = x;
ms.sizeY = y;
ms.interleaved = false;
ms.littleEndian = false;
ms.metadataComplete = true;
}
int nplanes = getSizeZ() * getEffectiveSizeC();
if (numSeries == 0)
numSeries = 1;
if (numSeries * nplanes * getSizeT() > vs.size()) {
numSeries = vs.size() / (nplanes * getSizeT());
}
offsets = new long[numSeries][getImageCount()];
for (int i = 0; i < getSizeT(); i++) {
for (int j = 0; j < numSeries; j++) {
for (int q = 0; q < nplanes; q++) {
offsets[j][i * nplanes + q] = vs.remove(0).longValue();
}
}
}
populateMetadataStore(handler);
}
use of loci.common.ByteArrayHandle in project bioformats by openmicroscopy.
the class NikonReader method openBytes.
/**
* @see loci.formats.IFormatReader#openBytes(int, byte[], int, int, int, int)
*/
@Override
public byte[] openBytes(int no, byte[] buf, int x, int y, int w, int h) throws FormatException, IOException {
FormatTools.checkPlaneParameters(this, no, buf.length, x, y, w, h);
IFD ifd = ifds.get(no);
int[] bps = ifd.getBitsPerSample();
int dataSize = bps[0];
long[] byteCounts = ifd.getStripByteCounts();
long totalBytes = 0;
for (long b : byteCounts) {
totalBytes += b;
}
if (totalBytes == FormatTools.getPlaneSize(this) || bps.length > 1) {
return super.openBytes(no, buf, x, y, w, h);
}
if (lastPlane == null || lastIndex != no) {
long[] offsets = ifd.getStripOffsets();
boolean maybeCompressed = ifd.getCompression() == TiffCompression.NIKON;
boolean compressed = vPredictor != null && curve != null && maybeCompressed;
if (!maybeCompressed && dataSize == 14)
dataSize = 16;
ByteArrayOutputStream src = new ByteArrayOutputStream();
NikonCodec codec = new NikonCodec();
NikonCodecOptions options = new NikonCodecOptions();
options.width = getSizeX();
options.height = getSizeY();
options.bitsPerSample = dataSize;
options.curve = curve;
if (vPredictor != null) {
options.vPredictor = new int[vPredictor.length];
}
options.lossless = !lossyCompression;
options.split = split;
for (int i = 0; i < byteCounts.length; i++) {
byte[] t = new byte[(int) byteCounts[i]];
in.seek(offsets[i]);
in.read(t);
if (compressed) {
options.maxBytes = (int) byteCounts[i];
System.arraycopy(vPredictor, 0, options.vPredictor, 0, vPredictor.length);
t = codec.decompress(t, options);
}
src.write(t);
}
RandomAccessInputStream bb = new RandomAccessInputStream(new ByteArrayHandle(src.toByteArray()));
short[] pix = new short[getSizeX() * getSizeY() * 3];
src.close();
// default color map
int[] colorMap = { 1, 0, 2, 1 };
short[] ifdColors = (short[]) ifd.get(COLOR_MAP);
if (ifdColors != null && ifdColors.length >= colorMap.length) {
boolean colorsValid = true;
for (int q = 0; q < colorMap.length; q++) {
if (ifdColors[q] < 0 || ifdColors[q] > 2) {
// found invalid channel index, use default color map instead
colorsValid = false;
break;
}
}
if (colorsValid) {
for (int q = 0; q < colorMap.length; q++) {
colorMap[q] = ifdColors[q];
}
}
}
boolean interleaveRows = offsets.length == 1 && !maybeCompressed && colorMap[0] != 0;
for (int row = 0; row < getSizeY(); row++) {
int realRow = interleaveRows ? (row < (getSizeY() / 2) ? row * 2 : (row - (getSizeY() / 2)) * 2 + 1) : row;
for (int col = 0; col < getSizeX(); col++) {
short val = (short) (bb.readBits(dataSize) & 0xffff);
int mapIndex = (realRow % 2) * 2 + (col % 2);
int redOffset = realRow * getSizeX() + col;
int greenOffset = (getSizeY() + realRow) * getSizeX() + col;
int blueOffset = (2 * getSizeY() + realRow) * getSizeX() + col;
if (colorMap[mapIndex] == 0) {
pix[redOffset] = adjustForWhiteBalance(val, 0);
} else if (colorMap[mapIndex] == 1) {
pix[greenOffset] = adjustForWhiteBalance(val, 1);
} else if (colorMap[mapIndex] == 2) {
pix[blueOffset] = adjustForWhiteBalance(val, 2);
}
if (maybeCompressed && !compressed) {
int toSkip = 0;
if ((col % 10) == 9) {
toSkip = 1;
}
if (col == getSizeX() - 1) {
toSkip = 10;
}
bb.skipBits(toSkip * 8);
}
}
}
bb.close();
lastPlane = new byte[FormatTools.getPlaneSize(this)];
ImageTools.interpolate(pix, lastPlane, colorMap, getSizeX(), getSizeY(), isLittleEndian());
lastIndex = no;
}
int bpp = FormatTools.getBytesPerPixel(getPixelType()) * 3;
int rowLen = w * bpp;
int width = getSizeX() * bpp;
for (int row = 0; row < h; row++) {
System.arraycopy(lastPlane, (row + y) * width + x * bpp, buf, row * rowLen, rowLen);
}
return buf;
}
use of loci.common.ByteArrayHandle in project bioformats by openmicroscopy.
the class OpenlabReader method openBytes.
/**
* @see loci.formats.IFormatReader#openBytes(int, byte[], int, int, int, int)
*/
@Override
public byte[] openBytes(int no, byte[] buf, int x, int y, int w, int h) throws FormatException, IOException {
FormatTools.checkPlaneParameters(this, no, buf.length, x, y, w, h);
lastPlane = no;
PlaneInfo planeInfo = null;
if (specialPlateNames) {
planeInfo = getPlane(getZCTCoords(no));
} else if (no < planeOffsets[getSeries()].length) {
int index = planeOffsets[getSeries()][no];
planeInfo = planes[index];
}
if (planeInfo == null)
return buf;
long first = planeInfo.planeOffset;
long last = first + FormatTools.getPlaneSize(this) * 2;
int bpp = FormatTools.getBytesPerPixel(getPixelType());
if (!planeInfo.pict) {
if (version == 2) {
in.seek(first);
readPlane(in, x, y, w, h, buf);
} else {
in.seek(first + 16);
int bytes = bpp * getRGBChannelCount();
byte[] b = new byte[(int) (last - first)];
in.read(b);
CodecOptions options = new CodecOptions();
options.width = getSizeX();
options.height = getSizeY();
options.bitsPerSample = bytes * 8;
options.maxBytes = getSizeX() * getSizeY() * bytes;
b = new LZOCodec().decompress(b, options);
if (getSizeX() * getSizeY() * 4 <= b.length) {
for (int yy = y; yy < h + y; yy++) {
for (int xx = x; xx < w + x; xx++) {
System.arraycopy(b, (yy * (getSizeX() + 4) + xx) * 4 + 1, buf, ((yy - y) * w + xx - x) * 3, 3);
}
}
} else {
int src = b.length / getSizeY();
if (src - (getSizeX() * bytes) != 16)
src = getSizeX() * bytes;
int dest = w * bytes;
for (int row = 0; row < h; row++) {
System.arraycopy(b, (row + y) * src + x * bytes, buf, row * dest, dest);
}
}
b = null;
}
if (planeInfo.volumeType == MAC_256_GREYS || planeInfo.volumeType == MAC_256_COLORS) {
for (int i = 0; i < buf.length; i++) {
buf[i] = (byte) (~buf[i] & 0xff);
}
}
} else {
// PICT plane
Exception exc = null;
if (getPixelType() == FormatTools.UINT8) {
in.seek(first);
byte[] b = new byte[(int) (last - first) + 512];
in.read(b, 512, b.length - 512);
IFormatReader r = getRGBChannelCount() == 1 ? new ChannelSeparator(pict) : pict;
try {
Location.mapFile("OPENLAB_PICT", new ByteArrayHandle(b));
r.setId("OPENLAB_PICT");
if (getPixelType() != r.getPixelType()) {
throw new FormatException("Pixel type of inner PICT does not " + "match pixel type of Openlab file");
}
if (isIndexed()) {
int index = no;
if (getSeries() < planeOffsets.length) {
index = planeOffsets[getSeries()][lastPlane];
}
luts.set(index, pict.get8BitLookupTable());
}
r.openBytes(0, buf, x, y, w, h);
} catch (FormatException e) {
exc = e;
} catch (IOException e) {
exc = e;
} finally {
r.close();
// remove file from map
Location.mapFile("OPENLAB_PICT", null);
}
b = null;
}
if (exc != null || getPixelType() != FormatTools.UINT8) {
LOGGER.debug("", exc);
in.seek(planeInfo.planeOffset - 298);
if (in.readByte() == 1)
in.skipBytes(297);
else
in.skipBytes(169);
int size = 0, expectedBlock = 0, totalBlocks = -1, pixPos = 0;
byte[] plane = new byte[FormatTools.getPlaneSize(this)];
while (expectedBlock != totalBlocks && pixPos < plane.length && in.getFilePointer() + 32 < last) {
findNextBlock();
if (in.getFilePointer() + 4 >= in.length())
break;
int num = in.readInt();
if (num != expectedBlock) {
throw new FormatException("Expected iPic block not found");
}
expectedBlock++;
if (totalBlocks == -1) {
totalBlocks = in.readInt();
in.skipBytes(8);
} else
in.skipBytes(12);
size = in.readInt();
in.skipBytes(4);
if (size + pixPos > plane.length)
size = plane.length - pixPos;
in.read(plane, pixPos, size);
pixPos += size;
}
RandomAccessInputStream pix = new RandomAccessInputStream(plane);
readPlane(pix, x, y, w, h, buf);
pix.close();
plane = null;
}
}
return buf;
}
use of loci.common.ByteArrayHandle in project bioformats by openmicroscopy.
the class InCell3000Reader method openBytes.
/**
* @see loci.formats.IFormatReader#openBytes(int, byte[], int, int, int, int)
*/
@Override
public byte[] openBytes(int no, byte[] buf, int x, int y, int w, int h) throws FormatException, IOException {
FormatTools.checkPlaneParameters(this, no, buf.length, x, y, w, h);
in.seek(pixelsOffset);
ByteArrayHandle pixels = new ByteArrayHandle();
pixels.setOrder(ByteOrder.LITTLE_ENDIAN);
int count = 0;
int startValue = 0;
int totalElements = getSizeX() * getSizeY() * 2;
while (pixels.length() < totalElements) {
short pixel = in.readShort();
if ((pixel & 0xffff) > 32768) {
count = (pixel & 0xffff) - 32768;
startValue = in.readShort() & 0xffff;
long fp = in.getFilePointer();
for (int i = 0; i < count; i++) {
in.seek(fp + 2 * (i / 3));
int intOfs = in.readShort() & 0xffff;
if ((i % 3) != 0) {
intOfs = (intOfs >> 5);
}
int tempVal = startValue + (intOfs & 31);
pixels.writeShort((short) tempVal);
}
in.seek(fp + 2 * (int) Math.ceil((double) count / 3));
} else {
pixels.writeShort((short) (pixel & 0xffff));
}
}
pixels.seek(0);
RandomAccessInputStream pix = new RandomAccessInputStream(pixels);
pix.order(isLittleEndian());
readPlane(pix, x, y, w, h, buf);
pix.close();
return buf;
}
Aggregations