Search in sources :

Example 6 with Thing

use of ini.trakem2.tree.Thing in project TrakEM2 by trakem2.

the class ProjectTree method mousePressed.

public void mousePressed(final MouseEvent me) {
    super.dispatcher.execSwing(new Runnable() {

        public void run() {
            if (!me.getSource().equals(ProjectTree.this) || !project.isInputEnabled()) {
                return;
            }
            final int x = me.getX();
            final int y = me.getY();
            // find the node and set it selected
            final TreePath path = getPathForLocation(x, y);
            if (null == path) {
                return;
            }
            ProjectTree.this.setSelectionPath(path);
            selected_node = (DefaultMutableTreeNode) path.getLastPathComponent();
            if (2 == me.getClickCount() && !me.isPopupTrigger() && MouseEvent.BUTTON1 == me.getButton()) {
                // show in the front Display
                if (null == selected_node)
                    return;
                Object obt = selected_node.getUserObject();
                if (!(obt instanceof ProjectThing))
                    return;
                ProjectThing thing = (ProjectThing) obt;
                thing.setVisible(true);
                Object obd = thing.getObject();
                if (obd instanceof Displayable) {
                    // additionaly, get the front Display (or make a new one if none) and show in it the layer in which the Displayable object is contained.
                    Displayable displ = (Displayable) obd;
                    Display.showCentered(displ.getLayer(), displ, true, me.isShiftDown());
                }
                return;
            } else if (me.isPopupTrigger() || (ij.IJ.isMacOSX() && me.isControlDown()) || MouseEvent.BUTTON2 == me.getButton() || 0 != (me.getModifiers() & Event.META_MASK)) {
                // the last block is from ij.gui.ImageCanvas, aparently to make the right-click work on windows?
                JPopupMenu popup = getPopupMenu(selected_node);
                if (null == popup)
                    return;
                popup.show(ProjectTree.this, x, y);
                return;
            }
        }
    });
}
Also used : Displayable(ini.trakem2.display.Displayable) ZDisplayable(ini.trakem2.display.ZDisplayable) TreePath(javax.swing.tree.TreePath) DefaultMutableTreeNode(javax.swing.tree.DefaultMutableTreeNode) DBObject(ini.trakem2.persistence.DBObject) JPopupMenu(javax.swing.JPopupMenu)

Example 7 with Thing

use of ini.trakem2.tree.Thing in project TrakEM2 by trakem2.

the class ProjectTree method remove.

/**
 * If the given node is null, it will be searched for.
 */
public boolean remove(final boolean check, final ProjectThing thing, final DefaultMutableTreeNode node) {
    final Object obd = thing.getObject();
    // shortcut to remove everything regardless.
    if (obd.getClass() == Project.class)
        return ((Project) obd).remove(check);
    final boolean b = thing.remove(check) && removeNode(null != node ? node : findNode(thing, this));
    Display.repaint();
    return b;
}
Also used : DBObject(ini.trakem2.persistence.DBObject)

Example 8 with Thing

use of ini.trakem2.tree.Thing in project TrakEM2 by trakem2.

the class FSLoader method generateMipMaps.

/**
 * Given an image and its source file name (without directory prepended), generate
 * a pyramid of images until reaching an image not smaller than 32x32 pixels.
 * <p>
 * Such images are stored as jpeg 85% quality in a folder named trakem2.mipmaps.
 * </p>
 * <p>
 * The Patch id and the right extension will be appended to the filename in all cases.
 * </p>
 * <p>
 * Any equally named files will be overwritten.
 * </p>
 */
protected boolean generateMipMaps(final Patch patch) {
    Utils.log2("mipmaps for " + patch);
    final String path = getAbsolutePath(patch);
    if (null == path) {
        Utils.log("generateMipMaps: null path for Patch " + patch);
        cannot_regenerate.add(patch);
        return false;
    }
    if (hs_unloadable.contains(patch)) {
        FilePathRepair.add(patch);
        return false;
    }
    synchronized (gm_lock) {
        try {
            if (null == dir_mipmaps)
                createMipMapsDir(null);
            if (null == dir_mipmaps || isURL(dir_mipmaps))
                return false;
        } catch (Exception e) {
            IJError.print(e);
        }
    }
    /**
     * Record Patch as modified
     */
    touched_mipmaps.add(patch);
    /**
     * Remove serialized features, if any
     */
    removeSerializedFeatures(patch);
    /**
     * Remove serialized pointmatches, if any
     */
    removeSerializedPointMatches(patch);
    /**
     * Alpha mask: setup to check if it was modified while regenerating.
     */
    final long alpha_mask_id = patch.getAlphaMaskId();
    final int resizing_mode = patch.getProject().getMipMapsMode();
    try {
        ImageProcessor ip;
        ByteProcessor alpha_mask = null;
        ByteProcessor outside_mask = null;
        int type = patch.getType();
        // Aggressive cache freeing
        releaseToFit(patch.getOWidth() * patch.getOHeight() * 4 + MIN_FREE_BYTES);
        // Obtain an image which may be coordinate-transformed, and an alpha mask.
        Patch.PatchImage pai = patch.createTransformedImage();
        if (null == pai || null == pai.target) {
            Utils.log("Can't regenerate mipmaps for patch " + patch);
            cannot_regenerate.add(patch);
            return false;
        }
        ip = pai.target;
        // can be null
        alpha_mask = pai.mask;
        // can be null
        outside_mask = pai.outside;
        pai = null;
        // Old style:
        // final String filename = new StringBuilder(new File(path).getName()).append('.').append(patch.getId()).append(mExt).toString();
        // New style:
        final String filename = createMipMapRelPath(patch, mExt);
        int w = ip.getWidth();
        int h = ip.getHeight();
        // sigma = sqrt(2^level - 0.5^2)
        // where 0.5 is the estimated sigma for a full-scale image
        // which means sigma = 0.75 for the full-scale image (has level 0)
        // prepare a 0.75 sigma image from the original
        double min = patch.getMin(), max = patch.getMax();
        // (The -1,-1 are flags really for "not set")
        if (-1 == min && -1 == max) {
            switch(type) {
                case ImagePlus.COLOR_RGB:
                case ImagePlus.COLOR_256:
                case ImagePlus.GRAY8:
                    patch.setMinAndMax(0, 255);
                    break;
                // Find and flow through to default:
                case ImagePlus.GRAY16:
                    ((ij.process.ShortProcessor) ip).findMinAndMax();
                    patch.setMinAndMax(ip.getMin(), ip.getMax());
                    break;
                case ImagePlus.GRAY32:
                    ((FloatProcessor) ip).findMinAndMax();
                    patch.setMinAndMax(ip.getMin(), ip.getMax());
                    break;
            }
            // may have changed
            min = patch.getMin();
            max = patch.getMax();
        }
        // Set for the level 0 image, which is a duplicate of the one in the cache in any case
        ip.setMinAndMax(min, max);
        // ImageJ no longer stretches the bytes for ByteProcessor with setMinAndmax
        if (ByteProcessor.class == ip.getClass()) {
            if (0 != min && 255 != max) {
                final byte[] b = (byte[]) ip.getPixels();
                final double scale = 255 / (max - min);
                for (int i = 0; i < b.length; ++i) {
                    final int val = b[i] & 0xff;
                    if (val < min)
                        b[i] = 0;
                    else
                        b[i] = (byte) Math.min(255, ((val - min) * scale));
                }
            }
        }
        // Proper support for LUT images: treat them as RGB
        if (ip.isColorLut() || type == ImagePlus.COLOR_256) {
            ip = ip.convertToRGB();
            type = ImagePlus.COLOR_RGB;
        }
        final int first_mipmap_level_saved = patch.getProject().getFirstMipMapLevelSaved();
        if (Loader.AREA_DOWNSAMPLING == resizing_mode) {
            long t0 = System.currentTimeMillis();
            final ImageBytes[] b = DownsamplerMipMaps.create(patch, type, ip, alpha_mask, outside_mask);
            long t1 = System.currentTimeMillis();
            for (int i = 0; i < b.length; ++i) {
                if (i < first_mipmap_level_saved) {
                    // Ignore level i
                    if (null != b[i])
                        CachingThread.storeForReuse(b[i].c);
                } else {
                    boolean written = mmio.save(getLevelDir(dir_mipmaps, i) + filename, b[i].c, b[i].width, b[i].height, 0.85f);
                    if (!written) {
                        Utils.log("Failed to save mipmap with area downsampling at level=" + i + " for patch " + patch);
                        cannot_regenerate.add(patch);
                        break;
                    }
                }
            }
            long t2 = System.currentTimeMillis();
            System.out.println("MipMaps with area downsampling: creation took " + (t1 - t0) + "ms, saving took " + (t2 - t1) + "ms, total: " + (t2 - t0) + "ms\n");
        } else if (Loader.GAUSSIAN == resizing_mode) {
            if (ImagePlus.COLOR_RGB == type) {
                // TODO releaseToFit proper
                releaseToFit(w * h * 4 * 10);
                final ColorProcessor cp = (ColorProcessor) ip;
                final FloatProcessorT2 red = new FloatProcessorT2(w, h, 0, 255);
                cp.toFloat(0, red);
                final FloatProcessorT2 green = new FloatProcessorT2(w, h, 0, 255);
                cp.toFloat(1, green);
                final FloatProcessorT2 blue = new FloatProcessorT2(w, h, 0, 255);
                cp.toFloat(2, blue);
                FloatProcessorT2 alpha;
                final FloatProcessorT2 outside;
                if (null != alpha_mask) {
                    alpha = new FloatProcessorT2(alpha_mask);
                } else {
                    alpha = null;
                }
                if (null != outside_mask) {
                    outside = new FloatProcessorT2(outside_mask);
                    if (null == alpha) {
                        alpha = outside;
                        alpha_mask = outside_mask;
                    }
                } else {
                    outside = null;
                }
                final String target_dir0 = getLevelDir(dir_mipmaps, 0);
                if (Thread.currentThread().isInterrupted())
                    return false;
                // Generate level 0 first:
                if (0 == first_mipmap_level_saved) {
                    boolean written;
                    if (null == alpha) {
                        written = mmio.save(cp, target_dir0 + filename, 0.85f, false);
                    } else {
                        written = mmio.save(target_dir0 + filename, P.asRGBABytes((int[]) cp.getPixels(), (byte[]) alpha_mask.getPixels(), null == outside ? null : (byte[]) outside_mask.getPixels()), w, h, 0.85f);
                    }
                    if (!written) {
                        Utils.log("Failed to save mipmap for COLOR_RGB, 'alpha = " + alpha + "', level = 0  for  patch " + patch);
                        cannot_regenerate.add(patch);
                    }
                }
                // Generate all other mipmap levels
                // TODO: for best performance, it should start from a direct Gaussian downscaling at the first level to write.
                // the scale level. Proper scale is: 1 / pow(2, k)
                int k = 0;
                do {
                    if (Thread.currentThread().isInterrupted())
                        return false;
                    // 1 - Prepare values for the next scaled image
                    k++;
                    // 2 - Check that the target folder for the desired scale exists
                    final String target_dir = getLevelDir(dir_mipmaps, k);
                    if (null == target_dir)
                        break;
                    // 3 - Blur the previous image to 0.75 sigma, and scale it
                    // will resize 'red' FloatProcessor in place.
                    final byte[] r = gaussianBlurResizeInHalf(red);
                    // idem
                    final byte[] g = gaussianBlurResizeInHalf(green);
                    // idem
                    final byte[] b = gaussianBlurResizeInHalf(blue);
                    // idem
                    final byte[] a = null == alpha ? null : gaussianBlurResizeInHalf(alpha);
                    if (null != outside) {
                        final byte[] o;
                        if (alpha != outside)
                            // idem
                            o = gaussianBlurResizeInHalf(outside);
                        else
                            o = a;
                        // If there was no alpha mask, alpha is the outside itself
                        for (int i = 0; i < o.length; i++) {
                            // TODO I am sure there is a bitwise operation to do this in one step. Some thing like: a[i] &= 127;
                            if ((o[i] & 0xff) != 255)
                                a[i] = 0;
                        }
                    }
                    w = red.getWidth();
                    h = red.getHeight();
                    // 4 - Compose ColorProcessor
                    if (first_mipmap_level_saved < k) {
                        // Skip saving this mipmap level
                        continue;
                    }
                    if (null == alpha) {
                        // 5 - Save as jpeg
                        if (!mmio.save(target_dir + filename, new byte[][] { r, g, b }, w, h, 0.85f)) {
                            Utils.log("Failed to save mipmap for COLOR_RGB, 'alpha = " + alpha + "', level = " + k + " for  patch " + patch);
                            cannot_regenerate.add(patch);
                            break;
                        }
                    } else {
                        if (!mmio.save(target_dir + filename, new byte[][] { r, g, b, a }, w, h, 0.85f)) {
                            Utils.log("Failed to save mipmap for COLOR_RGB, 'alpha = " + alpha + "', level = " + k + " for  patch " + patch);
                            cannot_regenerate.add(patch);
                            break;
                        }
                    }
                } while (// not smaller than 32x32
                w >= 32 && h >= 32);
            } else {
                long t0 = System.currentTimeMillis();
                // Greyscale:
                releaseToFit(w * h * 4 * 10);
                if (Thread.currentThread().isInterrupted())
                    return false;
                final FloatProcessorT2 fp = new FloatProcessorT2((FloatProcessor) ip.convertToFloat());
                if (ImagePlus.GRAY8 == type) {
                    // for 8-bit, the min,max has been applied when going to FloatProcessor
                    // just set it
                    fp.setMinMax(0, 255);
                } else {
                    fp.setMinAndMax(patch.getMin(), patch.getMax());
                }
                // fp.debugMinMax(patch.toString());
                FloatProcessorT2 alpha, outside;
                if (null != alpha_mask) {
                    alpha = new FloatProcessorT2(alpha_mask);
                } else {
                    alpha = null;
                }
                if (null != outside_mask) {
                    outside = new FloatProcessorT2(outside_mask);
                    if (null == alpha) {
                        alpha = outside;
                        alpha_mask = outside_mask;
                    }
                } else {
                    outside = null;
                }
                // the scale level. Proper scale is: 1 / pow(2, k)
                int k = 0;
                do {
                    if (Thread.currentThread().isInterrupted())
                        return false;
                    if (0 != k) {
                        // not doing so at the end because it would add one unnecessary blurring
                        gaussianBlurResizeInHalf(fp);
                        if (null != alpha) {
                            gaussianBlurResizeInHalf(alpha);
                            if (alpha != outside && outside != null) {
                                gaussianBlurResizeInHalf(outside);
                            }
                        }
                    }
                    w = fp.getWidth();
                    h = fp.getHeight();
                    // 1 - check that the target folder for the desired scale exists
                    final String target_dir = getLevelDir(dir_mipmaps, k);
                    if (null == target_dir)
                        break;
                    if (k < first_mipmap_level_saved) {
                        // Skip saving this mipmap level
                        k++;
                        continue;
                    }
                    if (null != alpha) {
                        // If there was no alpha mask, alpha is the outside itself
                        if (!mmio.save(target_dir + filename, new byte[][] { fp.getScaledBytePixels(), P.merge(alpha.getBytePixels(), null == outside ? null : outside.getBytePixels()) }, w, h, 0.85f)) {
                            Utils.log("Failed to save mipmap for GRAY8, 'alpha = " + alpha + "', level = " + k + " for  patch " + patch);
                            cannot_regenerate.add(patch);
                            break;
                        }
                    } else {
                        // 3 - save as 8-bit jpeg
                        if (!mmio.save(target_dir + filename, new byte[][] { fp.getScaledBytePixels() }, w, h, 0.85f)) {
                            Utils.log("Failed to save mipmap for GRAY8, 'alpha = " + alpha + "', level = " + k + " for  patch " + patch);
                            cannot_regenerate.add(patch);
                            break;
                        }
                    }
                    // 4 - prepare values for the next scaled image
                    k++;
                } while (// not smaller than 32x32
                fp.getWidth() >= 32 && fp.getHeight() >= 32);
                long t1 = System.currentTimeMillis();
                System.out.println("MipMaps took " + (t1 - t0));
            }
        } else {
            Utils.log("ERROR: unknown image resizing mode for mipmaps: " + resizing_mode);
        }
        return true;
    } catch (Throwable e) {
        Utils.log("*** ERROR: Can't generate mipmaps for patch " + patch);
        IJError.print(e);
        cannot_regenerate.add(patch);
        return false;
    } finally {
        // flush any cached tiles
        flushMipMaps(patch.getId());
        // flush any cached layer screenshots
        if (null != patch.getLayer()) {
            try {
                patch.getLayer().getParent().removeFromOffscreens(patch.getLayer());
            } catch (Exception e) {
                IJError.print(e);
            }
        }
        // gets executed even when returning from the catch statement or within the try/catch block
        synchronized (gm_lock) {
            regenerating_mipmaps.remove(patch);
        }
        // Has the alpha mask changed?
        if (patch.getAlphaMaskId() != alpha_mask_id) {
            Utils.log2("Alpha mask changed: resubmitting mipmap regeneration for " + patch);
            regenerateMipMaps(patch);
        }
    }
}
Also used : ByteProcessor(ij.process.ByteProcessor) FloatProcessor(ij.process.FloatProcessor) TimeoutException(java.util.concurrent.TimeoutException) ExecutionException(java.util.concurrent.ExecutionException) ImageProcessor(ij.process.ImageProcessor) ColorProcessor(ij.process.ColorProcessor) Patch(ini.trakem2.display.Patch) FloatProcessorT2(ini.trakem2.imaging.FloatProcessorT2)

Example 9 with Thing

use of ini.trakem2.tree.Thing in project TrakEM2 by trakem2.

the class ProjectTree method getPopupMenu.

/**
 * Get a custom, context-sensitive popup menu for the selected node.
 */
private JPopupMenu getPopupMenu(DefaultMutableTreeNode node) {
    Object ob = node.getUserObject();
    ProjectThing thing = null;
    if (ob instanceof ProjectThing) {
        thing = (ProjectThing) ob;
    } else {
        return null;
    }
    // context-sensitive popup
    JMenuItem[] items = thing.getPopupItems(this);
    if (0 == items.length)
        return null;
    JPopupMenu popup = new JPopupMenu();
    for (int i = 0; i < items.length; i++) {
        popup.add(items[i]);
    }
    JMenu node_menu = new JMenu("Node");
    JMenuItem item = new JMenuItem("Move up");
    item.addActionListener(this);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0, true));
    node_menu.add(item);
    item = new JMenuItem("Move down");
    item.addActionListener(this);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0, true));
    node_menu.add(item);
    item = new JMenuItem("Collapse nodes of children nodes");
    item.addActionListener(this);
    node_menu.add(item);
    popup.add(node_menu);
    JMenu send_menu = new JMenu("Send to");
    item = new JMenuItem("Sibling project");
    item.addActionListener(this);
    send_menu.add(item);
    popup.add(send_menu);
    return popup;
}
Also used : DBObject(ini.trakem2.persistence.DBObject) JMenuItem(javax.swing.JMenuItem) JPopupMenu(javax.swing.JPopupMenu) JMenu(javax.swing.JMenu)

Example 10 with Thing

use of ini.trakem2.tree.Thing in project TrakEM2 by trakem2.

the class ProjectTree method rename.

public void rename(final ProjectThing thing) {
    final Object ob = thing.getObject();
    final String old_title;
    if (null == ob)
        old_title = thing.getType();
    else if (ob instanceof DBObject)
        old_title = ((DBObject) ob).getTitle();
    else
        old_title = ob.toString();
    GenericDialog gd = ControlWindow.makeGenericDialog("New name");
    gd.addMessage("Old name: " + old_title);
    gd.addStringField("New name: ", old_title, 40);
    gd.showDialog();
    if (gd.wasCanceled())
        return;
    String title = gd.getNextString();
    if (null == title) {
        Utils.log("WARNING: avoided setting the title to null for " + thing);
        return;
    }
    // avoid XML problems - could also replace by double '', then replace again by " when reading.
    title = title.replace('"', '\'').trim();
    project.getRootLayerSet().addUndoStep(new RenameThingStep(thing));
    if (title.length() == 0) {
        // Set the title to the template type
        thing.setTitle(thing.getTemplate().getType());
        return;
    }
    thing.setTitle(title);
    this.updateUILater();
    project.getRootLayerSet().addUndoStep(new RenameThingStep(thing));
}
Also used : GenericDialog(ij.gui.GenericDialog) DBObject(ini.trakem2.persistence.DBObject) DBObject(ini.trakem2.persistence.DBObject)

Aggregations

DBObject (ini.trakem2.persistence.DBObject)16 ProjectThing (ini.trakem2.tree.ProjectThing)15 TemplateThing (ini.trakem2.tree.TemplateThing)9 DefaultMutableTreeNode (javax.swing.tree.DefaultMutableTreeNode)9 LayerThing (ini.trakem2.tree.LayerThing)8 TreePath (javax.swing.tree.TreePath)8 HashMap (java.util.HashMap)7 Displayable (ini.trakem2.display.Displayable)6 ZDisplayable (ini.trakem2.display.ZDisplayable)6 Thing (ini.trakem2.tree.Thing)6 GenericDialog (ij.gui.GenericDialog)5 Layer (ini.trakem2.display.Layer)5 LayerSet (ini.trakem2.display.LayerSet)5 ArrayList (java.util.ArrayList)5 HashSet (java.util.HashSet)5 ProjectTree (ini.trakem2.tree.ProjectTree)4 JPopupMenu (javax.swing.JPopupMenu)4 DefaultTreeModel (javax.swing.tree.DefaultTreeModel)4 Project (ini.trakem2.Project)3 Profile (ini.trakem2.display.Profile)3