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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[builtins writer] using .png or .jpg extension when saving single-channel image layer results in a traceback #6670

Open
psobolewskiPhD opened this issue Feb 19, 2024 · 2 comments 路 May be fixed by #6884
Labels
bug Something isn't working

Comments

@psobolewskiPhD
Copy link
Member

psobolewskiPhD commented Feb 19, 2024

馃悰 Bug Report

First reported here: #3080 (comment)
If you have a simple image layer like:
np.zeros or np.ones -- anything single channel -- and use Save Selected Layers... and use .png or .jpg extension to save as png, you get a traceback:
OSError: cannot write mode F as PNG


Traceback (most recent call last):
  File "/Users/piotrsobolewski/Dev/miniforge3/envs/napari-dev/lib/python3.11/site-packages/PIL/PngImagePlugin.py", line 1279, in _save
    rawmode, mode = _OUTMODES[mode]
                    ~~~~~~~~~^^^^^^
KeyError: 'F'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/piotrsobolewski/Dev/miniforge3/envs/napari-dev/lib/python3.11/site-packages/app_model/backends/qt/_qaction.py", line 53, in _on_triggered
    self._app.commands.execute_command(self._command_id).result()
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/piotrsobolewski/Dev/miniforge3/envs/napari-dev/lib/python3.11/site-packages/app_model/registries/_commands_reg.py", line 197, in execute_command
    raise e
  File "/Users/piotrsobolewski/Dev/miniforge3/envs/napari-dev/lib/python3.11/site-packages/app_model/registries/_commands_reg.py", line 192, in execute_command
    future.set_result(cmd(*args, **kwargs))
                      ^^^^^^^^^^^^^^^^^^^^
  File "/Users/piotrsobolewski/Dev/miniforge3/envs/napari-dev/lib/python3.11/site-packages/in_n_out/_store.py", line 936, in _exec
    result = func(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/piotrsobolewski/Dev/miniforge3/envs/napari-dev/lib/python3.11/site-packages/in_n_out/_store.py", line 804, in _exec
    result = func(**bound.arguments)
             ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/piotrsobolewski/Dev/napari/napari/_qt/_qapp_model/qactions/_file.py", line 30, in _save_selected_layers
    qt_viewer._save_layers_dialog(selected=True)
  File "/Users/piotrsobolewski/Dev/napari/napari/_qt/qt_viewer.py", line 745, in _save_layers_dialog
    saved = self.viewer.layers.save(
            ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/piotrsobolewski/Dev/napari/napari/components/layerlist.py", line 491, in save
    return save_layers(path, layers, plugin=plugin, _writer=_writer)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/piotrsobolewski/Dev/napari/napari/plugins/io.py", line 243, in save_layers
    _written, writer_name = _write_single_layer_with_plugins(
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/piotrsobolewski/Dev/napari/napari/plugins/io.py", line 456, in _write_single_layer_with_plugins
    written_paths, writer_name = _npe2.write_layers(
                                 ^^^^^^^^^^^^^^^^^^^
  File "/Users/piotrsobolewski/Dev/napari/napari/plugins/_npe2.py", line 125, in write_layers
    res = writer.exec(args=args)
          ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/piotrsobolewski/Dev/miniforge3/envs/napari-dev/lib/python3.11/site-packages/npe2/manifest/utils.py", line 61, in exec
    return self.get_callable(reg)(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/piotrsobolewski/Dev/napari/napari_builtins/io/_write.py", line 124, in napari_write_image
    imsave(path, data)
  File "/Users/piotrsobolewski/Dev/napari/napari/utils/io.py", line 28, in imsave
    imsave_png(filename, data)
  File "/Users/piotrsobolewski/Dev/napari/napari/utils/io.py", line 58, in imsave_png
    iio.imwrite(
  File "/Users/piotrsobolewski/Dev/miniforge3/envs/napari-dev/lib/python3.11/site-packages/imageio/v3.py", line 139, in imwrite
    with imopen(
  File "/Users/piotrsobolewski/Dev/miniforge3/envs/napari-dev/lib/python3.11/site-packages/imageio/core/v3_plugin_api.py", line 367, in __exit__
    self.close()
  File "/Users/piotrsobolewski/Dev/miniforge3/envs/napari-dev/lib/python3.11/site-packages/imageio/plugins/pillow.py", line 144, in close
    self._flush_writer()
  File "/Users/piotrsobolewski/Dev/miniforge3/envs/napari-dev/lib/python3.11/site-packages/imageio/plugins/pillow.py", line 485, in _flush_writer
    primary_image.save(self._request.get_file(), **self.save_args)
  File "/Users/piotrsobolewski/Dev/miniforge3/envs/napari-dev/lib/python3.11/site-packages/PIL/Image.py", line 2439, in save
    save_handler(self, fp, filename)
  File "/Users/piotrsobolewski/Dev/miniforge3/envs/napari-dev/lib/python3.11/site-packages/PIL/PngImagePlugin.py", line 1282, in _save
    raise OSError(msg) from e
OSError: cannot write mode F as PNG

Worse yet, a file is created, but it's empty so it's misleading.

Seems related to the layer/file type, because RGB layers are fine.

Edit: OK, it's because these simple np layers are dtype('float64')

馃挕 Steps to Reproduce

Use:

import numpy as np
import napari

w = napari.Viewer()
w.add_image(np.ones((10,10)))

(or you can use zeros)
Then try Meta/Command-S (Save selected layers) and use .png as extension

馃挕 Expected Behavior

The data should be saved properly.

馃寧 Environment

napari: 0.5.0a2.dev543+gad78ee21a
Platform: macOS-13.3.1-arm64-arm-64bit
System: MacOS 13.3.1
Python: 3.11.7 | packaged by conda-forge | (main, Dec 23 2023, 14:38:07) [Clang 16.0.6 ]
Qt: 6.6.1
PyQt6:
NumPy: 1.26.3
SciPy: 1.12.0
Dask: 2024.1.1
VisPy: 0.14.1
magicgui: 0.8.1
superqt: 0.6.1
in-n-out: 0.1.9
app-model: 0.2.4
npe2: 0.7.4

OpenGL:

  • GL version: 2.1 Metal - 83.1
  • MAX_TEXTURE_SIZE: 16384
  • GL_MAX_3D_TEXTURE_SIZE: 2048

Screens:

  • screen 1: resolution 1680x1050, scale 2.0

Settings path:

  • /Users/piotrsobolewski/Library/Application Support/napari/napari-dev_a1eb8b76ba95fa16ad06e26097b46b8455dfbf0b/settings.yaml

馃挕 Additional Context

No response

@psobolewskiPhD psobolewskiPhD added the bug Something isn't working label Feb 19, 2024
@psobolewskiPhD
Copy link
Member Author

psobolewskiPhD commented Feb 19, 2024

I think converting from float could be tricky, so best solution is to warn the user?
Alas, for image layers convert type isn't implemented, so little recourse in the GUI.

@Czaki
Copy link
Collaborator

Czaki commented Feb 19, 2024

I think that we could use here code from #6537

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants