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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added FITS reading, deprecate FitsStubImagePlugin #6056

Merged
merged 6 commits into from Feb 20, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Binary file modified Tests/images/hopper.fits
Binary file not shown.
32 changes: 7 additions & 25 deletions Tests/test_file_fitsstub.py → Tests/test_file_fits.py
Expand Up @@ -2,7 +2,9 @@

import pytest

from PIL import FitsStubImagePlugin, Image
from PIL import FitsImagePlugin, Image

from .helper import assert_image_equal, hopper

TEST_FILE = "Tests/images/hopper.fits"

Expand All @@ -16,30 +18,23 @@ def test_open():
assert im.size == (128, 128)
assert im.mode == "L"

assert_image_equal(im, hopper("L"))


def test_invalid_file():
# Arrange
invalid_file = "Tests/images/flower.jpg"

# Act / Assert
with pytest.raises(SyntaxError):
FitsStubImagePlugin.FITSStubImageFile(invalid_file)


def test_load():
# Arrange
with Image.open(TEST_FILE) as im:

# Act / Assert: stub cannot load without an implemented handler
with pytest.raises(OSError):
im.load()
FitsImagePlugin.FitsImageFile(invalid_file)


def test_truncated_fits():
# No END to headers
image_data = b"SIMPLE = T" + b" " * 50 + b"TRUNCATE"
with pytest.raises(OSError):
FitsStubImagePlugin.FITSStubImageFile(BytesIO(image_data))
FitsImagePlugin.FitsImageFile(BytesIO(image_data))


def test_naxis_zero():
Expand All @@ -48,16 +43,3 @@ def test_naxis_zero():
with pytest.raises(ValueError):
with Image.open("Tests/images/hopper_naxis_zero.fits"):
pass


def test_save():
# Arrange
with Image.open(TEST_FILE) as im:
dummy_fp = None
dummy_filename = "dummy.filename"

# Act / Assert: stub cannot save without an implemented handler
with pytest.raises(OSError):
im.save(dummy_filename)
with pytest.raises(OSError):
FitsStubImagePlugin._save(im, dummy_fp, dummy_filename)
15 changes: 5 additions & 10 deletions docs/handbook/image-file-formats.rst
Expand Up @@ -1064,6 +1064,11 @@ is commonly used in fax applications. The DCX decoder can read files containing
When the file is opened, only the first image is read. You can use
:py:meth:`~PIL.Image.Image.seek` or :py:mod:`~PIL.ImageSequence` to read other images.

FITS
^^^^

radarhere marked this conversation as resolved.
Show resolved Hide resolved
Pillow identifies and reads FITS files, commonly used for astronomy.

FLI, FLC
^^^^^^^^

Expand Down Expand Up @@ -1354,16 +1359,6 @@ Pillow provides a stub driver for BUFR files.
To add read or write support to your application, use
:py:func:`PIL.BufrStubImagePlugin.register_handler`.

FITS
^^^^

.. versionadded:: 1.1.5

Pillow provides a stub driver for FITS files.

To add read or write support to your application, use
:py:func:`PIL.FitsStubImagePlugin.register_handler`.

GRIB
^^^^

Expand Down
4 changes: 2 additions & 2 deletions docs/reference/plugins.rst
Expand Up @@ -41,10 +41,10 @@ Plugin reference
:undoc-members:
:show-inheritance:

:mod:`~PIL.FitsStubImagePlugin` Module
:mod:`~PIL.FitsImagePlugin` Module
--------------------------------------

.. automodule:: PIL.FitsStubImagePlugin
.. automodule:: PIL.FitsImagePlugin
:members:
:undoc-members:
:show-inheritance:
Expand Down
45 changes: 8 additions & 37 deletions src/PIL/FitsStubImagePlugin.py → src/PIL/FitsImagePlugin.py
Expand Up @@ -2,44 +2,28 @@
# The Python Imaging Library
# $Id$
#
# FITS stub adapter
# FITS file handling
#
# Copyright (c) 1998-2003 by Fredrik Lundh
#
# See the README file for information on usage and redistribution.
#

from . import Image, ImageFile

_handler = None


def register_handler(handler):
"""
Install application-specific FITS image handler.
import math

:param handler: Handler object.
"""
global _handler
_handler = handler


# --------------------------------------------------------------------
# Image adapter
from . import Image, ImageFile


def _accept(prefix):
return prefix[:6] == b"SIMPLE"


class FITSStubImageFile(ImageFile.StubImageFile):
class FitsImageFile(ImageFile.ImageFile):

format = "FITS"
format_description = "FITS"

def _open(self):
offset = self.fp.tell()

headers = {}
while True:
header = self.fp.read(80)
Expand Down Expand Up @@ -75,26 +59,13 @@ def _open(self):
self.mode = "F"
# rawmode = "F" if number_of_bits == -32 else "F;64F"

self.fp.seek(offset)

loader = self._load()
if loader:
loader.open(self)

def _load(self):
return _handler


def _save(im, fp, filename):
if _handler is None or not hasattr("_handler", "save"):
raise OSError("FITS save handler not installed")
_handler.save(im, fp, filename)
offset = math.ceil(self.fp.tell() / 2880) * 2880
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation mentioned that the offset for the image data was a multiple of 2880.

https://fits.gsfc.nasa.gov/fits_primer.html

Each header or data unit is a multiple of 2880 bytes long. If necessary, the header or data unit is padded out to the required length with ASCII blanks or NULLs depending on the type of unit.

The data unit, if present, immediately follows the last 2880-byte block in the header unit.

self.tile = [("raw", (0, 0) + self.size, offset, (self.mode, 0, -1))]


# --------------------------------------------------------------------
# Registry

Image.register_open(FITSStubImageFile.format, FITSStubImageFile, _accept)
Image.register_save(FITSStubImageFile.format, _save)
Image.register_open(FitsImageFile.format, FitsImageFile, _accept)

Image.register_extensions(FITSStubImageFile.format, [".fit", ".fits"])
Image.register_extensions(FitsImageFile.format, [".fit", ".fits"])
2 changes: 1 addition & 1 deletion src/PIL/__init__.py
Expand Up @@ -30,7 +30,7 @@
"DcxImagePlugin",
"DdsImagePlugin",
"EpsImagePlugin",
"FitsStubImagePlugin",
"FitsImagePlugin",
"FliImagePlugin",
"FpxImagePlugin",
"FtexImagePlugin",
Expand Down