Search in sources :

Example 31 with CodecOptions

use of loci.formats.codec.CodecOptions in project bioformats by openmicroscopy.

the class DicomReader method initFile.

// -- Internal FormatReader API methods --
/* @see loci.formats.FormatReader#initFile(String) */
@Override
protected void initFile(String id) throws FormatException, IOException {
    super.initFile(id);
    in = new RandomAccessInputStream(id);
    in.order(true);
    CoreMetadata m = core.get(0);
    // look for companion files
    attachCompanionFiles();
    helper = new DicomReader();
    helper.setGroupFiles(false);
    m.littleEndian = true;
    location = 0;
    isJPEG = false;
    isRLE = false;
    bigEndianTransferSyntax = false;
    oddLocations = false;
    inSequence = false;
    bitsPerPixel = 0;
    elementLength = 0;
    vr = 0;
    lut = null;
    offsets = null;
    inverted = false;
    // some DICOM files have a 128 byte header followed by a 4 byte identifier
    LOGGER.info("Verifying DICOM format");
    MetadataLevel level = getMetadataOptions().getMetadataLevel();
    in.seek(128);
    if (in.readString(4).equals("DICM")) {
        if (level != MetadataLevel.MINIMUM) {
            // header exists, so we'll read it
            in.seek(0);
            addSeriesMeta("Header information", in.readString(128));
            in.skipBytes(4);
        }
        location = 128;
    } else
        in.seek(0);
    LOGGER.info("Reading tags");
    long baseOffset = 0;
    boolean decodingTags = true;
    boolean signed = false;
    String currentType = "";
    while (decodingTags) {
        if (in.getFilePointer() + 4 >= in.length()) {
            break;
        }
        LOGGER.debug("Reading tag from {}", in.getFilePointer());
        int tag = getNextTag(in);
        if (elementLength <= 0)
            continue;
        oddLocations = (location & 1) != 0;
        LOGGER.debug("  tag={} len={} fp=", new Object[] { tag, elementLength, in.getFilePointer() });
        String s = null;
        switch(tag) {
            case TRANSFER_SYNTAX_UID:
                // this tag can indicate which compression scheme is used
                s = in.readString(elementLength);
                addInfo(tag, s);
                if (s.startsWith("1.2.840.10008.1.2.4.9"))
                    isJP2K = true;
                else if (s.startsWith("1.2.840.10008.1.2.4"))
                    isJPEG = true;
                else if (s.startsWith("1.2.840.10008.1.2.5"))
                    isRLE = true;
                else if (s.equals("1.2.8.10008.1.2.1.99"))
                    isDeflate = true;
                else if (s.indexOf("1.2.4") > -1 || s.indexOf("1.2.5") > -1) {
                    throw new UnsupportedCompressionException("Sorry, compression type " + s + " not supported");
                }
                if (s.indexOf("1.2.840.10008.1.2.2") >= 0) {
                    bigEndianTransferSyntax = true;
                }
                break;
            case NUMBER_OF_FRAMES:
                s = in.readString(elementLength);
                addInfo(tag, s);
                double frames = Double.parseDouble(s);
                if (frames > 1.0)
                    imagesPerFile = (int) frames;
                break;
            case SAMPLES_PER_PIXEL:
                addInfo(tag, in.readShort());
                break;
            case PLANAR_CONFIGURATION:
                int config = in.readShort();
                m.interleaved = config == 0;
                addInfo(tag, config);
                break;
            case ROWS:
                int y = in.readShort();
                if (y > getSizeY()) {
                    m.sizeY = y;
                }
                addInfo(tag, getSizeY());
                break;
            case COLUMNS:
                int x = in.readShort();
                if (x > getSizeX()) {
                    m.sizeX = x;
                }
                addInfo(tag, getSizeX());
                break;
            case PHOTOMETRIC_INTERPRETATION:
            case PIXEL_SPACING:
            case SLICE_SPACING:
            case RESCALE_INTERCEPT:
            case WINDOW_CENTER:
                String winCenter = in.readString(elementLength);
                if (winCenter.trim().length() == 0)
                    centerPixelValue = -1;
                else {
                    try {
                        centerPixelValue = new Double(winCenter).intValue();
                    } catch (NumberFormatException e) {
                        centerPixelValue = -1;
                    }
                }
                addInfo(tag, winCenter);
                break;
            case RESCALE_SLOPE:
                addInfo(tag, in.readString(elementLength));
                break;
            case BITS_ALLOCATED:
                if (bitsPerPixel == 0)
                    bitsPerPixel = in.readShort();
                else
                    in.skipBytes(2);
                addInfo(tag, bitsPerPixel);
                break;
            case PIXEL_REPRESENTATION:
            case PIXEL_SIGN:
                short ss = in.readShort();
                signed = ss == 1;
                addInfo(tag, ss);
                break;
            case 537262910:
            case WINDOW_WIDTH:
                String t = in.readString(elementLength);
                if (t.trim().length() == 0)
                    maxPixelRange = -1;
                else {
                    try {
                        maxPixelRange = new Double(t.trim()).intValue();
                    } catch (NumberFormatException e) {
                        maxPixelRange = -1;
                    }
                }
                addInfo(tag, t);
                break;
            case PIXEL_DATA:
            case ITEM:
            case 0xffee000:
                if (elementLength != 0) {
                    baseOffset = in.getFilePointer();
                    addInfo(tag, location);
                    decodingTags = false;
                } else
                    addInfo(tag, null);
                break;
            case 0x7f880010:
                if (elementLength != 0) {
                    baseOffset = location + 4;
                    decodingTags = false;
                }
                break;
            case 0x7fe00000:
                in.skipBytes(elementLength);
                break;
            case 0:
                in.seek(in.getFilePointer() - 4);
                break;
            case 0x41430:
                currentType = getHeaderInfo(tag, s).trim();
                break;
            case 0x41500:
                if (currentType.equals("IMAGE")) {
                    if (fileList == null) {
                        fileList = new HashMap<Integer, List<String>>();
                    }
                    int seriesIndex = 0;
                    if (originalInstance != null) {
                        try {
                            seriesIndex = Integer.parseInt(originalInstance);
                        } catch (NumberFormatException e) {
                            LOGGER.debug("Could not parse instance number: {}", originalInstance);
                        }
                    }
                    if (fileList.get(seriesIndex) == null) {
                        fileList.put(seriesIndex, new ArrayList<String>());
                    }
                    fileList.get(seriesIndex).add(getHeaderInfo(tag, s).trim());
                } else {
                    companionFiles.add(getHeaderInfo(tag, s).trim());
                }
                currentType = "";
                break;
            default:
                long oldfp = in.getFilePointer();
                addInfo(tag, s);
                in.seek(oldfp + elementLength);
        }
        if (in.getFilePointer() >= (in.length() - 4)) {
            decodingTags = false;
        }
    }
    if (imagesPerFile == 0)
        imagesPerFile = 1;
    if (id.endsWith("DICOMDIR")) {
        String parent = new Location(currentId).getAbsoluteFile().getParent();
        for (int q = 0; q < fileList.size(); q++) {
            Integer[] fileKeys = fileList.keySet().toArray(new Integer[0]);
            for (int i = 0; i < fileList.get(fileKeys[q]).size(); i++) {
                String file = fileList.get(fileKeys[q]).get(i);
                file = file.replace('\\', File.separatorChar);
                file = file.replaceAll("/", File.separator);
                fileList.get(fileKeys[q]).set(i, parent + File.separator + file);
            }
        }
        for (int i = 0; i < companionFiles.size(); i++) {
            String file = companionFiles.get(i);
            file = file.replace('\\', File.separatorChar);
            file = file.replaceAll("/", File.separator);
            companionFiles.set(i, parent + File.separator + file);
        }
        companionFiles.add(new Location(currentId).getAbsolutePath());
        initFile(fileList.get(0).get(0));
        return;
    }
    m.bitsPerPixel = bitsPerPixel;
    while (bitsPerPixel % 8 != 0) bitsPerPixel++;
    if (bitsPerPixel == 24 || bitsPerPixel == 48) {
        bitsPerPixel /= 3;
        m.bitsPerPixel /= 3;
    }
    m.pixelType = FormatTools.pixelTypeFromBytes(bitsPerPixel / 8, signed, false);
    int bpp = FormatTools.getBytesPerPixel(getPixelType());
    int plane = getSizeX() * getSizeY() * (lut == null ? getSizeC() : 1) * bpp;
    LOGGER.info("Calculating image offsets");
    // calculate the offset to each plane
    in.seek(baseOffset - 12);
    int len = in.readInt();
    if (len >= 0 && len + in.getFilePointer() < in.length()) {
        in.skipBytes(len);
        int check = in.readShort() & 0xffff;
        if (check == 0xfffe) {
            baseOffset = in.getFilePointer() + 2;
        }
    }
    offsets = new long[imagesPerFile];
    for (int i = 0; i < imagesPerFile; i++) {
        if (isRLE) {
            if (i == 0)
                in.seek(baseOffset);
            else {
                in.seek(offsets[i - 1]);
                CodecOptions options = new CodecOptions();
                options.maxBytes = plane / bpp;
                for (int q = 0; q < bpp; q++) {
                    new PackbitsCodec().decompress(in, options);
                    while (in.read() == 0) ;
                    in.seek(in.getFilePointer() - 1);
                }
            }
            in.skipBytes(i == 0 ? 64 : 53);
            while (in.read() == 0) ;
            offsets[i] = in.getFilePointer() - 1;
        } else if (isJPEG || isJP2K) {
            // scan for next JPEG magic byte sequence
            if (i == 0)
                offsets[i] = baseOffset;
            else
                offsets[i] = offsets[i - 1] + 3;
            byte secondCheck = isJPEG ? (byte) 0xd8 : (byte) 0x4f;
            in.seek(offsets[i]);
            byte[] buf = new byte[8192];
            int n = in.read(buf);
            boolean found = false;
            while (!found) {
                for (int q = 0; q < n - 2; q++) {
                    if (buf[q] == (byte) 0xff && buf[q + 1] == secondCheck && buf[q + 2] == (byte) 0xff) {
                        if (isJPEG || (isJP2K && buf[q + 3] == 0x51)) {
                            found = true;
                            offsets[i] = in.getFilePointer() + q - n;
                            break;
                        }
                    }
                }
                if (!found) {
                    for (int q = 0; q < 4; q++) {
                        buf[q] = buf[buf.length + q - 4];
                    }
                    n = in.read(buf, 4, buf.length - 4) + 4;
                }
            }
        } else
            offsets[i] = baseOffset + plane * i;
    }
    makeFileList();
    LOGGER.info("Populating metadata");
    int seriesCount = fileList.size();
    Integer[] keys = fileList.keySet().toArray(new Integer[0]);
    Arrays.sort(keys);
    if (seriesCount > 1) {
        core.clear();
    }
    for (int i = 0; i < seriesCount; i++) {
        if (seriesCount == 1) {
            CoreMetadata ms = core.get(i);
            ms.sizeZ = imagesPerFile * fileList.get(keys[i]).size();
            if (ms.sizeC == 0)
                ms.sizeC = 1;
            ms.rgb = ms.sizeC > 1;
            ms.sizeT = 1;
            ms.dimensionOrder = "XYCZT";
            ms.metadataComplete = true;
            ms.falseColor = false;
            if (isRLE)
                core.get(i).interleaved = false;
            ms.imageCount = ms.sizeZ;
        } else {
            helper.close();
            helper.setId(fileList.get(keys[i]).get(0));
            CoreMetadata ms = helper.getCoreMetadataList().get(0);
            ms.sizeZ *= fileList.get(keys[i]).size();
            ms.imageCount = ms.sizeZ;
            core.add(ms);
        }
    }
    // The metadata store we're working with.
    MetadataStore store = makeFilterMetadata();
    MetadataTools.populatePixels(store, this, true);
    String stamp = null;
    if (date != null && time != null) {
        stamp = date + " " + time;
        stamp = DateTools.formatDate(stamp, "yyyy.MM.dd HH:mm:ss", ".");
    }
    if (stamp == null || stamp.trim().equals(""))
        stamp = null;
    for (int i = 0; i < core.size(); i++) {
        if (stamp != null)
            store.setImageAcquisitionDate(new Timestamp(stamp), i);
        store.setImageName("Series " + i, i);
    }
    if (level != MetadataLevel.MINIMUM) {
        for (int i = 0; i < core.size(); i++) {
            store.setImageDescription(imageType, i);
            // all physical sizes were stored in mm, so must be converted to um
            if (pixelSizeX != null) {
                Length x = FormatTools.getPhysicalSizeX(new Double(pixelSizeX), UNITS.MILLIMETER);
                if (x != null) {
                    store.setPixelsPhysicalSizeX(x, i);
                }
            }
            if (pixelSizeY != null) {
                Length y = FormatTools.getPhysicalSizeY(new Double(pixelSizeY), UNITS.MILLIMETER);
                if (y != null) {
                    store.setPixelsPhysicalSizeY(y, i);
                }
            }
            if (pixelSizeZ != null) {
                Length z = FormatTools.getPhysicalSizeZ(new Double(pixelSizeZ), UNITS.MILLIMETER);
                if (z != null) {
                    store.setPixelsPhysicalSizeZ(z, i);
                }
            }
            for (int p = 0; p < getImageCount(); p++) {
                if (p < positionX.size()) {
                    if (positionX.get(p) != null) {
                        Length x = new Length(positionX.get(p), UNITS.MM);
                        if (x != null) {
                            store.setPlanePositionX(x, 0, p);
                        }
                    }
                }
                if (p < positionY.size()) {
                    if (positionY.get(p) != null) {
                        Length y = new Length(positionY.get(p), UNITS.MM);
                        if (y != null) {
                            store.setPlanePositionY(y, 0, p);
                        }
                    }
                }
                if (p < positionZ.size()) {
                    if (positionZ.get(p) != null) {
                        Length z = new Length(positionZ.get(p), UNITS.MM);
                        if (z != null) {
                            store.setPlanePositionZ(z, 0, p);
                        }
                    }
                }
            }
        }
    }
}
Also used : CodecOptions(loci.formats.codec.CodecOptions) UnsupportedCompressionException(loci.formats.UnsupportedCompressionException) CoreMetadata(loci.formats.CoreMetadata) Timestamp(ome.xml.model.primitives.Timestamp) PackbitsCodec(loci.formats.codec.PackbitsCodec) MetadataStore(loci.formats.meta.MetadataStore) Length(ome.units.quantity.Length) ArrayList(java.util.ArrayList) List(java.util.List) RandomAccessInputStream(loci.common.RandomAccessInputStream) Location(loci.common.Location)

Example 32 with CodecOptions

use of loci.formats.codec.CodecOptions in project bioformats by openmicroscopy.

the class OMEXMLReader 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 {
    if (binDataOffsets.size() == 0)
        return buf;
    FormatTools.checkPlaneParameters(this, no, buf.length, x, y, w, h);
    int index = no;
    int series = getSeries();
    for (int i = 0; i < series; i++) {
        index += core.get(i).imageCount;
    }
    if (index >= binDataOffsets.size()) {
        index = binDataOffsets.size() - 1;
    }
    long offset = binDataOffsets.get(index).longValue();
    String compress = compression.get(index);
    in.seek(offset);
    int depth = FormatTools.getBytesPerPixel(getPixelType());
    int planeSize = getSizeX() * getSizeY() * depth;
    CodecOptions options = new CodecOptions();
    options.width = getSizeX();
    options.height = getSizeY();
    options.bitsPerSample = depth * 8;
    options.channels = getRGBChannelCount();
    options.maxBytes = planeSize;
    options.littleEndian = isLittleEndian();
    options.interleaved = isInterleaved();
    String encoded = in.readString("<");
    encoded = encoded.trim();
    if (encoded.length() == 0 || encoded.equals("<")) {
        LOGGER.debug("No pixel data for plane #{}", no);
        return buf;
    }
    encoded = encoded.substring(0, encoded.length() - 1);
    byte[] pixels = BaseEncoding.base64().decode(encoded);
    // return a blank plane if no pixel data was stored
    if (pixels.length == 0) {
        LOGGER.debug("No pixel data for plane #{}", no);
        return buf;
    }
    // TODO: Create a method uncompress to handle all compression methods
    if (compress.equals("bzip2")) {
        byte[] tempPixels = pixels;
        pixels = new byte[tempPixels.length - 2];
        System.arraycopy(tempPixels, 2, pixels, 0, pixels.length);
        ByteArrayInputStream bais = new ByteArrayInputStream(pixels);
        CBZip2InputStream bzip = new CBZip2InputStream(bais);
        pixels = new byte[planeSize];
        bzip.read(pixels, 0, pixels.length);
        tempPixels = null;
        bais.close();
        bzip.close();
        bais = null;
        bzip = null;
    } else if (compress.equals("zlib")) {
        pixels = new ZlibCodec().decompress(pixels, options);
    } else if (compress.equals("J2K")) {
        pixels = new JPEG2000Codec().decompress(pixels, options);
    } else if (compress.equals("JPEG")) {
        pixels = new JPEGCodec().decompress(pixels, options);
    }
    for (int row = 0; row < h; row++) {
        int off = (row + y) * getSizeX() * depth + x * depth;
        System.arraycopy(pixels, off, buf, row * w * depth, w * depth);
    }
    pixels = null;
    return buf;
}
Also used : ZlibCodec(loci.formats.codec.ZlibCodec) CodecOptions(loci.formats.codec.CodecOptions) JPEG2000Codec(loci.formats.codec.JPEG2000Codec) ByteArrayInputStream(java.io.ByteArrayInputStream) CBZip2InputStream(loci.common.CBZip2InputStream) JPEGCodec(loci.formats.codec.JPEGCodec)

Example 33 with CodecOptions

use of loci.formats.codec.CodecOptions in project bioformats by openmicroscopy.

the class CompressDecompressTest method assertCompression.

/**
 * Tests the writing of the tiles.
 * @param compression The compression to use.
 * @param lossy whether or not this is a lossy compression type
 */
private void assertCompression(TiffCompression compression, boolean lossy) throws Exception {
    IFD ifd = new IFD();
    int w = 64;
    int h = 64;
    int bpp = 8;
    ifd.put(IFD.IMAGE_WIDTH, w);
    ifd.put(IFD.IMAGE_LENGTH, h);
    ifd.put(IFD.BITS_PER_SAMPLE, new int[] { bpp });
    ifd.put(IFD.SAMPLES_PER_PIXEL, 1);
    ifd.put(IFD.LITTLE_ENDIAN, Boolean.TRUE);
    byte[] plane = new byte[w * h * (bpp / 8)];
    for (int i = 0; i < plane.length; i++) {
        plane[i] = (byte) i;
    }
    String beforeCompression, afterCompression, afterDecompression;
    CodecOptions options = compression.getCompressionCodecOptions(ifd);
    byte[] compressed;
    beforeCompression = Hashing.md5().hashBytes(plane).toString();
    compressed = compression.compress(plane, options);
    afterCompression = Hashing.md5().hashBytes(compressed).toString();
    if (compression.equals(TiffCompression.UNCOMPRESSED)) {
        if (!beforeCompression.equals(afterCompression)) {
            fail("Compression: " + compression.getCodecName() + " " + String.format("Compression MD5 %s != %s", beforeCompression, afterCompression));
        }
        afterDecompression = Hashing.md5().hashBytes(compression.decompress(compressed, options)).toString();
        if (!beforeCompression.equals(afterDecompression)) {
            fail("Compression: " + compression.getCodecName() + " " + String.format("Decompression MD5 %s != %s", beforeCompression, afterDecompression));
        }
    } else {
        if (beforeCompression.equals(afterCompression)) {
            fail("Compression: " + compression.getCodecName() + " " + String.format("Compression MD5 %s != %s", beforeCompression, afterCompression));
        }
        afterDecompression = Hashing.md5().hashBytes(compression.decompress(compressed, options)).toString();
        if (!lossy && !beforeCompression.equals(afterDecompression)) {
            fail("Compression: " + compression.getCodecName() + " " + String.format("Decompression MD5 %s != %s", beforeCompression, afterDecompression));
        }
    }
}
Also used : CodecOptions(loci.formats.codec.CodecOptions) IFD(loci.formats.tiff.IFD)

Example 34 with CodecOptions

use of loci.formats.codec.CodecOptions 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);
}
Also used : CodecOptions(loci.formats.codec.CodecOptions) IOException(java.io.IOException) CoreMetadata(loci.formats.CoreMetadata) Length(ome.units.quantity.Length) RandomAccessInputStream(loci.common.RandomAccessInputStream) ByteArrayHandle(loci.common.ByteArrayHandle)

Example 35 with CodecOptions

use of loci.formats.codec.CodecOptions 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;
}
Also used : CodecOptions(loci.formats.codec.CodecOptions) IFormatReader(loci.formats.IFormatReader) LZOCodec(loci.formats.codec.LZOCodec) IOException(java.io.IOException) FormatException(loci.formats.FormatException) IOException(java.io.IOException) ChannelSeparator(loci.formats.ChannelSeparator) FormatException(loci.formats.FormatException) RandomAccessInputStream(loci.common.RandomAccessInputStream) ByteArrayHandle(loci.common.ByteArrayHandle)

Aggregations

CodecOptions (loci.formats.codec.CodecOptions)37 JPEG2000CodecOptions (loci.formats.codec.JPEG2000CodecOptions)18 TiffCompression (loci.formats.tiff.TiffCompression)18 Test (org.testng.annotations.Test)18 RandomAccessInputStream (loci.common.RandomAccessInputStream)9 JPEGCodec (loci.formats.codec.JPEGCodec)8 PackbitsCodec (loci.formats.codec.PackbitsCodec)6 ByteArrayHandle (loci.common.ByteArrayHandle)5 ZlibCodec (loci.formats.codec.ZlibCodec)5 UnsupportedCompressionException (loci.formats.UnsupportedCompressionException)4 JPEG2000Codec (loci.formats.codec.JPEG2000Codec)4 IOException (java.io.IOException)3 CoreMetadata (loci.formats.CoreMetadata)3 Codec (loci.formats.codec.Codec)3 FormatException (loci.formats.FormatException)2 IFormatReader (loci.formats.IFormatReader)2 MetadataStore (loci.formats.meta.MetadataStore)2 Length (ome.units.quantity.Length)2 ByteArrayInputStream (java.io.ByteArrayInputStream)1 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1