Search in sources :

Example 1 with MipMapImage

use of ini.trakem2.display.MipMapImage in project TrakEM2 by trakem2.

the class Loader method preload.

/**
 * Returns null when on low memory condition.
 */
@SuppressWarnings("unchecked")
public static final FutureTask<MipMapImage> preload(final Patch p, final double mag, final boolean repaint) {
    if (low_memory_conditions || num_preloader_threads < 1)
        return null;
    final FutureTask<MipMapImage>[] fu = (FutureTask<MipMapImage>[]) new FutureTask[1];
    fu[0] = new FutureTask<MipMapImage>(new Callable<MipMapImage>() {

        @Override
        public MipMapImage call() {
            // Utils.log2("preloading " + mag + " :: " + repaint + " :: " + p);
            try {
                if (p.getProject().getLoader().hs_unloadable.contains(p))
                    return null;
                if (repaint) {
                    if (Display.willPaint(p)) {
                        final MipMapImage mipMap = p.getProject().getLoader().fetchImage(p, mag);
                        // To prevent it:
                        if (null != mipMap) {
                            if (!Loader.isSignalImage(mipMap.image) && p.getProject().getLoader().isCached(p, mag)) {
                                // not the navigator
                                Display.repaint(p.getLayer(), p, p.getBoundingBox(null), 1, true, false);
                            }
                        }
                        return mipMap;
                    }
                } else {
                    // just load it into the cache if possible
                    return p.getProject().getLoader().fetchImage(p, mag);
                }
            } catch (final Throwable t) {
                IJError.print(t);
            } finally {
                preloads.remove(fu[0]);
            }
            return null;
        }
    });
    try {
        preloads.add(fu[0]);
        preloader.submit(fu[0]);
    } catch (final Throwable t) {
        Utils.log2("Ignoring error with preloading a Patch");
    }
    return fu[0];
}
Also used : FutureTask(java.util.concurrent.FutureTask) MipMapImage(ini.trakem2.display.MipMapImage) Callable(java.util.concurrent.Callable)

Example 2 with MipMapImage

use of ini.trakem2.display.MipMapImage in project TrakEM2 by trakem2.

the class FSLoader method fetchMipMap.

/**
 * Does the actual fetching of the file. Returns null if the file does not exist.
 *  Does NOT pre-release memory from the cache;
 *  call releaseToFit to do that.
 */
public final MipMapImage fetchMipMap(final Patch patch, int level, final long n_bytes) {
    final int max_level = getHighestMipMapLevel(patch);
    if (level > max_level)
        level = max_level;
    final double scale = Math.pow(2.0, level);
    final String filename = getInternalFileName(patch);
    if (null == filename) {
        Utils.log2("null internal filename!");
        return null;
    }
    // New style:
    final String path = new StringBuilder(dir_mipmaps).append(level).append('/').append(createIdPath(Long.toString(patch.getId()), filename, mExt)).toString();
    if (patch.hasAlphaChannel()) {
        final Image img = mmio.open(path);
        return img == null ? null : new MipMapImage(img, scale, scale);
    } else if (patch.paintsWithFalseColor()) {
        // AKA Patch has a LUT or is LUT image like a GIF
        final Image img = mmio.open(path);
        // considers c_alphas
        return img == null ? null : new MipMapImage(img, scale, scale);
    } else {
        final Image img;
        switch(patch.getType()) {
            case ImagePlus.GRAY16:
            case ImagePlus.GRAY8:
            case ImagePlus.GRAY32:
                // ImageSaver.openGreyJpeg(path);
                img = mmio.openGrey(path);
                return img == null ? null : new MipMapImage(img, scale, scale);
            default:
                // For color images: (considers URL as well)
                img = mmio.open(path);
                // considers c_alphas
                return img == null ? null : new MipMapImage(img, scale, scale);
        }
    }
}
Also used : MipMapImage(ini.trakem2.display.MipMapImage) Image(java.awt.Image) BufferedImage(java.awt.image.BufferedImage) MipMapImage(ini.trakem2.display.MipMapImage)

Example 3 with MipMapImage

use of ini.trakem2.display.MipMapImage in project TrakEM2 by trakem2.

the class Loader method fetchAWTImage.

public final MipMapImage fetchAWTImage(final Patch p, final int level, final int max_level) {
    // Below, the complexity of the synchronized blocks is to provide sufficient granularity. Keep in mind that only one thread at at a time can access a synchronized block for the same object (in this case, the db_lock), and thus calling lock() and unlock() is not enough. One needs to break the statement in as many synch blocks as possible for maximizing the number of threads concurrently accessing different parts of this function.
    // find an equal or larger existing pyramid awt
    final long id = p.getId();
    ImageLoadingLock plock = null;
    synchronized (db_lock) {
        try {
            if (null == mawts) {
                // when lazy repainting after closing a project, the awts is null
                return new MipMapImage(NOT_FOUND, p.getWidth() / NOT_FOUND.getWidth(), p.getHeight() / NOT_FOUND.getHeight());
            }
            if (level >= 0 && isMipMapsRegenerationEnabled()) {
                // 1 - check if the exact level is cached
                final Image mawt = mawts.get(id, level);
                if (null != mawt) {
                    // Utils.log2("returning cached exact mawt for level " + level);
                    final double scale = Math.pow(2.0, level);
                    return new MipMapImage(mawt, scale, scale);
                }
                plock = getOrMakeImageLoadingLock(p.getId(), level);
            }
        } catch (final Exception e) {
            IJError.print(e);
        }
    }
    MipMapImage mipMap = null;
    // 2 - check if the exact file is present for the desired level
    if (level >= 0 && isMipMapsRegenerationEnabled()) {
        synchronized (plock) {
            final Image mawt;
            synchronized (db_lock) {
                mawt = mawts.get(id, level);
            }
            if (null != mawt) {
                final double scale = Math.pow(2.0, level);
                // was loaded by a different thread
                return new MipMapImage(mawt, scale, scale);
            }
        }
        final long n_bytes = estimateImageFileSize(p, level);
        // going to load:
        releaseToFit(n_bytes * 8);
        synchronized (plock) {
            try {
                mipMap = fetchMipMapAWT(p, level, n_bytes);
            } catch (final Throwable t) {
                IJError.print(t);
                mipMap = null;
            }
            synchronized (db_lock) {
                try {
                    if (null != mipMap) {
                        // Utils.log2("returning exact mawt from file for level " + level);
                        if (REGENERATING != mipMap.image) {
                            mawts.put(id, mipMap.image, level);
                            Display.repaintSnapshot(p);
                        }
                        return mipMap;
                    }
                    // Check if an appropriate level is cached
                    mipMap = mawts.getClosestAbove(id, level);
                    if (mipMap == null) {
                        // 3 - else, load closest level to it but still giving a larger image
                        // finds the file for the returned level, otherwise returns zero
                        final int lev = getClosestMipMapLevel(p, level, max_level);
                        // Utils.log2("closest mipmap level is " + lev);
                        if (lev > -1) {
                            // overestimating n_bytes
                            mipMap = fetchMipMapAWT(p, lev, n_bytes);
                            if (null != mipMap) {
                                mawts.put(id, mipMap.image, lev);
                                // Utils.log2("from getClosestMipMapLevel: mawt is " + mawt);
                                Display.repaintSnapshot(p);
                                // Utils.log2("returning from getClosestMipMapAWT with level " + lev);
                                return mipMap;
                            }
                        } else if (ERROR_PATH_NOT_FOUND == lev) {
                            mipMap = new MipMapImage(NOT_FOUND, p.getWidth() / NOT_FOUND.getWidth(), p.getHeight() / NOT_FOUND.getHeight());
                        }
                    } else {
                        return mipMap;
                    }
                } catch (final Throwable t) {
                    handleCacheError(t);
                } finally {
                    removeImageLoadingLock(plock);
                }
            }
        }
    }
    synchronized (db_lock) {
        try {
            // 4 - check if any suitable level is cached (whithout mipmaps, it may be the large image)
            mipMap = mawts.getClosestAbove(id, level);
            if (null != mipMap) {
                // Utils.log2("returning from getClosest with level " + level);
                return mipMap;
            }
        } catch (final Exception e) {
            IJError.print(e);
        }
    }
    if (hs_unloadable.contains(p))
        return new MipMapImage(NOT_FOUND, p.getWidth() / NOT_FOUND.getWidth(), p.getHeight() / NOT_FOUND.getHeight());
    synchronized (db_lock) {
        try {
            plock = getOrMakeImageLoadingLock(p.getId(), level);
        } catch (final Exception e) {
            // TODO there may be a flaw in the image loading locks: when removing it, if it had been acquired by another thread, then a third thread will create it new. The image loading locks should count the number of threads that have them, and remove themselves when zero.
            if (null != plock)
                removeImageLoadingLock(plock);
            return new MipMapImage(NOT_FOUND, p.getWidth() / NOT_FOUND.getWidth(), p.getHeight() / NOT_FOUND.getHeight());
        }
    }
    synchronized (plock) {
        // Check if a previous call made it while waiting:
        mipMap = mawts.getClosestAbove(id, level);
        if (null != mipMap) {
            synchronized (db_lock) {
                removeImageLoadingLock(plock);
            }
            return mipMap;
        }
    }
    Image mawt = null;
    try {
        // Else, create the mawt:
        final Patch.PatchImage pai = p.createTransformedImage();
        synchronized (plock) {
            if (null != pai && null != pai.target) {
                mawt = pai.createImage(p.getMin(), p.getMax());
            }
        }
    } catch (final Exception e) {
        Utils.log2("Could not create an image for Patch " + p);
        mawt = null;
    }
    synchronized (db_lock) {
        try {
            if (null != mawt) {
                mawts.put(id, mawt, 0);
                Display.repaintSnapshot(p);
                // Utils.log2("Created mawt from scratch.");
                return new MipMapImage(mawt, 1.0, 1.0);
            }
        } catch (final Throwable t) {
            handleCacheError(t);
        } finally {
            removeImageLoadingLock(plock);
        }
    }
    return new MipMapImage(NOT_FOUND, p.getWidth() / NOT_FOUND.getWidth(), p.getHeight() / NOT_FOUND.getHeight());
}
Also used : MipMapImage(ini.trakem2.display.MipMapImage) Image(java.awt.Image) BufferedImage(java.awt.image.BufferedImage) MipMapImage(ini.trakem2.display.MipMapImage) Patch(ini.trakem2.display.Patch) IOException(java.io.IOException) FormatException(loci.formats.FormatException)

Example 4 with MipMapImage

use of ini.trakem2.display.MipMapImage in project TrakEM2 by trakem2.

the class FSLoader method fetchMipMapAWT.

/**
 * Will NOT free memory.
 */
private final MipMapImage fetchMipMapAWT(final Patch patch, final int level, final long n_bytes, final int retries) {
    if (null == dir_mipmaps) {
        Utils.log2("null dir_mipmaps");
        return null;
    }
    while (retries < MAX_RETRIES) {
        try {
            // TODO should wait if the file is currently being generated
            final MipMapImage mipMap = fetchMipMap(patch, level, n_bytes);
            if (null != mipMap)
                return mipMap;
            // if we got so far ... try to regenerate the mipmaps
            if (!mipmaps_regen) {
                return null;
            }
            // check that REALLY the file doesn't exist.
            if (cannot_regenerate.contains(patch)) {
                Utils.log("Cannot regenerate mipmaps for patch " + patch);
                return null;
            }
            // Utils.log2("getMipMapAwt: imp is " + imp + " for path " +  dir_mipmaps + level + "/" + new File(getAbsolutePath(patch)).getName() + "." + patch.getId() + mExt);
            // Regenerate in the case of not asking for an image under 32x32
            double scale = 1 / Math.pow(2, level);
            if (level >= 0 && patch.getWidth() * scale >= 32 && patch.getHeight() * scale >= 32 && isMipMapsRegenerationEnabled()) {
                // regenerate in a separate thread
                regenerateMipMaps(patch);
                return new MipMapImage(REGENERATING, patch.getWidth() / REGENERATING.getWidth(), patch.getHeight() / REGENERATING.getHeight());
            }
        } catch (OutOfMemoryError oome) {
            Utils.log2("fetchMipMapAWT: recovering from OutOfMemoryError");
            recoverOOME();
            Thread.yield();
            // Retry:
            return fetchMipMapAWT(patch, level, n_bytes, retries + 1);
        } catch (Throwable t) {
            IJError.print(t);
        }
    }
    return null;
}
Also used : MipMapImage(ini.trakem2.display.MipMapImage)

Example 5 with MipMapImage

use of ini.trakem2.display.MipMapImage in project TrakEM2 by trakem2.

the class FSLoader method fetchDataImage.

/**
 * Waits until a proper image of the desired size or larger can be returned, which is never the Loader.REGENERATING image.
 *  If no image can be loaded, returns Loader.NOT_FOUND.
 *  If the Patch is undergoing mipmap regeneration, it waits until done.
 */
@Override
public MipMapImage fetchDataImage(final Patch p, final double mag) {
    Future<Boolean> fu = null;
    MipMapImage mipMap = null;
    synchronized (gm_lock) {
        fu = regenerating_mipmaps.get(p);
    }
    if (null == fu) {
        // Patch is currently not under regeneration
        mipMap = fetchImage(p, mag);
        // and img will be now Loader.REGENERATING
        if (Loader.REGENERATING != mipMap.image) {
            return mipMap;
        } else {
            synchronized (gm_lock) {
                fu = regenerating_mipmaps.get(p);
            }
        }
    }
    if (null != fu) {
        try {
            if (!fu.get()) {
                Utils.log("Loader.fetchDataImage: could not regenerate mipmaps and get an image for patch " + p);
                return new MipMapImage(NOT_FOUND, p.getWidth() / NOT_FOUND.getWidth(), p.getHeight() / NOT_FOUND.getHeight());
            }
            // Now the image should be good:
            mipMap = fetchImage(p, mag);
            // Check in any case:
            if (Loader.isSignalImage(mipMap.image)) {
                // Attempt to create from scratch
                return new MipMapImage(p.createTransformedImage().createImage(p.getMin(), p.getMax()), 1, 1);
            } else {
                return mipMap;
            }
        } catch (Throwable e) {
            IJError.print(e);
        }
    }
    // else:
    Utils.log("Loader.fetchDataImage: could not get a data image for patch " + p);
    return new MipMapImage(NOT_FOUND, p.getWidth() / NOT_FOUND.getWidth(), p.getHeight() / NOT_FOUND.getHeight());
}
Also used : MipMapImage(ini.trakem2.display.MipMapImage)

Aggregations

MipMapImage (ini.trakem2.display.MipMapImage)6 BufferedImage (java.awt.image.BufferedImage)3 Patch (ini.trakem2.display.Patch)2 Image (java.awt.Image)2 ByteProcessor (ij.process.ByteProcessor)1 ColorProcessor (ij.process.ColorProcessor)1 Loader (ini.trakem2.persistence.Loader)1 Graphics2D (java.awt.Graphics2D)1 AffineTransform (java.awt.geom.AffineTransform)1 IOException (java.io.IOException)1 Callable (java.util.concurrent.Callable)1 FutureTask (java.util.concurrent.FutureTask)1 FormatException (loci.formats.FormatException)1 CoordinateTransformMesh (mpicbg.models.CoordinateTransformMesh)1 Pair (mpicbg.trakem2.util.Pair)1