def __setitem__(self, k: str, v: str) -> None:
     # noinspection PyProtectedMember
     if self._image._readonly:
         raise AttributeError("project in readonly mode")
     if not isinstance(k, str):
         raise TypeError(f"key must be of type `str` got `{type(k)}`")
     if not isinstance(v, str):
         raise TypeError(f"value must be of type `str` got `{type(v)}`")
     self._entry.putMetadataValue(String(str(k)), String(str(v)))
 def __getitem__(self, k: str) -> Any:
     if not isinstance(k, str):
         raise TypeError(f"key must be of type `str` got `{type(k)}`")
     if k not in self:
         raise KeyError(f"'{k}' not in metadata")
     v = self._image_data.getProperty(String(k))
     return v
 def __delitem__(self, k: str) -> None:
     # noinspection PyProtectedMember
     if self._image._readonly:
         raise AttributeError("project in readonly mode")
     if not isinstance(k, str):
         raise TypeError(f"key must be of type `str` got `{type(k)}`")
     self._image_data.removeProperty(String(k))
 def __getitem__(self, k: str) -> str:
     if not isinstance(k, str):
         raise TypeError(f"key must be of type `str` got `{type(k)}`")
     v = self._entry.getMetadataValue(String(str(k)))
     if v is None:
         raise KeyError(f"'{k}' not in metadata")
     return str(v)
Esempio n. 5
0
    def add_image(
            self,
            image_id:
        Any,  # this should actually be ID type of the image provider
            image_type: Optional[QuPathImageType] = None,
            *,
            allow_duplicates: bool = False) -> QuPathProjectImageEntry:
        """add an image to the project

        Parameters
        ----------
        image_id:
            image_id pointing to the image file (with default image_provider: filename)
        image_type:
            provide an image type for the image. If not provided the user will
            be prompted before opening the image in QuPath.
        allow_duplicates:
            check if file has already been added to the project.

        """
        # readonly?
        if self._readonly:
            raise OSError("project in readonly mode")
        # test if we may add:
        img_uri = self._image_provider.uri(image_id)
        if img_uri is None:
            raise FileNotFoundError(
                f"image_provider can't provide URI for requested image_id: '{image_id}'"
            )
        img_id = self._image_provider.id(img_uri)
        if not img_id == image_id:  # pragma: no cover
            _log.warning(
                f"image_provider roundtrip error: '{image_id}' -> uri -> '{img_id}'"
            )
            raise RuntimeError(
                "the image provider failed to roundtrip the image id correctly"
            )

        if not allow_duplicates:
            for entry in self.images:
                uri = self._image_provider.id(entry.uri)
                if img_id == uri:
                    raise FileExistsError(img_id)

        # first get a server builder
        try:
            support = ImageServerProvider.getPreferredUriImageSupport(
                BufferedImage, String(str(img_uri)))
        except IOException:  # pragma: no cover
            # it's possible that an image_provider returns an URI but that URI
            # is not actually reachable. In that case catch the java IOException
            # and raise a FileNotFoundError here
            raise FileNotFoundError(image_id)
        except ExceptionInInitializerError:
            raise OSError("no preferred support found")
        if not support:
            raise OSError("no preferred support found")  # pragma: no cover
        server_builders = list(support.getBuilders())
        if not server_builders:
            raise OSError(
                "no supported server builders found")  # pragma: no cover
        server_builder = server_builders[0]

        with self._stage_image_entry(server_builder) as j_entry:
            # all of this happens in qupath.lib.gui.commands.ProjectImportImagesCommand
            try:
                server = server_builder.build()
            except IOException:
                _, _, _sb = server_builder.__class__.__name__.rpartition(".")
                raise OSError(f"{_sb} can't open {str(image_id)}")
            j_entry.setImageName(ServerTools.getDisplayableImageName(server))

            # add some informative logging
            _md = server.getMetadata()
            width = int(_md.getWidth())
            height = int(_md.getHeight())
            downsamples = [
                float(x) for x in _md.getPreferredDownsamplesArray()
            ]
            target_downsample = math.sqrt(width / 1024.0 * height / 1024.0)
            _log.info(
                f"Image[{width}x{height}] with downsamples {downsamples}")
            if not any(d >= target_downsample for d in downsamples):
                _log.warning(
                    "No matching downsample for thumbnail! This might take a long time..."
                )

            # set the project thumbnail
            try:
                thumbnail = ProjectImportImagesCommand_getThumbnailRGB(
                    server, None)
            except NegativeArraySizeException:  # pragma: no cover
                raise RuntimeError(
                    "Thumbnailing FAILED. Image might be too large and has no embedded thumbnail."
                )
            else:
                j_entry.setThumbnail(thumbnail)

        py_entry = self._image_entries_proxy[-1]
        if image_type is not None:
            py_entry.image_type = image_type
        # save project after adding image
        py_entry.save()
        self.save(images=False)
        return py_entry
Esempio n. 6
0
 def description(self, value: str):
     if not isinstance(value, str):
         raise TypeError("requires a str")
     self.java_object.setDescription(String(value))
Esempio n. 7
0
 def name(self: PathROIObjectType, name: Union[str, None]) -> None:
     if name is not None:
         name = String(name)
     self.java_object.setName(name)
     if self._update_callback:
         self._update_callback(self)
Esempio n. 8
0
 def from_geojson(cls: Type[PathROIObjectType],
                  geojson) -> PathROIObjectType:
     """create a new Path Object from geojson"""
     gson = GsonTools.getInstance()
     java_obj = gson.fromJson(String(json.dumps(geojson)), cls.java_class)
     return cls(java_obj)
 def image_name(self, name: str) -> None:
     if self._readonly:
         raise AttributeError("project in readonly mode")
     self.java_object.setImageName(String(name))
 def __contains__(self, item: Any) -> bool:
     if not isinstance(item, str):
         return False
     return bool(self._image_data.getProperties().containsKey(String(item)))
 def __contains__(self, item):
     return bool(self._entry.containsMetadata(String(str(item))))
    def __init__(self,
                 name: str,
                 color: Optional[ColorType] = None,
                 parent: Optional['QuPathPathClass'] = None,
                 **_kwargs) -> None:
        """create a QuPathPathClass

        The QuPathPathClasses are wrappers around singletons defined by their
        name and their ancestors. Internally there's only one java PathClass
        instance per ancestor chain + name. (The internal unique id is chaining
        names via ':', which is why ':' is an unsupported name character)

        Parameters
        ----------
        name:
            the name of your path class
        color:
            a color (r,g,b) or (r,g,b,a) with 0 < x < 255 or a QuPathColor
            if color is None, a color calculated from the name is used
        parent:
            the parent of the class

        Returns
        -------
        path_class:
            the QuPathPathClass
        """
        # internal: check if a java path class was already provided
        _java_path_class = _kwargs.pop('_java_path_class', None)
        if _java_path_class is not None:
            self.java_object = _java_path_class
            return

        # called by user
        if name is None:
            if parent is None:
                # note:
                #   parent=None for name=None creates the root node on the qupath java side
                #   will have to consider if we expose this here.
                raise NotImplementedError(
                    "creating Root PathClass is currently not supported")
            else:
                raise ValueError(
                    "cannot create derived QuPathPathClass with name=None")
        elif isinstance(name, str):
            if ":" in name or "\n" in name:
                raise ValueError("PathClass names cannot contain ':' or '\n'")
            name = String(name)
        else:
            raise TypeError(f"name requires type 'str' got '{type(name)}'")

        # get the parent class if requested
        java_parent = None
        if parent is not None:
            if not isinstance(parent, QuPathPathClass):
                raise TypeError("parent must be a QuPathPathClass")
            java_parent = parent.java_object

        # set the color if requested
        java_color = None
        if color is not None:
            java_color = QuPathColor.from_any(
                color).to_java_rgba()  # use rgba?

        path_class = PathClassFactory.getDerivedPathClass(
            java_parent, name, java_color)
        self.java_object = path_class