1#
2# The Python Imaging Library.
3# $Id$
4#
5# Microsoft Image Composer support for PIL
6#
7# Notes:
8# uses TiffImagePlugin.py to read the actual image streams
9#
10# History:
11# 97-01-20 fl Created
12#
13# Copyright (c) Secret Labs AB 1997.
14# Copyright (c) Fredrik Lundh 1997.
15#
16# See the README file for information on usage and redistribution.
17#
18from __future__ import annotations
19
20import olefile
21
22from . import Image, TiffImagePlugin
23
24#
25# --------------------------------------------------------------------
26
27
28def _accept(prefix: bytes) -> bool:
29 return prefix[:8] == olefile.MAGIC
30
31
32##
33# Image plugin for Microsoft's Image Composer file format.
34
35
36class MicImageFile(TiffImagePlugin.TiffImageFile):
37 format = "MIC"
38 format_description = "Microsoft Image Composer"
39 _close_exclusive_fp_after_loading = False
40
41 def _open(self) -> None:
42 # read the OLE directory and see if this is a likely
43 # to be a Microsoft Image Composer file
44
45 try:
46 self.ole = olefile.OleFileIO(self.fp)
47 except OSError as e:
48 msg = "not an MIC file; invalid OLE file"
49 raise SyntaxError(msg) from e
50
51 # find ACI subfiles with Image members (maybe not the
52 # best way to identify MIC files, but what the... ;-)
53
54 self.images = [
55 path
56 for path in self.ole.listdir()
57 if path[1:] and path[0][-4:] == ".ACI" and path[1] == "Image"
58 ]
59
60 # if we didn't find any images, this is probably not
61 # an MIC file.
62 if not self.images:
63 msg = "not an MIC file; no image entries"
64 raise SyntaxError(msg)
65
66 self.frame = -1
67 self._n_frames = len(self.images)
68 self.is_animated = self._n_frames > 1
69
70 self.__fp = self.fp
71 self.seek(0)
72
73 def seek(self, frame):
74 if not self._seek_check(frame):
75 return
76 try:
77 filename = self.images[frame]
78 except IndexError as e:
79 msg = "no such frame"
80 raise EOFError(msg) from e
81
82 self.fp = self.ole.openstream(filename)
83
84 TiffImagePlugin.TiffImageFile._open(self)
85
86 self.frame = frame
87
88 def tell(self) -> int:
89 return self.frame
90
91 def close(self) -> None:
92 self.__fp.close()
93 self.ole.close()
94 super().close()
95
96 def __exit__(self, *args: object) -> None:
97 self.__fp.close()
98 self.ole.close()
99 super().__exit__()
100
101
102#
103# --------------------------------------------------------------------
104
105Image.register_open(MicImageFile.format, MicImageFile, _accept)
106
107Image.register_extension(MicImageFile.format, ".mic")