updates
This commit is contained in:
@@ -32,14 +32,20 @@
|
||||
# Details about the Spider image format:
|
||||
# https://spider.wadsworth.org/spider_doc/spider/docs/image_doc.html
|
||||
#
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
from typing import IO, Any, cast
|
||||
|
||||
from . import Image, ImageFile
|
||||
from ._util import DeferredError
|
||||
|
||||
TYPE_CHECKING = False
|
||||
|
||||
|
||||
def isInt(f):
|
||||
def isInt(f: Any) -> int:
|
||||
try:
|
||||
i = int(f)
|
||||
if f - i == 0:
|
||||
@@ -59,7 +65,7 @@ iforms = [1, 3, -11, -12, -21, -22]
|
||||
# otherwise returns 0
|
||||
|
||||
|
||||
def isSpiderHeader(t):
|
||||
def isSpiderHeader(t: tuple[float, ...]) -> int:
|
||||
h = (99,) + t # add 1 value so can use spider header index start=1
|
||||
# header values 1,2,5,12,13,22,23 should be integers
|
||||
for i in [1, 2, 5, 12, 13, 22, 23]:
|
||||
@@ -79,7 +85,7 @@ def isSpiderHeader(t):
|
||||
return labbyt
|
||||
|
||||
|
||||
def isSpiderImage(filename):
|
||||
def isSpiderImage(filename: str) -> int:
|
||||
with open(filename, "rb") as fp:
|
||||
f = fp.read(92) # read 23 * 4 bytes
|
||||
t = struct.unpack(">23f", f) # try big-endian first
|
||||
@@ -95,7 +101,7 @@ class SpiderImageFile(ImageFile.ImageFile):
|
||||
format_description = "Spider 2D image"
|
||||
_close_exclusive_fp_after_loading = False
|
||||
|
||||
def _open(self):
|
||||
def _open(self) -> None:
|
||||
# check header
|
||||
n = 27 * 4 # read 27 float values
|
||||
f = self.fp.read(n)
|
||||
@@ -151,46 +157,53 @@ class SpiderImageFile(ImageFile.ImageFile):
|
||||
self.rawmode = "F;32F"
|
||||
self._mode = "F"
|
||||
|
||||
self.tile = [("raw", (0, 0) + self.size, offset, (self.rawmode, 0, 1))]
|
||||
self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, offset, self.rawmode)]
|
||||
self._fp = self.fp # FIXME: hack
|
||||
|
||||
@property
|
||||
def n_frames(self):
|
||||
def n_frames(self) -> int:
|
||||
return self._nimages
|
||||
|
||||
@property
|
||||
def is_animated(self):
|
||||
def is_animated(self) -> bool:
|
||||
return self._nimages > 1
|
||||
|
||||
# 1st image index is zero (although SPIDER imgnumber starts at 1)
|
||||
def tell(self):
|
||||
def tell(self) -> int:
|
||||
if self.imgnumber < 1:
|
||||
return 0
|
||||
else:
|
||||
return self.imgnumber - 1
|
||||
|
||||
def seek(self, frame):
|
||||
def seek(self, frame: int) -> None:
|
||||
if self.istack == 0:
|
||||
msg = "attempt to seek in a non-stack file"
|
||||
raise EOFError(msg)
|
||||
if not self._seek_check(frame):
|
||||
return
|
||||
if isinstance(self._fp, DeferredError):
|
||||
raise self._fp.ex
|
||||
self.stkoffset = self.hdrlen + frame * (self.hdrlen + self.imgbytes)
|
||||
self.fp = self._fp
|
||||
self.fp.seek(self.stkoffset)
|
||||
self._open()
|
||||
|
||||
# returns a byte image after rescaling to 0..255
|
||||
def convert2byte(self, depth=255):
|
||||
(minimum, maximum) = self.getextrema()
|
||||
m = 1
|
||||
def convert2byte(self, depth: int = 255) -> Image.Image:
|
||||
extrema = self.getextrema()
|
||||
assert isinstance(extrema[0], float)
|
||||
minimum, maximum = cast(tuple[float, float], extrema)
|
||||
m: float = 1
|
||||
if maximum != minimum:
|
||||
m = depth / (maximum - minimum)
|
||||
b = -m * minimum
|
||||
return self.point(lambda i, m=m, b=b: i * m + b).convert("L")
|
||||
return self.point(lambda i: i * m + b).convert("L")
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from . import ImageTk
|
||||
|
||||
# returns a ImageTk.PhotoImage object, after rescaling to 0..255
|
||||
def tkPhotoImage(self):
|
||||
def tkPhotoImage(self) -> ImageTk.PhotoImage:
|
||||
from . import ImageTk
|
||||
|
||||
return ImageTk.PhotoImage(self.convert2byte(), palette=256)
|
||||
@@ -201,33 +214,34 @@ class SpiderImageFile(ImageFile.ImageFile):
|
||||
|
||||
|
||||
# given a list of filenames, return a list of images
|
||||
def loadImageSeries(filelist=None):
|
||||
def loadImageSeries(filelist: list[str] | None = None) -> list[Image.Image] | None:
|
||||
"""create a list of :py:class:`~PIL.Image.Image` objects for use in a montage"""
|
||||
if filelist is None or len(filelist) < 1:
|
||||
return
|
||||
return None
|
||||
|
||||
imglist = []
|
||||
byte_imgs = []
|
||||
for img in filelist:
|
||||
if not os.path.exists(img):
|
||||
print(f"unable to find {img}")
|
||||
continue
|
||||
try:
|
||||
with Image.open(img) as im:
|
||||
im = im.convert2byte()
|
||||
assert isinstance(im, SpiderImageFile)
|
||||
byte_im = im.convert2byte()
|
||||
except Exception:
|
||||
if not isSpiderImage(img):
|
||||
print(img + " is not a Spider image file")
|
||||
print(f"{img} is not a Spider image file")
|
||||
continue
|
||||
im.info["filename"] = img
|
||||
imglist.append(im)
|
||||
return imglist
|
||||
byte_im.info["filename"] = img
|
||||
byte_imgs.append(byte_im)
|
||||
return byte_imgs
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# For saving images in Spider format
|
||||
|
||||
|
||||
def makeSpiderHeader(im):
|
||||
def makeSpiderHeader(im: Image.Image) -> list[bytes]:
|
||||
nsam, nrow = im.size
|
||||
lenbyt = nsam * 4 # There are labrec records in the header
|
||||
labrec = int(1024 / lenbyt)
|
||||
@@ -238,9 +252,7 @@ def makeSpiderHeader(im):
|
||||
if nvalues < 23:
|
||||
return []
|
||||
|
||||
hdr = []
|
||||
for i in range(nvalues):
|
||||
hdr.append(0.0)
|
||||
hdr = [0.0] * nvalues
|
||||
|
||||
# NB these are Fortran indices
|
||||
hdr[1] = 1.0 # nslice (=1 for an image)
|
||||
@@ -259,8 +271,8 @@ def makeSpiderHeader(im):
|
||||
return [struct.pack("f", v) for v in hdr]
|
||||
|
||||
|
||||
def _save(im, fp, filename):
|
||||
if im.mode[0] != "F":
|
||||
def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
||||
if im.mode != "F":
|
||||
im = im.convert("F")
|
||||
|
||||
hdr = makeSpiderHeader(im)
|
||||
@@ -272,12 +284,13 @@ def _save(im, fp, filename):
|
||||
fp.writelines(hdr)
|
||||
|
||||
rawmode = "F;32NF" # 32-bit native floating point
|
||||
ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))])
|
||||
ImageFile._save(im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, rawmode)])
|
||||
|
||||
|
||||
def _save_spider(im, fp, filename):
|
||||
def _save_spider(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
||||
# get the filename extension and register it with Image
|
||||
ext = os.path.splitext(filename)[1]
|
||||
filename_ext = os.path.splitext(filename)[1]
|
||||
ext = filename_ext.decode() if isinstance(filename_ext, bytes) else filename_ext
|
||||
Image.register_extension(SpiderImageFile.format, ext)
|
||||
_save(im, fp, filename)
|
||||
|
||||
@@ -299,10 +312,10 @@ if __name__ == "__main__":
|
||||
sys.exit()
|
||||
|
||||
with Image.open(filename) as im:
|
||||
print("image: " + str(im))
|
||||
print("format: " + str(im.format))
|
||||
print("size: " + str(im.size))
|
||||
print("mode: " + str(im.mode))
|
||||
print(f"image: {im}")
|
||||
print(f"format: {im.format}")
|
||||
print(f"size: {im.size}")
|
||||
print(f"mode: {im.mode}")
|
||||
print("max, min: ", end=" ")
|
||||
print(im.getextrema())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user