Search in sources :

Example 11 with ByteArrayHandle

use of loci.common.ByteArrayHandle in project bioformats by openmicroscopy.

the class JPEGReader method setId.

// -- FormatReader API methods --
/* @see FormatReader#setId(String) */
@Override
public void setId(String id) throws FormatException, IOException {
    try {
        super.setId(id);
    } catch (CMMException e) {
        // strip out all but the first application marker
        // ImageIO isn't too keen on supporting multiple application markers
        // in the same stream, as evidenced by:
        // 
        // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6488904
        in = new RandomAccessInputStream(id);
        ByteArrayOutputStream v = new ByteArrayOutputStream();
        byte[] tag = new byte[2];
        in.read(tag);
        v.write(tag);
        in.read(tag);
        int tagValue = DataTools.bytesToShort(tag, false) & 0xffff;
        boolean appNoteFound = false;
        while (tagValue != 0xffdb) {
            if (!appNoteFound || (tagValue < 0xffe0 && tagValue >= 0xfff0)) {
                v.write(tag);
                in.read(tag);
                int len = DataTools.bytesToShort(tag, false) & 0xffff;
                byte[] tagContents = new byte[len - 2];
                in.read(tagContents);
                v.write(tag);
                v.write(tagContents);
            } else {
                in.read(tag);
                int len = DataTools.bytesToShort(tag, false) & 0xffff;
                in.skipBytes(len - 2);
            }
            if (tagValue >= 0xffe0 && tagValue < 0xfff0 && !appNoteFound) {
                appNoteFound = true;
            }
            in.read(tag);
            tagValue = DataTools.bytesToShort(tag, false) & 0xffff;
        }
        v.write(tag);
        byte[] remainder = new byte[(int) (in.length() - in.getFilePointer())];
        in.read(remainder);
        v.write(remainder);
        ByteArrayHandle bytes = new ByteArrayHandle(v.toByteArray());
        Location.mapFile(currentId + ".fixed", bytes);
        super.setId(currentId + ".fixed");
    }
    if (getSizeX() > MAX_SIZE && getSizeY() > MAX_SIZE && !legacyReaderInitialized) {
        // this is a large image, so try to open with TileJPEGReader first
        // TileJPEGReader requires restart markers to be present; if this file
        // doesn't contain restarts then TileJPEGReader will throw IOException
        // and we'll try again with DefaultJPEGReader
        close();
        useLegacy = true;
        try {
            super.setId(id);
        } catch (IOException e) {
            // this case usually requires a lot of memory as it's a big image
            // that requires the whole image to be opened for any size tile
            LOGGER.debug("Initialization with TileJPEGReader failed", e);
            close();
            useLegacy = false;
            super.setId(id);
        }
    }
    if (currentId.endsWith(".fixed")) {
        currentId = currentId.substring(0, currentId.lastIndexOf("."));
    }
}
Also used : RandomAccessInputStream(loci.common.RandomAccessInputStream) ByteArrayOutputStream(java.io.ByteArrayOutputStream) IOException(java.io.IOException) ByteArrayHandle(loci.common.ByteArrayHandle) CMMException(java.awt.color.CMMException)

Example 12 with ByteArrayHandle

use of loci.common.ByteArrayHandle in project bioformats by openmicroscopy.

the class TiffParser method unpackBytes.

// -- Utility methods - byte stream decoding --
/**
 * Extracts pixel information from the given byte array according to the
 * bits per sample, photometric interpretation and color map IFD directory
 * entry values, and the specified byte ordering.
 * No error checking is performed.
 */
public static void unpackBytes(byte[] samples, int startIndex, byte[] bytes, IFD ifd) throws FormatException {
    boolean planar = ifd.getPlanarConfiguration() == 2;
    TiffCompression compression = ifd.getCompression();
    PhotoInterp photoInterp = ifd.getPhotometricInterpretation();
    if (compression == TiffCompression.JPEG)
        photoInterp = PhotoInterp.RGB;
    int[] bitsPerSample = ifd.getBitsPerSample();
    int nChannels = bitsPerSample.length;
    int sampleCount = (int) (((long) 8 * bytes.length) / bitsPerSample[0]);
    if (photoInterp == PhotoInterp.Y_CB_CR)
        sampleCount *= 3;
    if (planar) {
        nChannels = 1;
    } else {
        sampleCount /= nChannels;
    }
    LOGGER.trace("unpacking {} samples (startIndex={}; totalBits={}; numBytes={})", new Object[] { sampleCount, startIndex, nChannels * bitsPerSample[0], bytes.length });
    long imageWidth = ifd.getImageWidth();
    long imageHeight = ifd.getImageLength();
    int bps0 = bitsPerSample[0];
    int numBytes = ifd.getBytesPerSample()[0];
    int nSamples = samples.length / (nChannels * numBytes);
    boolean noDiv8 = bps0 % 8 != 0;
    boolean bps8 = bps0 == 8;
    boolean bps16 = bps0 == 16;
    boolean littleEndian = ifd.isLittleEndian();
    // Chris Allan <callan@glencoesoftware.com>
    if ((bps8 || bps16) && bytes.length <= samples.length && nChannels == 1 && photoInterp != PhotoInterp.WHITE_IS_ZERO && photoInterp != PhotoInterp.CMYK && photoInterp != PhotoInterp.Y_CB_CR) {
        System.arraycopy(bytes, 0, samples, 0, bytes.length);
        return;
    }
    long maxValue = (long) Math.pow(2, bps0) - 1;
    if (photoInterp == PhotoInterp.CMYK)
        maxValue = Integer.MAX_VALUE;
    int skipBits = (int) (8 - ((imageWidth * bps0 * nChannels) % 8));
    if (skipBits == 8 || (bytes.length * 8 < bps0 * (nChannels * imageWidth + imageHeight))) {
        skipBits = 0;
    }
    // set up YCbCr-specific values
    float lumaRed = PhotoInterp.LUMA_RED;
    float lumaGreen = PhotoInterp.LUMA_GREEN;
    float lumaBlue = PhotoInterp.LUMA_BLUE;
    int[] reference = ifd.getIFDIntArray(IFD.REFERENCE_BLACK_WHITE);
    if (reference == null) {
        reference = new int[] { 0, 0, 0, 0, 0, 0 };
    }
    int[] subsampling = ifd.getIFDIntArray(IFD.Y_CB_CR_SUB_SAMPLING);
    TiffRational[] coefficients = (TiffRational[]) ifd.getIFDValue(IFD.Y_CB_CR_COEFFICIENTS);
    if (coefficients != null) {
        lumaRed = coefficients[0].floatValue();
        lumaGreen = coefficients[1].floatValue();
        lumaBlue = coefficients[2].floatValue();
    }
    int subX = subsampling == null ? 2 : subsampling[0];
    int subY = subsampling == null ? 2 : subsampling[1];
    int block = subX * subY;
    int nTiles = (int) (imageWidth / subX);
    RandomAccessInputStream bb = null;
    try {
        bb = new RandomAccessInputStream(new ByteArrayHandle(bytes));
        // unpack pixels
        for (int sample = 0; sample < sampleCount; sample++) {
            int ndx = startIndex + sample;
            if (ndx >= nSamples)
                break;
            for (int channel = 0; channel < nChannels; channel++) {
                int index = numBytes * (sample * nChannels + channel);
                int outputIndex = (channel * nSamples + ndx) * numBytes;
                // unpack non-YCbCr samples
                if (photoInterp != PhotoInterp.Y_CB_CR) {
                    long value = 0;
                    if (noDiv8) {
                        if ((channel == 0 && photoInterp == PhotoInterp.RGB_PALETTE) || (photoInterp != PhotoInterp.CFA_ARRAY && photoInterp != PhotoInterp.RGB_PALETTE)) {
                            try {
                                value = bb.readBits(bps0) & 0xffff;
                            } catch (ArrayIndexOutOfBoundsException e) {
                            // leave the value at 0 if there aren't enough bytes
                            // to cover the total number of samples
                            }
                            if ((ndx % imageWidth) == imageWidth - 1) {
                                bb.skipBits(skipBits);
                            }
                        }
                    } else {
                        value = DataTools.bytesToLong(bytes, index, numBytes, littleEndian);
                    }
                    if (photoInterp == PhotoInterp.WHITE_IS_ZERO || photoInterp == PhotoInterp.CMYK) {
                        value = maxValue - value;
                    }
                    if (outputIndex + numBytes <= samples.length) {
                        DataTools.unpackBytes(value, samples, outputIndex, numBytes, littleEndian);
                    }
                } else {
                    // the RGB components depends upon two or more of the YCbCr components
                    if (channel == nChannels - 1) {
                        int lumaIndex = sample + (2 * (sample / block));
                        int chromaIndex = (sample / block) * (block + 2) + block;
                        if (chromaIndex + 1 >= bytes.length)
                            break;
                        int tile = ndx / block;
                        int pixel = ndx % block;
                        long r = subY * (tile / nTiles) + (pixel / subX);
                        long c = subX * (tile % nTiles) + (pixel % subX);
                        int idx = (int) (r * imageWidth + c);
                        if (idx < nSamples) {
                            int y = (bytes[lumaIndex] & 0xff) - reference[0];
                            int cb = (bytes[chromaIndex] & 0xff) - reference[2];
                            int cr = (bytes[chromaIndex + 1] & 0xff) - reference[4];
                            int red = (int) (cr * (2 - 2 * lumaRed) + y);
                            int blue = (int) (cb * (2 - 2 * lumaBlue) + y);
                            int green = (int) ((y - lumaBlue * blue - lumaRed * red) / lumaGreen);
                            samples[idx] = (byte) (red & 0xff);
                            samples[nSamples + idx] = (byte) (green & 0xff);
                            samples[2 * nSamples + idx] = (byte) (blue & 0xff);
                        }
                    }
                }
            }
        }
    } catch (IOException e) {
        throw new FormatException(e);
    } finally {
        if (bb != null) {
            try {
                bb.close();
            } catch (IOException e) {
                throw new FormatException(e);
            }
        }
    }
}
Also used : IOException(java.io.IOException) FormatException(loci.formats.FormatException) RandomAccessInputStream(loci.common.RandomAccessInputStream) ByteArrayHandle(loci.common.ByteArrayHandle)

Example 13 with ByteArrayHandle

use of loci.common.ByteArrayHandle in project bioformats by openmicroscopy.

the class TiffSaver method overwriteIFDValue.

/**
 * Surgically overwrites an existing IFD value with the given one. This
 * method requires that the IFD directory entry already exist. It
 * intelligently updates the count field of the entry to match the new
 * length. If the new length is longer than the old length, it appends the
 * new data to the end of the file and updates the offset field; if not, or
 * if the old data is already at the end of the file, it overwrites the old
 * data in place.
 */
public void overwriteIFDValue(RandomAccessInputStream raf, int ifd, int tag, Object value) throws FormatException, IOException {
    if (raf == null)
        throw new FormatException("Output cannot be null");
    LOGGER.debug("overwriteIFDValue (ifd={}; tag={}; value={})", new Object[] { ifd, tag, value });
    raf.seek(0);
    TiffParser parser = new TiffParser(raf);
    Boolean valid = parser.checkHeader();
    if (valid == null) {
        throw new FormatException("Invalid TIFF header");
    }
    boolean little = valid.booleanValue();
    boolean bigTiff = parser.isBigTiff();
    setLittleEndian(little);
    setBigTiff(bigTiff);
    // offset to the IFD
    long offset = bigTiff ? 8 : 4;
    int bytesPerEntry = bigTiff ? TiffConstants.BIG_TIFF_BYTES_PER_ENTRY : TiffConstants.BYTES_PER_ENTRY;
    raf.seek(offset);
    // skip to the correct IFD
    long[] offsets = parser.getIFDOffsets();
    if (ifd >= offsets.length) {
        throw new FormatException("No such IFD (" + ifd + " of " + offsets.length + ")");
    }
    raf.seek(offsets[ifd]);
    // get the number of directory entries
    long num = bigTiff ? raf.readLong() : raf.readUnsignedShort();
    // search directory entries for proper tag
    for (int i = 0; i < num; i++) {
        raf.seek(offsets[ifd] + (bigTiff ? 8 : 2) + bytesPerEntry * i);
        TiffIFDEntry entry = parser.readTiffIFDEntry();
        if (entry.getTag() == tag) {
            // write new value to buffers
            ByteArrayHandle ifdBuf = new ByteArrayHandle(bytesPerEntry);
            RandomAccessOutputStream ifdOut = new RandomAccessOutputStream(ifdBuf);
            ByteArrayHandle extraBuf = new ByteArrayHandle();
            RandomAccessOutputStream extraOut = new RandomAccessOutputStream(extraBuf);
            extraOut.order(little);
            TiffSaver saver = new TiffSaver(ifdOut, ifdBuf);
            saver.setLittleEndian(isLittleEndian());
            saver.writeIFDValue(extraOut, entry.getValueOffset(), tag, value);
            ifdOut.close();
            saver.close();
            extraOut.close();
            ifdBuf.seek(0);
            extraBuf.seek(0);
            // extract new directory entry parameters
            int newTag = ifdBuf.readShort();
            int newType = ifdBuf.readShort();
            int newCount;
            long newOffset;
            if (bigTiff) {
                newCount = ifdBuf.readInt();
                newOffset = ifdBuf.readLong();
            } else {
                newCount = ifdBuf.readInt();
                newOffset = ifdBuf.readInt();
            }
            LOGGER.debug("overwriteIFDValue:");
            LOGGER.debug("\told ({});", entry);
            LOGGER.debug("\tnew: (tag={}; type={}; count={}; offset={})", new Object[] { newTag, newType, newCount, newOffset });
            // determine the best way to overwrite the old entry
            if (extraBuf.length() == 0) {
                // new entry is inline; if old entry wasn't, old data is orphaned
                // do not override new offset value since data is inline
                LOGGER.debug("overwriteIFDValue: new entry is inline");
            } else if (entry.getValueOffset() + entry.getValueCount() * entry.getType().getBytesPerElement() == raf.length()) {
                // old entry was already at EOF; overwrite it
                newOffset = entry.getValueOffset();
                LOGGER.debug("overwriteIFDValue: old entry is at EOF");
            } else if (newCount <= entry.getValueCount()) {
                // new entry is as small or smaller than old entry; overwrite it
                newOffset = entry.getValueOffset();
                LOGGER.debug("overwriteIFDValue: new entry is <= old entry");
            } else {
                // old entry was elsewhere; append to EOF, orphaning old entry
                newOffset = raf.length();
                LOGGER.debug("overwriteIFDValue: old entry will be orphaned");
            }
            // overwrite old entry
            out.seek(offsets[ifd] + (bigTiff ? 8 : 2) + bytesPerEntry * i + 2);
            out.writeShort(newType);
            writeIntValue(out, newCount);
            writeIntValue(out, newOffset);
            if (extraBuf.length() > 0) {
                out.seek(newOffset);
                out.write(extraBuf.getByteBuffer(), 0, newCount);
            }
            return;
        }
    }
    throw new FormatException("Tag not found (" + IFD.getIFDTagName(tag) + ")");
}
Also used : RandomAccessOutputStream(loci.common.RandomAccessOutputStream) ByteArrayHandle(loci.common.ByteArrayHandle) FormatException(loci.formats.FormatException)

Example 14 with ByteArrayHandle

use of loci.common.ByteArrayHandle in project bioformats by openmicroscopy.

the class PictReader 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);
    if (jpegOffsets.size() > 0) {
        ByteArrayHandle v = new ByteArrayHandle();
        in.seek(jpegOffsets.get(0));
        byte[] b = new byte[(int) (in.length() - in.getFilePointer())];
        in.read(b);
        RandomAccessInputStream s = new RandomAccessInputStream(b);
        for (long jpegOffset : jpegOffsets) {
            s.seek(jpegOffset - jpegOffsets.get(0));
            CodecOptions options = new CodecOptions();
            options.interleaved = isInterleaved();
            options.littleEndian = isLittleEndian();
            v.write(new JPEGCodec().decompress(s, options));
        }
        s.close();
        s = new RandomAccessInputStream(v);
        s.seek(0);
        readPlane(s, x, y, w, h, buf);
        s.close();
        return buf;
    }
    if (legacy || strips.size() == 0) {
        in.seek(512);
        byte[] pix = new byte[(int) (in.length() - in.getFilePointer())];
        in.read(pix);
        byte[][] b = AWTImageTools.getBytes(AWTImageTools.makeBuffered(qtTools.pictToImage(pix)));
        pix = null;
        for (int i = 0; i < b.length; i++) {
            System.arraycopy(b[i], 0, buf, i * b[i].length, b[i].length);
        }
        b = null;
        return buf;
    }
    if ((getSizeY() * 4 < strips.size()) && (((strips.size() / 3) % getSizeY()) != 0)) {
        core.get(0).sizeY = strips.size();
    }
    int plane = w * h;
    if (lookup != null) {
        // 8 bit data
        byte[] row;
        for (int i = y; i < y + h; i++) {
            row = (byte[]) strips.get(i);
            int len = (int) Math.min(row.length, w);
            System.arraycopy(row, x, buf, (i - y) * w, len);
        }
    } else if (getSizeY() * 3 == strips.size() || getSizeY() * 4 == strips.size()) {
        // 24 or 32 bit data
        int nc = strips.size() / getSizeY();
        byte[] c0 = null;
        byte[] c1 = null;
        byte[] c2 = null;
        for (int i = y; i < h + y; i++) {
            c0 = (byte[]) strips.get(i * nc + nc - 3);
            c1 = (byte[]) strips.get(i * nc + nc - 2);
            c2 = (byte[]) strips.get(i * nc + nc - 1);
            int baseOffset = (i - y) * w;
            System.arraycopy(c0, x, buf, baseOffset, w);
            System.arraycopy(c1, x, buf, plane + baseOffset, w);
            System.arraycopy(c2, x, buf, 2 * plane + baseOffset, w);
        }
    } else {
        // RGB value is packed into a single short: xRRR RRGG GGGB BBBB
        int[] row = null;
        for (int i = y; i < h + y; i++) {
            row = (int[]) strips.get(i);
            for (int j = x; j < w + x; j++) {
                int base = (i - y) * w + (j - x);
                buf[base] = (byte) ((row[j] & 0x7c00) >> 10);
                buf[plane + base] = (byte) ((row[j] & 0x3e0) >> 5);
                buf[2 * plane + base] = (byte) (row[j] & 0x1f);
            }
        }
    }
    return buf;
}
Also used : CodecOptions(loci.formats.codec.CodecOptions) RandomAccessInputStream(loci.common.RandomAccessInputStream) ByteArrayHandle(loci.common.ByteArrayHandle) JPEGCodec(loci.formats.codec.JPEGCodec)

Example 15 with ByteArrayHandle

use of loci.common.ByteArrayHandle in project bioformats by openmicroscopy.

the class DNGReader 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) {
        if (tiffParser == null) {
            initTiffParser();
        }
        byte[] b = new byte[buf.length / 2];
        tiffParser.getSamples(ifds.get(0), b, x, y, w, h);
        for (int i = 0; i < b.length; i++) {
            int c = isInterleaved() ? i % 3 : i / (b.length / 3);
            short v = (short) (b[i] & 0xff);
            v = adjustForWhiteBalance(v, c);
            DataTools.unpackBytes(v, buf, i * 2, 2, isLittleEndian());
        }
        return buf;
    }
    if (lastPlane == null || lastIndex != no) {
        long[] offsets = ifd.getStripOffsets();
        ByteArrayOutputStream src = new ByteArrayOutputStream();
        for (int i = 0; i < byteCounts.length; i++) {
            byte[] t = new byte[(int) byteCounts[i]];
            in.seek(offsets[i]);
            in.read(t);
            src.write(t);
        }
        // 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];
                }
            }
        }
        lastPlane = new byte[FormatTools.getPlaneSize(this)];
        RandomAccessInputStream bb = new RandomAccessInputStream(new ByteArrayHandle(src.toByteArray()));
        src.close();
        short[] pix = new short[getSizeX() * getSizeY() * 3];
        for (int row = 0; row < getSizeY(); row++) {
            int realRow = 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);
                }
            }
        }
        bb.close();
        ImageTools.interpolate(pix, buf, 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;
}
Also used : IFD(loci.formats.tiff.IFD) ByteArrayOutputStream(java.io.ByteArrayOutputStream) RandomAccessInputStream(loci.common.RandomAccessInputStream) ByteArrayHandle(loci.common.ByteArrayHandle)

Aggregations

ByteArrayHandle (loci.common.ByteArrayHandle)26 RandomAccessInputStream (loci.common.RandomAccessInputStream)18 RandomAccessOutputStream (loci.common.RandomAccessOutputStream)7 IOException (java.io.IOException)6 FormatException (loci.formats.FormatException)6 CodecOptions (loci.formats.codec.CodecOptions)5 CoreMetadata (loci.formats.CoreMetadata)4 TiffSaver (loci.formats.tiff.TiffSaver)4 ByteArrayOutputStream (java.io.ByteArrayOutputStream)3 Location (loci.common.Location)3 DependencyException (loci.common.services.DependencyException)3 ServiceFactory (loci.common.services.ServiceFactory)3 IFD (loci.formats.tiff.IFD)3 TiffParser (loci.formats.tiff.TiffParser)3 Length (ome.units.quantity.Length)3 Test (org.testng.annotations.Test)3 ArrayList (java.util.ArrayList)2 IFormatReader (loci.formats.IFormatReader)2 Codec (loci.formats.codec.Codec)2 JPEGCodec (loci.formats.codec.JPEGCodec)2