source: trunk/loci/formats/reader-guide.txt @ 2874

Revision 2874, 9.2 KB checked in by melissa, 13 years ago (diff)

Updated info on automated testing.

Line 
1            Bio-Formats File Format Reader Guide by Melissa Linkert
2
3This document is a brief guide to writing new Bio-Formats file format readers.
4
5All format readers should extend either loci.formats.FormatReader or a reader
6in loci.formats.in.
7
8                              Methods to Override
9                             ---------------------
10
11boolean isThisType(byte[]) :
12  Check the first few bytes of a file to determine if the file can be read by
13  this reader.  You can assume that the first byte of the array corresponds to
14  the first byte of the file.  Return true if the file can be read; false if
15  not (or if there is no way of checking).
16
17String[] getUsedFiles() throws FormatException, IOException :
18  You only need to override this if your format uses multiple files in a single
19  dataset.  This method should return a list of all the files associated with
20  the given file name (i.e. every file needed to display the current dataset).
21  For an example of how this works, see loci.formats.in.PerkinElmerReader.
22  It is recommended that the first line of this method be
23  "FormatTools.assertId(currentId, true, 1)" - this ensures that the file name
24  is non-null.
25
26byte[] openBytes(int) throws FormatException, IOException :
27  Returns a byte array containing the pixel data for the specified image from
28  the given file.  Should throw a FormatException if the image number is invalid
29  (less than 0 or >= the number of images).  The ordering of the array
30  returned by openBytes should correspond to the values returned by
31  isLittleEndian() and isInterleaved().  Also, the length of the
32  byte array should be [image width * image height * bytes per pixel].  Extra
33  bytes will generally be truncated. It is recommended that the first line of
34  this method be "FormatTools.asserId(currentId, true, 1)" - this ensures that
35  the file name is non-null.
36
37BufferedImage openImage(int) throws FormatException, IOException :
38  Basically the same as openBytes, but returns a java.awt.image.BufferedImage
39  instead of a byte array.  In general, the easiest way to implement this is
40  by getting the corresponding byte array from openBytes, then returning
41  loci.formats.ImageTools.makeImage(byte[], int width, int height, int
42  numberOfChannels, boolean isInterleaved, int bytesPerPixel, boolean
43  isLittleEndian). It is recommended that the first line of this method be
44  "FormatTools.assertId(currentId, true, 1)" - this ensures that the file name
45  is non-null.
46
47protected void initFile(String) throws FormatException, IOException :
48  The majority of the file parsing logic should be placed in this method.  The
49  idea is to call this method once (and only once!) when the file is first
50  opened.  Generally, you will want to start by calling
51  super.initFile(String).  You will also need to set up the stream for reading
52  the file, as well as initializing any dimension information and metadata.
53  Most of this logic is up to you; however, you should populate the 'core'
54  variable (see loci.formats.CoreMetadata).
55
56  Note that each variable is initialized to 0 or null when
57  super.initFile(String) is called.
58  Also, super.initFile(String) constructs a Hashtable called "metadata" where
59  you should store any relevant metadata.
60
61Note that if the new format is a variant of a format currently supported by
62Bio-Formats, it is more efficient to make the new reader a subclass of the
63existing reader (rather than subclassing FormatReader).  In this case, it is
64usually sufficient to override initFile(String) and isThisType(byte[]).
65
66Every reader also has an instance of loci.formats.CoreMetadata.  All readers
67should populate the fields in CoreMetadata, which are essential to reading
68image planes.
69
70If you read from a file using something other than RandomAccessStream or
71Location, you *must* use the file name returned by Location.getMappedId(String),
72not the file name passed to the reader.
73Thus, a stub for initFile(String) might look like this:
74
75  protected void initFile(String id) throws FormatException, IOException {
76    super.initFile(id);
77
78    RandomAccessStream in = new RandomAccessStream(id);
79    // alternatively,
80    //FileInputStream in = new FileInputStream(Location.getMappedId(id));
81
82    // read basic file structure and metadata from stream
83  }
84
85For more details, see the javadoc for Location.mapId(String, String)
86and Location.getMappedId(String).
87
88                              Other Useful Things
89                             ---------------------
90
91- loci.formats.RandomAccessStream is a hybrid RandomAccessFile/InputStream
92  class that is generally more efficient than either RandomAccessFile or
93  InputStream, and implements the DataInput interface.  It also keeps track
94  of open files, and will automatically close and re-open files as needed
95  to ensure that there aren't too many files open at one time.
96  It is recommended that you use this for reading binary files.
97
98- loci.formats.Location provides an API similar to java.io.File, and supports
99  File-like operations on URLs.  It is highly recommended that you use this
100  instead of File.  See the javadoc for additional information.
101
102- loci.formats.DataTools provides a number of methods for converting bytes to
103  shorts, ints, longs, etc.  It also supports reading most primitive types
104  directly from a RandomAccessStream (or other DataInput implementation).
105
106- loci.formats.ImageTools provides several methods for manipulating
107  java.awt.image.BufferedImage objects.  In particular, it can create
108  BufferedImages from primitive type arrays, resize images, split RGB images
109  into 3 grayscale images, and so on.  Consult the source or javadoc for more
110  information.
111
112- If your reader relies on third-party code which may not be available to all
113  users, it is strongly suggested that you access this code only through a
114  loci.formats.ReflectedUniverse object.  For an example of how this works,
115  see loci.formats.in.ZeissZVIReader.
116
117- Several common image compression types are supported through subclasses of
118  loci.formats.BaseCompressor.  These include LZW, LZO, Base64, ZIP and
119  RLE (PackBits).
120
121- Debugging statements can be added using FormatHandler.debug(String).
122
123- If you wish to convert a file's metadata to OME-XML (strongly encouraged),
124  loci.formats.ome.OMEXMLMetadataStore provides methods for creating OME-XML
125  from metadata values.  Note that OMEXMLMetadataStore is a subclass of
126  loci.formats.MetadataStore (every subclass of FormatReader keeps an instance
127  of MetadataStore by default); so to add OME-XML support is as simple as
128  calling getMetadataStore() on a format reader instance, and then
129  calling the appropriate "set" methods as documented in OMEXMLMetadataStore.
130
131- Utility methods for reading and writing individual bits from a byte array
132  can be found in loci.formats.BitBuffer and loci.formats.BitWriter
133
134- Once you have written your file format reader, add a line to the readers.txt
135  file with the fully qualified name of the reader, followed by a '#' and the
136  file extensions associated with the file format. Note that ImageReader,
137  the master file format reader, tries to identify which format reader to use
138  according to the order given in readers.txt, so be sure to place your reader
139  in an appropriate position within the list.
140
141- The easiest way to test your new reader is by calling "java
142  loci.formats.ImageReader <file name>".  If all goes well, you should see
143  all of the metadata and dimension information, along with a window showing
144  the images in the file.  ImageReader can take additional parameters; a
145  brief listing is provided for reference, but it is recommended that you
146  take a look at the contents of ConsoleTools.testRead to see exactly what
147  each one does.
148
149    Argument            Action
150    --------------------------
151    -nopix              Read metadata only; don't display images.
152    -nometa             Output only core metadata (dimension information).
153    -thumbs             Read thumbnails instead of regular images.
154    -merge              Combine separate channels into a set of RGB images.
155    -stitch             Open all files with a similar name.
156    -separate           Force RGB images to be split into separate channels.
157    -omexml             Output the OME-XML for the file.
158    -normalize          Normalize floating point images.
159    -fast               Display RGB images as quickly as possible.
160    -debug              Turn on debugging output.
161    -range              Specify a range of images to open.
162    -series             Set the series number (for container file formats).
163    -map                Specify file on disk to which name should be mapped.
164
165- If you wish to test using TestNG, loci.formats.test.ReaderTest provides 15
166  basic tests that work with all Bio-Formats readers.  See the
167  ReaderTest source code for additional information.
168
169- For more details, please look at the source code and javadocs.  Studying
170  existing readers is probably the best way to get a feel for the API; I would
171  recommend first looking at loci.formats.in.ImarisReader (this is the most
172  straightforward one).  loci.formats.in.LIFReader and ZeissZVIReader are also
173  good references that show off some of the nicer features of Bio-Formats.
174
175If you have questions about Bio-Formats, please contact:
176  Curtis Rueden <ctrueden@wisc.edu>
177  Melissa Linkert <linkert@wisc.edu>
Note: See TracBrowser for help on using the repository browser.