diff --git a/java/pom.xml b/java/pom.xml
index 5ca09ae..026ba39 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -2,7 +2,7 @@
4.0.0
org.micro-manager.ndtiffstorage
NDTiffStorage
- 2.19.2
+ 2.19.3
jar
NDTiff Storage file format
Java-based writer and reader used for NDTiffStorage format and NDRAM storage
diff --git a/java/src/main/java/org/micromanager/ndtiffstorage/NDTiffWriter.java b/java/src/main/java/org/micromanager/ndtiffstorage/NDTiffWriter.java
index 4427c58..5996891 100644
--- a/java/src/main/java/org/micromanager/ndtiffstorage/NDTiffWriter.java
+++ b/java/src/main/java/org/micromanager/ndtiffstorage/NDTiffWriter.java
@@ -292,9 +292,48 @@ private long unsignInt(int i) {
public void overwritePixels(String indexKey, Object pixels, boolean rgb) throws IOException {
long pixelOffset = indexMap_.get(indexKey).pixOffset_;
Buffer pixBuff = getPixelBuffer(pixels, rgb);
+ if (fileChannel_ == null) {
+ // This writer has already been finishedWriting() (its file was rotated/closed as
+ // the file set grew). Pixels still need to be overwritten in place -- e.g. when
+ // building low-res pyramid levels, a downsampled tile receives contributions from
+ // several full-res tiles, and the tile's first write may live in an earlier,
+ // now-closed file. Reopen the file read-write just for this in-place write, then
+ // close it again so we don't leak file descriptors for every rotated file.
+ overwritePixelsReopening(pixBuff, pixelOffset);
+ return;
+ }
fileChannelWrite(pixBuff, pixelOffset);
}
+ /**
+ * Overwrite pixels in place in a file whose channel has been closed (after
+ * finishedWriting()). Opens the existing file read-write at {@code position}, writes the
+ * buffer, and closes -- the writer stays in its finished state. The index entry's
+ * pixOffset_ is an absolute file offset, so no header re-parsing is needed.
+ */
+ private void overwritePixelsReopening(final Buffer buffer, final long position)
+ throws IOException {
+ buffer.rewind();
+ ByteBuffer byteBuffer = (ByteBuffer) buffer;
+ RandomAccessFile raf = null;
+ try {
+ raf = new RandomAccessFile(filename_, "rw");
+ FileChannel ch = raf.getChannel();
+ // A single positional write is not guaranteed to write the whole buffer; loop
+ // until it is fully written, advancing the file position by the bytes written.
+ long pos = position;
+ while (byteBuffer.hasRemaining()) {
+ pos += ch.write(byteBuffer, pos);
+ }
+ } finally {
+ // Recycle in finally so a write/IO failure cannot leak a large direct buffer.
+ masterMPTiffStorage_.tryRecycleLargeBuffer(byteBuffer);
+ if (raf != null) {
+ raf.close();
+ }
+ }
+ }
+
private IndexEntryData writeIFD(String indexKey, Object pixels, byte[] metadata,
boolean rgb, int imageHeight, int imageWidth, int bitDepth
) throws IOException {