mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 09:57:43 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			297 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			297 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#
 | 
						|
# The Python Imaging Library.
 | 
						|
#
 | 
						|
# SPIDER image file handling
 | 
						|
#
 | 
						|
# History:
 | 
						|
# 2004-08-02    Created BB
 | 
						|
# 2006-03-02    added save method
 | 
						|
# 2006-03-13    added support for stack images
 | 
						|
#
 | 
						|
# Copyright (c) 2004 by Health Research Inc. (HRI) RENSSELAER, NY 12144.
 | 
						|
# Copyright (c) 2004 by William Baxter.
 | 
						|
# Copyright (c) 2004 by Secret Labs AB.
 | 
						|
# Copyright (c) 2004 by Fredrik Lundh.
 | 
						|
#
 | 
						|
 | 
						|
##
 | 
						|
# Image plugin for the Spider image format.  This format is is used
 | 
						|
# by the SPIDER software, in processing image data from electron
 | 
						|
# microscopy and tomography.
 | 
						|
##
 | 
						|
 | 
						|
#
 | 
						|
# SpiderImagePlugin.py
 | 
						|
#
 | 
						|
# The Spider image format is used by SPIDER software, in processing
 | 
						|
# image data from electron microscopy and tomography.
 | 
						|
#
 | 
						|
# Spider home page:
 | 
						|
# http://www.wadsworth.org/spider_doc/spider/docs/spider.html
 | 
						|
#
 | 
						|
# Details about the Spider image format:
 | 
						|
# http://www.wadsworth.org/spider_doc/spider/docs/image_doc.html
 | 
						|
#
 | 
						|
 | 
						|
from __future__ import print_function
 | 
						|
 | 
						|
from PIL import Image, ImageFile
 | 
						|
import os, struct, sys
 | 
						|
 | 
						|
def isInt(f):
 | 
						|
    try:
 | 
						|
        i = int(f)
 | 
						|
        if f-i == 0: return 1
 | 
						|
        else:        return 0
 | 
						|
    except:
 | 
						|
        return 0
 | 
						|
 | 
						|
iforms = [1,3,-11,-12,-21,-22]
 | 
						|
 | 
						|
# There is no magic number to identify Spider files, so just check a
 | 
						|
# series of header locations to see if they have reasonable values.
 | 
						|
# Returns no.of bytes in the header, if it is a valid Spider header,
 | 
						|
# otherwise returns 0
 | 
						|
 | 
						|
def isSpiderHeader(t):
 | 
						|
    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]:
 | 
						|
        if not isInt(h[i]): return 0
 | 
						|
    # check iform
 | 
						|
    iform = int(h[5])
 | 
						|
    if not iform in iforms: return 0
 | 
						|
    # check other header values
 | 
						|
    labrec = int(h[13])   # no. records in file header
 | 
						|
    labbyt = int(h[22])   # total no. of bytes in header
 | 
						|
    lenbyt = int(h[23])   # record length in bytes
 | 
						|
    #print "labrec = %d, labbyt = %d, lenbyt = %d" % (labrec,labbyt,lenbyt)
 | 
						|
    if labbyt != (labrec * lenbyt): return 0
 | 
						|
    # looks like a valid header
 | 
						|
    return labbyt
 | 
						|
 | 
						|
def isSpiderImage(filename):
 | 
						|
    fp = open(filename,'rb')
 | 
						|
    f = fp.read(92)   # read 23 * 4 bytes
 | 
						|
    fp.close()
 | 
						|
    bigendian = 1
 | 
						|
    t = struct.unpack('>23f',f)    # try big-endian first
 | 
						|
    hdrlen = isSpiderHeader(t)
 | 
						|
    if hdrlen == 0:
 | 
						|
        bigendian = 0
 | 
						|
        t = struct.unpack('<23f',f)  # little-endian
 | 
						|
        hdrlen = isSpiderHeader(t)
 | 
						|
    return hdrlen
 | 
						|
 | 
						|
 | 
						|
class SpiderImageFile(ImageFile.ImageFile):
 | 
						|
 | 
						|
    format = "SPIDER"
 | 
						|
    format_description = "Spider 2D image"
 | 
						|
 | 
						|
    def _open(self):
 | 
						|
        # check header
 | 
						|
        n = 27 * 4  # read 27 float values
 | 
						|
        f = self.fp.read(n)
 | 
						|
 | 
						|
        try:
 | 
						|
            self.bigendian = 1
 | 
						|
            t = struct.unpack('>27f',f)    # try big-endian first
 | 
						|
            hdrlen = isSpiderHeader(t)
 | 
						|
            if hdrlen == 0:
 | 
						|
                self.bigendian = 0
 | 
						|
                t = struct.unpack('<27f',f)  # little-endian
 | 
						|
                hdrlen = isSpiderHeader(t)
 | 
						|
            if hdrlen == 0:
 | 
						|
                raise SyntaxError("not a valid Spider file")
 | 
						|
        except struct.error:
 | 
						|
            raise SyntaxError("not a valid Spider file")
 | 
						|
 | 
						|
        h = (99,) + t   # add 1 value : spider header index starts at 1
 | 
						|
        iform = int(h[5])
 | 
						|
        if iform != 1:
 | 
						|
            raise SyntaxError("not a Spider 2D image")
 | 
						|
 | 
						|
        self.size = int(h[12]), int(h[2]) # size in pixels (width, height)
 | 
						|
        self.istack = int(h[24])
 | 
						|
        self.imgnumber = int(h[27])
 | 
						|
 | 
						|
        if self.istack == 0 and self.imgnumber == 0:
 | 
						|
            # stk=0, img=0: a regular 2D image
 | 
						|
            offset = hdrlen
 | 
						|
            self.nimages = 1
 | 
						|
        elif self.istack > 0 and self.imgnumber == 0:
 | 
						|
            # stk>0, img=0: Opening the stack for the first time
 | 
						|
            self.imgbytes = int(h[12]) * int(h[2]) * 4
 | 
						|
            self.hdrlen = hdrlen
 | 
						|
            self.nimages = int(h[26])
 | 
						|
            # Point to the first image in the stack
 | 
						|
            offset = hdrlen * 2
 | 
						|
            self.imgnumber = 1
 | 
						|
        elif self.istack == 0 and self.imgnumber > 0:
 | 
						|
            # stk=0, img>0: an image within the stack
 | 
						|
            offset = hdrlen + self.stkoffset
 | 
						|
            self.istack = 2  # So Image knows it's still a stack
 | 
						|
        else:
 | 
						|
            raise SyntaxError("inconsistent stack header values")
 | 
						|
 | 
						|
        if self.bigendian:
 | 
						|
            self.rawmode = "F;32BF"
 | 
						|
        else:
 | 
						|
            self.rawmode = "F;32F"
 | 
						|
        self.mode = "F"
 | 
						|
 | 
						|
        self.tile = [("raw", (0, 0) + self.size, offset,
 | 
						|
                    (self.rawmode, 0, 1))]
 | 
						|
        self.__fp = self.fp # FIXME: hack
 | 
						|
 | 
						|
    # 1st image index is zero (although SPIDER imgnumber starts at 1)
 | 
						|
    def tell(self):
 | 
						|
        if self.imgnumber < 1:
 | 
						|
            return 0
 | 
						|
        else:
 | 
						|
            return self.imgnumber - 1
 | 
						|
 | 
						|
    def seek(self, frame):
 | 
						|
        if self.istack == 0:
 | 
						|
            return
 | 
						|
        if frame >= self.nimages:
 | 
						|
            raise EOFError("attempt to seek past end of file")
 | 
						|
        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):
 | 
						|
        (min, max) = self.getextrema()
 | 
						|
        m = 1
 | 
						|
        if max != min:
 | 
						|
            m = depth / (max-min)
 | 
						|
        b = -m * min
 | 
						|
        return self.point(lambda i, m=m, b=b: i * m + b).convert("L")
 | 
						|
 | 
						|
    # returns a ImageTk.PhotoImage object, after rescaling to 0..255
 | 
						|
    def tkPhotoImage(self):
 | 
						|
        from PIL import ImageTk
 | 
						|
        return ImageTk.PhotoImage(self.convert2byte(), palette=256)
 | 
						|
 | 
						|
# --------------------------------------------------------------------
 | 
						|
# Image series
 | 
						|
 | 
						|
# given a list of filenames, return a list of images
 | 
						|
def loadImageSeries(filelist=None):
 | 
						|
    " create a list of Image.images for use in montage "
 | 
						|
    if filelist == None or len(filelist) < 1:
 | 
						|
        return
 | 
						|
 | 
						|
    imglist = []
 | 
						|
    for img in filelist:
 | 
						|
        if not os.path.exists(img):
 | 
						|
            print("unable to find %s" % img)
 | 
						|
            continue
 | 
						|
        try:
 | 
						|
            im = Image.open(img).convert2byte()
 | 
						|
        except:
 | 
						|
            if not isSpiderImage(img):
 | 
						|
                print(img + " is not a Spider image file")
 | 
						|
            continue
 | 
						|
        im.info['filename'] = img
 | 
						|
        imglist.append(im)
 | 
						|
    return imglist
 | 
						|
 | 
						|
# --------------------------------------------------------------------
 | 
						|
# For saving images in Spider format
 | 
						|
 | 
						|
def makeSpiderHeader(im):
 | 
						|
    nsam,nrow = im.size
 | 
						|
    lenbyt = nsam * 4  # There are labrec records in the header
 | 
						|
    labrec = 1024 / lenbyt
 | 
						|
    if 1024%lenbyt != 0: labrec += 1
 | 
						|
    labbyt = labrec * lenbyt
 | 
						|
    hdr = []
 | 
						|
    nvalues = labbyt / 4
 | 
						|
    for i in range(nvalues):
 | 
						|
        hdr.append(0.0)
 | 
						|
 | 
						|
    if len(hdr) < 23:
 | 
						|
        return []
 | 
						|
 | 
						|
    # NB these are Fortran indices
 | 
						|
    hdr[1]  = 1.0           # nslice (=1 for an image)
 | 
						|
    hdr[2]  = float(nrow)   # number of rows per slice
 | 
						|
    hdr[5]  = 1.0           # iform for 2D image
 | 
						|
    hdr[12] = float(nsam)   # number of pixels per line
 | 
						|
    hdr[13] = float(labrec) # number of records in file header
 | 
						|
    hdr[22] = float(labbyt) # total number of bytes in header
 | 
						|
    hdr[23] = float(lenbyt) # record length in bytes
 | 
						|
 | 
						|
    # adjust for Fortran indexing
 | 
						|
    hdr = hdr[1:]
 | 
						|
    hdr.append(0.0)
 | 
						|
    # pack binary data into a string
 | 
						|
    hdrstr = []
 | 
						|
    for v in hdr:
 | 
						|
        hdrstr.append(struct.pack('f',v))
 | 
						|
    return hdrstr
 | 
						|
 | 
						|
def _save(im, fp, filename):
 | 
						|
    if im.mode[0] != "F":
 | 
						|
        im = im.convert('F')
 | 
						|
 | 
						|
    hdr = makeSpiderHeader(im)
 | 
						|
    if len(hdr) < 256:
 | 
						|
        raise IOError("Error creating Spider header")
 | 
						|
 | 
						|
    # write the SPIDER header
 | 
						|
    try:
 | 
						|
        fp = open(filename, 'wb')
 | 
						|
    except:
 | 
						|
        raise IOError("Unable to open %s for writing" % 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))])
 | 
						|
 | 
						|
    fp.close()
 | 
						|
 | 
						|
def _save_spider(im, fp, filename):
 | 
						|
    # get the filename extension and register it with Image
 | 
						|
    fn, ext = os.path.splitext(filename)
 | 
						|
    Image.register_extension("SPIDER", ext)
 | 
						|
    _save(im, fp, filename)
 | 
						|
 | 
						|
# --------------------------------------------------------------------
 | 
						|
 | 
						|
Image.register_open("SPIDER", SpiderImageFile)
 | 
						|
Image.register_save("SPIDER", _save_spider)
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
 | 
						|
    if not sys.argv[1:]:
 | 
						|
        print("Syntax: python SpiderImagePlugin.py Spiderimage [outfile]")
 | 
						|
        sys.exit()
 | 
						|
 | 
						|
    filename = sys.argv[1]
 | 
						|
    if not isSpiderImage(filename):
 | 
						|
        print("input image must be in Spider format")
 | 
						|
        sys.exit()
 | 
						|
 | 
						|
    outfile = ""
 | 
						|
    if len(sys.argv[1:]) > 1:
 | 
						|
        outfile = sys.argv[2]
 | 
						|
 | 
						|
    im = Image.open(filename)
 | 
						|
    print("image: " + str(im))
 | 
						|
    print("format: " + str(im.format))
 | 
						|
    print("size: " + str(im.size))
 | 
						|
    print("mode: " + str(im.mode))
 | 
						|
    print("max, min: ", end=' ')
 | 
						|
    print(im.getextrema())
 | 
						|
 | 
						|
    if outfile != "":
 | 
						|
        # perform some image operation
 | 
						|
        im = im.transpose(Image.FLIP_LEFT_RIGHT)
 | 
						|
        print("saving a flipped version of %s as %s " % (os.path.basename(filename), outfile))
 | 
						|
        im.save(outfile, "SPIDER")
 |