Search in sources :

Example 1 with ObservableDoubleValue

use of javafx.beans.value.ObservableDoubleValue in project qupath by qupath.

the class Commands method promptToExportImageRegion.

/**
 * Prompt to export the current image region selected in the viewer.
 * @param viewer the viewer containing the image to export
 * @param renderedImage if true, export the rendered (RGB) image rather than original pixel values
 */
public static void promptToExportImageRegion(QuPathViewer viewer, boolean renderedImage) {
    if (viewer == null || viewer.getServer() == null) {
        Dialogs.showErrorMessage("Export image region", "No viewer & image selected!");
        return;
    }
    ImageServer<BufferedImage> server = viewer.getServer();
    if (renderedImage)
        server = RenderedImageServer.createRenderedServer(viewer);
    PathObject pathObject = viewer.getSelectedObject();
    ROI roi = pathObject == null ? null : pathObject.getROI();
    double regionWidth = roi == null ? server.getWidth() : roi.getBoundsWidth();
    double regionHeight = roi == null ? server.getHeight() : roi.getBoundsHeight();
    // Create a dialog
    GridPane pane = new GridPane();
    int row = 0;
    pane.add(new Label("Export format"), 0, row);
    ComboBox<ImageWriter<BufferedImage>> comboImageType = new ComboBox<>();
    Function<ImageWriter<BufferedImage>, String> fun = (ImageWriter<BufferedImage> writer) -> writer.getName();
    comboImageType.setCellFactory(p -> GuiTools.createCustomListCell(fun));
    comboImageType.setButtonCell(GuiTools.createCustomListCell(fun));
    var writers = ImageWriterTools.getCompatibleWriters(server, null);
    comboImageType.getItems().setAll(writers);
    comboImageType.setTooltip(new Tooltip("Choose export image format"));
    if (writers.contains(lastWriter))
        comboImageType.getSelectionModel().select(lastWriter);
    else
        comboImageType.getSelectionModel().selectFirst();
    comboImageType.setMaxWidth(Double.MAX_VALUE);
    GridPane.setHgrow(comboImageType, Priority.ALWAYS);
    pane.add(comboImageType, 1, row++);
    TextArea textArea = new TextArea();
    textArea.setPrefRowCount(2);
    textArea.setEditable(false);
    textArea.setWrapText(true);
    // textArea.setPadding(new Insets(15, 0, 0, 0));
    comboImageType.setOnAction(e -> textArea.setText(((ImageWriter<BufferedImage>) comboImageType.getValue()).getDetails()));
    textArea.setText(((ImageWriter<BufferedImage>) comboImageType.getValue()).getDetails());
    pane.add(textArea, 0, row++, 2, 1);
    var label = new Label("Downsample factor");
    pane.add(label, 0, row);
    TextField tfDownsample = new TextField();
    label.setLabelFor(tfDownsample);
    pane.add(tfDownsample, 1, row++);
    tfDownsample.setTooltip(new Tooltip("Amount to scale down image - choose 1 to export at full resolution (note: for large images this may not succeed for memory reasons)"));
    ObservableDoubleValue downsample = Bindings.createDoubleBinding(() -> {
        try {
            return Double.parseDouble(tfDownsample.getText());
        } catch (NumberFormatException e) {
            return Double.NaN;
        }
    }, tfDownsample.textProperty());
    // Define a sensible limit for non-pyramidal images
    long maxPixels = 10000 * 10000;
    Label labelSize = new Label();
    labelSize.setMinWidth(400);
    labelSize.setTextAlignment(TextAlignment.CENTER);
    labelSize.setContentDisplay(ContentDisplay.CENTER);
    labelSize.setAlignment(Pos.CENTER);
    labelSize.setMaxWidth(Double.MAX_VALUE);
    labelSize.setTooltip(new Tooltip("Estimated size of exported image"));
    pane.add(labelSize, 0, row++, 2, 1);
    labelSize.textProperty().bind(Bindings.createStringBinding(() -> {
        if (!Double.isFinite(downsample.get())) {
            labelSize.setStyle("-fx-text-fill: red;");
            return "Invalid downsample value!  Must be >= 1";
        } else {
            long w = (long) (regionWidth / downsample.get() + 0.5);
            long h = (long) (regionHeight / downsample.get() + 0.5);
            String warning = "";
            var writer = comboImageType.getSelectionModel().getSelectedItem();
            boolean supportsPyramid = writer == null ? false : writer.supportsPyramidal();
            if (!supportsPyramid && w * h > maxPixels) {
                labelSize.setStyle("-fx-text-fill: red;");
                warning = " (too big!)";
            } else if (w < 5 || h < 5) {
                labelSize.setStyle("-fx-text-fill: red;");
                warning = " (too small!)";
            } else
                labelSize.setStyle(null);
            return String.format("Output image size: %d x %d pixels%s", w, h, warning);
        }
    }, downsample, comboImageType.getSelectionModel().selectedIndexProperty()));
    tfDownsample.setText(Double.toString(exportDownsample.get()));
    PaneTools.setMaxWidth(Double.MAX_VALUE, labelSize, textArea, tfDownsample, comboImageType);
    PaneTools.setHGrowPriority(Priority.ALWAYS, labelSize, textArea, tfDownsample, comboImageType);
    pane.setVgap(5);
    pane.setHgap(5);
    if (!Dialogs.showConfirmDialog("Export image region", pane))
        return;
    var writer = comboImageType.getSelectionModel().getSelectedItem();
    boolean supportsPyramid = writer == null ? false : writer.supportsPyramidal();
    int w = (int) (regionWidth / downsample.get() + 0.5);
    int h = (int) (regionHeight / downsample.get() + 0.5);
    if (!supportsPyramid && w * h > maxPixels) {
        Dialogs.showErrorNotification("Export image region", "Requested export region too large - try selecting a smaller region, or applying a higher downsample factor");
        return;
    }
    if (downsample.get() < 1 || !Double.isFinite(downsample.get())) {
        Dialogs.showErrorMessage("Export image region", "Downsample factor must be >= 1!");
        return;
    }
    exportDownsample.set(downsample.get());
    // Now that we know the output, we can create a new server to ensure it is downsampled as the necessary resolution
    if (renderedImage && downsample.get() != server.getDownsampleForResolution(0))
        server = new RenderedImageServer.Builder(viewer).downsamples(downsample.get()).build();
    // selectedImageType.set(comboImageType.getSelectionModel().getSelectedItem());
    // Create RegionRequest
    RegionRequest request = null;
    if (pathObject != null && pathObject.hasROI())
        request = RegionRequest.createInstance(server.getPath(), exportDownsample.get(), roi);
    // Create a sensible default file name, and prompt for the actual name
    String ext = writer.getDefaultExtension();
    String writerName = writer.getName();
    String defaultName = GeneralTools.getNameWithoutExtension(new File(ServerTools.getDisplayableImageName(server)));
    if (roi != null) {
        defaultName = String.format("%s (%s, x=%d, y=%d, w=%d, h=%d)", defaultName, GeneralTools.formatNumber(request.getDownsample(), 2), request.getX(), request.getY(), request.getWidth(), request.getHeight());
    }
    File fileOutput = Dialogs.promptToSaveFile("Export image region", null, defaultName, writerName, ext);
    if (fileOutput == null)
        return;
    try {
        if (request == null) {
            if (exportDownsample.get() == 1.0)
                writer.writeImage(server, fileOutput.getAbsolutePath());
            else
                writer.writeImage(ImageServers.pyramidalize(server, exportDownsample.get()), fileOutput.getAbsolutePath());
        } else
            writer.writeImage(server, request, fileOutput.getAbsolutePath());
        lastWriter = writer;
    } catch (IOException e) {
        Dialogs.showErrorMessage("Export region", e);
    }
}
Also used : ObservableDoubleValue(javafx.beans.value.ObservableDoubleValue) TextArea(javafx.scene.control.TextArea) Label(javafx.scene.control.Label) ImageWriter(qupath.lib.images.writers.ImageWriter) BufferedImage(java.awt.image.BufferedImage) TextField(javafx.scene.control.TextField) GridPane(javafx.scene.layout.GridPane) ComboBox(javafx.scene.control.ComboBox) Tooltip(javafx.scene.control.Tooltip) IOException(java.io.IOException) RectangleROI(qupath.lib.roi.RectangleROI) ROI(qupath.lib.roi.interfaces.ROI) PolygonROI(qupath.lib.roi.PolygonROI) PathObject(qupath.lib.objects.PathObject) RegionRequest(qupath.lib.regions.RegionRequest) File(java.io.File)

Aggregations

BufferedImage (java.awt.image.BufferedImage)1 File (java.io.File)1 IOException (java.io.IOException)1 ObservableDoubleValue (javafx.beans.value.ObservableDoubleValue)1 ComboBox (javafx.scene.control.ComboBox)1 Label (javafx.scene.control.Label)1 TextArea (javafx.scene.control.TextArea)1 TextField (javafx.scene.control.TextField)1 Tooltip (javafx.scene.control.Tooltip)1 GridPane (javafx.scene.layout.GridPane)1 ImageWriter (qupath.lib.images.writers.ImageWriter)1 PathObject (qupath.lib.objects.PathObject)1 RegionRequest (qupath.lib.regions.RegionRequest)1 PolygonROI (qupath.lib.roi.PolygonROI)1 RectangleROI (qupath.lib.roi.RectangleROI)1 ROI (qupath.lib.roi.interfaces.ROI)1