You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

804 lines
27 KiB

4 years ago
  1. #
  2. # The Python Imaging Library.
  3. # $Id$
  4. #
  5. # JPEG (JFIF) file handling
  6. #
  7. # See "Digital Compression and Coding of Continuous-Tone Still Images,
  8. # Part 1, Requirements and Guidelines" (CCITT T.81 / ISO 10918-1)
  9. #
  10. # History:
  11. # 1995-09-09 fl Created
  12. # 1995-09-13 fl Added full parser
  13. # 1996-03-25 fl Added hack to use the IJG command line utilities
  14. # 1996-05-05 fl Workaround Photoshop 2.5 CMYK polarity bug
  15. # 1996-05-28 fl Added draft support, JFIF version (0.1)
  16. # 1996-12-30 fl Added encoder options, added progression property (0.2)
  17. # 1997-08-27 fl Save mode 1 images as BW (0.3)
  18. # 1998-07-12 fl Added YCbCr to draft and save methods (0.4)
  19. # 1998-10-19 fl Don't hang on files using 16-bit DQT's (0.4.1)
  20. # 2001-04-16 fl Extract DPI settings from JFIF files (0.4.2)
  21. # 2002-07-01 fl Skip pad bytes before markers; identify Exif files (0.4.3)
  22. # 2003-04-25 fl Added experimental EXIF decoder (0.5)
  23. # 2003-06-06 fl Added experimental EXIF GPSinfo decoder
  24. # 2003-09-13 fl Extract COM markers
  25. # 2009-09-06 fl Added icc_profile support (from Florian Hoech)
  26. # 2009-03-06 fl Changed CMYK handling; always use Adobe polarity (0.6)
  27. # 2009-03-08 fl Added subsampling support (from Justin Huff).
  28. #
  29. # Copyright (c) 1997-2003 by Secret Labs AB.
  30. # Copyright (c) 1995-1996 by Fredrik Lundh.
  31. #
  32. # See the README file for information on usage and redistribution.
  33. #
  34. from __future__ import print_function
  35. import array
  36. import struct
  37. import io
  38. import warnings
  39. from . import Image, ImageFile, TiffImagePlugin
  40. from ._binary import i8, o8, i16be as i16
  41. from .JpegPresets import presets
  42. from ._util import isStringType
  43. __version__ = "0.6"
  44. #
  45. # Parser
  46. def Skip(self, marker):
  47. n = i16(self.fp.read(2))-2
  48. ImageFile._safe_read(self.fp, n)
  49. def APP(self, marker):
  50. #
  51. # Application marker. Store these in the APP dictionary.
  52. # Also look for well-known application markers.
  53. n = i16(self.fp.read(2))-2
  54. s = ImageFile._safe_read(self.fp, n)
  55. app = "APP%d" % (marker & 15)
  56. self.app[app] = s # compatibility
  57. self.applist.append((app, s))
  58. if marker == 0xFFE0 and s[:4] == b"JFIF":
  59. # extract JFIF information
  60. self.info["jfif"] = version = i16(s, 5) # version
  61. self.info["jfif_version"] = divmod(version, 256)
  62. # extract JFIF properties
  63. try:
  64. jfif_unit = i8(s[7])
  65. jfif_density = i16(s, 8), i16(s, 10)
  66. except:
  67. pass
  68. else:
  69. if jfif_unit == 1:
  70. self.info["dpi"] = jfif_density
  71. self.info["jfif_unit"] = jfif_unit
  72. self.info["jfif_density"] = jfif_density
  73. elif marker == 0xFFE1 and s[:5] == b"Exif\0":
  74. if "exif" not in self.info:
  75. # extract Exif information (incomplete)
  76. self.info["exif"] = s # FIXME: value will change
  77. elif marker == 0xFFE2 and s[:5] == b"FPXR\0":
  78. # extract FlashPix information (incomplete)
  79. self.info["flashpix"] = s # FIXME: value will change
  80. elif marker == 0xFFE2 and s[:12] == b"ICC_PROFILE\0":
  81. # Since an ICC profile can be larger than the maximum size of
  82. # a JPEG marker (64K), we need provisions to split it into
  83. # multiple markers. The format defined by the ICC specifies
  84. # one or more APP2 markers containing the following data:
  85. # Identifying string ASCII "ICC_PROFILE\0" (12 bytes)
  86. # Marker sequence number 1, 2, etc (1 byte)
  87. # Number of markers Total of APP2's used (1 byte)
  88. # Profile data (remainder of APP2 data)
  89. # Decoders should use the marker sequence numbers to
  90. # reassemble the profile, rather than assuming that the APP2
  91. # markers appear in the correct sequence.
  92. self.icclist.append(s)
  93. elif marker == 0xFFEE and s[:5] == b"Adobe":
  94. self.info["adobe"] = i16(s, 5)
  95. # extract Adobe custom properties
  96. try:
  97. adobe_transform = i8(s[1])
  98. except:
  99. pass
  100. else:
  101. self.info["adobe_transform"] = adobe_transform
  102. elif marker == 0xFFE2 and s[:4] == b"MPF\0":
  103. # extract MPO information
  104. self.info["mp"] = s[4:]
  105. # offset is current location minus buffer size
  106. # plus constant header size
  107. self.info["mpoffset"] = self.fp.tell() - n + 4
  108. # If DPI isn't in JPEG header, fetch from EXIF
  109. if "dpi" not in self.info and "exif" in self.info:
  110. try:
  111. exif = self._getexif()
  112. resolution_unit = exif[0x0128]
  113. x_resolution = exif[0x011A]
  114. try:
  115. dpi = x_resolution[0] / x_resolution[1]
  116. except TypeError:
  117. dpi = x_resolution
  118. if resolution_unit == 3: # cm
  119. # 1 dpcm = 2.54 dpi
  120. dpi *= 2.54
  121. self.info["dpi"] = dpi, dpi
  122. except (KeyError, SyntaxError, ZeroDivisionError):
  123. # SyntaxError for invalid/unreadable exif
  124. # KeyError for dpi not included
  125. # ZeroDivisionError for invalid dpi rational value
  126. self.info["dpi"] = 72, 72
  127. def COM(self, marker):
  128. #
  129. # Comment marker. Store these in the APP dictionary.
  130. n = i16(self.fp.read(2))-2
  131. s = ImageFile._safe_read(self.fp, n)
  132. self.app["COM"] = s # compatibility
  133. self.applist.append(("COM", s))
  134. def SOF(self, marker):
  135. #
  136. # Start of frame marker. Defines the size and mode of the
  137. # image. JPEG is colour blind, so we use some simple
  138. # heuristics to map the number of layers to an appropriate
  139. # mode. Note that this could be made a bit brighter, by
  140. # looking for JFIF and Adobe APP markers.
  141. n = i16(self.fp.read(2))-2
  142. s = ImageFile._safe_read(self.fp, n)
  143. self._size = i16(s[3:]), i16(s[1:])
  144. self.bits = i8(s[0])
  145. if self.bits != 8:
  146. raise SyntaxError("cannot handle %d-bit layers" % self.bits)
  147. self.layers = i8(s[5])
  148. if self.layers == 1:
  149. self.mode = "L"
  150. elif self.layers == 3:
  151. self.mode = "RGB"
  152. elif self.layers == 4:
  153. self.mode = "CMYK"
  154. else:
  155. raise SyntaxError("cannot handle %d-layer images" % self.layers)
  156. if marker in [0xFFC2, 0xFFC6, 0xFFCA, 0xFFCE]:
  157. self.info["progressive"] = self.info["progression"] = 1
  158. if self.icclist:
  159. # fixup icc profile
  160. self.icclist.sort() # sort by sequence number
  161. if i8(self.icclist[0][13]) == len(self.icclist):
  162. profile = []
  163. for p in self.icclist:
  164. profile.append(p[14:])
  165. icc_profile = b"".join(profile)
  166. else:
  167. icc_profile = None # wrong number of fragments
  168. self.info["icc_profile"] = icc_profile
  169. self.icclist = None
  170. for i in range(6, len(s), 3):
  171. t = s[i:i+3]
  172. # 4-tuples: id, vsamp, hsamp, qtable
  173. self.layer.append((t[0], i8(t[1])//16, i8(t[1]) & 15, i8(t[2])))
  174. def DQT(self, marker):
  175. #
  176. # Define quantization table. Support baseline 8-bit tables
  177. # only. Note that there might be more than one table in
  178. # each marker.
  179. # FIXME: The quantization tables can be used to estimate the
  180. # compression quality.
  181. n = i16(self.fp.read(2))-2
  182. s = ImageFile._safe_read(self.fp, n)
  183. while len(s):
  184. if len(s) < 65:
  185. raise SyntaxError("bad quantization table marker")
  186. v = i8(s[0])
  187. if v//16 == 0:
  188. self.quantization[v & 15] = array.array("B", s[1:65])
  189. s = s[65:]
  190. else:
  191. return # FIXME: add code to read 16-bit tables!
  192. # raise SyntaxError, "bad quantization table element size"
  193. #
  194. # JPEG marker table
  195. MARKER = {
  196. 0xFFC0: ("SOF0", "Baseline DCT", SOF),
  197. 0xFFC1: ("SOF1", "Extended Sequential DCT", SOF),
  198. 0xFFC2: ("SOF2", "Progressive DCT", SOF),
  199. 0xFFC3: ("SOF3", "Spatial lossless", SOF),
  200. 0xFFC4: ("DHT", "Define Huffman table", Skip),
  201. 0xFFC5: ("SOF5", "Differential sequential DCT", SOF),
  202. 0xFFC6: ("SOF6", "Differential progressive DCT", SOF),
  203. 0xFFC7: ("SOF7", "Differential spatial", SOF),
  204. 0xFFC8: ("JPG", "Extension", None),
  205. 0xFFC9: ("SOF9", "Extended sequential DCT (AC)", SOF),
  206. 0xFFCA: ("SOF10", "Progressive DCT (AC)", SOF),
  207. 0xFFCB: ("SOF11", "Spatial lossless DCT (AC)", SOF),
  208. 0xFFCC: ("DAC", "Define arithmetic coding conditioning", Skip),
  209. 0xFFCD: ("SOF13", "Differential sequential DCT (AC)", SOF),
  210. 0xFFCE: ("SOF14", "Differential progressive DCT (AC)", SOF),
  211. 0xFFCF: ("SOF15", "Differential spatial (AC)", SOF),
  212. 0xFFD0: ("RST0", "Restart 0", None),
  213. 0xFFD1: ("RST1", "Restart 1", None),
  214. 0xFFD2: ("RST2", "Restart 2", None),
  215. 0xFFD3: ("RST3", "Restart 3", None),
  216. 0xFFD4: ("RST4", "Restart 4", None),
  217. 0xFFD5: ("RST5", "Restart 5", None),
  218. 0xFFD6: ("RST6", "Restart 6", None),
  219. 0xFFD7: ("RST7", "Restart 7", None),
  220. 0xFFD8: ("SOI", "Start of image", None),
  221. 0xFFD9: ("EOI", "End of image", None),
  222. 0xFFDA: ("SOS", "Start of scan", Skip),
  223. 0xFFDB: ("DQT", "Define quantization table", DQT),
  224. 0xFFDC: ("DNL", "Define number of lines", Skip),
  225. 0xFFDD: ("DRI", "Define restart interval", Skip),
  226. 0xFFDE: ("DHP", "Define hierarchical progression", SOF),
  227. 0xFFDF: ("EXP", "Expand reference component", Skip),
  228. 0xFFE0: ("APP0", "Application segment 0", APP),
  229. 0xFFE1: ("APP1", "Application segment 1", APP),
  230. 0xFFE2: ("APP2", "Application segment 2", APP),
  231. 0xFFE3: ("APP3", "Application segment 3", APP),
  232. 0xFFE4: ("APP4", "Application segment 4", APP),
  233. 0xFFE5: ("APP5", "Application segment 5", APP),
  234. 0xFFE6: ("APP6", "Application segment 6", APP),
  235. 0xFFE7: ("APP7", "Application segment 7", APP),
  236. 0xFFE8: ("APP8", "Application segment 8", APP),
  237. 0xFFE9: ("APP9", "Application segment 9", APP),
  238. 0xFFEA: ("APP10", "Application segment 10", APP),
  239. 0xFFEB: ("APP11", "Application segment 11", APP),
  240. 0xFFEC: ("APP12", "Application segment 12", APP),
  241. 0xFFED: ("APP13", "Application segment 13", APP),
  242. 0xFFEE: ("APP14", "Application segment 14", APP),
  243. 0xFFEF: ("APP15", "Application segment 15", APP),
  244. 0xFFF0: ("JPG0", "Extension 0", None),
  245. 0xFFF1: ("JPG1", "Extension 1", None),
  246. 0xFFF2: ("JPG2", "Extension 2", None),
  247. 0xFFF3: ("JPG3", "Extension 3", None),
  248. 0xFFF4: ("JPG4", "Extension 4", None),
  249. 0xFFF5: ("JPG5", "Extension 5", None),
  250. 0xFFF6: ("JPG6", "Extension 6", None),
  251. 0xFFF7: ("JPG7", "Extension 7", None),
  252. 0xFFF8: ("JPG8", "Extension 8", None),
  253. 0xFFF9: ("JPG9", "Extension 9", None),
  254. 0xFFFA: ("JPG10", "Extension 10", None),
  255. 0xFFFB: ("JPG11", "Extension 11", None),
  256. 0xFFFC: ("JPG12", "Extension 12", None),
  257. 0xFFFD: ("JPG13", "Extension 13", None),
  258. 0xFFFE: ("COM", "Comment", COM)
  259. }
  260. def _accept(prefix):
  261. return prefix[0:1] == b"\377"
  262. ##
  263. # Image plugin for JPEG and JFIF images.
  264. class JpegImageFile(ImageFile.ImageFile):
  265. format = "JPEG"
  266. format_description = "JPEG (ISO 10918)"
  267. def _open(self):
  268. s = self.fp.read(1)
  269. if i8(s) != 255:
  270. raise SyntaxError("not a JPEG file")
  271. # Create attributes
  272. self.bits = self.layers = 0
  273. # JPEG specifics (internal)
  274. self.layer = []
  275. self.huffman_dc = {}
  276. self.huffman_ac = {}
  277. self.quantization = {}
  278. self.app = {} # compatibility
  279. self.applist = []
  280. self.icclist = []
  281. while True:
  282. i = i8(s)
  283. if i == 0xFF:
  284. s = s + self.fp.read(1)
  285. i = i16(s)
  286. else:
  287. # Skip non-0xFF junk
  288. s = self.fp.read(1)
  289. continue
  290. if i in MARKER:
  291. name, description, handler = MARKER[i]
  292. if handler is not None:
  293. handler(self, i)
  294. if i == 0xFFDA: # start of scan
  295. rawmode = self.mode
  296. if self.mode == "CMYK":
  297. rawmode = "CMYK;I" # assume adobe conventions
  298. self.tile = [("jpeg", (0, 0) + self.size, 0,
  299. (rawmode, ""))]
  300. # self.__offset = self.fp.tell()
  301. break
  302. s = self.fp.read(1)
  303. elif i == 0 or i == 0xFFFF:
  304. # padded marker or junk; move on
  305. s = b"\xff"
  306. elif i == 0xFF00: # Skip extraneous data (escaped 0xFF)
  307. s = self.fp.read(1)
  308. else:
  309. raise SyntaxError("no marker found")
  310. def load_read(self, read_bytes):
  311. """
  312. internal: read more image data
  313. For premature EOF and LOAD_TRUNCATED_IMAGES adds EOI marker
  314. so libjpeg can finish decoding
  315. """
  316. s = self.fp.read(read_bytes)
  317. if not s and ImageFile.LOAD_TRUNCATED_IMAGES:
  318. # Premature EOF.
  319. # Pretend file is finished adding EOI marker
  320. return b"\xFF\xD9"
  321. return s
  322. def draft(self, mode, size):
  323. if len(self.tile) != 1:
  324. return
  325. # Protect from second call
  326. if self.decoderconfig:
  327. return
  328. d, e, o, a = self.tile[0]
  329. scale = 0
  330. if a[0] == "RGB" and mode in ["L", "YCbCr"]:
  331. self.mode = mode
  332. a = mode, ""
  333. if size:
  334. scale = min(self.size[0] // size[0], self.size[1] // size[1])
  335. for s in [8, 4, 2, 1]:
  336. if scale >= s:
  337. break
  338. e = e[0], e[1], (e[2]-e[0]+s-1)//s+e[0], (e[3]-e[1]+s-1)//s+e[1]
  339. self._size = ((self.size[0]+s-1)//s, (self.size[1]+s-1)//s)
  340. scale = s
  341. self.tile = [(d, e, o, a)]
  342. self.decoderconfig = (scale, 0)
  343. return self
  344. def load_djpeg(self):
  345. # ALTERNATIVE: handle JPEGs via the IJG command line utilities
  346. import subprocess
  347. import tempfile
  348. import os
  349. f, path = tempfile.mkstemp()
  350. os.close(f)
  351. if os.path.exists(self.filename):
  352. subprocess.check_call(["djpeg", "-outfile", path, self.filename])
  353. else:
  354. raise ValueError("Invalid Filename")
  355. try:
  356. _im = Image.open(path)
  357. _im.load()
  358. self.im = _im.im
  359. finally:
  360. try:
  361. os.unlink(path)
  362. except OSError:
  363. pass
  364. self.mode = self.im.mode
  365. self._size = self.im.size
  366. self.tile = []
  367. def _getexif(self):
  368. return _getexif(self)
  369. def _getmp(self):
  370. return _getmp(self)
  371. def _fixup_dict(src_dict):
  372. # Helper function for _getexif()
  373. # returns a dict with any single item tuples/lists as individual values
  374. def _fixup(value):
  375. try:
  376. if len(value) == 1 and not isinstance(value, dict):
  377. return value[0]
  378. except:
  379. pass
  380. return value
  381. return {k: _fixup(v) for k, v in src_dict.items()}
  382. def _getexif(self):
  383. # Extract EXIF information. This method is highly experimental,
  384. # and is likely to be replaced with something better in a future
  385. # version.
  386. # The EXIF record consists of a TIFF file embedded in a JPEG
  387. # application marker (!).
  388. try:
  389. data = self.info["exif"]
  390. except KeyError:
  391. return None
  392. file = io.BytesIO(data[6:])
  393. head = file.read(8)
  394. # process dictionary
  395. info = TiffImagePlugin.ImageFileDirectory_v1(head)
  396. info.load(file)
  397. exif = dict(_fixup_dict(info))
  398. # get exif extension
  399. try:
  400. # exif field 0x8769 is an offset pointer to the location
  401. # of the nested embedded exif ifd.
  402. # It should be a long, but may be corrupted.
  403. file.seek(exif[0x8769])
  404. except (KeyError, TypeError):
  405. pass
  406. else:
  407. info = TiffImagePlugin.ImageFileDirectory_v1(head)
  408. info.load(file)
  409. exif.update(_fixup_dict(info))
  410. # get gpsinfo extension
  411. try:
  412. # exif field 0x8825 is an offset pointer to the location
  413. # of the nested embedded gps exif ifd.
  414. # It should be a long, but may be corrupted.
  415. file.seek(exif[0x8825])
  416. except (KeyError, TypeError):
  417. pass
  418. else:
  419. info = TiffImagePlugin.ImageFileDirectory_v1(head)
  420. info.load(file)
  421. exif[0x8825] = _fixup_dict(info)
  422. return exif
  423. def _getmp(self):
  424. # Extract MP information. This method was inspired by the "highly
  425. # experimental" _getexif version that's been in use for years now,
  426. # itself based on the ImageFileDirectory class in the TIFF plug-in.
  427. # The MP record essentially consists of a TIFF file embedded in a JPEG
  428. # application marker.
  429. try:
  430. data = self.info["mp"]
  431. except KeyError:
  432. return None
  433. file_contents = io.BytesIO(data)
  434. head = file_contents.read(8)
  435. endianness = '>' if head[:4] == b'\x4d\x4d\x00\x2a' else '<'
  436. # process dictionary
  437. try:
  438. info = TiffImagePlugin.ImageFileDirectory_v2(head)
  439. info.load(file_contents)
  440. mp = dict(info)
  441. except:
  442. raise SyntaxError("malformed MP Index (unreadable directory)")
  443. # it's an error not to have a number of images
  444. try:
  445. quant = mp[0xB001]
  446. except KeyError:
  447. raise SyntaxError("malformed MP Index (no number of images)")
  448. # get MP entries
  449. mpentries = []
  450. try:
  451. rawmpentries = mp[0xB002]
  452. for entrynum in range(0, quant):
  453. unpackedentry = struct.unpack_from(
  454. '{}LLLHH'.format(endianness), rawmpentries, entrynum * 16)
  455. labels = ('Attribute', 'Size', 'DataOffset', 'EntryNo1',
  456. 'EntryNo2')
  457. mpentry = dict(zip(labels, unpackedentry))
  458. mpentryattr = {
  459. 'DependentParentImageFlag': bool(mpentry['Attribute'] &
  460. (1 << 31)),
  461. 'DependentChildImageFlag': bool(mpentry['Attribute'] &
  462. (1 << 30)),
  463. 'RepresentativeImageFlag': bool(mpentry['Attribute'] &
  464. (1 << 29)),
  465. 'Reserved': (mpentry['Attribute'] & (3 << 27)) >> 27,
  466. 'ImageDataFormat': (mpentry['Attribute'] & (7 << 24)) >> 24,
  467. 'MPType': mpentry['Attribute'] & 0x00FFFFFF
  468. }
  469. if mpentryattr['ImageDataFormat'] == 0:
  470. mpentryattr['ImageDataFormat'] = 'JPEG'
  471. else:
  472. raise SyntaxError("unsupported picture format in MPO")
  473. mptypemap = {
  474. 0x000000: 'Undefined',
  475. 0x010001: 'Large Thumbnail (VGA Equivalent)',
  476. 0x010002: 'Large Thumbnail (Full HD Equivalent)',
  477. 0x020001: 'Multi-Frame Image (Panorama)',
  478. 0x020002: 'Multi-Frame Image: (Disparity)',
  479. 0x020003: 'Multi-Frame Image: (Multi-Angle)',
  480. 0x030000: 'Baseline MP Primary Image'
  481. }
  482. mpentryattr['MPType'] = mptypemap.get(mpentryattr['MPType'],
  483. 'Unknown')
  484. mpentry['Attribute'] = mpentryattr
  485. mpentries.append(mpentry)
  486. mp[0xB002] = mpentries
  487. except KeyError:
  488. raise SyntaxError("malformed MP Index (bad MP Entry)")
  489. # Next we should try and parse the individual image unique ID list;
  490. # we don't because I've never seen this actually used in a real MPO
  491. # file and so can't test it.
  492. return mp
  493. # --------------------------------------------------------------------
  494. # stuff to save JPEG files
  495. RAWMODE = {
  496. "1": "L",
  497. "L": "L",
  498. "RGB": "RGB",
  499. "RGBX": "RGB",
  500. "CMYK": "CMYK;I", # assume adobe conventions
  501. "YCbCr": "YCbCr",
  502. }
  503. zigzag_index = (0, 1, 5, 6, 14, 15, 27, 28,
  504. 2, 4, 7, 13, 16, 26, 29, 42,
  505. 3, 8, 12, 17, 25, 30, 41, 43,
  506. 9, 11, 18, 24, 31, 40, 44, 53,
  507. 10, 19, 23, 32, 39, 45, 52, 54,
  508. 20, 22, 33, 38, 46, 51, 55, 60,
  509. 21, 34, 37, 47, 50, 56, 59, 61,
  510. 35, 36, 48, 49, 57, 58, 62, 63)
  511. samplings = {(1, 1, 1, 1, 1, 1): 0,
  512. (2, 1, 1, 1, 1, 1): 1,
  513. (2, 2, 1, 1, 1, 1): 2,
  514. }
  515. def convert_dict_qtables(qtables):
  516. qtables = [qtables[key] for key in range(len(qtables)) if key in qtables]
  517. for idx, table in enumerate(qtables):
  518. qtables[idx] = [table[i] for i in zigzag_index]
  519. return qtables
  520. def get_sampling(im):
  521. # There's no subsampling when image have only 1 layer
  522. # (grayscale images) or when they are CMYK (4 layers),
  523. # so set subsampling to default value.
  524. #
  525. # NOTE: currently Pillow can't encode JPEG to YCCK format.
  526. # If YCCK support is added in the future, subsampling code will have
  527. # to be updated (here and in JpegEncode.c) to deal with 4 layers.
  528. if not hasattr(im, 'layers') or im.layers in (1, 4):
  529. return -1
  530. sampling = im.layer[0][1:3] + im.layer[1][1:3] + im.layer[2][1:3]
  531. return samplings.get(sampling, -1)
  532. def _save(im, fp, filename):
  533. try:
  534. rawmode = RAWMODE[im.mode]
  535. except KeyError:
  536. raise IOError("cannot write mode %s as JPEG" % im.mode)
  537. info = im.encoderinfo
  538. dpi = [int(round(x)) for x in info.get("dpi", (0, 0))]
  539. quality = info.get("quality", 0)
  540. subsampling = info.get("subsampling", -1)
  541. qtables = info.get("qtables")
  542. if quality == "keep":
  543. quality = 0
  544. subsampling = "keep"
  545. qtables = "keep"
  546. elif quality in presets:
  547. preset = presets[quality]
  548. quality = 0
  549. subsampling = preset.get('subsampling', -1)
  550. qtables = preset.get('quantization')
  551. elif not isinstance(quality, int):
  552. raise ValueError("Invalid quality setting")
  553. else:
  554. if subsampling in presets:
  555. subsampling = presets[subsampling].get('subsampling', -1)
  556. if isStringType(qtables) and qtables in presets:
  557. qtables = presets[qtables].get('quantization')
  558. if subsampling == "4:4:4":
  559. subsampling = 0
  560. elif subsampling == "4:2:2":
  561. subsampling = 1
  562. elif subsampling == "4:2:0":
  563. subsampling = 2
  564. elif subsampling == "4:1:1":
  565. # For compatibility. Before Pillow 4.3, 4:1:1 actually meant 4:2:0.
  566. # Set 4:2:0 if someone is still using that value.
  567. subsampling = 2
  568. elif subsampling == "keep":
  569. if im.format != "JPEG":
  570. raise ValueError(
  571. "Cannot use 'keep' when original image is not a JPEG")
  572. subsampling = get_sampling(im)
  573. def validate_qtables(qtables):
  574. if qtables is None:
  575. return qtables
  576. if isStringType(qtables):
  577. try:
  578. lines = [int(num) for line in qtables.splitlines()
  579. for num in line.split('#', 1)[0].split()]
  580. except ValueError:
  581. raise ValueError("Invalid quantization table")
  582. else:
  583. qtables = [lines[s:s+64] for s in range(0, len(lines), 64)]
  584. if isinstance(qtables, (tuple, list, dict)):
  585. if isinstance(qtables, dict):
  586. qtables = convert_dict_qtables(qtables)
  587. elif isinstance(qtables, tuple):
  588. qtables = list(qtables)
  589. if not (0 < len(qtables) < 5):
  590. raise ValueError("None or too many quantization tables")
  591. for idx, table in enumerate(qtables):
  592. try:
  593. if len(table) != 64:
  594. raise TypeError
  595. table = array.array('B', table)
  596. except TypeError:
  597. raise ValueError("Invalid quantization table")
  598. else:
  599. qtables[idx] = list(table)
  600. return qtables
  601. if qtables == "keep":
  602. if im.format != "JPEG":
  603. raise ValueError(
  604. "Cannot use 'keep' when original image is not a JPEG")
  605. qtables = getattr(im, "quantization", None)
  606. qtables = validate_qtables(qtables)
  607. extra = b""
  608. icc_profile = info.get("icc_profile")
  609. if icc_profile:
  610. ICC_OVERHEAD_LEN = 14
  611. MAX_BYTES_IN_MARKER = 65533
  612. MAX_DATA_BYTES_IN_MARKER = MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN
  613. markers = []
  614. while icc_profile:
  615. markers.append(icc_profile[:MAX_DATA_BYTES_IN_MARKER])
  616. icc_profile = icc_profile[MAX_DATA_BYTES_IN_MARKER:]
  617. i = 1
  618. for marker in markers:
  619. size = struct.pack(">H", 2 + ICC_OVERHEAD_LEN + len(marker))
  620. extra += (b"\xFF\xE2" + size + b"ICC_PROFILE\0" + o8(i) +
  621. o8(len(markers)) + marker)
  622. i += 1
  623. # "progressive" is the official name, but older documentation
  624. # says "progression"
  625. # FIXME: issue a warning if the wrong form is used (post-1.1.7)
  626. progressive = (info.get("progressive", False) or
  627. info.get("progression", False))
  628. optimize = info.get("optimize", False)
  629. # get keyword arguments
  630. im.encoderconfig = (
  631. quality,
  632. progressive,
  633. info.get("smooth", 0),
  634. optimize,
  635. info.get("streamtype", 0),
  636. dpi[0], dpi[1],
  637. subsampling,
  638. qtables,
  639. extra,
  640. info.get("exif", b"")
  641. )
  642. # if we optimize, libjpeg needs a buffer big enough to hold the whole image
  643. # in a shot. Guessing on the size, at im.size bytes. (raw pixel size is
  644. # channels*size, this is a value that's been used in a django patch.
  645. # https://github.com/matthewwithanm/django-imagekit/issues/50
  646. bufsize = 0
  647. if optimize or progressive:
  648. # CMYK can be bigger
  649. if im.mode == 'CMYK':
  650. bufsize = 4 * im.size[0] * im.size[1]
  651. # keep sets quality to 0, but the actual value may be high.
  652. elif quality >= 95 or quality == 0:
  653. bufsize = 2 * im.size[0] * im.size[1]
  654. else:
  655. bufsize = im.size[0] * im.size[1]
  656. # The exif info needs to be written as one block, + APP1, + one spare byte.
  657. # Ensure that our buffer is big enough. Same with the icc_profile block.
  658. bufsize = max(ImageFile.MAXBLOCK, bufsize, len(info.get("exif", b"")) + 5,
  659. len(extra) + 1)
  660. ImageFile._save(im, fp, [("jpeg", (0, 0)+im.size, 0, rawmode)], bufsize)
  661. def _save_cjpeg(im, fp, filename):
  662. # ALTERNATIVE: handle JPEGs via the IJG command line utilities.
  663. import os
  664. import subprocess
  665. tempfile = im._dump()
  666. subprocess.check_call(["cjpeg", "-outfile", filename, tempfile])
  667. try:
  668. os.unlink(tempfile)
  669. except OSError:
  670. pass
  671. ##
  672. # Factory for making JPEG and MPO instances
  673. def jpeg_factory(fp=None, filename=None):
  674. im = JpegImageFile(fp, filename)
  675. try:
  676. mpheader = im._getmp()
  677. if mpheader[45057] > 1:
  678. # It's actually an MPO
  679. from .MpoImagePlugin import MpoImageFile
  680. im = MpoImageFile(fp, filename)
  681. except (TypeError, IndexError):
  682. # It is really a JPEG
  683. pass
  684. except SyntaxError:
  685. warnings.warn("Image appears to be a malformed MPO file, it will be "
  686. "interpreted as a base JPEG file")
  687. return im
  688. # ---------------------------------------------------------------------
  689. # Registry stuff
  690. Image.register_open(JpegImageFile.format, jpeg_factory, _accept)
  691. Image.register_save(JpegImageFile.format, _save)
  692. Image.register_extensions(JpegImageFile.format,
  693. [".jfif", ".jpe", ".jpg", ".jpeg"])
  694. Image.register_mime(JpegImageFile.format, "image/jpeg")