Search in sources :

Example 1 with ImageWriter

use of qupath.lib.images.writers.ImageWriter 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)

Example 2 with ImageWriter

use of qupath.lib.images.writers.ImageWriter in project qupath by qupath.

the class Commands method saveSnapshot.

/**
 * Save an image snapshot, prompting the user to select the output file.
 * @param qupath the {@link QuPathGUI} instance to snapshot
 * @param type the snapshot type
 * @return true if a snapshot was saved, false otherwise
 */
public static boolean saveSnapshot(QuPathGUI qupath, GuiTools.SnapshotType type) {
    BufferedImage img = GuiTools.makeSnapshot(qupath, type);
    String ext = defaultScreenshotExtension.get();
    List<ImageWriter<BufferedImage>> compatibleWriters = ImageWriterTools.getCompatibleWriters(BufferedImage.class, ext);
    if (compatibleWriters.isEmpty()) {
        logger.error("No compatible image writers found for extension: " + ext);
        return false;
    }
    File fileOutput = Dialogs.promptToSaveFile(null, null, null, ext, ext);
    if (fileOutput == null)
        return false;
    // Loop through the writers and stop when we are successful
    for (var writer : compatibleWriters) {
        try {
            writer.writeImage(img, fileOutput.getAbsolutePath());
            return true;
        } catch (Exception e) {
            logger.error("Error saving snapshot " + type + " to " + fileOutput.getAbsolutePath(), e);
        }
    }
    return false;
}
Also used : ImageWriter(qupath.lib.images.writers.ImageWriter) File(java.io.File) BufferedImage(java.awt.image.BufferedImage) IOException(java.io.IOException)

Aggregations

BufferedImage (java.awt.image.BufferedImage)2 File (java.io.File)2 IOException (java.io.IOException)2 ImageWriter (qupath.lib.images.writers.ImageWriter)2 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 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