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.

99 lines
2.9 KiB

4 years ago
  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. #
  20. from . import Image, JpegImagePlugin
  21. __version__ = "0.1"
  22. def _accept(prefix):
  23. return JpegImagePlugin._accept(prefix)
  24. def _save(im, fp, filename):
  25. # Note that we can only save the current frame at present
  26. return JpegImagePlugin._save(im, fp, filename)
  27. ##
  28. # Image plugin for MPO images.
  29. class MpoImageFile(JpegImagePlugin.JpegImageFile):
  30. format = "MPO"
  31. format_description = "MPO (CIPA DC-007)"
  32. _close_exclusive_fp_after_loading = False
  33. def _open(self):
  34. self.fp.seek(0) # prep the fp in order to pass the JPEG test
  35. JpegImagePlugin.JpegImageFile._open(self)
  36. self.mpinfo = self._getmp()
  37. self.__framecount = self.mpinfo[0xB001]
  38. self.__mpoffsets = [mpent['DataOffset'] + self.info['mpoffset']
  39. for mpent in self.mpinfo[0xB002]]
  40. self.__mpoffsets[0] = 0
  41. # Note that the following assertion will only be invalid if something
  42. # gets broken within JpegImagePlugin.
  43. assert self.__framecount == len(self.__mpoffsets)
  44. del self.info['mpoffset'] # no longer needed
  45. self.__fp = self.fp # FIXME: hack
  46. self.__fp.seek(self.__mpoffsets[0]) # get ready to read first frame
  47. self.__frame = 0
  48. self.offset = 0
  49. # for now we can only handle reading and individual frame extraction
  50. self.readonly = 1
  51. def load_seek(self, pos):
  52. self.__fp.seek(pos)
  53. @property
  54. def n_frames(self):
  55. return self.__framecount
  56. @property
  57. def is_animated(self):
  58. return self.__framecount > 1
  59. def seek(self, frame):
  60. if not self._seek_check(frame):
  61. return
  62. self.fp = self.__fp
  63. self.offset = self.__mpoffsets[frame]
  64. self.tile = [
  65. ("jpeg", (0, 0) + self.size, self.offset, (self.mode, ""))
  66. ]
  67. self.__frame = frame
  68. def tell(self):
  69. return self.__frame
  70. # ---------------------------------------------------------------------
  71. # Registry stuff
  72. # Note that since MPO shares a factory with JPEG, we do not need to do a
  73. # separate registration for it here.
  74. # Image.register_open(MpoImageFile.format,
  75. # JpegImagePlugin.jpeg_factory, _accept)
  76. Image.register_save(MpoImageFile.format, _save)
  77. Image.register_extension(MpoImageFile.format, ".mpo")
  78. Image.register_mime(MpoImageFile.format, "image/mpo")