Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/PIL/WmfImagePlugin.py: 67%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

81 statements  

1# 

2# The Python Imaging Library 

3# $Id$ 

4# 

5# WMF stub codec 

6# 

7# history: 

8# 1996-12-14 fl Created 

9# 2004-02-22 fl Turned into a stub driver 

10# 2004-02-23 fl Added EMF support 

11# 

12# Copyright (c) Secret Labs AB 1997-2004. All rights reserved. 

13# Copyright (c) Fredrik Lundh 1996. 

14# 

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

16# 

17# WMF/EMF reference documentation: 

18# https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-WMF/[MS-WMF].pdf 

19# http://wvware.sourceforge.net/caolan/index.html 

20# http://wvware.sourceforge.net/caolan/ora-wmf.html 

21from __future__ import annotations 

22 

23from typing import IO 

24 

25from . import Image, ImageFile 

26from ._binary import i16le as word 

27from ._binary import si16le as short 

28from ._binary import si32le as _long 

29 

30_handler = None 

31 

32 

33def register_handler(handler: ImageFile.StubHandler | None) -> None: 

34 """ 

35 Install application-specific WMF image handler. 

36 

37 :param handler: Handler object. 

38 """ 

39 global _handler 

40 _handler = handler 

41 

42 

43if hasattr(Image.core, "drawwmf"): 

44 # install default handler (windows only) 

45 

46 class WmfHandler(ImageFile.StubHandler): 

47 def open(self, im: ImageFile.StubImageFile) -> None: 

48 im._mode = "RGB" 

49 self.bbox = im.info["wmf_bbox"] 

50 

51 def load(self, im: ImageFile.StubImageFile) -> Image.Image: 

52 im.fp.seek(0) # rewind 

53 return Image.frombytes( 

54 "RGB", 

55 im.size, 

56 Image.core.drawwmf(im.fp.read(), im.size, self.bbox), 

57 "raw", 

58 "BGR", 

59 (im.size[0] * 3 + 3) & -4, 

60 -1, 

61 ) 

62 

63 register_handler(WmfHandler()) 

64 

65# 

66# -------------------------------------------------------------------- 

67# Read WMF file 

68 

69 

70def _accept(prefix: bytes) -> bool: 

71 return prefix.startswith((b"\xd7\xcd\xc6\x9a\x00\x00", b"\x01\x00\x00\x00")) 

72 

73 

74## 

75# Image plugin for Windows metafiles. 

76 

77 

78class WmfStubImageFile(ImageFile.StubImageFile): 

79 format = "WMF" 

80 format_description = "Windows Metafile" 

81 

82 def _open(self) -> None: 

83 # check placable header 

84 s = self.fp.read(44) 

85 

86 if s.startswith(b"\xd7\xcd\xc6\x9a\x00\x00"): 

87 # placeable windows metafile 

88 

89 # get units per inch 

90 inch = word(s, 14) 

91 if inch == 0: 

92 msg = "Invalid inch" 

93 raise ValueError(msg) 

94 self._inch: tuple[float, float] = inch, inch 

95 

96 # get bounding box 

97 x0 = short(s, 6) 

98 y0 = short(s, 8) 

99 x1 = short(s, 10) 

100 y1 = short(s, 12) 

101 

102 # normalize size to 72 dots per inch 

103 self.info["dpi"] = 72 

104 size = ( 

105 (x1 - x0) * self.info["dpi"] // inch, 

106 (y1 - y0) * self.info["dpi"] // inch, 

107 ) 

108 

109 self.info["wmf_bbox"] = x0, y0, x1, y1 

110 

111 # sanity check (standard metafile header) 

112 if s[22:26] != b"\x01\x00\t\x00": 

113 msg = "Unsupported WMF file format" 

114 raise SyntaxError(msg) 

115 

116 elif s.startswith(b"\x01\x00\x00\x00") and s[40:44] == b" EMF": 

117 # enhanced metafile 

118 

119 # get bounding box 

120 x0 = _long(s, 8) 

121 y0 = _long(s, 12) 

122 x1 = _long(s, 16) 

123 y1 = _long(s, 20) 

124 

125 # get frame (in 0.01 millimeter units) 

126 frame = _long(s, 24), _long(s, 28), _long(s, 32), _long(s, 36) 

127 

128 size = x1 - x0, y1 - y0 

129 

130 # calculate dots per inch from bbox and frame 

131 xdpi = 2540.0 * (x1 - x0) / (frame[2] - frame[0]) 

132 ydpi = 2540.0 * (y1 - y0) / (frame[3] - frame[1]) 

133 

134 self.info["wmf_bbox"] = x0, y0, x1, y1 

135 

136 if xdpi == ydpi: 

137 self.info["dpi"] = xdpi 

138 else: 

139 self.info["dpi"] = xdpi, ydpi 

140 self._inch = xdpi, ydpi 

141 

142 else: 

143 msg = "Unsupported file format" 

144 raise SyntaxError(msg) 

145 

146 self._mode = "RGB" 

147 self._size = size 

148 

149 loader = self._load() 

150 if loader: 

151 loader.open(self) 

152 

153 def _load(self) -> ImageFile.StubHandler | None: 

154 return _handler 

155 

156 def load( 

157 self, dpi: float | tuple[float, float] | None = None 

158 ) -> Image.core.PixelAccess | None: 

159 if dpi is not None: 

160 self.info["dpi"] = dpi 

161 x0, y0, x1, y1 = self.info["wmf_bbox"] 

162 if not isinstance(dpi, tuple): 

163 dpi = dpi, dpi 

164 self._size = ( 

165 int((x1 - x0) * dpi[0] / self._inch[0]), 

166 int((y1 - y0) * dpi[1] / self._inch[1]), 

167 ) 

168 return super().load() 

169 

170 

171def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: 

172 if _handler is None or not hasattr(_handler, "save"): 

173 msg = "WMF save handler not installed" 

174 raise OSError(msg) 

175 _handler.save(im, fp, filename) 

176 

177 

178# 

179# -------------------------------------------------------------------- 

180# Registry stuff 

181 

182 

183Image.register_open(WmfStubImageFile.format, WmfStubImageFile, _accept) 

184Image.register_save(WmfStubImageFile.format, _save) 

185 

186Image.register_extensions(WmfStubImageFile.format, [".wmf", ".emf"])