Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugins: Configure slice label name using pattern #2891

Merged
merged 20 commits into from Aug 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -70,6 +70,7 @@
import loci.common.Constants;
import loci.common.DateTools;
import loci.formats.FormatTools;
import loci.plugins.util.LociPrefs;
import loci.plugins.util.WindowTools;

/**
Expand All @@ -91,13 +92,16 @@ public class ConfigWindow extends JFrame
private DefaultListModel formatsListModel;
private JList formatsList;
private JPanel formatInfo;
private JTextField extensions;
private JTextField extensions, sliceLabel;
private JCheckBox enabledBox, windowlessBox, upgradeBox;

private DefaultListModel libsListModel;
private JList libsList;
private JTextField type, status, version, path, url, license;
private JTextArea notes;
private JButton installButton;
private JButton setSliceLabelButton;
private JButton resetSliceLabelButton;

private PrintWriter log;

Expand All @@ -115,10 +119,56 @@ public ConfigWindow() {
tabs.setBorder(new EmptyBorder(PAD, PAD, PAD, PAD));
setContentPane(tabs);

JPanel bfOptionsPanel = new JPanel(new SpringLayout());
tabs.addTab("General", bfOptionsPanel);

JPanel upgradePanel = new JPanel(new SpringLayout());
JLabel upgradeLabel =
new JLabel("Automatically check for new versions of the Bio-Formats plugins");
upgradePanel.add(upgradeLabel);

final boolean checkForUpgrades = Prefs.get(UPGRADE_CHECK_KEY, true);
upgradeBox = new JCheckBox("", checkForUpgrades);
upgradeBox.addItemListener(this);
upgradePanel.add(upgradeBox);

SpringUtilities.makeCompactGrid(upgradePanel,1, 2, PAD, PAD, PAD, PAD);

JPanel sliceNamePanel = new JPanel(new SpringLayout());
JLabel sliceNameLabel = new JLabel("Slice Label Pattern");
sliceNamePanel.add(sliceNameLabel);

final String sliceLabelPattern = LociPrefs.getSliceLabelPattern();
sliceLabel = new JTextField(sliceLabelPattern);
int prefHeight = sliceLabel.getPreferredSize().height;
sliceLabel.setMaximumSize(new Dimension(Integer.MAX_VALUE, prefHeight));
sliceNamePanel.add(sliceLabel);

setSliceLabelButton = new JButton("Set");
resetSliceLabelButton = new JButton("Reset");
setSliceLabelButton.addActionListener(this);
resetSliceLabelButton.addActionListener(this);
sliceNamePanel.add(setSliceLabelButton);
sliceNamePanel.add(resetSliceLabelButton);
SpringUtilities.makeCompactGrid(sliceNamePanel,1, 4, PAD, PAD, PAD, PAD);

bfOptionsPanel.add(upgradePanel);
bfOptionsPanel.add(sliceNamePanel);
JLabel sliceDescription = new JLabel("<html>Customize the slice label by specifying a pattern string:"
+ "<br>%s - series index"
+ "<br>%n - series name"
+ "<br>%c - channel index"
+ "<br>%w - channel name"
+ "<br>%z - Z index"
+ "<br>%t - T index"
+ "<br>%A - acquisition timestamp</html>");
bfOptionsPanel.add(sliceDescription);
SpringUtilities.makeCompactGrid(bfOptionsPanel,3, 1, PAD, PAD, PAD, PAD);

JPanel installPanel = new JPanel();
//tabs.addTab("Install", installPanel);

JButton installButton = new JButton(
installButton = new JButton(
"<html><center><br><font size=\"+1\">Check my system,<br>" +
"install missing libraries,<br>" +
"and upgrade old files</font><br>" +
Expand Down Expand Up @@ -192,22 +242,6 @@ public ConfigWindow() {

// TODO: "How to install" for each library?

JPanel upgradePanel = new JPanel();
tabs.addTab("Upgrade", upgradePanel);

upgradePanel.setLayout(new SpringLayout());

JLabel upgradeLabel =
new JLabel("Automatically check for new versions of the Bio-Formats plugins");
upgradePanel.add(upgradeLabel);

final boolean checkForUpgrades = Prefs.get(UPGRADE_CHECK_KEY, true);
upgradeBox = new JCheckBox("", checkForUpgrades);
upgradeBox.addItemListener(this);
upgradePanel.add(upgradeBox);

SpringUtilities.makeCompactGrid(upgradePanel, 1, 2, PAD, PAD, PAD, PAD);

JPanel logPanel = new JPanel();
tabs.addTab("Log", logPanel);

Expand All @@ -232,8 +266,20 @@ public ConfigWindow() {

@Override
public void actionPerformed(ActionEvent e) {
new LociInstaller().run(null);
dispose();
Object src = e.getSource();
if (src == installButton) {
new LociInstaller().run(null);
dispose();
}
else if (src == setSliceLabelButton) {
Prefs.set(LociPrefs.PREF_SLICE_LABEL_PATTERN, sliceLabel.getText());
return;
}
else if (src == resetSliceLabelButton) {
Prefs.set(LociPrefs.PREF_SLICE_LABEL_PATTERN, null);
sliceLabel.setText(LociPrefs.getSliceLabelPattern());
return;
}
}

// -- ItemListener API methods --
Expand Down
175 changes: 125 additions & 50 deletions components/bio-formats-plugins/src/loci/plugins/in/ImagePlusReader.java
Expand Up @@ -40,6 +40,7 @@
import java.util.List;
import java.util.Vector;

import loci.common.DateTools;
import loci.common.Location;
import loci.common.Region;
import loci.common.StatusEvent;
Expand All @@ -50,12 +51,20 @@
import loci.formats.FormatTools;
import loci.formats.IFormatReader;
import loci.formats.Modulo;
import loci.formats.meta.DummyMetadata;
import loci.formats.meta.IMetadata;
import loci.formats.meta.MetadataRetrieve;
import loci.formats.meta.MetadataStore;
import loci.plugins.Slicer;
import loci.plugins.util.BFVirtualStack;
import loci.plugins.util.ImageProcessorReader;
import loci.plugins.util.LociPrefs;
import loci.plugins.util.LuraWave;
import loci.plugins.util.VirtualImagePlus;
import ome.units.UNITS;
import ome.units.quantity.Time;
import ome.xml.model.enums.DimensionOrder;
import ome.xml.model.primitives.Timestamp;

/**
* A high-level reader for {@link ij.ImagePlus} objects.
Expand Down Expand Up @@ -330,8 +339,7 @@ private ImageStack createVirtualStack(ImportProcess process, int s,
final BFVirtualStack virtualStack = new BFVirtualStack(options.getId(),
reader, false, false, false);
for (int i=0; i<imageCount; i++) {
final String label = constructSliceLabel(i,
reader, meta, s, zCount, cCount, tCount);
String label = constructSliceLabel(i, reader, meta, s, zCount, cCount, tCount);
virtualStack.addSlice(label);
}

Expand Down Expand Up @@ -381,8 +389,7 @@ private ImageStack readPlanes(ImportProcess process, int s, List<LUT> luts,
throw new FormatException("Cannot read plane #" + i);
}
// generate a label for ith plane
final String label = constructSliceLabel(i,
reader, meta, s, zCount, cCount, tCount);
String label = constructSliceLabel(i, reader, meta, s, zCount, cCount, tCount);

for (ImageProcessor ip : p) {
procs.add(ip);
Expand Down Expand Up @@ -572,60 +579,128 @@ private String constructSliceLabel(int ndx, IFormatReader r,
IMetadata meta, int series, int zCount, int cCount, int tCount)
{
r.setSeries(series);
String sliceLabelPattern = LociPrefs.getSliceLabelPattern();

String order = r.getDimensionOrder();
int sizeC = r.getEffectiveSizeC();
int sizeT = r.getSizeT();
int sizeZ = r.getSizeZ();
int seriesCount = r.getImageCount();
int indexBase = LociPrefs.getSliceLabelBaseIndex();
int[] coordinates = FormatTools.getZCTCoords(order, sizeZ, sizeC, sizeT, sizeZ*sizeC*sizeT, ndx);

MetadataStore store = r.getMetadataStore();
MetadataRetrieve retrieve = store instanceof MetadataRetrieve ? (MetadataRetrieve) store : new DummyMetadata();
String filename = sliceLabelPattern.replaceAll(FormatTools.SERIES_NUM, String.format("%d", series));

String imageName = retrieve.getImageName(series);
if (imageName == null) imageName = "Series" + series;
filename = sliceLabelPattern;

filename = filename.replaceAll(FormatTools.SERIES_NUM, String.format("%d", series));
filename = filename.replaceAll(FormatTools.SERIES_NAME, imageName);
if (sizeC > 1) {
int[] subC;
String[] subCTypes;
Modulo moduloC = r.getModuloC();
if (moduloC.length() > 1) {
subC = new int[] {r.getSizeC() / moduloC.length(), moduloC.length()};
subCTypes = new String[] {moduloC.parentType, moduloC.type};
} else {
subC = new int[] {r.getSizeC()};
subCTypes = new String[] {FormatTools.CHANNEL};
}
int[] subCPos = FormatTools.rasterToPosition(subC, coordinates[1]);
StringBuffer channelString = new StringBuffer();
for (int i=0; i<subC.length; i++) {
boolean ch = subCTypes[i] == null || FormatTools.CHANNEL.equals(subCTypes[i]);
channelString.append(ch ? "c" : subCTypes[i]);
channelString.append(":");
channelString.append(subCPos[i] + 1);
channelString.append("/");
channelString.append(subC[i]);
if (i < subC.length - 1) channelString.append(", ");
}
filename = filename.replaceAll(FormatTools.CHANNEL_NUM, channelString.toString() + " ");

final int[] zct = r.getZCTCoords(ndx);
final StringBuffer sb = new StringBuffer();

int[] subC;
String[] subCTypes;
Modulo moduloC = r.getModuloC();
if (moduloC.length() > 1) {
subC = new int[] {r.getSizeC() / moduloC.length(), moduloC.length()};
subCTypes = new String[] {moduloC.parentType, moduloC.type};
} else {
subC = new int[] {r.getSizeC()};
subCTypes = new String[] {FormatTools.CHANNEL};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to keep a way to include the modulo information in the slice labels?

int channelCount = retrieve.getChannelCount(series);
if (coordinates[1] < channelCount) {
String channelName = retrieve.getChannelName(series, coordinates[1]);
if (channelName == null) channelName = String.valueOf(coordinates[1]);
filename = filename.replaceAll(FormatTools.CHANNEL_NAME, channelName);
}
else {
filename = filename.replaceAll(FormatTools.CHANNEL_NAME, String.valueOf(coordinates[1]));
}
}
else {
filename = filename.replaceAll(FormatTools.CHANNEL_NUM, "");
filename = filename.replaceAll(FormatTools.CHANNEL_NAME, "");
}
if (sizeZ > 1) {
filename = filename.replaceAll(FormatTools.Z_NUM, "z:" + String.format("%d", coordinates[0] + 1) + "/" + String.format("%d", sizeZ) + " ");
}
else {
filename = filename.replaceAll(FormatTools.Z_NUM, "");
}
if (sizeT > 1) {
filename = filename.replaceAll(FormatTools.T_NUM, "t:" + String.format("%d", coordinates[2] + 1) + "/" + String.format("%d", sizeT) + " ");
}
else {
filename = filename.replaceAll(FormatTools.T_NUM, "");
}

boolean first = true;
if (cCount > 1) {
if (first) first = false;
else sb.append("; ");
int[] subCPos = FormatTools.rasterToPosition(subC, zct[1]);
for (int i=0; i<subC.length; i++) {
boolean ch =
subCTypes[i] == null || FormatTools.CHANNEL.equals(subCTypes[i]);
sb.append(ch ? "c" : subCTypes[i]);
sb.append(":");
sb.append(subCPos[i] + 1);
sb.append("/");
sb.append(subC[i]);
if (i < subC.length - 1) sb.append(", ");
Timestamp timestamp = retrieve.getImageAcquisitionDate(series);
long stamp = 0;
String date = null;
if (timestamp != null) {
date = timestamp.getValue();
if (retrieve.getPlaneCount(series) > ndx) {
Time deltaT = retrieve.getPlaneDeltaT(series, ndx);
if (deltaT != null) {
stamp = (long) (deltaT.value(UNITS.SECOND).doubleValue() * 1000);
}
}
stamp += DateTools.getTime(date, DateTools.ISO8601_FORMAT);
}
if (zCount > 1) {
if (first) first = false;
else sb.append("; ");
sb.append("z:");
sb.append(zct[0] + 1);
sb.append("/");
sb.append(r.getSizeZ());
else {
stamp = System.currentTimeMillis();
}
if (tCount > 1) {
if (first) first = false;
else sb.append("; ");
sb.append("t:");
sb.append(zct[2] + 1);
sb.append("/");
sb.append(r.getSizeT());
date = DateTools.convertDate(stamp, (int) DateTools.UNIX_EPOCH);

filename = filename.replaceAll(FormatTools.TIMESTAMP, date);
return filename;
}

private static String[] substringsBetween(String str, String open, String close) {
if (str == null || open == null || close == null || open.length() == 0 || close.length() == 0) {
return null;
}
int strLen = str.length();
if (strLen == 0) {
return new String [0];
}
// put image name at the end, in case it is long
String imageName = meta.getImageName(series);
if (imageName != null && !imageName.trim().equals("")) {
sb.append(" - ");
sb.append(imageName);
int closeLen = close.length();
int openLen = open.length();
List<String> list = new ArrayList<String>();
int pos = 0;
while (pos < (strLen - closeLen)) {
int start = str.indexOf(open, pos);
if (start < 0) {
break;
}
start += openLen;
int end = str.indexOf(close, start);
if (end < 0) {
break;
}
list.add(str.substring(start, end));
pos = end + closeLen;
}
return sb.toString();
if (list.isEmpty()) {
return null;
}
return (String[]) list.toArray(new String [list.size()]);
}

private static void saveLUTs(ImagePlus imp, List<LUT> luts) {
Expand Down
Expand Up @@ -30,6 +30,7 @@
import ij.Prefs;

import loci.formats.ClassList;
import loci.formats.FormatTools;
import loci.formats.IFormatReader;
import loci.formats.ImageReader;
import loci.formats.in.CellSensReader;
Expand Down Expand Up @@ -68,6 +69,8 @@ public final class LociPrefs {
"bioformats.nativend2.chunkmap";
public static final String PREF_LEICA_LIF_PHYSICAL_SIZE =
"bioformats.leicalif.physicalsize.compatibility";
public static final String PREF_SLICE_LABEL_PATTERN = "bioformats.sliceLabelPattern";
public static final String PREF_SLICE_LABEL_BASE_INDEX = "bioformats.sliceLabelBaseIndex";
public static final String PREF_CELLSENS_FAIL =
"bioformats.cellsens.fail_on_missing_ets";

Expand Down Expand Up @@ -195,6 +198,14 @@ public static boolean isLeicaLIFPhysicalSizeBackwardsCompatible() {
LIFReader.OLD_PHYSICAL_SIZE_DEFAULT);
}

public static String getSliceLabelPattern() {
return Prefs.get(PREF_SLICE_LABEL_PATTERN, "%c%z%t- %n");
}

public static int getSliceLabelBaseIndex() {
return Prefs.getInt(PREF_SLICE_LABEL_BASE_INDEX, 1);
}

public static boolean isCellsensFailOnMissing() {
return Prefs.get(PREF_CELLSENS_FAIL, CellSensReader.FAIL_ON_MISSING_DEFAULT);
}
Expand Down