Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/PIL/MpoImagePlugin.py: 24%
62 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« 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# MPO file handling
6#
7# See "Multi-Picture Format" (CIPA DC-007-Translation 2009, Standard of the
8# Camera & Imaging Products Association)
9#
10# The multi-picture object combines multiple JPEG images (with a modified EXIF
11# data format) into a single file. While it can theoretically be used much like
12# a GIF animation, it is commonly used to represent 3D photographs and is (as
13# of this writing) the most commonly used format by 3D cameras.
14#
15# History:
16# 2014-03-13 Feneric Created
17#
18# See the README file for information on usage and redistribution.
19#
21from . import Image, ImageFile, JpegImagePlugin
22from ._binary import i16be as i16
24# def _accept(prefix):
25# return JpegImagePlugin._accept(prefix)
28def _save(im, fp, filename):
29 # Note that we can only save the current frame at present
30 return JpegImagePlugin._save(im, fp, filename)
33##
34# Image plugin for MPO images.
37class MpoImageFile(JpegImagePlugin.JpegImageFile):
39 format = "MPO"
40 format_description = "MPO (CIPA DC-007)"
41 _close_exclusive_fp_after_loading = False
43 def _open(self):
44 self.fp.seek(0) # prep the fp in order to pass the JPEG test
45 JpegImagePlugin.JpegImageFile._open(self)
46 self._after_jpeg_open()
48 def _after_jpeg_open(self, mpheader=None):
49 self._initial_size = self.size
50 self.mpinfo = mpheader if mpheader is not None else self._getmp()
51 self.n_frames = self.mpinfo[0xB001]
52 self.__mpoffsets = [
53 mpent["DataOffset"] + self.info["mpoffset"] for mpent in self.mpinfo[0xB002]
54 ]
55 self.__mpoffsets[0] = 0
56 # Note that the following assertion will only be invalid if something
57 # gets broken within JpegImagePlugin.
58 assert self.n_frames == len(self.__mpoffsets)
59 del self.info["mpoffset"] # no longer needed
60 self.is_animated = self.n_frames > 1
61 self._fp = self.fp # FIXME: hack
62 self._fp.seek(self.__mpoffsets[0]) # get ready to read first frame
63 self.__frame = 0
64 self.offset = 0
65 # for now we can only handle reading and individual frame extraction
66 self.readonly = 1
68 def load_seek(self, pos):
69 self._fp.seek(pos)
71 def seek(self, frame):
72 if not self._seek_check(frame):
73 return
74 self.fp = self._fp
75 self.offset = self.__mpoffsets[frame]
77 self.fp.seek(self.offset + 2) # skip SOI marker
78 segment = self.fp.read(2)
79 if not segment:
80 raise ValueError("No data found for frame")
81 self._size = self._initial_size
82 if i16(segment) == 0xFFE1: # APP1
83 n = i16(self.fp.read(2)) - 2
84 self.info["exif"] = ImageFile._safe_read(self.fp, n)
85 self._reload_exif()
87 mptype = self.mpinfo[0xB002][frame]["Attribute"]["MPType"]
88 if mptype.startswith("Large Thumbnail"):
89 exif = self.getexif().get_ifd(0x8769)
90 if 40962 in exif and 40963 in exif:
91 self._size = (exif[40962], exif[40963])
92 elif "exif" in self.info:
93 del self.info["exif"]
94 self._reload_exif()
96 self.tile = [("jpeg", (0, 0) + self.size, self.offset, (self.mode, ""))]
97 self.__frame = frame
99 def tell(self):
100 return self.__frame
102 @staticmethod
103 def adopt(jpeg_instance, mpheader=None):
104 """
105 Transform the instance of JpegImageFile into
106 an instance of MpoImageFile.
107 After the call, the JpegImageFile is extended
108 to be an MpoImageFile.
110 This is essentially useful when opening a JPEG
111 file that reveals itself as an MPO, to avoid
112 double call to _open.
113 """
114 jpeg_instance.__class__ = MpoImageFile
115 jpeg_instance._after_jpeg_open(mpheader)
116 return jpeg_instance
119# ---------------------------------------------------------------------
120# Registry stuff
122# Note that since MPO shares a factory with JPEG, we do not need to do a
123# separate registration for it here.
124# Image.register_open(MpoImageFile.format,
125# JpegImagePlugin.jpeg_factory, _accept)
126Image.register_save(MpoImageFile.format, _save)
128Image.register_extension(MpoImageFile.format, ".mpo")
130Image.register_mime(MpoImageFile.format, "image/mpo")