Skip to content

Image

Usage

Images and Icons are not the same!

Toga draws a distinction between an Image and an Icon. An Image can have an arbitrary size or aspect ratio, and is not platform dependent - the same image will be used on every platform. An Image is not an interactive element, because there is no visual cue to the user that the image can be interacted with.

An Icon, on the other hand, is small, square, and might vary between platforms. It is a visual element that is often used as part of an interactive element such as a button, a toolbar item, or a tab selector - but the Icon itself isn't an interactive element.

If you are looking for a widget that the user can click on, you're looking for a widget configured to use an Icon (probably Button), not an on_press handler on an Image or ImageView.

An image can be constructed from a wide range of sources:

from pathlib import Path
import toga

# Load an image in the same folder as the file that declares the App class
my_image = toga.Image("brutus.png")

# Load an image at an absolute path
my_image = toga.Image(Path.home() / "path/to/brutus.png")

# Create an image from raw data
with (Path.home() / "path/to/brutus.png").open("rb") as f:
    my_image = toga.Image(data=f.read())

# Create an image from a PIL image (if PIL is installed)
import PIL.Image
my_pil_image = PIL.Image.new("L", (30, 30))
my_toga_image = toga.Image(my_pil_image)

You can also tell Toga how to convert from (and to) other classes that represent images via image format plugins.

Notes

  • PNG and JPEG formats are guaranteed to be supported. Other formats are available on some platforms:
    • GTK: BMP
    • macOS: GIF, BMP, TIFF
    • Windows: GIF, BMP, TIFF

  • The native platform representations for images are:
    • Android: android.graphics.Bitmap
    • GTK: GdkPixbuf.Pixbuf
    • iOS: UIImage
    • macOS: NSImage
    • Windows: System.Drawing.Image

  • If you subclass toga.Image, you can supply that subclass as the requested format to any as_format() method in Toga, provided that your subclass has a constructor signature compatible with the base toga.Image class.

Reference

Source code in core/src/toga/images.py
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
class Image:
    def __init__(
        self,
        src: ImageContentT = NOT_PROVIDED,
        *,
        path: object = NOT_PROVIDED,  # DEPRECATED
        data: object = NOT_PROVIDED,  # DEPRECATED
    ):
        """Create a new image.

        :param src: The source from which to load the image. Can be any valid
            [`ImageContentT`][toga.images.ImageContentT] type.
        :param path: **DEPRECATED** - Use `src`.
        :param data: **DEPRECATED** - Use `src`.
        :raises FileNotFoundError: If a path is provided, but that path does not exist.
        :raises ValueError: If the source cannot be loaded as an image.
        """
        ######################################################################
        # 2023-11: Backwards compatibility for <= 0.4.0
        ######################################################################
        num_provided = sum(arg is not NOT_PROVIDED for arg in (src, path, data))
        if num_provided > 1:
            raise TypeError("Received multiple arguments to constructor.")
        if num_provided == 0:
            raise TypeError(
                "Image.__init__() missing 1 required positional argument: 'src'"
            )
        if path is not NOT_PROVIDED:
            src = path
            warn(
                "Path argument is deprecated, use src instead.",
                DeprecationWarning,
                stacklevel=2,
            )
        elif data is not NOT_PROVIDED:
            src = data
            warn(
                "Data argument is deprecated, use src instead.",
                DeprecationWarning,
                stacklevel=2,
            )
        ######################################################################
        # End backwards compatibility
        ######################################################################

        self.factory = get_factory()
        self._path = None

        # Any "lump of bytes" should be valid here.
        if isinstance(src, bytes | bytearray | memoryview):
            try:
                self._impl = self.factory.Image(interface=self, data=src)
            except ImageLoadError as exc:
                raise ValueError("Unable to load image from data") from exc

        elif isinstance(src, str | Path):
            self._path = toga.App.app.paths.app / src
            if not self._path.is_file():
                raise FileNotFoundError(f"Image file {self._path} does not exist")
            data = self._path.read_bytes()
            try:
                self._impl = self.factory.Image(interface=self, data=data)
            except ImageLoadError as exc:
                raise ValueError(f"Unable to load image from {self._path}") from exc

        elif isinstance(src, Image):
            self._impl = self.factory.Image(interface=self, data=src.data)

        elif isinstance(src, self.factory.Image.RAW_TYPE):
            self._impl = self.factory.Image(interface=self, raw=src)

        else:
            for converter in self._converters():
                if isinstance(src, converter.image_class):
                    data = converter.convert_from_format(src)
                    self._impl = self.factory.Image(interface=self, data=data)
                    return

            raise TypeError("Unsupported source type for Image")

    @classmethod
    @cache
    def _converters(cls) -> list[ImageConverter]:
        """Return list of registered image plugin converters. Only loaded once."""
        converters = []

        for image_plugin in entry_points(group="toga.image_formats"):
            module_name, class_name = image_plugin.value.rsplit(".", 1)
            module = importlib.import_module(module_name)
            converter = getattr(module, class_name)

            if converter.image_class is not None:
                converters.append(converter)

        return converters

    @property
    def size(self) -> tuple[int, int]:
        """The size of the image, as a (width, height) tuple."""
        return self._impl.get_width(), self._impl.get_height()

    @property
    def width(self) -> int:
        """The width of the image, in pixels."""
        return self._impl.get_width()

    @property
    def height(self) -> int:
        """The height of the image, in pixels."""
        return self._impl.get_height()

    @property
    def data(self) -> bytes:
        """The raw data for the image, in PNG format."""
        return self._impl.get_data()

    @property
    def path(self) -> Path | None:
        """The path from which the image was opened, if any (or None)."""
        return self._path

    def save(self, path: str | Path) -> None:
        """Save image to given path.

        The file format of the saved image will be determined by the extension of
        the filename provided (e.g `path/to/mypicture.png` will save a PNG file).

        :param path: Path to save the image to.
        """
        self._impl.save(path)

    def as_format(self, format: type[ImageT]) -> ImageT:
        """Return the image, converted to the image format specified.

        :param format: Format to provide. Defaults to [`Image`][toga.images.Image]; also
             supports [`PIL.Image.Image`][] if Pillow is installed, as well as any
             image types defined by installed
             [image format plugin][image-format-plugins].
        :returns: The image in the requested format
        :raises TypeError: If the format supplied is not recognized.
        """
        if isinstance(format, type):
            if issubclass(format, Image):
                return format(self.data)

            for converter in self._converters():
                if issubclass(format, converter.image_class):
                    return converter.convert_to_format(self.data, format)

        raise TypeError(f"Unknown conversion format for Image: {format}")

data property

The raw data for the image, in PNG format.

height property

The height of the image, in pixels.

path property

The path from which the image was opened, if any (or None).

size property

The size of the image, as a (width, height) tuple.

width property

The width of the image, in pixels.

__init__(src=NOT_PROVIDED, *, path=NOT_PROVIDED, data=NOT_PROVIDED)

Create a new image.

:param src: The source from which to load the image. Can be any valid ImageContentT type. :param path: DEPRECATED - Use src. :param data: DEPRECATED - Use src. :raises FileNotFoundError: If a path is provided, but that path does not exist. :raises ValueError: If the source cannot be loaded as an image.

Source code in core/src/toga/images.py
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
def __init__(
    self,
    src: ImageContentT = NOT_PROVIDED,
    *,
    path: object = NOT_PROVIDED,  # DEPRECATED
    data: object = NOT_PROVIDED,  # DEPRECATED
):
    """Create a new image.

    :param src: The source from which to load the image. Can be any valid
        [`ImageContentT`][toga.images.ImageContentT] type.
    :param path: **DEPRECATED** - Use `src`.
    :param data: **DEPRECATED** - Use `src`.
    :raises FileNotFoundError: If a path is provided, but that path does not exist.
    :raises ValueError: If the source cannot be loaded as an image.
    """
    ######################################################################
    # 2023-11: Backwards compatibility for <= 0.4.0
    ######################################################################
    num_provided = sum(arg is not NOT_PROVIDED for arg in (src, path, data))
    if num_provided > 1:
        raise TypeError("Received multiple arguments to constructor.")
    if num_provided == 0:
        raise TypeError(
            "Image.__init__() missing 1 required positional argument: 'src'"
        )
    if path is not NOT_PROVIDED:
        src = path
        warn(
            "Path argument is deprecated, use src instead.",
            DeprecationWarning,
            stacklevel=2,
        )
    elif data is not NOT_PROVIDED:
        src = data
        warn(
            "Data argument is deprecated, use src instead.",
            DeprecationWarning,
            stacklevel=2,
        )
    ######################################################################
    # End backwards compatibility
    ######################################################################

    self.factory = get_factory()
    self._path = None

    # Any "lump of bytes" should be valid here.
    if isinstance(src, bytes | bytearray | memoryview):
        try:
            self._impl = self.factory.Image(interface=self, data=src)
        except ImageLoadError as exc:
            raise ValueError("Unable to load image from data") from exc

    elif isinstance(src, str | Path):
        self._path = toga.App.app.paths.app / src
        if not self._path.is_file():
            raise FileNotFoundError(f"Image file {self._path} does not exist")
        data = self._path.read_bytes()
        try:
            self._impl = self.factory.Image(interface=self, data=data)
        except ImageLoadError as exc:
            raise ValueError(f"Unable to load image from {self._path}") from exc

    elif isinstance(src, Image):
        self._impl = self.factory.Image(interface=self, data=src.data)

    elif isinstance(src, self.factory.Image.RAW_TYPE):
        self._impl = self.factory.Image(interface=self, raw=src)

    else:
        for converter in self._converters():
            if isinstance(src, converter.image_class):
                data = converter.convert_from_format(src)
                self._impl = self.factory.Image(interface=self, data=data)
                return

        raise TypeError("Unsupported source type for Image")

as_format(format)

Return the image, converted to the image format specified.

:param format: Format to provide. Defaults to Image; also supports [PIL.Image.Image][] if Pillow is installed, as well as any image types defined by installed image format plugin. :returns: The image in the requested format :raises TypeError: If the format supplied is not recognized.

Source code in core/src/toga/images.py
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
def as_format(self, format: type[ImageT]) -> ImageT:
    """Return the image, converted to the image format specified.

    :param format: Format to provide. Defaults to [`Image`][toga.images.Image]; also
         supports [`PIL.Image.Image`][] if Pillow is installed, as well as any
         image types defined by installed
         [image format plugin][image-format-plugins].
    :returns: The image in the requested format
    :raises TypeError: If the format supplied is not recognized.
    """
    if isinstance(format, type):
        if issubclass(format, Image):
            return format(self.data)

        for converter in self._converters():
            if issubclass(format, converter.image_class):
                return converter.convert_to_format(self.data, format)

    raise TypeError(f"Unknown conversion format for Image: {format}")

save(path)

Save image to given path.

The file format of the saved image will be determined by the extension of the filename provided (e.g path/to/mypicture.png will save a PNG file).

:param path: Path to save the image to.

Source code in core/src/toga/images.py
237
238
239
240
241
242
243
244
245
def save(self, path: str | Path) -> None:
    """Save image to given path.

    The file format of the saved image will be determined by the extension of
    the filename provided (e.g `path/to/mypicture.png` will save a PNG file).

    :param path: Path to save the image to.
    """
    self._impl.save(path)

When specifying content for an toga.Image, you can provide:

If a relative path is provided, it will be anchored relative to the module that defines your Toga application class.

Toga is able to receive and return content in a wide range of image formats. ImageT describes any "image-like" object. This could be an instance of toga.Image, an image type from a third party library (such as [PIL.Image.Image][] from Pillow), or the platform's native type for representing images.

A type describing an image-like object provided by a third-party library, such as [PIL.Image.Image][] from Pillow.