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.

PalmImagePlugin.py 9.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. #
  2. # The Python Imaging Library.
  3. # $Id$
  4. #
  5. ##
  6. # Image plugin for Palm pixmap images (output only).
  7. ##
  8. from . import Image, ImageFile
  9. from ._binary import o8, o16be as o16b
  10. # __version__ is deprecated and will be removed in a future version. Use
  11. # PIL.__version__ instead.
  12. __version__ = "1.0"
  13. # fmt: off
  14. _Palm8BitColormapValues = ( # noqa: E131
  15. (255, 255, 255), (255, 204, 255), (255, 153, 255), (255, 102, 255),
  16. (255, 51, 255), (255, 0, 255), (255, 255, 204), (255, 204, 204),
  17. (255, 153, 204), (255, 102, 204), (255, 51, 204), (255, 0, 204),
  18. (255, 255, 153), (255, 204, 153), (255, 153, 153), (255, 102, 153),
  19. (255, 51, 153), (255, 0, 153), (204, 255, 255), (204, 204, 255),
  20. (204, 153, 255), (204, 102, 255), (204, 51, 255), (204, 0, 255),
  21. (204, 255, 204), (204, 204, 204), (204, 153, 204), (204, 102, 204),
  22. (204, 51, 204), (204, 0, 204), (204, 255, 153), (204, 204, 153),
  23. (204, 153, 153), (204, 102, 153), (204, 51, 153), (204, 0, 153),
  24. (153, 255, 255), (153, 204, 255), (153, 153, 255), (153, 102, 255),
  25. (153, 51, 255), (153, 0, 255), (153, 255, 204), (153, 204, 204),
  26. (153, 153, 204), (153, 102, 204), (153, 51, 204), (153, 0, 204),
  27. (153, 255, 153), (153, 204, 153), (153, 153, 153), (153, 102, 153),
  28. (153, 51, 153), (153, 0, 153), (102, 255, 255), (102, 204, 255),
  29. (102, 153, 255), (102, 102, 255), (102, 51, 255), (102, 0, 255),
  30. (102, 255, 204), (102, 204, 204), (102, 153, 204), (102, 102, 204),
  31. (102, 51, 204), (102, 0, 204), (102, 255, 153), (102, 204, 153),
  32. (102, 153, 153), (102, 102, 153), (102, 51, 153), (102, 0, 153),
  33. (51, 255, 255), (51, 204, 255), (51, 153, 255), (51, 102, 255),
  34. (51, 51, 255), (51, 0, 255), (51, 255, 204), (51, 204, 204),
  35. (51, 153, 204), (51, 102, 204), (51, 51, 204), (51, 0, 204),
  36. (51, 255, 153), (51, 204, 153), (51, 153, 153), (51, 102, 153),
  37. (51, 51, 153), (51, 0, 153), (0, 255, 255), (0, 204, 255),
  38. (0, 153, 255), (0, 102, 255), (0, 51, 255), (0, 0, 255),
  39. (0, 255, 204), (0, 204, 204), (0, 153, 204), (0, 102, 204),
  40. (0, 51, 204), (0, 0, 204), (0, 255, 153), (0, 204, 153),
  41. (0, 153, 153), (0, 102, 153), (0, 51, 153), (0, 0, 153),
  42. (255, 255, 102), (255, 204, 102), (255, 153, 102), (255, 102, 102),
  43. (255, 51, 102), (255, 0, 102), (255, 255, 51), (255, 204, 51),
  44. (255, 153, 51), (255, 102, 51), (255, 51, 51), (255, 0, 51),
  45. (255, 255, 0), (255, 204, 0), (255, 153, 0), (255, 102, 0),
  46. (255, 51, 0), (255, 0, 0), (204, 255, 102), (204, 204, 102),
  47. (204, 153, 102), (204, 102, 102), (204, 51, 102), (204, 0, 102),
  48. (204, 255, 51), (204, 204, 51), (204, 153, 51), (204, 102, 51),
  49. (204, 51, 51), (204, 0, 51), (204, 255, 0), (204, 204, 0),
  50. (204, 153, 0), (204, 102, 0), (204, 51, 0), (204, 0, 0),
  51. (153, 255, 102), (153, 204, 102), (153, 153, 102), (153, 102, 102),
  52. (153, 51, 102), (153, 0, 102), (153, 255, 51), (153, 204, 51),
  53. (153, 153, 51), (153, 102, 51), (153, 51, 51), (153, 0, 51),
  54. (153, 255, 0), (153, 204, 0), (153, 153, 0), (153, 102, 0),
  55. (153, 51, 0), (153, 0, 0), (102, 255, 102), (102, 204, 102),
  56. (102, 153, 102), (102, 102, 102), (102, 51, 102), (102, 0, 102),
  57. (102, 255, 51), (102, 204, 51), (102, 153, 51), (102, 102, 51),
  58. (102, 51, 51), (102, 0, 51), (102, 255, 0), (102, 204, 0),
  59. (102, 153, 0), (102, 102, 0), (102, 51, 0), (102, 0, 0),
  60. (51, 255, 102), (51, 204, 102), (51, 153, 102), (51, 102, 102),
  61. (51, 51, 102), (51, 0, 102), (51, 255, 51), (51, 204, 51),
  62. (51, 153, 51), (51, 102, 51), (51, 51, 51), (51, 0, 51),
  63. (51, 255, 0), (51, 204, 0), (51, 153, 0), (51, 102, 0),
  64. (51, 51, 0), (51, 0, 0), (0, 255, 102), (0, 204, 102),
  65. (0, 153, 102), (0, 102, 102), (0, 51, 102), (0, 0, 102),
  66. (0, 255, 51), (0, 204, 51), (0, 153, 51), (0, 102, 51),
  67. (0, 51, 51), (0, 0, 51), (0, 255, 0), (0, 204, 0),
  68. (0, 153, 0), (0, 102, 0), (0, 51, 0), (17, 17, 17),
  69. (34, 34, 34), (68, 68, 68), (85, 85, 85), (119, 119, 119),
  70. (136, 136, 136), (170, 170, 170), (187, 187, 187), (221, 221, 221),
  71. (238, 238, 238), (192, 192, 192), (128, 0, 0), (128, 0, 128),
  72. (0, 128, 0), (0, 128, 128), (0, 0, 0), (0, 0, 0),
  73. (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0),
  74. (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0),
  75. (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0),
  76. (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0),
  77. (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0),
  78. (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0))
  79. # fmt: on
  80. # so build a prototype image to be used for palette resampling
  81. def build_prototype_image():
  82. image = Image.new("L", (1, len(_Palm8BitColormapValues)))
  83. image.putdata(list(range(len(_Palm8BitColormapValues))))
  84. palettedata = ()
  85. for colormapValue in _Palm8BitColormapValues:
  86. palettedata += colormapValue
  87. palettedata += (0, 0, 0) * (256 - len(_Palm8BitColormapValues))
  88. image.putpalette(palettedata)
  89. return image
  90. Palm8BitColormapImage = build_prototype_image()
  91. # OK, we now have in Palm8BitColormapImage,
  92. # a "P"-mode image with the right palette
  93. #
  94. # --------------------------------------------------------------------
  95. _FLAGS = {"custom-colormap": 0x4000, "is-compressed": 0x8000, "has-transparent": 0x2000}
  96. _COMPRESSION_TYPES = {"none": 0xFF, "rle": 0x01, "scanline": 0x00}
  97. #
  98. # --------------------------------------------------------------------
  99. ##
  100. # (Internal) Image save plugin for the Palm format.
  101. def _save(im, fp, filename):
  102. if im.mode == "P":
  103. # we assume this is a color Palm image with the standard colormap,
  104. # unless the "info" dict has a "custom-colormap" field
  105. rawmode = "P"
  106. bpp = 8
  107. version = 1
  108. elif im.mode == "L":
  109. if im.encoderinfo.get("bpp") in (1, 2, 4):
  110. # this is 8-bit grayscale, so we shift it to get the high-order bits,
  111. # and invert it because
  112. # Palm does greyscale from white (0) to black (1)
  113. bpp = im.encoderinfo["bpp"]
  114. im = im.point(
  115. lambda x, shift=8 - bpp, maxval=(1 << bpp) - 1: maxval - (x >> shift)
  116. )
  117. elif im.info.get("bpp") in (1, 2, 4):
  118. # here we assume that even though the inherent mode is 8-bit grayscale,
  119. # only the lower bpp bits are significant.
  120. # We invert them to match the Palm.
  121. bpp = im.info["bpp"]
  122. im = im.point(lambda x, maxval=(1 << bpp) - 1: maxval - (x & maxval))
  123. else:
  124. raise IOError("cannot write mode %s as Palm" % im.mode)
  125. # we ignore the palette here
  126. im.mode = "P"
  127. rawmode = "P;" + str(bpp)
  128. version = 1
  129. elif im.mode == "1":
  130. # monochrome -- write it inverted, as is the Palm standard
  131. rawmode = "1;I"
  132. bpp = 1
  133. version = 0
  134. else:
  135. raise IOError("cannot write mode %s as Palm" % im.mode)
  136. #
  137. # make sure image data is available
  138. im.load()
  139. # write header
  140. cols = im.size[0]
  141. rows = im.size[1]
  142. rowbytes = int((cols + (16 // bpp - 1)) / (16 // bpp)) * 2
  143. transparent_index = 0
  144. compression_type = _COMPRESSION_TYPES["none"]
  145. flags = 0
  146. if im.mode == "P" and "custom-colormap" in im.info:
  147. flags = flags & _FLAGS["custom-colormap"]
  148. colormapsize = 4 * 256 + 2
  149. colormapmode = im.palette.mode
  150. colormap = im.getdata().getpalette()
  151. else:
  152. colormapsize = 0
  153. if "offset" in im.info:
  154. offset = (rowbytes * rows + 16 + 3 + colormapsize) // 4
  155. else:
  156. offset = 0
  157. fp.write(o16b(cols) + o16b(rows) + o16b(rowbytes) + o16b(flags))
  158. fp.write(o8(bpp))
  159. fp.write(o8(version))
  160. fp.write(o16b(offset))
  161. fp.write(o8(transparent_index))
  162. fp.write(o8(compression_type))
  163. fp.write(o16b(0)) # reserved by Palm
  164. # now write colormap if necessary
  165. if colormapsize > 0:
  166. fp.write(o16b(256))
  167. for i in range(256):
  168. fp.write(o8(i))
  169. if colormapmode == "RGB":
  170. fp.write(
  171. o8(colormap[3 * i])
  172. + o8(colormap[3 * i + 1])
  173. + o8(colormap[3 * i + 2])
  174. )
  175. elif colormapmode == "RGBA":
  176. fp.write(
  177. o8(colormap[4 * i])
  178. + o8(colormap[4 * i + 1])
  179. + o8(colormap[4 * i + 2])
  180. )
  181. # now convert data to raw form
  182. ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, rowbytes, 1))])
  183. if hasattr(fp, "flush"):
  184. fp.flush()
  185. #
  186. # --------------------------------------------------------------------
  187. Image.register_save("Palm", _save)
  188. Image.register_extension("Palm", ".palm")
  189. Image.register_mime("Palm", "image/palm")