In-memory reading and writing in Bio-Formats

Bio-Formats readers and writers are traditionally used to handle image files from disk. However it is also possible to achieve reading and writing of files from in-memory sources. This is handled by mapping the in-memory data to a file location using Location.mapFile().

Location.mapFile(fileName, byteArrayHandle);

This file location is not created on disk but rather maps internally to the in-memory data provided.

Reading file from memory

In order for Bio-Formats to read a file from memory it must be available in a byte array. For this example an input file is read from disk into a byte array.

    // read in entire file
    System.out.println("Reading file into memory from disk...");
    File inputFile = new File(path);
    int fileSize = (int) inputFile.length();
    DataInputStream in = new DataInputStream(new FileInputStream(inputFile));
    byte[] inBytes = new byte[fileSize];
    in.readFully(inBytes);
    System.out.println(fileSize + " bytes read.");

This data can now be handled by a Bio-Formats reader. This is achieved by providing a mapping from the in-memory data to a suitable filename which will be used by the reader. The filename used must have the same suffix as the original data type.

    // determine input file suffix
    String fileName = inputFile.getName();
    int dot = fileName.lastIndexOf(".");
    String suffix = dot < 0 ? "" : fileName.substring(dot);

    // map input id string to input byte array
    String inId = "inBytes" + suffix;
    Location.mapFile(inId, new ByteArrayHandle(inBytes));

Once the in-memory data has been mapped to a suitable filename the data can be handled by the reader as normal.

    // read in entire file
    System.out.println("Reading file into memory from disk...");
    File inputFile = new File(path);
    int fileSize = (int) inputFile.length();
    DataInputStream in = new DataInputStream(new FileInputStream(inputFile));
    byte[] inBytes = new byte[fileSize];
    in.readFully(inBytes);
    System.out.println(fileSize + " bytes read.");

Writing to memory

To use a writer to output to memory rather than an output file a similar process is required. First a mapping is created between a suitable output filename and the in-memory data.

    // map output id string to output byte array
    String outId = fileName + ".ome.tif";
    ByteArrayHandle outputFile = new ByteArrayHandle();
    Location.mapFile(outId, outputFile);

The mapped filename can now be passed to initialize the writer as standard.

    // write data to byte array using ImageWriter
    System.out.println();
    System.out.print("Writing planes to destination in memory: ");
    ImageWriter writer = new ImageWriter();
    writer.setMetadataRetrieve(omeMeta);
    writer.setId(outId);

The data can then be written to memory using the same read and write loop which would normally be used to write a file to disk.

    byte[] plane = null;
    for (int i=0; i<imageCount; i++) {
      if (plane == null) {
        // allow reader to allocate a new byte array
        plane = reader.openBytes(i);
      }
      else {
        // reuse previously allocated byte array
        reader.openBytes(i, plane);
      }
      writer.saveBytes(i, plane);
      System.out.print(".");
    }
    reader.close();
    writer.close();
    System.out.println();

    byte[] outBytes = outputFile.getBytes();
    outputFile.close();

If desired the data written to memory can then be flushed to disk and written to an output file location.

    // flush output byte array to disk
    System.out.println();
    System.out.println("Flushing image data to disk...");
    File outFile = new File(fileName + ".ome.tif");
    DataOutputStream out = new DataOutputStream(new FileOutputStream(outFile));
    out.write(outBytes);
    out.close();

See also

ReadWriteInMemory.java - Full source code which is referenced here in part. You will need to have bioformats_package.jar in your Java CLASSPATH in order to compile ReadWriteInMemory.java.