Skip to content

Commit

Permalink
* Added basic TIFF tile export. Closes #413.
Browse files Browse the repository at this point in the history
* Throw an exception in writers that don't support tiled export.
  • Loading branch information
melissalinkert committed Jun 8, 2010
1 parent 137b430 commit 58e089d
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 12 deletions.
4 changes: 4 additions & 0 deletions components/bio-formats/src/loci/formats/out/APNGWriter.java
Expand Up @@ -74,6 +74,10 @@ public void saveBytes(int no, byte[] buf, int x, int y, int w, int h)
throws FormatException, IOException
{
checkParams(no, buf, x, y, w, h);
if (!isFullPlane(x, y, w, h)) {
throw new FormatException(
"APNGWriter does not yet support saving image tiles.");
}
MetadataRetrieve meta = getMetadataRetrieve();

int width = meta.getPixelsSizeX(series).getValue().intValue();
Expand Down
4 changes: 4 additions & 0 deletions components/bio-formats/src/loci/formats/out/AVIWriter.java
Expand Up @@ -103,6 +103,10 @@ public void saveBytes(int no, byte[] buf, int x, int y, int w, int h)
throws FormatException, IOException
{
checkParams(no, buf, x, y, w, h);
if (!isFullPlane(x, y, w, h)) {
throw new FormatException(
"AVIWriter does not yet support saving image tiles.");
}
int nChannels = getSamplesPerPixel();

if (!initialized[series][no]) {
Expand Down
Expand Up @@ -58,6 +58,10 @@ public void saveBytes(int no, byte[] buf, int x, int y, int w, int h)
throws FormatException, IOException
{
checkParams(no, buf, x, y, w, h);
if (!isFullPlane(x, y, w, h)) {
throw new FormatException(
"JPEG2000Writer does not yet support saving image tiles.");
}
MetadataRetrieve retrieve = getMetadataRetrieve();
boolean littleEndian =
!retrieve.getPixelsBinDataBigEndian(series, 0).booleanValue();
Expand Down
4 changes: 4 additions & 0 deletions components/bio-formats/src/loci/formats/out/JavaWriter.java
Expand Up @@ -58,6 +58,10 @@ public void saveBytes(int no, byte[] buf, int x, int y, int w, int h)
throws FormatException, IOException
{
checkParams(no, buf, x, y, w, h);
if (!isFullPlane(x, y, w, h)) {
throw new FormatException(
"JavaWriter does not yet support saving image tiles.");
}

// check pixel type
MetadataRetrieve meta = getMetadataRetrieve();
Expand Down
4 changes: 4 additions & 0 deletions components/bio-formats/src/loci/formats/out/OMEXMLWriter.java
Expand Up @@ -120,6 +120,10 @@ public void saveBytes(int no, byte[] buf, int x, int y, int w, int h)
throws FormatException, IOException
{
checkParams(no, buf, x, y, w, h);
if (!isFullPlane(x, y, w, h)) {
throw new FormatException(
"OMEXMLWriter does not yet support saving image tiles.");
}
MetadataRetrieve retrieve = getMetadataRetrieve();

String type = retrieve.getPixelsType(series).toString();
Expand Down
3 changes: 3 additions & 0 deletions components/bio-formats/src/loci/formats/out/TiffWriter.java
Expand Up @@ -177,8 +177,11 @@ public void saveBytes(int no, byte[] buf, IFD ifd, int x, int y, int w, int h)
ifd.put(new Integer(IFD.LITTLE_ENDIAN), new Boolean(littleEndian));
out.seek(out.length());
ifd.putIFDValue(IFD.PLANAR_CONFIGURATION, interleaved ? 1 : 2);
RandomAccessInputStream in = new RandomAccessInputStream(currentId);
tiffSaver.setInputStream(in);
tiffSaver.writeImage(buf, ifd, no, type, x, y, w, h,
no == getPlaneCount() - 1);
in.close();
}

// -- IFormatWriter API methods --
Expand Down
58 changes: 46 additions & 12 deletions components/bio-formats/src/loci/formats/tiff/TiffSaver.java
Expand Up @@ -62,6 +62,9 @@ public class TiffSaver {
/** Output stream to use when saving TIFF data. */
protected RandomAccessOutputStream out;

/** Input stream to use when overwriting data. */
protected RandomAccessInputStream in;

/** Whether or not to write BigTIFF data. */
private boolean bigTiff = false;

Expand All @@ -82,6 +85,11 @@ public TiffSaver(String filename) throws IOException {

// -- TiffSaver methods --

/** Sets the input stream. */
public void setInputStream(RandomAccessInputStream in) {
this.in = in;
}

/** Gets the stream from which TIFF data is being saved. */
public RandomAccessOutputStream getStream() {
return out;
Expand Down Expand Up @@ -166,15 +174,24 @@ public void writeImage(byte[] buf, IFD ifd, int no, int pixelType, int x,
throw new FormatException("Image data cannot be null");
}

if (in == null) {
throw new FormatException("RandomAccessInputStream is null. " +
"Call setInputStream(RandomAccessInputStream) first.");
}

if (ifd == null) {
throw new FormatException("IFD cannot be null");
}

int width = (int) ifd.getImageWidth();
if (w != width) {
// TODO : allow the tile to be narrower than the full image
throw new FormatException("Tile must be as wide as the full image.");
}
int height = (int) ifd.getImageLength();
int bytesPerPixel = FormatTools.getBytesPerPixel(pixelType);
int plane = width * height * bytesPerPixel;
int nChannels = buf.length / plane;
int nChannels = buf.length / (w * h * bytesPerPixel);
boolean interleaved = ifd.getPlanarConfiguration() == 1;

//boolean indexed = ifd.getIFDValue(IFD.COLOR_MAP) != null;
Expand All @@ -184,13 +201,7 @@ public void writeImage(byte[] buf, IFD ifd, int no, int pixelType, int x,
// create pixel output buffers

TiffCompression compression = ifd.getCompression();
boolean compressFullImage = compression == TiffCompression.JPEG_2000 ||
compression == TiffCompression.JPEG_2000_LOSSY ||
compression == TiffCompression.JPEG ||
compression == TiffCompression.ALT_JPEG;

int pixels = width;
if (compressFullImage) pixels *= height;

int rowsPerStrip = (int) ifd.getRowsPerStrip()[0];
int stripSize = rowsPerStrip * width * bytesPerPixel;
Expand All @@ -208,10 +219,10 @@ public void writeImage(byte[] buf, IFD ifd, int no, int pixelType, int x,
int[] bps = ifd.getBitsPerSample();

// write pixel strips to output buffers
for (int row=0; row<height; row++) {
for (int row=y; row<h+y; row++) {
int strip = row / rowsPerStrip;
for (int col=0; col<width; col++) {
int ndx = row * width * bytesPerPixel + col * bytesPerPixel;
int ndx = (row - y) * width * bytesPerPixel + col * bytesPerPixel;
for (int c=0; c<nChannels; c++) {
for (int n=0; n<bps[c]/8; n++) {
if (interleaved) {
Expand All @@ -237,13 +248,29 @@ public void writeImage(byte[] buf, IFD ifd, int no, int pixelType, int x,
strips[strip] = compression.compress(strips[strip], options);
}

TiffParser parser = new TiffParser(in);
long[] ifdOffsets = parser.getIFDOffsets();
if (no < ifdOffsets.length) {
out.seek(ifdOffsets[no]);
ifd = parser.getIFD(ifdOffsets[no]);
}

// record strip byte counts and offsets

long[] stripByteCounts = new long[nStrips];
long[] stripOffsets = new long[nStrips];

if (ifd.containsKey(IFD.STRIP_BYTE_COUNTS)) {
stripByteCounts = ifd.getStripByteCounts();
}
if (ifd.containsKey(IFD.STRIP_OFFSETS)) {
stripOffsets = ifd.getStripOffsets();
}

for (int i=0; i<nStrips; i++) {
stripByteCounts[i] = strips[i].length;
if (stripByteCounts[i] == 0) {
stripByteCounts[i] = strips[i].length;
}
}

ifd.putIFDValue(IFD.STRIP_BYTE_COUNTS, stripByteCounts);
Expand All @@ -253,9 +280,16 @@ public void writeImage(byte[] buf, IFD ifd, int no, int pixelType, int x,
writeIFD(ifd, 0);

for (int i=0; i<strips.length; i++) {
stripOffsets[i] = out.getFilePointer();
out.write(strips[i]);
if (stripOffsets[i] > 0 && strips[i].length == 0) {
out.seek(stripOffsets[i] + stripByteCounts[i]);
}
else {
stripOffsets[i] = out.getFilePointer();
out.write(strips[i]);
}
}
ifd.putIFDValue(IFD.STRIP_BYTE_COUNTS, stripByteCounts);
ifd.putIFDValue(IFD.STRIP_OFFSETS, stripOffsets);
long endFP = out.getFilePointer();
out.seek(fp);
writeIFD(ifd, last ? 0 : endFP);
Expand Down

0 comments on commit 58e089d

Please sign in to comment.