Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/PIL/SgiImagePlugin.py: 16%

110 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1# 

2# The Python Imaging Library. 

3# $Id$ 

4# 

5# SGI image file handling 

6# 

7# See "The SGI Image File Format (Draft version 0.97)", Paul Haeberli. 

8# <ftp://ftp.sgi.com/graphics/SGIIMAGESPEC> 

9# 

10# 

11# History: 

12# 2017-22-07 mb Add RLE decompression 

13# 2016-16-10 mb Add save method without compression 

14# 1995-09-10 fl Created 

15# 

16# Copyright (c) 2016 by Mickael Bonfill. 

17# Copyright (c) 2008 by Karsten Hiddemann. 

18# Copyright (c) 1997 by Secret Labs AB. 

19# Copyright (c) 1995 by Fredrik Lundh. 

20# 

21# See the README file for information on usage and redistribution. 

22# 

23 

24 

25import os 

26import struct 

27 

28from . import Image, ImageFile 

29from ._binary import i16be as i16 

30from ._binary import o8 

31 

32 

33def _accept(prefix): 

34 return len(prefix) >= 2 and i16(prefix) == 474 

35 

36 

37MODES = { 

38 (1, 1, 1): "L", 

39 (1, 2, 1): "L", 

40 (2, 1, 1): "L;16B", 

41 (2, 2, 1): "L;16B", 

42 (1, 3, 3): "RGB", 

43 (2, 3, 3): "RGB;16B", 

44 (1, 3, 4): "RGBA", 

45 (2, 3, 4): "RGBA;16B", 

46} 

47 

48 

49## 

50# Image plugin for SGI images. 

51class SgiImageFile(ImageFile.ImageFile): 

52 

53 format = "SGI" 

54 format_description = "SGI Image File Format" 

55 

56 def _open(self): 

57 

58 # HEAD 

59 headlen = 512 

60 s = self.fp.read(headlen) 

61 

62 if not _accept(s): 

63 raise ValueError("Not an SGI image file") 

64 

65 # compression : verbatim or RLE 

66 compression = s[2] 

67 

68 # bpc : 1 or 2 bytes (8bits or 16bits) 

69 bpc = s[3] 

70 

71 # dimension : 1, 2 or 3 (depending on xsize, ysize and zsize) 

72 dimension = i16(s, 4) 

73 

74 # xsize : width 

75 xsize = i16(s, 6) 

76 

77 # ysize : height 

78 ysize = i16(s, 8) 

79 

80 # zsize : channels count 

81 zsize = i16(s, 10) 

82 

83 # layout 

84 layout = bpc, dimension, zsize 

85 

86 # determine mode from bits/zsize 

87 rawmode = "" 

88 try: 

89 rawmode = MODES[layout] 

90 except KeyError: 

91 pass 

92 

93 if rawmode == "": 

94 raise ValueError("Unsupported SGI image mode") 

95 

96 self._size = xsize, ysize 

97 self.mode = rawmode.split(";")[0] 

98 if self.mode == "RGB": 

99 self.custom_mimetype = "image/rgb" 

100 

101 # orientation -1 : scanlines begins at the bottom-left corner 

102 orientation = -1 

103 

104 # decoder info 

105 if compression == 0: 

106 pagesize = xsize * ysize * bpc 

107 if bpc == 2: 

108 self.tile = [ 

109 ("SGI16", (0, 0) + self.size, headlen, (self.mode, 0, orientation)) 

110 ] 

111 else: 

112 self.tile = [] 

113 offset = headlen 

114 for layer in self.mode: 

115 self.tile.append( 

116 ("raw", (0, 0) + self.size, offset, (layer, 0, orientation)) 

117 ) 

118 offset += pagesize 

119 elif compression == 1: 

120 self.tile = [ 

121 ("sgi_rle", (0, 0) + self.size, headlen, (rawmode, orientation, bpc)) 

122 ] 

123 

124 

125def _save(im, fp, filename): 

126 if im.mode != "RGB" and im.mode != "RGBA" and im.mode != "L": 

127 raise ValueError("Unsupported SGI image mode") 

128 

129 # Get the keyword arguments 

130 info = im.encoderinfo 

131 

132 # Byte-per-pixel precision, 1 = 8bits per pixel 

133 bpc = info.get("bpc", 1) 

134 

135 if bpc not in (1, 2): 

136 raise ValueError("Unsupported number of bytes per pixel") 

137 

138 # Flip the image, since the origin of SGI file is the bottom-left corner 

139 orientation = -1 

140 # Define the file as SGI File Format 

141 magic_number = 474 

142 # Run-Length Encoding Compression - Unsupported at this time 

143 rle = 0 

144 

145 # Number of dimensions (x,y,z) 

146 dim = 3 

147 # X Dimension = width / Y Dimension = height 

148 x, y = im.size 

149 if im.mode == "L" and y == 1: 

150 dim = 1 

151 elif im.mode == "L": 

152 dim = 2 

153 # Z Dimension: Number of channels 

154 z = len(im.mode) 

155 

156 if dim == 1 or dim == 2: 

157 z = 1 

158 

159 # assert we've got the right number of bands. 

160 if len(im.getbands()) != z: 

161 raise ValueError( 

162 f"incorrect number of bands in SGI write: {z} vs {len(im.getbands())}" 

163 ) 

164 

165 # Minimum Byte value 

166 pinmin = 0 

167 # Maximum Byte value (255 = 8bits per pixel) 

168 pinmax = 255 

169 # Image name (79 characters max, truncated below in write) 

170 img_name = os.path.splitext(os.path.basename(filename))[0] 

171 img_name = img_name.encode("ascii", "ignore") 

172 # Standard representation of pixel in the file 

173 colormap = 0 

174 fp.write(struct.pack(">h", magic_number)) 

175 fp.write(o8(rle)) 

176 fp.write(o8(bpc)) 

177 fp.write(struct.pack(">H", dim)) 

178 fp.write(struct.pack(">H", x)) 

179 fp.write(struct.pack(">H", y)) 

180 fp.write(struct.pack(">H", z)) 

181 fp.write(struct.pack(">l", pinmin)) 

182 fp.write(struct.pack(">l", pinmax)) 

183 fp.write(struct.pack("4s", b"")) # dummy 

184 fp.write(struct.pack("79s", img_name)) # truncates to 79 chars 

185 fp.write(struct.pack("s", b"")) # force null byte after img_name 

186 fp.write(struct.pack(">l", colormap)) 

187 fp.write(struct.pack("404s", b"")) # dummy 

188 

189 rawmode = "L" 

190 if bpc == 2: 

191 rawmode = "L;16B" 

192 

193 for channel in im.split(): 

194 fp.write(channel.tobytes("raw", rawmode, 0, orientation)) 

195 

196 if hasattr(fp, "flush"): 

197 fp.flush() 

198 

199 

200class SGI16Decoder(ImageFile.PyDecoder): 

201 _pulls_fd = True 

202 

203 def decode(self, buffer): 

204 rawmode, stride, orientation = self.args 

205 pagesize = self.state.xsize * self.state.ysize 

206 zsize = len(self.mode) 

207 self.fd.seek(512) 

208 

209 for band in range(zsize): 

210 channel = Image.new("L", (self.state.xsize, self.state.ysize)) 

211 channel.frombytes( 

212 self.fd.read(2 * pagesize), "raw", "L;16B", stride, orientation 

213 ) 

214 self.im.putband(channel.im, band) 

215 

216 return -1, 0 

217 

218 

219# 

220# registry 

221 

222 

223Image.register_decoder("SGI16", SGI16Decoder) 

224Image.register_open(SgiImageFile.format, SgiImageFile, _accept) 

225Image.register_save(SgiImageFile.format, _save) 

226Image.register_mime(SgiImageFile.format, "image/sgi") 

227 

228Image.register_extensions(SgiImageFile.format, [".bw", ".rgb", ".rgba", ".sgi"]) 

229 

230# End of file