/* * #%L * BSD implementations of Bio-Formats readers and writers * %% * Copyright (C) 2005 - 2015 Open Microscopy Environment: * - Board of Regents of the University of Wisconsin-Madison * - Glencoe Software, Inc. * - University of Dundee * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * #L% */ package loci.formats.tools; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import loci.common.services.DependencyException; import loci.common.services.ServiceException; import loci.common.services.ServiceFactory; import loci.formats.CoreMetadata; import loci.formats.FormatException; import loci.formats.FormatTools; import loci.formats.MetadataTools; import loci.formats.gui.BufferedImageWriter; import loci.formats.meta.IMetadata; import loci.formats.out.OMETiffWriter; import loci.formats.services.OMEXMLService; import ome.xml.model.enums.EnumerationException; /** * Creates sample OME-TIFF datasets according to the given parameters. */ public class MakeTestOmeTiff { public int sizeZsub = 1; public int sizeTsub = 1; public int sizeCsub = 1; public boolean isModulo = false; public void makeSamples() throws FormatException, IOException { makeOmeTiff("single-channel", "439", "167", "1", "1", "1", "XYZCT"); makeOmeTiff("multi-channel", "439", "167", "1", "3", "1", "XYZCT"); makeOmeTiff("z-series", "439", "167", "5", "1", "1", "XYZCT"); makeOmeTiff("multi-channel-z-series", "439", "167", "5", "3", "1", "XYZCT"); makeOmeTiff("time-series", "439", "167", "1", "1", "7", "XYZCT"); makeOmeTiff("multi-channel-time-series", "439", "167", "1", "3", "7", "XYZCT"); makeOmeTiff("4D-series", "439", "167", "5", "1", "7", "XYZCT"); makeOmeTiff("multi-channel-4D-series", "439", "167", "5", "3", "7", "XYZCT"); makeOmeTiff("modulo-6D-Z", "250", "200", "8", "3", "2", "XYZCT", "4", "1", "1"); makeOmeTiff("modulo-6D-C", "250", "200", "4", "9", "2", "XYZCT", "1", "3", "1"); makeOmeTiff("modulo-6D-T", "250", "200", "4", "3", "6", "XYZCT", "1", "1", "2"); makeOmeTiff("modulo-7D-ZC", "250", "220", "8", "9", "2", "XYZCT", "4", "3", "1"); makeOmeTiff("modulo-7D-CT", "250", "220", "4", "9", "6", "XYZCT", "1", "3", "2"); makeOmeTiff("modulo-7D-ZT", "250", "220", "8", "3", "6", "XYZCT", "4", "1", "2"); makeOmeTiff("modulo-8D", "200", "250", "8", "9", "6", "XYZCT", "4", "3", "2"); } public int makeOmeTiff(final String... args) throws FormatException, IOException { if (args == null || args.length == 0) { makeSamples(); return 0; } // parse command line arguments if (args.length != 7 && args.length != 10 ) { displayUsage(); return 1; } if (args.length == 10 ) { isModulo = true; } final String name = args[0]; final CoreMetadata info = new CoreMetadata(); info.sizeX = Integer.parseInt(args[1]); info.sizeY = Integer.parseInt(args[2]); info.sizeZ = Integer.parseInt(args[3]); info.sizeC = Integer.parseInt(args[4]); info.sizeT = Integer.parseInt(args[5]); info.imageCount = info.sizeZ * info.sizeC * info.sizeT; info.dimensionOrder = args[6].toUpperCase(); if (isModulo) { sizeZsub = Integer.parseInt(args[7]); sizeCsub = Integer.parseInt(args[8]); sizeTsub = Integer.parseInt(args[9]); } makeOmeTiff(name, info); return 0; } public void makeOmeTiff(final String name, final CoreMetadata info) throws FormatException, IOException { final String id = getId(name); final OMETiffWriter out = createWriter(name, info, id); writeData(name, info, id, out); } public static void main(final String[] args) throws FormatException, IOException { final int returnCode = new MakeTestOmeTiff().makeOmeTiff(args); System.exit(returnCode); } // -- Helper methods -- private void displayUsage() { System.out.println("Usage: java loci.formats.tools.MakeTestOmeTiff name"); System.out.println(" SizeX SizeY SizeZ SizeC SizeT DimOrder"); System.out.println(); System.out.println(" name: output filename"); System.out.println(" SizeX: width of image planes"); System.out.println(" SizeY: height of image planes"); System.out.println(" SizeZ: number of focal planes"); System.out.println(" SizeC: number of channels"); System.out.println(" SizeT: number of time points"); System.out.println(" DimOrder: planar ordering:"); System.out.println(" XYZCT, XYZTC, XYCZT, XYCTZ, XYTZC, or XYTCZ"); System.out.println(); System.out.println("Example:"); System.out.println(" java loci.formats.tools.MakeTestOmeTiff test \\"); System.out.println(" 517 239 5 3 4 XYCZT"); System.out.println(); System.out.println("Optional Usage: java loci.formats.tools.MakeTestOmeTiff name"); System.out.println(" SizeX SizeY SizeZ SizeC SizeT DimOrder SubZ SubC SubT"); System.out.println("This creates a 6D, 7D, or 8D file using the Modulo extension"); System.out.println(); System.out.println(" SubZ: splits of Z planes into extra dimension"); System.out.println(" SubC: splits of channels into extra dimension"); System.out.println(" SubT: splits of time points into extra dimension"); System.out.println("A value of 1 means no split"); System.out.println(); System.out.println("Example:"); System.out.println(" java loci.formats.tools.MakeTestOmeTiff test8D \\"); System.out.println(" 200 250 6 4 8 XYCZT 3 2 2"); } private String getId(final String name) { final String id; if (name.toLowerCase().endsWith(".ome.tif")) id = name; else id = name + ".ome.tif"; return id; } private OMETiffWriter createWriter(final String name, final CoreMetadata info, final String id) throws FormatException, IOException { final OMETiffWriter out = new OMETiffWriter(); try { out.setMetadataRetrieve(createMetadata(name, info)); } catch (final DependencyException e) { throw new FormatException(e); } catch (final ServiceException e) { throw new FormatException(e); } catch (final EnumerationException e) { throw new FormatException(e); } ensureNonExisting(id); out.setId(id); return out; } private void writeData(final String name, final CoreMetadata info, final String id, final OMETiffWriter out) throws FormatException, IOException { System.out.print(id); for (int i = 0; i < info.imageCount; i++) { final BufferedImage plane = createPlane(name, info, i); out.saveBytes(i, BufferedImageWriter.toBytes(plane, out)); System.out.print("."); } System.out.println(); out.close(); } private void ensureNonExisting(final String id) { final File idFile = new File(id); if (idFile.exists()) idFile.delete(); } private IMetadata createMetadata(final String name, final CoreMetadata info) throws DependencyException, ServiceException, EnumerationException { final ServiceFactory serviceFactory = new ServiceFactory(); final OMEXMLService omexmlService = serviceFactory.getInstance(OMEXMLService.class); final IMetadata meta = omexmlService.createOMEXMLMetadata(); MetadataTools.populateMetadata(meta, 0, name, info); if (isModulo) { meta.setXMLAnnotationID("Annotation:Modulo:0", 0); meta.setXMLAnnotationNamespace("openmicroscopy.org/omero/dimension/modulo", 0); meta.setXMLAnnotationDescription("For a description of how 6D, 7D, and 8D data is stored using the Modulo extension see http://www.openmicroscopy.org/site/support/ome-model/developers/6d-7d-and-8d-storage.html", 0); StringBuilder moduloBlock = new StringBuilder(); moduloBlock.append("<Modulo namespace=\"http://www.openmicroscopy.org/Schemas/Additions/2011-09\">"); if (sizeZsub != 1) { moduloBlock.append("<ModuloAlongZ Type=\"other\" TypeDescription=\"Example Data Over Z-Plane\" Start=\"0\" Step=\"1\" End=\""); moduloBlock.append(sizeZsub); moduloBlock.append("\"/>"); } if (sizeTsub != 1) { moduloBlock.append("<ModuloAlongT Type=\"other\" TypeDescription=\"Example Data Over Time \" Start=\"0\" Step=\"1\" End=\""); moduloBlock.append(sizeTsub); moduloBlock.append("\"/>"); } if (sizeCsub != 1) { moduloBlock.append("<ModuloAlongC Type=\"other\" TypeDescription=\"Example Data Over Channel\" Start=\"0\" Step=\"1\" End=\""); moduloBlock.append(sizeCsub); moduloBlock.append("\"/>"); } moduloBlock.append("</Modulo>"); meta.setXMLAnnotationValue(moduloBlock.toString(), 0); meta.setImageAnnotationRef("Annotation:Modulo:0", 0, 0); } return meta; } private BufferedImage createPlane(final String name, final CoreMetadata info, final int no) { final int[] zct = FormatTools.getZCTCoords(info.dimensionOrder, info.sizeZ, info.sizeC, info.sizeT, info.imageCount, no); final BufferedImage plane = new BufferedImage(info.sizeX, info.sizeY, BufferedImage.TYPE_BYTE_GRAY); final Graphics2D g = plane.createGraphics(); // draw gradient final int type = 0; for (int y = 0; y < info.sizeY; y++) { final int v = gradient(type, y, info.sizeY); g.setColor(new Color(v, v, v)); g.drawLine(0, y, info.sizeX, y); } // build list of text lines from planar information final ArrayList<TextLine> lines = new ArrayList<TextLine>(); final Font font = g.getFont(); lines.add(new TextLine(name, font.deriveFont(32f), 5, -5)); lines.add(new TextLine(info.sizeX + " x " + info.sizeY, font.deriveFont( Font.ITALIC, 16f), 20, 10)); lines.add(new TextLine(info.dimensionOrder, font.deriveFont(Font.ITALIC, 14f), 30, 5)); int space = 5; if (info.sizeZ > 1) { lines.add(new TextLine( "Focal plane = " + (zct[0] + 1) + "/" + info.sizeZ, font, 20, space)); space = 2; } if (info.sizeC > 1) { lines.add(new TextLine("Channel = " + (zct[1] + 1) + "/" + info.sizeC, font, 20, space)); space = 2; } if (info.sizeT > 1) { lines.add(new TextLine("Time point = " + (zct[2] + 1) + "/" + info.sizeT, font, 20, space)); space = 2; } if (isModulo) { if (sizeZsub > 1) { lines.add(new TextLine("True-Z point = " + ((zct[0]/sizeZsub) + 1) + "/" + info.sizeZ/sizeZsub, font, 20, space)); space = 2; } if (sizeZsub > 1) { lines.add(new TextLine("Sub-Z = " + ((zct[0]%sizeZsub) + 1) + "/" + sizeZsub, font, 20, space)); space = 2; } if (sizeCsub > 1) { lines.add(new TextLine("True Channel = " + ((zct[1]/sizeCsub) + 1) + "/" + info.sizeC/sizeCsub, font, 20, space)); space = 2; } if (sizeCsub > 1) { lines.add(new TextLine("Sub Channel = " + ((zct[1]%sizeCsub) + 1) + "/" + sizeCsub, font, 20, space)); space = 2; } if (sizeTsub > 1) { lines.add(new TextLine("True-T point = " + ((zct[2]/sizeTsub) + 1) + "/" + info.sizeT/sizeTsub, font, 20, space)); space = 2; } if (sizeTsub > 1) { lines.add(new TextLine("Sub-T = " + ((zct[2]%sizeTsub) + 1) + "/" + sizeTsub, font, 20, space)); space = 2; } } // draw text lines to image g.setColor(Color.white); int yoff = 0; for (int l = 0; l < lines.size(); l++) { final TextLine text = lines.get(l); g.setFont(text.font); final Rectangle2D r = g.getFont().getStringBounds(text.line, g.getFontRenderContext()); yoff += r.getHeight() + text.ypad; g.drawString(text.line, text.xoff, yoff); } g.dispose(); return plane; } private int gradient(final int type, final int num, final int total) { final int max = 96; final int split = type / 2 + 1; final boolean reverse = type % 2 == 0; int v = max; final int splitTotal = total / split; for (int i = 1; i <= split + 1; i++) { if (num < i * splitTotal) { if (i % 2 == 0) v = max * (num % splitTotal) / splitTotal; else v = max * (splitTotal - num % splitTotal) / splitTotal; break; } } if (reverse) v = max - v; return v; } // -- Helper classes -- private static class TextLine { final String line; final Font font; final int xoff; final int ypad; TextLine(final String line, final Font font, final int xoff, final int ypad) { this.line = line; this.font = font; this.xoff = xoff; this.ypad = ypad; } } }