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.

158 lines
4.1 KiB

4 years ago
  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__ = "0.2"
  18. #
  19. # --------------------------------------------------------------------
  20. b_whitespace = b'\x20\x09\x0a\x0b\x0c\x0d'
  21. MODES = {
  22. # standard
  23. b"P4": "1",
  24. b"P5": "L",
  25. b"P6": "RGB",
  26. # extensions
  27. b"P0CMYK": "CMYK",
  28. # PIL extensions (for test purposes only)
  29. b"PyP": "P",
  30. b"PyRGBA": "RGBA",
  31. b"PyCMYK": "CMYK"
  32. }
  33. def _accept(prefix):
  34. return prefix[0:1] == b"P" and prefix[1] in b"0456y"
  35. ##
  36. # Image plugin for PBM, PGM, and PPM images.
  37. class PpmImageFile(ImageFile.ImageFile):
  38. format = "PPM"
  39. format_description = "Pbmplus image"
  40. def _token(self, s=b""):
  41. while True: # read until next whitespace
  42. c = self.fp.read(1)
  43. if not c or c in b_whitespace:
  44. break
  45. if c > b'\x79':
  46. raise ValueError("Expected ASCII value, found binary")
  47. s = s + c
  48. if (len(s) > 9):
  49. raise ValueError("Expected int, got > 9 digits")
  50. return s
  51. def _open(self):
  52. # check magic
  53. s = self.fp.read(1)
  54. if s != b"P":
  55. raise SyntaxError("not a PPM file")
  56. mode = MODES[self._token(s)]
  57. if mode == "1":
  58. self.mode = "1"
  59. rawmode = "1;I"
  60. else:
  61. self.mode = rawmode = mode
  62. for ix in range(3):
  63. while True:
  64. while True:
  65. s = self.fp.read(1)
  66. if s not in b_whitespace:
  67. break
  68. if s == b"":
  69. raise ValueError(
  70. "File does not extend beyond magic number")
  71. if s != b"#":
  72. break
  73. s = self.fp.readline()
  74. s = int(self._token(s))
  75. if ix == 0:
  76. xsize = s
  77. elif ix == 1:
  78. ysize = s
  79. if mode == "1":
  80. break
  81. elif ix == 2:
  82. # maxgrey
  83. if s > 255:
  84. if not mode == 'L':
  85. raise ValueError("Too many colors for band: %s" % s)
  86. if s < 2**16:
  87. self.mode = 'I'
  88. rawmode = 'I;16B'
  89. else:
  90. self.mode = 'I'
  91. rawmode = 'I;32B'
  92. self._size = xsize, ysize
  93. self.tile = [("raw",
  94. (0, 0, xsize, ysize),
  95. self.fp.tell(),
  96. (rawmode, 0, 1))]
  97. #
  98. # --------------------------------------------------------------------
  99. def _save(im, fp, filename):
  100. if im.mode == "1":
  101. rawmode, head = "1;I", b"P4"
  102. elif im.mode == "L":
  103. rawmode, head = "L", b"P5"
  104. elif im.mode == "I":
  105. if im.getextrema()[1] < 2**16:
  106. rawmode, head = "I;16B", b"P5"
  107. else:
  108. rawmode, head = "I;32B", b"P5"
  109. elif im.mode == "RGB":
  110. rawmode, head = "RGB", b"P6"
  111. elif im.mode == "RGBA":
  112. rawmode, head = "RGB", b"P6"
  113. else:
  114. raise IOError("cannot write mode %s as PPM" % im.mode)
  115. fp.write(head + ("\n%d %d\n" % im.size).encode('ascii'))
  116. if head == b"P6":
  117. fp.write(b"255\n")
  118. if head == b"P5":
  119. if rawmode == "L":
  120. fp.write(b"255\n")
  121. elif rawmode == "I;16B":
  122. fp.write(b"65535\n")
  123. elif rawmode == "I;32B":
  124. fp.write(b"2147483648\n")
  125. ImageFile._save(im, fp, [("raw", (0, 0)+im.size, 0, (rawmode, 0, 1))])
  126. # ALTERNATIVE: save via builtin debug function
  127. # im._dump(filename)
  128. #
  129. # --------------------------------------------------------------------
  130. Image.register_open(PpmImageFile.format, PpmImageFile, _accept)
  131. Image.register_save(PpmImageFile.format, _save)
  132. Image.register_extensions(PpmImageFile.format, [".pbm", ".pgm", ".ppm"])