mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-11-11 20:27:06 +03:00
d50445ff30
Similar to the recent adoption of Black. isort is a Python utility to sort imports alphabetically and automatically separate into sections. By using isort, contributors can quickly and automatically conform to the projects style without thinking. Just let the tool do it. Uses the configuration recommended by the Black to avoid conflicts of style. Rewrite TestImageQt.test_deprecated to no rely on import order.
236 lines
6.1 KiB
Python
236 lines
6.1 KiB
Python
#
|
|
# The Python Imaging Library.
|
|
# $Id$
|
|
#
|
|
# SGI image file handling
|
|
#
|
|
# See "The SGI Image File Format (Draft version 0.97)", Paul Haeberli.
|
|
# <ftp://ftp.sgi.com/graphics/SGIIMAGESPEC>
|
|
#
|
|
#
|
|
# History:
|
|
# 2017-22-07 mb Add RLE decompression
|
|
# 2016-16-10 mb Add save method without compression
|
|
# 1995-09-10 fl Created
|
|
#
|
|
# Copyright (c) 2016 by Mickael Bonfill.
|
|
# Copyright (c) 2008 by Karsten Hiddemann.
|
|
# Copyright (c) 1997 by Secret Labs AB.
|
|
# Copyright (c) 1995 by Fredrik Lundh.
|
|
#
|
|
# See the README file for information on usage and redistribution.
|
|
#
|
|
|
|
|
|
import os
|
|
import struct
|
|
|
|
from . import Image, ImageFile
|
|
from ._binary import i8, i16be as i16, o8
|
|
from ._util import py3
|
|
|
|
# __version__ is deprecated and will be removed in a future version. Use
|
|
# PIL.__version__ instead.
|
|
__version__ = "0.3"
|
|
|
|
|
|
def _accept(prefix):
|
|
return len(prefix) >= 2 and i16(prefix) == 474
|
|
|
|
|
|
MODES = {
|
|
(1, 1, 1): "L",
|
|
(1, 2, 1): "L",
|
|
(2, 1, 1): "L;16B",
|
|
(2, 2, 1): "L;16B",
|
|
(1, 3, 3): "RGB",
|
|
(2, 3, 3): "RGB;16B",
|
|
(1, 3, 4): "RGBA",
|
|
(2, 3, 4): "RGBA;16B",
|
|
}
|
|
|
|
|
|
##
|
|
# Image plugin for SGI images.
|
|
class SgiImageFile(ImageFile.ImageFile):
|
|
|
|
format = "SGI"
|
|
format_description = "SGI Image File Format"
|
|
|
|
def _open(self):
|
|
|
|
# HEAD
|
|
headlen = 512
|
|
s = self.fp.read(headlen)
|
|
|
|
# magic number : 474
|
|
if i16(s) != 474:
|
|
raise ValueError("Not an SGI image file")
|
|
|
|
# compression : verbatim or RLE
|
|
compression = i8(s[2])
|
|
|
|
# bpc : 1 or 2 bytes (8bits or 16bits)
|
|
bpc = i8(s[3])
|
|
|
|
# dimension : 1, 2 or 3 (depending on xsize, ysize and zsize)
|
|
dimension = i16(s[4:])
|
|
|
|
# xsize : width
|
|
xsize = i16(s[6:])
|
|
|
|
# ysize : height
|
|
ysize = i16(s[8:])
|
|
|
|
# zsize : channels count
|
|
zsize = i16(s[10:])
|
|
|
|
# layout
|
|
layout = bpc, dimension, zsize
|
|
|
|
# determine mode from bits/zsize
|
|
rawmode = ""
|
|
try:
|
|
rawmode = MODES[layout]
|
|
except KeyError:
|
|
pass
|
|
|
|
if rawmode == "":
|
|
raise ValueError("Unsupported SGI image mode")
|
|
|
|
self._size = xsize, ysize
|
|
self.mode = rawmode.split(";")[0]
|
|
if self.mode == "RGB":
|
|
self.custom_mimetype = "image/rgb"
|
|
|
|
# orientation -1 : scanlines begins at the bottom-left corner
|
|
orientation = -1
|
|
|
|
# decoder info
|
|
if compression == 0:
|
|
pagesize = xsize * ysize * bpc
|
|
if bpc == 2:
|
|
self.tile = [
|
|
("SGI16", (0, 0) + self.size, headlen, (self.mode, 0, orientation))
|
|
]
|
|
else:
|
|
self.tile = []
|
|
offset = headlen
|
|
for layer in self.mode:
|
|
self.tile.append(
|
|
("raw", (0, 0) + self.size, offset, (layer, 0, orientation))
|
|
)
|
|
offset += pagesize
|
|
elif compression == 1:
|
|
self.tile = [
|
|
("sgi_rle", (0, 0) + self.size, headlen, (rawmode, orientation, bpc))
|
|
]
|
|
|
|
|
|
def _save(im, fp, filename):
|
|
if im.mode != "RGB" and im.mode != "RGBA" and im.mode != "L":
|
|
raise ValueError("Unsupported SGI image mode")
|
|
|
|
# Get the keyword arguments
|
|
info = im.encoderinfo
|
|
|
|
# Byte-per-pixel precision, 1 = 8bits per pixel
|
|
bpc = info.get("bpc", 1)
|
|
|
|
if bpc not in (1, 2):
|
|
raise ValueError("Unsupported number of bytes per pixel")
|
|
|
|
# Flip the image, since the origin of SGI file is the bottom-left corner
|
|
orientation = -1
|
|
# Define the file as SGI File Format
|
|
magicNumber = 474
|
|
# Run-Length Encoding Compression - Unsupported at this time
|
|
rle = 0
|
|
|
|
# Number of dimensions (x,y,z)
|
|
dim = 3
|
|
# X Dimension = width / Y Dimension = height
|
|
x, y = im.size
|
|
if im.mode == "L" and y == 1:
|
|
dim = 1
|
|
elif im.mode == "L":
|
|
dim = 2
|
|
# Z Dimension: Number of channels
|
|
z = len(im.mode)
|
|
|
|
if dim == 1 or dim == 2:
|
|
z = 1
|
|
|
|
# assert we've got the right number of bands.
|
|
if len(im.getbands()) != z:
|
|
raise ValueError(
|
|
"incorrect number of bands in SGI write: %s vs %s" % (z, len(im.getbands()))
|
|
)
|
|
|
|
# Minimum Byte value
|
|
pinmin = 0
|
|
# Maximum Byte value (255 = 8bits per pixel)
|
|
pinmax = 255
|
|
# Image name (79 characters max, truncated below in write)
|
|
imgName = os.path.splitext(os.path.basename(filename))[0]
|
|
if py3:
|
|
imgName = imgName.encode("ascii", "ignore")
|
|
# Standard representation of pixel in the file
|
|
colormap = 0
|
|
fp.write(struct.pack(">h", magicNumber))
|
|
fp.write(o8(rle))
|
|
fp.write(o8(bpc))
|
|
fp.write(struct.pack(">H", dim))
|
|
fp.write(struct.pack(">H", x))
|
|
fp.write(struct.pack(">H", y))
|
|
fp.write(struct.pack(">H", z))
|
|
fp.write(struct.pack(">l", pinmin))
|
|
fp.write(struct.pack(">l", pinmax))
|
|
fp.write(struct.pack("4s", b"")) # dummy
|
|
fp.write(struct.pack("79s", imgName)) # truncates to 79 chars
|
|
fp.write(struct.pack("s", b"")) # force null byte after imgname
|
|
fp.write(struct.pack(">l", colormap))
|
|
fp.write(struct.pack("404s", b"")) # dummy
|
|
|
|
rawmode = "L"
|
|
if bpc == 2:
|
|
rawmode = "L;16B"
|
|
|
|
for channel in im.split():
|
|
fp.write(channel.tobytes("raw", rawmode, 0, orientation))
|
|
|
|
fp.close()
|
|
|
|
|
|
class SGI16Decoder(ImageFile.PyDecoder):
|
|
_pulls_fd = True
|
|
|
|
def decode(self, buffer):
|
|
rawmode, stride, orientation = self.args
|
|
pagesize = self.state.xsize * self.state.ysize
|
|
zsize = len(self.mode)
|
|
self.fd.seek(512)
|
|
|
|
for band in range(zsize):
|
|
channel = Image.new("L", (self.state.xsize, self.state.ysize))
|
|
channel.frombytes(
|
|
self.fd.read(2 * pagesize), "raw", "L;16B", stride, orientation
|
|
)
|
|
self.im.putband(channel.im, band)
|
|
|
|
return -1, 0
|
|
|
|
|
|
#
|
|
# registry
|
|
|
|
|
|
Image.register_decoder("SGI16", SGI16Decoder)
|
|
Image.register_open(SgiImageFile.format, SgiImageFile, _accept)
|
|
Image.register_save(SgiImageFile.format, _save)
|
|
Image.register_mime(SgiImageFile.format, "image/sgi")
|
|
|
|
Image.register_extensions(SgiImageFile.format, [".bw", ".rgb", ".rgba", ".sgi"])
|
|
|
|
# End of file
|