PpmImagePlugin.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. #
  2. # The Python Imaging Library.
  3. # $Id$
  4. #
  5. # PPM support for PIL
  6. #
  7. # History:
  8. # 96-03-24 fl Created
  9. # 98-03-06 fl Write RGBA images (as RGB, that is)
  10. #
  11. # Copyright (c) Secret Labs AB 1997-98.
  12. # Copyright (c) Fredrik Lundh 1996.
  13. #
  14. # See the README file for information on usage and redistribution.
  15. #
  16. from . import Image, ImageFile
  17. # __version__ is deprecated and will be removed in a future version. Use
  18. # PIL.__version__ instead.
  19. __version__ = "0.2"
  20. #
  21. # --------------------------------------------------------------------
  22. b_whitespace = b"\x20\x09\x0a\x0b\x0c\x0d"
  23. MODES = {
  24. # standard
  25. b"P4": "1",
  26. b"P5": "L",
  27. b"P6": "RGB",
  28. # extensions
  29. b"P0CMYK": "CMYK",
  30. # PIL extensions (for test purposes only)
  31. b"PyP": "P",
  32. b"PyRGBA": "RGBA",
  33. b"PyCMYK": "CMYK",
  34. }
  35. def _accept(prefix):
  36. return prefix[0:1] == b"P" and prefix[1] in b"0456y"
  37. ##
  38. # Image plugin for PBM, PGM, and PPM images.
  39. class PpmImageFile(ImageFile.ImageFile):
  40. format = "PPM"
  41. format_description = "Pbmplus image"
  42. def _token(self, s=b""):
  43. while True: # read until next whitespace
  44. c = self.fp.read(1)
  45. if not c or c in b_whitespace:
  46. break
  47. if c > b"\x79":
  48. raise ValueError("Expected ASCII value, found binary")
  49. s = s + c
  50. if len(s) > 9:
  51. raise ValueError("Expected int, got > 9 digits")
  52. return s
  53. def _open(self):
  54. # check magic
  55. s = self.fp.read(1)
  56. if s != b"P":
  57. raise SyntaxError("not a PPM file")
  58. magic_number = self._token(s)
  59. mode = MODES[magic_number]
  60. self.custom_mimetype = {
  61. b"P4": "image/x-portable-bitmap",
  62. b"P5": "image/x-portable-graymap",
  63. b"P6": "image/x-portable-pixmap",
  64. }.get(magic_number)
  65. if mode == "1":
  66. self.mode = "1"
  67. rawmode = "1;I"
  68. else:
  69. self.mode = rawmode = mode
  70. for ix in range(3):
  71. while True:
  72. while True:
  73. s = self.fp.read(1)
  74. if s not in b_whitespace:
  75. break
  76. if s == b"":
  77. raise ValueError("File does not extend beyond magic number")
  78. if s != b"#":
  79. break
  80. s = self.fp.readline()
  81. s = int(self._token(s))
  82. if ix == 0:
  83. xsize = s
  84. elif ix == 1:
  85. ysize = s
  86. if mode == "1":
  87. break
  88. elif ix == 2:
  89. # maxgrey
  90. if s > 255:
  91. if not mode == "L":
  92. raise ValueError("Too many colors for band: %s" % s)
  93. if s < 2 ** 16:
  94. self.mode = "I"
  95. rawmode = "I;16B"
  96. else:
  97. self.mode = "I"
  98. rawmode = "I;32B"
  99. self._size = xsize, ysize
  100. self.tile = [("raw", (0, 0, xsize, ysize), self.fp.tell(), (rawmode, 0, 1))]
  101. #
  102. # --------------------------------------------------------------------
  103. def _save(im, fp, filename):
  104. if im.mode == "1":
  105. rawmode, head = "1;I", b"P4"
  106. elif im.mode == "L":
  107. rawmode, head = "L", b"P5"
  108. elif im.mode == "I":
  109. if im.getextrema()[1] < 2 ** 16:
  110. rawmode, head = "I;16B", b"P5"
  111. else:
  112. rawmode, head = "I;32B", b"P5"
  113. elif im.mode == "RGB":
  114. rawmode, head = "RGB", b"P6"
  115. elif im.mode == "RGBA":
  116. rawmode, head = "RGB", b"P6"
  117. else:
  118. raise IOError("cannot write mode %s as PPM" % im.mode)
  119. fp.write(head + ("\n%d %d\n" % im.size).encode("ascii"))
  120. if head == b"P6":
  121. fp.write(b"255\n")
  122. if head == b"P5":
  123. if rawmode == "L":
  124. fp.write(b"255\n")
  125. elif rawmode == "I;16B":
  126. fp.write(b"65535\n")
  127. elif rawmode == "I;32B":
  128. fp.write(b"2147483648\n")
  129. ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))])
  130. # ALTERNATIVE: save via builtin debug function
  131. # im._dump(filename)
  132. #
  133. # --------------------------------------------------------------------
  134. Image.register_open(PpmImageFile.format, PpmImageFile, _accept)
  135. Image.register_save(PpmImageFile.format, _save)
  136. Image.register_extensions(PpmImageFile.format, [".pbm", ".pgm", ".ppm", ".pnm"])
  137. Image.register_mime(PpmImageFile.format, "image/x-portable-anymap")