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.

169 lines
4.1 KiB

4 years ago
  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
  21. from __future__ import print_function
  22. from . import Image, ImageFile
  23. from ._binary import i16le as word, si16le as short, \
  24. i32le as dword, si32le as _long
  25. from ._util import py3
  26. __version__ = "0.2"
  27. _handler = None
  28. if py3:
  29. long = int
  30. def register_handler(handler):
  31. """
  32. Install application-specific WMF image handler.
  33. :param handler: Handler object.
  34. """
  35. global _handler
  36. _handler = handler
  37. if hasattr(Image.core, "drawwmf"):
  38. # install default handler (windows only)
  39. class WmfHandler(object):
  40. def open(self, im):
  41. im.mode = "RGB"
  42. self.bbox = im.info["wmf_bbox"]
  43. def load(self, im):
  44. im.fp.seek(0) # rewind
  45. return Image.frombytes(
  46. "RGB", im.size,
  47. Image.core.drawwmf(im.fp.read(), im.size, self.bbox),
  48. "raw", "BGR", (im.size[0]*3 + 3) & -4, -1
  49. )
  50. register_handler(WmfHandler())
  51. #
  52. # --------------------------------------------------------------------
  53. # Read WMF file
  54. def _accept(prefix):
  55. return (
  56. prefix[:6] == b"\xd7\xcd\xc6\x9a\x00\x00" or
  57. prefix[:4] == b"\x01\x00\x00\x00"
  58. )
  59. ##
  60. # Image plugin for Windows metafiles.
  61. class WmfStubImageFile(ImageFile.StubImageFile):
  62. format = "WMF"
  63. format_description = "Windows Metafile"
  64. def _open(self):
  65. # check placable header
  66. s = self.fp.read(80)
  67. if s[:6] == b"\xd7\xcd\xc6\x9a\x00\x00":
  68. # placeable windows metafile
  69. # get units per inch
  70. inch = word(s, 14)
  71. # get bounding box
  72. x0 = short(s, 6)
  73. y0 = short(s, 8)
  74. x1 = short(s, 10)
  75. y1 = short(s, 12)
  76. # normalize size to 72 dots per inch
  77. size = (x1 - x0) * 72 // inch, (y1 - y0) * 72 // inch
  78. self.info["wmf_bbox"] = x0, y0, x1, y1
  79. self.info["dpi"] = 72
  80. # sanity check (standard metafile header)
  81. if s[22:26] != b"\x01\x00\t\x00":
  82. raise SyntaxError("Unsupported WMF file format")
  83. elif dword(s) == 1 and s[40:44] == b" EMF":
  84. # enhanced metafile
  85. # get bounding box
  86. x0 = _long(s, 8)
  87. y0 = _long(s, 12)
  88. x1 = _long(s, 16)
  89. y1 = _long(s, 20)
  90. # get frame (in 0.01 millimeter units)
  91. frame = _long(s, 24), _long(s, 28), _long(s, 32), _long(s, 36)
  92. # normalize size to 72 dots per inch
  93. size = x1 - x0, y1 - y0
  94. # calculate dots per inch from bbox and frame
  95. xdpi = 2540 * (x1 - y0) // (frame[2] - frame[0])
  96. ydpi = 2540 * (y1 - y0) // (frame[3] - frame[1])
  97. self.info["wmf_bbox"] = x0, y0, x1, y1
  98. if xdpi == ydpi:
  99. self.info["dpi"] = xdpi
  100. else:
  101. self.info["dpi"] = xdpi, ydpi
  102. else:
  103. raise SyntaxError("Unsupported file format")
  104. self.mode = "RGB"
  105. self._size = size
  106. loader = self._load()
  107. if loader:
  108. loader.open(self)
  109. def _load(self):
  110. return _handler
  111. def _save(im, fp, filename):
  112. if _handler is None or not hasattr(_handler, "save"):
  113. raise IOError("WMF save handler not installed")
  114. _handler.save(im, fp, filename)
  115. #
  116. # --------------------------------------------------------------------
  117. # Registry stuff
  118. Image.register_open(WmfStubImageFile.format, WmfStubImageFile, _accept)
  119. Image.register_save(WmfStubImageFile.format, _save)
  120. Image.register_extensions(WmfStubImageFile.format, [".wmf", ".emf"])