private <T extends RealType<T>> void populatePlane( IFormatReader r, int no, byte[] plane, LocalizablePlaneCursor<T> cursor) { final int sizeX = r.getSizeX(); final int pixelType = r.getPixelType(); final boolean little = r.isLittleEndian(); final int[] dimLengths = getDimLengths(r); final int[] pos = new int[dimLengths.length]; final int planeX = 0; final int planeY = 1; getPosition(r, no, pos); cursor.reset(planeX, planeY, pos); while (cursor.hasNext()) { cursor.fwd(); final int index = cursor.getPosition(planeX) + cursor.getPosition(planeY) * sizeX; final double value = decodeWord(plane, index, pixelType, little); cursor.getType().setReal(value); } }
/** * Reads in an imglib {@link Image} from the given initialized {@link IFormatReader}, using the * given {@link ImageFactory}. */ public <T extends RealType<T>> Image<T> openImage(IFormatReader r, ImageFactory<T> imageFactory) throws FormatException, IOException { final String[] dimTypes = getDimTypes(r); final int[] dimLengths = getDimLengths(r); // TEMP - make suffix out of dimension types, until imglib supports them final String id = r.getCurrentFile(); final File idFile = new File(id); String name = idFile.exists() ? idFile.getName() : id; name = encodeName(name, dimTypes); // create image object final Image<T> img = imageFactory.createImage(dimLengths, name); // set calibration of the image img.setCalibration(getCalibration(r, dimLengths)); // TODO - create better container types; either: // 1) an array container type using one byte array per plane // 2) as #1, but with an IFormatReader reference reading planes on demand // 3) as PlanarContainer, but with an IFormatReader reference // reading planes on demand // PlanarContainer is useful for efficient access to pixels in ImageJ // (e.g., getPixels) // #1 is useful for efficient Bio-Formats import, and useful for tools // needing byte arrays (e.g., BufferedImage Java3D texturing by reference) // #2 is useful for efficient memory use for tools wanting matching // primitive arrays (e.g., virtual stacks in ImageJ) // #3 is useful for efficient memory use // get container final PlanarAccess<?> planarAccess = getPlanarAccess(img); final T inputType = makeType(r.getPixelType()); final T outputType = imageFactory.createType(); final boolean compatibleTypes = outputType.getClass().isAssignableFrom(inputType.getClass()); final long startTime = System.currentTimeMillis(); // populate planes final int planeCount = r.getImageCount(); if (planarAccess == null || !compatibleTypes) { // use cursor to populate planes // NB: This solution is general and works regardless of container, // but at the expense of performance both now and later. final LocalizablePlaneCursor<T> cursor = img.createLocalizablePlaneCursor(); byte[] plane = null; for (int no = 0; no < planeCount; no++) { notifyListeners( new StatusEvent(no, planeCount, "Reading plane " + (no + 1) + "/" + planeCount)); if (plane == null) plane = r.openBytes(no); else r.openBytes(no, plane); populatePlane(r, no, plane, cursor); } cursor.close(); } else { // populate the values directly using PlanarAccess interface; // e.g., to a PlanarContainer byte[] plane = null; for (int no = 0; no < planeCount; no++) { notifyListeners( new StatusEvent(no, planeCount, "Reading plane " + (no + 1) + "/" + planeCount)); if (plane == null) plane = r.openBytes(no); else r.openBytes(no, plane); populatePlane(r, no, plane, planarAccess); } } r.close(); final long endTime = System.currentTimeMillis(); final float time = (endTime - startTime) / 1000f; notifyListeners( new StatusEvent( planeCount, planeCount, id + ": read " + planeCount + " planes in " + time + "s")); return img; }