// // WritePrecompressedPlanes.java // import java.io.IOException; import loci.common.RandomAccessInputStream; import loci.common.RandomAccessOutputStream; import loci.formats.FormatException; import loci.formats.FormatTools; import loci.formats.ImageReader; import loci.formats.MetadataTools; import loci.formats.meta.IMetadata; import loci.formats.tiff.IFD; import loci.formats.tiff.TiffCompression; import loci.formats.tiff.TiffSaver; import ome.xml.model.primitives.PositiveInteger; /** * Writes the pixels from a set of JPEG files to a single TIFF. * The pixel data is used as-is, so no decompression or re-compression is * performed. * * <dl><dt><b>Source code:</b></dt> * <dd><a href="http://trac.openmicroscopy.org.uk/ome/browser/bioformats.git/components/bio-formats/utils/WritePrecompressedPlanes.java">Trac</a>, * <a href="http://git.openmicroscopy.org/?p=bioformats.git;a=blob;f=components/bio-formats/utils/WritePrecompressedPlanes.java;hb=HEAD">Gitweb</a></dd></dl> */ public class WritePrecompressedPlanes { public static void main(String[] args) throws FormatException, IOException { // print usage if no args specified if (args.length == 0) { System.out.println("Usage: java WritePrecompressedPlanes " + "[input file 1] ... [input file n] [output file]"); System.exit(0); } // first n - 1 args are the input files String[] inputFiles = new String[args.length - 1]; System.arraycopy(args, 0, inputFiles, 0, inputFiles.length); // last arg is the output file String outputFile = args[args.length - 1]; // open up one of the input files so that we can read the metadata // this assumes that the dimensions of the input files are the same ImageReader reader = new ImageReader(); reader.setId(inputFiles[0]); int pixelType = reader.getPixelType(); // write the pixel data to the output file RandomAccessOutputStream out = new RandomAccessOutputStream(outputFile); TiffSaver saver = new TiffSaver(out, outputFile); saver.setWritingSequentially(true); saver.setLittleEndian(reader.isLittleEndian()); saver.setBigTiff(false); saver.writeHeader(); for (int i=0; i<inputFiles.length; i++) { RandomAccessInputStream in = new RandomAccessInputStream(inputFiles[i]); byte[] buf = new byte[(int) in.length()]; in.readFully(buf); in.close(); IFD ifd = new IFD(); ifd.put(IFD.IMAGE_WIDTH, reader.getSizeX()); ifd.put(IFD.IMAGE_LENGTH, reader.getSizeY()); ifd.put(IFD.LITTLE_ENDIAN, reader.isLittleEndian()); ifd.put(IFD.SAMPLE_FORMAT, FormatTools.isSigned(pixelType) ? 2 : FormatTools.isFloatingPoint(pixelType) ? 3 : 1); ifd.put(IFD.PLANAR_CONFIGURATION, 1); ifd.put(IFD.REUSE, out.length()); out.seek(out.length()); // this is very important // the data is already compressed in a single chunk, so setting the // number of rows per strip to something smaller than the full height // will require us to re-compress the data ifd.put(IFD.ROWS_PER_STRIP, reader.getSizeY()); saver.writeImage(buf, ifd, i, pixelType, 0, 0, reader.getSizeX(), reader.getSizeY(), i == inputFiles.length - 1, reader.getRGBChannelCount(), true); } reader.close(); out.close(); // reset the TIFF file's compression flag // you cannot do this before the pixel data is written, otherwise // the pixels will be re-compressed saver = new TiffSaver(outputFile); for (int i=0; i<inputFiles.length; i++) { RandomAccessInputStream in = new RandomAccessInputStream(outputFile); saver.overwriteLastIFDOffset(in); saver.overwriteIFDValue(in, i, IFD.COMPRESSION, TiffCompression.JPEG.getCode()); in.close(); } saver.getStream().close(); } }