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("."));
}
}
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);
}
}
}
}
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) + ")");
}
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;
}
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;
}
Aggregations