@ai-ecoverse/py-pillow 12.3.0-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/LICENSE +30 -0
  2. package/README.md +4 -0
  3. package/lib/python3.14/site-packages/PIL/AvifImagePlugin.py +295 -0
  4. package/lib/python3.14/site-packages/PIL/BdfFontFile.py +124 -0
  5. package/lib/python3.14/site-packages/PIL/BlpImagePlugin.py +498 -0
  6. package/lib/python3.14/site-packages/PIL/BmpImagePlugin.py +514 -0
  7. package/lib/python3.14/site-packages/PIL/BufrStubImagePlugin.py +72 -0
  8. package/lib/python3.14/site-packages/PIL/ContainerIO.py +173 -0
  9. package/lib/python3.14/site-packages/PIL/CurImagePlugin.py +103 -0
  10. package/lib/python3.14/site-packages/PIL/DcxImagePlugin.py +84 -0
  11. package/lib/python3.14/site-packages/PIL/DdsImagePlugin.py +632 -0
  12. package/lib/python3.14/site-packages/PIL/EpsImagePlugin.py +484 -0
  13. package/lib/python3.14/site-packages/PIL/ExifTags.py +384 -0
  14. package/lib/python3.14/site-packages/PIL/FitsImagePlugin.py +153 -0
  15. package/lib/python3.14/site-packages/PIL/FliImagePlugin.py +184 -0
  16. package/lib/python3.14/site-packages/PIL/FontFile.py +160 -0
  17. package/lib/python3.14/site-packages/PIL/FpxImagePlugin.py +262 -0
  18. package/lib/python3.14/site-packages/PIL/FtexImagePlugin.py +115 -0
  19. package/lib/python3.14/site-packages/PIL/GbrImagePlugin.py +103 -0
  20. package/lib/python3.14/site-packages/PIL/GdImageFile.py +104 -0
  21. package/lib/python3.14/site-packages/PIL/GifImagePlugin.py +1223 -0
  22. package/lib/python3.14/site-packages/PIL/GimpGradientFile.py +154 -0
  23. package/lib/python3.14/site-packages/PIL/GimpPaletteFile.py +75 -0
  24. package/lib/python3.14/site-packages/PIL/GribStubImagePlugin.py +72 -0
  25. package/lib/python3.14/site-packages/PIL/Hdf5StubImagePlugin.py +72 -0
  26. package/lib/python3.14/site-packages/PIL/IcnsImagePlugin.py +401 -0
  27. package/lib/python3.14/site-packages/PIL/IcoImagePlugin.py +396 -0
  28. package/lib/python3.14/site-packages/PIL/ImImagePlugin.py +390 -0
  29. package/lib/python3.14/site-packages/PIL/Image.py +4385 -0
  30. package/lib/python3.14/site-packages/PIL/ImageChops.py +311 -0
  31. package/lib/python3.14/site-packages/PIL/ImageCms.py +1078 -0
  32. package/lib/python3.14/site-packages/PIL/ImageColor.py +320 -0
  33. package/lib/python3.14/site-packages/PIL/ImageDraw.py +1002 -0
  34. package/lib/python3.14/site-packages/PIL/ImageDraw2.py +244 -0
  35. package/lib/python3.14/site-packages/PIL/ImageEnhance.py +113 -0
  36. package/lib/python3.14/site-packages/PIL/ImageFile.py +938 -0
  37. package/lib/python3.14/site-packages/PIL/ImageFilter.py +617 -0
  38. package/lib/python3.14/site-packages/PIL/ImageFont.py +1330 -0
  39. package/lib/python3.14/site-packages/PIL/ImageGrab.py +234 -0
  40. package/lib/python3.14/site-packages/PIL/ImageMath.py +314 -0
  41. package/lib/python3.14/site-packages/PIL/ImageMode.py +85 -0
  42. package/lib/python3.14/site-packages/PIL/ImageMorph.py +317 -0
  43. package/lib/python3.14/site-packages/PIL/ImageOps.py +749 -0
  44. package/lib/python3.14/site-packages/PIL/ImagePalette.py +290 -0
  45. package/lib/python3.14/site-packages/PIL/ImagePath.py +20 -0
  46. package/lib/python3.14/site-packages/PIL/ImageQt.py +219 -0
  47. package/lib/python3.14/site-packages/PIL/ImageSequence.py +88 -0
  48. package/lib/python3.14/site-packages/PIL/ImageShow.py +367 -0
  49. package/lib/python3.14/site-packages/PIL/ImageStat.py +167 -0
  50. package/lib/python3.14/site-packages/PIL/ImageText.py +509 -0
  51. package/lib/python3.14/site-packages/PIL/ImageTk.py +266 -0
  52. package/lib/python3.14/site-packages/PIL/ImageTransform.py +136 -0
  53. package/lib/python3.14/site-packages/PIL/ImageWin.py +247 -0
  54. package/lib/python3.14/site-packages/PIL/ImtImagePlugin.py +103 -0
  55. package/lib/python3.14/site-packages/PIL/IptcImagePlugin.py +226 -0
  56. package/lib/python3.14/site-packages/PIL/Jpeg2KImagePlugin.py +466 -0
  57. package/lib/python3.14/site-packages/PIL/JpegImagePlugin.py +889 -0
  58. package/lib/python3.14/site-packages/PIL/JpegPresets.py +242 -0
  59. package/lib/python3.14/site-packages/PIL/McIdasImagePlugin.py +78 -0
  60. package/lib/python3.14/site-packages/PIL/MicImagePlugin.py +103 -0
  61. package/lib/python3.14/site-packages/PIL/MpegImagePlugin.py +84 -0
  62. package/lib/python3.14/site-packages/PIL/MpoImagePlugin.py +203 -0
  63. package/lib/python3.14/site-packages/PIL/MspImagePlugin.py +200 -0
  64. package/lib/python3.14/site-packages/PIL/PSDraw.py +238 -0
  65. package/lib/python3.14/site-packages/PIL/PaletteFile.py +54 -0
  66. package/lib/python3.14/site-packages/PIL/PalmImagePlugin.py +217 -0
  67. package/lib/python3.14/site-packages/PIL/PcdImagePlugin.py +68 -0
  68. package/lib/python3.14/site-packages/PIL/PcfFontFile.py +256 -0
  69. package/lib/python3.14/site-packages/PIL/PcxImagePlugin.py +232 -0
  70. package/lib/python3.14/site-packages/PIL/PdfImagePlugin.py +315 -0
  71. package/lib/python3.14/site-packages/PIL/PdfParser.py +1092 -0
  72. package/lib/python3.14/site-packages/PIL/PixarImagePlugin.py +72 -0
  73. package/lib/python3.14/site-packages/PIL/PngImagePlugin.py +1578 -0
  74. package/lib/python3.14/site-packages/PIL/PpmImagePlugin.py +375 -0
  75. package/lib/python3.14/site-packages/PIL/PsdImagePlugin.py +339 -0
  76. package/lib/python3.14/site-packages/PIL/QoiImagePlugin.py +235 -0
  77. package/lib/python3.14/site-packages/PIL/SgiImagePlugin.py +231 -0
  78. package/lib/python3.14/site-packages/PIL/SpiderImagePlugin.py +332 -0
  79. package/lib/python3.14/site-packages/PIL/SunImagePlugin.py +145 -0
  80. package/lib/python3.14/site-packages/PIL/TarIO.py +61 -0
  81. package/lib/python3.14/site-packages/PIL/TgaImagePlugin.py +284 -0
  82. package/lib/python3.14/site-packages/PIL/TiffImagePlugin.py +2354 -0
  83. package/lib/python3.14/site-packages/PIL/TiffTags.py +566 -0
  84. package/lib/python3.14/site-packages/PIL/WalImageFile.py +129 -0
  85. package/lib/python3.14/site-packages/PIL/WebPImagePlugin.py +322 -0
  86. package/lib/python3.14/site-packages/PIL/WmfImagePlugin.py +183 -0
  87. package/lib/python3.14/site-packages/PIL/XVThumbImagePlugin.py +83 -0
  88. package/lib/python3.14/site-packages/PIL/XbmImagePlugin.py +98 -0
  89. package/lib/python3.14/site-packages/PIL/XpmImagePlugin.py +157 -0
  90. package/lib/python3.14/site-packages/PIL/__init__.py +87 -0
  91. package/lib/python3.14/site-packages/PIL/__main__.py +7 -0
  92. package/lib/python3.14/site-packages/PIL/__pycache__/AvifImagePlugin.cpython-314.pyc +0 -0
  93. package/lib/python3.14/site-packages/PIL/__pycache__/BdfFontFile.cpython-314.pyc +0 -0
  94. package/lib/python3.14/site-packages/PIL/__pycache__/BlpImagePlugin.cpython-314.pyc +0 -0
  95. package/lib/python3.14/site-packages/PIL/__pycache__/BmpImagePlugin.cpython-314.pyc +0 -0
  96. package/lib/python3.14/site-packages/PIL/__pycache__/BufrStubImagePlugin.cpython-314.pyc +0 -0
  97. package/lib/python3.14/site-packages/PIL/__pycache__/ContainerIO.cpython-314.pyc +0 -0
  98. package/lib/python3.14/site-packages/PIL/__pycache__/CurImagePlugin.cpython-314.pyc +0 -0
  99. package/lib/python3.14/site-packages/PIL/__pycache__/DcxImagePlugin.cpython-314.pyc +0 -0
  100. package/lib/python3.14/site-packages/PIL/__pycache__/DdsImagePlugin.cpython-314.pyc +0 -0
  101. package/lib/python3.14/site-packages/PIL/__pycache__/EpsImagePlugin.cpython-314.pyc +0 -0
  102. package/lib/python3.14/site-packages/PIL/__pycache__/ExifTags.cpython-314.pyc +0 -0
  103. package/lib/python3.14/site-packages/PIL/__pycache__/FitsImagePlugin.cpython-314.pyc +0 -0
  104. package/lib/python3.14/site-packages/PIL/__pycache__/FliImagePlugin.cpython-314.pyc +0 -0
  105. package/lib/python3.14/site-packages/PIL/__pycache__/FontFile.cpython-314.pyc +0 -0
  106. package/lib/python3.14/site-packages/PIL/__pycache__/FpxImagePlugin.cpython-314.pyc +0 -0
  107. package/lib/python3.14/site-packages/PIL/__pycache__/FtexImagePlugin.cpython-314.pyc +0 -0
  108. package/lib/python3.14/site-packages/PIL/__pycache__/GbrImagePlugin.cpython-314.pyc +0 -0
  109. package/lib/python3.14/site-packages/PIL/__pycache__/GdImageFile.cpython-314.pyc +0 -0
  110. package/lib/python3.14/site-packages/PIL/__pycache__/GifImagePlugin.cpython-314.pyc +0 -0
  111. package/lib/python3.14/site-packages/PIL/__pycache__/GimpGradientFile.cpython-314.pyc +0 -0
  112. package/lib/python3.14/site-packages/PIL/__pycache__/GimpPaletteFile.cpython-314.pyc +0 -0
  113. package/lib/python3.14/site-packages/PIL/__pycache__/GribStubImagePlugin.cpython-314.pyc +0 -0
  114. package/lib/python3.14/site-packages/PIL/__pycache__/Hdf5StubImagePlugin.cpython-314.pyc +0 -0
  115. package/lib/python3.14/site-packages/PIL/__pycache__/IcnsImagePlugin.cpython-314.pyc +0 -0
  116. package/lib/python3.14/site-packages/PIL/__pycache__/IcoImagePlugin.cpython-314.pyc +0 -0
  117. package/lib/python3.14/site-packages/PIL/__pycache__/ImImagePlugin.cpython-314.pyc +0 -0
  118. package/lib/python3.14/site-packages/PIL/__pycache__/Image.cpython-314.pyc +0 -0
  119. package/lib/python3.14/site-packages/PIL/__pycache__/ImageChops.cpython-314.pyc +0 -0
  120. package/lib/python3.14/site-packages/PIL/__pycache__/ImageCms.cpython-314.pyc +0 -0
  121. package/lib/python3.14/site-packages/PIL/__pycache__/ImageColor.cpython-314.pyc +0 -0
  122. package/lib/python3.14/site-packages/PIL/__pycache__/ImageDraw.cpython-314.pyc +0 -0
  123. package/lib/python3.14/site-packages/PIL/__pycache__/ImageDraw2.cpython-314.pyc +0 -0
  124. package/lib/python3.14/site-packages/PIL/__pycache__/ImageEnhance.cpython-314.pyc +0 -0
  125. package/lib/python3.14/site-packages/PIL/__pycache__/ImageFile.cpython-314.pyc +0 -0
  126. package/lib/python3.14/site-packages/PIL/__pycache__/ImageFilter.cpython-314.pyc +0 -0
  127. package/lib/python3.14/site-packages/PIL/__pycache__/ImageFont.cpython-314.pyc +0 -0
  128. package/lib/python3.14/site-packages/PIL/__pycache__/ImageGrab.cpython-314.pyc +0 -0
  129. package/lib/python3.14/site-packages/PIL/__pycache__/ImageMath.cpython-314.pyc +0 -0
  130. package/lib/python3.14/site-packages/PIL/__pycache__/ImageMode.cpython-314.pyc +0 -0
  131. package/lib/python3.14/site-packages/PIL/__pycache__/ImageMorph.cpython-314.pyc +0 -0
  132. package/lib/python3.14/site-packages/PIL/__pycache__/ImageOps.cpython-314.pyc +0 -0
  133. package/lib/python3.14/site-packages/PIL/__pycache__/ImagePalette.cpython-314.pyc +0 -0
  134. package/lib/python3.14/site-packages/PIL/__pycache__/ImagePath.cpython-314.pyc +0 -0
  135. package/lib/python3.14/site-packages/PIL/__pycache__/ImageQt.cpython-314.pyc +0 -0
  136. package/lib/python3.14/site-packages/PIL/__pycache__/ImageSequence.cpython-314.pyc +0 -0
  137. package/lib/python3.14/site-packages/PIL/__pycache__/ImageShow.cpython-314.pyc +0 -0
  138. package/lib/python3.14/site-packages/PIL/__pycache__/ImageStat.cpython-314.pyc +0 -0
  139. package/lib/python3.14/site-packages/PIL/__pycache__/ImageText.cpython-314.pyc +0 -0
  140. package/lib/python3.14/site-packages/PIL/__pycache__/ImageTk.cpython-314.pyc +0 -0
  141. package/lib/python3.14/site-packages/PIL/__pycache__/ImageTransform.cpython-314.pyc +0 -0
  142. package/lib/python3.14/site-packages/PIL/__pycache__/ImageWin.cpython-314.pyc +0 -0
  143. package/lib/python3.14/site-packages/PIL/__pycache__/ImtImagePlugin.cpython-314.pyc +0 -0
  144. package/lib/python3.14/site-packages/PIL/__pycache__/IptcImagePlugin.cpython-314.pyc +0 -0
  145. package/lib/python3.14/site-packages/PIL/__pycache__/Jpeg2KImagePlugin.cpython-314.pyc +0 -0
  146. package/lib/python3.14/site-packages/PIL/__pycache__/JpegImagePlugin.cpython-314.pyc +0 -0
  147. package/lib/python3.14/site-packages/PIL/__pycache__/JpegPresets.cpython-314.pyc +0 -0
  148. package/lib/python3.14/site-packages/PIL/__pycache__/McIdasImagePlugin.cpython-314.pyc +0 -0
  149. package/lib/python3.14/site-packages/PIL/__pycache__/MicImagePlugin.cpython-314.pyc +0 -0
  150. package/lib/python3.14/site-packages/PIL/__pycache__/MpegImagePlugin.cpython-314.pyc +0 -0
  151. package/lib/python3.14/site-packages/PIL/__pycache__/MpoImagePlugin.cpython-314.pyc +0 -0
  152. package/lib/python3.14/site-packages/PIL/__pycache__/MspImagePlugin.cpython-314.pyc +0 -0
  153. package/lib/python3.14/site-packages/PIL/__pycache__/PSDraw.cpython-314.pyc +0 -0
  154. package/lib/python3.14/site-packages/PIL/__pycache__/PaletteFile.cpython-314.pyc +0 -0
  155. package/lib/python3.14/site-packages/PIL/__pycache__/PalmImagePlugin.cpython-314.pyc +0 -0
  156. package/lib/python3.14/site-packages/PIL/__pycache__/PcdImagePlugin.cpython-314.pyc +0 -0
  157. package/lib/python3.14/site-packages/PIL/__pycache__/PcfFontFile.cpython-314.pyc +0 -0
  158. package/lib/python3.14/site-packages/PIL/__pycache__/PcxImagePlugin.cpython-314.pyc +0 -0
  159. package/lib/python3.14/site-packages/PIL/__pycache__/PdfImagePlugin.cpython-314.pyc +0 -0
  160. package/lib/python3.14/site-packages/PIL/__pycache__/PdfParser.cpython-314.pyc +0 -0
  161. package/lib/python3.14/site-packages/PIL/__pycache__/PixarImagePlugin.cpython-314.pyc +0 -0
  162. package/lib/python3.14/site-packages/PIL/__pycache__/PngImagePlugin.cpython-314.pyc +0 -0
  163. package/lib/python3.14/site-packages/PIL/__pycache__/PpmImagePlugin.cpython-314.pyc +0 -0
  164. package/lib/python3.14/site-packages/PIL/__pycache__/PsdImagePlugin.cpython-314.pyc +0 -0
  165. package/lib/python3.14/site-packages/PIL/__pycache__/QoiImagePlugin.cpython-314.pyc +0 -0
  166. package/lib/python3.14/site-packages/PIL/__pycache__/SgiImagePlugin.cpython-314.pyc +0 -0
  167. package/lib/python3.14/site-packages/PIL/__pycache__/SpiderImagePlugin.cpython-314.pyc +0 -0
  168. package/lib/python3.14/site-packages/PIL/__pycache__/SunImagePlugin.cpython-314.pyc +0 -0
  169. package/lib/python3.14/site-packages/PIL/__pycache__/TarIO.cpython-314.pyc +0 -0
  170. package/lib/python3.14/site-packages/PIL/__pycache__/TgaImagePlugin.cpython-314.pyc +0 -0
  171. package/lib/python3.14/site-packages/PIL/__pycache__/TiffImagePlugin.cpython-314.pyc +0 -0
  172. package/lib/python3.14/site-packages/PIL/__pycache__/TiffTags.cpython-314.pyc +0 -0
  173. package/lib/python3.14/site-packages/PIL/__pycache__/WalImageFile.cpython-314.pyc +0 -0
  174. package/lib/python3.14/site-packages/PIL/__pycache__/WebPImagePlugin.cpython-314.pyc +0 -0
  175. package/lib/python3.14/site-packages/PIL/__pycache__/WmfImagePlugin.cpython-314.pyc +0 -0
  176. package/lib/python3.14/site-packages/PIL/__pycache__/XVThumbImagePlugin.cpython-314.pyc +0 -0
  177. package/lib/python3.14/site-packages/PIL/__pycache__/XbmImagePlugin.cpython-314.pyc +0 -0
  178. package/lib/python3.14/site-packages/PIL/__pycache__/XpmImagePlugin.cpython-314.pyc +0 -0
  179. package/lib/python3.14/site-packages/PIL/__pycache__/__init__.cpython-314.pyc +0 -0
  180. package/lib/python3.14/site-packages/PIL/__pycache__/__main__.cpython-314.pyc +0 -0
  181. package/lib/python3.14/site-packages/PIL/__pycache__/_binary.cpython-314.pyc +0 -0
  182. package/lib/python3.14/site-packages/PIL/__pycache__/_deprecate.cpython-314.pyc +0 -0
  183. package/lib/python3.14/site-packages/PIL/__pycache__/_tkinter_finder.cpython-314.pyc +0 -0
  184. package/lib/python3.14/site-packages/PIL/__pycache__/_typing.cpython-314.pyc +0 -0
  185. package/lib/python3.14/site-packages/PIL/__pycache__/_util.cpython-314.pyc +0 -0
  186. package/lib/python3.14/site-packages/PIL/__pycache__/_version.cpython-314.pyc +0 -0
  187. package/lib/python3.14/site-packages/PIL/__pycache__/features.cpython-314.pyc +0 -0
  188. package/lib/python3.14/site-packages/PIL/__pycache__/report.cpython-314.pyc +0 -0
  189. package/lib/python3.14/site-packages/PIL/_avif.pyi +3 -0
  190. package/lib/python3.14/site-packages/PIL/_binary.py +113 -0
  191. package/lib/python3.14/site-packages/PIL/_deprecate.py +72 -0
  192. package/lib/python3.14/site-packages/PIL/_imaging.cpython-314-wasm32-wasix.so +0 -0
  193. package/lib/python3.14/site-packages/PIL/_imaging.pyi +31 -0
  194. package/lib/python3.14/site-packages/PIL/_imagingcms.pyi +143 -0
  195. package/lib/python3.14/site-packages/PIL/_imagingft.cpython-314-wasm32-wasix.so +0 -0
  196. package/lib/python3.14/site-packages/PIL/_imagingft.pyi +70 -0
  197. package/lib/python3.14/site-packages/PIL/_imagingmath.cpython-314-wasm32-wasix.so +0 -0
  198. package/lib/python3.14/site-packages/PIL/_imagingmath.pyi +3 -0
  199. package/lib/python3.14/site-packages/PIL/_imagingmorph.cpython-314-wasm32-wasix.so +0 -0
  200. package/lib/python3.14/site-packages/PIL/_imagingmorph.pyi +3 -0
  201. package/lib/python3.14/site-packages/PIL/_imagingtk.cpython-314-wasm32-wasix.so +0 -0
  202. package/lib/python3.14/site-packages/PIL/_imagingtk.pyi +3 -0
  203. package/lib/python3.14/site-packages/PIL/_tkinter_finder.py +20 -0
  204. package/lib/python3.14/site-packages/PIL/_typing.py +45 -0
  205. package/lib/python3.14/site-packages/PIL/_util.py +29 -0
  206. package/lib/python3.14/site-packages/PIL/_version.py +4 -0
  207. package/lib/python3.14/site-packages/PIL/_webp.pyi +3 -0
  208. package/lib/python3.14/site-packages/PIL/features.py +343 -0
  209. package/lib/python3.14/site-packages/PIL/py.typed +0 -0
  210. package/lib/python3.14/site-packages/PIL/report.py +5 -0
  211. package/lib/python3.14/site-packages/pillow-12.3.0.dist-info/METADATA +180 -0
  212. package/lib/python3.14/site-packages/pillow-12.3.0.dist-info/RECORD +117 -0
  213. package/lib/python3.14/site-packages/pillow-12.3.0.dist-info/WHEEL +5 -0
  214. package/lib/python3.14/site-packages/pillow-12.3.0.dist-info/licenses/LICENSE +30 -0
  215. package/lib/python3.14/site-packages/pillow-12.3.0.dist-info/top_level.txt +1 -0
  216. package/lib/python3.14/site-packages/pillow-12.3.0.dist-info/zip-safe +1 -0
  217. package/package.json +46 -0
@@ -0,0 +1,203 @@
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 __future__ import annotations
21
+
22
+ import os
23
+ import struct
24
+ from typing import IO, Any, cast
25
+
26
+ from . import (
27
+ Image,
28
+ ImageFile,
29
+ ImageSequence,
30
+ JpegImagePlugin,
31
+ TiffImagePlugin,
32
+ )
33
+ from ._binary import o32le
34
+ from ._util import DeferredError
35
+
36
+
37
+ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
38
+ JpegImagePlugin._save(im, fp, filename)
39
+
40
+
41
+ def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
42
+ append_images = im.encoderinfo.get("append_images", [])
43
+ if not append_images and not getattr(im, "is_animated", False):
44
+ _save(im, fp, filename)
45
+ return
46
+
47
+ mpf_offset = 28
48
+ offsets: list[int] = []
49
+ im_sequences = [im, *append_images]
50
+ total = sum(getattr(seq, "n_frames", 1) for seq in im_sequences)
51
+ for im_sequence in im_sequences:
52
+ for im_frame in ImageSequence.Iterator(im_sequence):
53
+ if not offsets:
54
+ # APP2 marker
55
+ ifd_length = 66 + 16 * total
56
+ im_frame.encoderinfo["extra"] = (
57
+ b"\xff\xe2"
58
+ + struct.pack(">H", 6 + ifd_length)
59
+ + b"MPF\0"
60
+ + b" " * ifd_length
61
+ )
62
+ if exif := im_frame.encoderinfo.get("exif"):
63
+ if isinstance(exif, Image.Exif):
64
+ exif = exif.tobytes()
65
+ im_frame.encoderinfo["exif"] = exif
66
+ mpf_offset += 4 + len(exif)
67
+
68
+ JpegImagePlugin._save(im_frame, fp, filename)
69
+ offsets.append(fp.tell())
70
+ else:
71
+ encoderinfo = im_frame._attach_default_encoderinfo(im)
72
+ im_frame.save(fp, "JPEG")
73
+ im_frame.encoderinfo = encoderinfo
74
+ offsets.append(fp.tell() - offsets[-1])
75
+
76
+ ifd = TiffImagePlugin.ImageFileDirectory_v2()
77
+ ifd[0xB000] = b"0100"
78
+ ifd[0xB001] = len(offsets)
79
+
80
+ mpentries = b""
81
+ data_offset = 0
82
+ for i, size in enumerate(offsets):
83
+ if i == 0:
84
+ mptype = 0x030000 # Baseline MP Primary Image
85
+ else:
86
+ mptype = 0x000000 # Undefined
87
+ mpentries += struct.pack("<LLLHH", mptype, size, data_offset, 0, 0)
88
+ if i == 0:
89
+ data_offset -= mpf_offset
90
+ data_offset += size
91
+ ifd[0xB002] = mpentries
92
+
93
+ fp.seek(mpf_offset)
94
+ fp.write(b"II\x2a\x00" + o32le(8) + ifd.tobytes(8))
95
+ fp.seek(0, os.SEEK_END)
96
+
97
+
98
+ ##
99
+ # Image plugin for MPO images.
100
+
101
+
102
+ class MpoImageFile(JpegImagePlugin.JpegImageFile):
103
+ format = "MPO"
104
+ format_description = "MPO (CIPA DC-007)"
105
+ _close_exclusive_fp_after_loading = False
106
+
107
+ def _open(self) -> None:
108
+ assert self.fp is not None
109
+ self.fp.seek(0) # prep the fp in order to pass the JPEG test
110
+ JpegImagePlugin.JpegImageFile._open(self)
111
+ self._after_jpeg_open()
112
+
113
+ def _after_jpeg_open(self, mpheader: dict[int, Any] | None = None) -> None:
114
+ self.mpinfo = mpheader if mpheader is not None else self._getmp()
115
+ if self.mpinfo is None:
116
+ msg = "Image appears to be a malformed MPO file"
117
+ raise ValueError(msg)
118
+ self.n_frames = self.mpinfo[0xB001]
119
+ self.__mpoffsets = [
120
+ mpent["DataOffset"] + self.info["mpoffset"] for mpent in self.mpinfo[0xB002]
121
+ ]
122
+ self.__mpoffsets[0] = 0
123
+ # Note that the following assertion will only be invalid if something
124
+ # gets broken within JpegImagePlugin.
125
+ assert self.n_frames == len(self.__mpoffsets)
126
+ del self.info["mpoffset"] # no longer needed
127
+ self.is_animated = self.n_frames > 1
128
+ assert self.fp is not None
129
+ self._fp = self.fp # FIXME: hack
130
+ self._fp.seek(self.__mpoffsets[0]) # get ready to read first frame
131
+ self.__frame = 0
132
+ self.offset = 0
133
+ # for now we can only handle reading and individual frame extraction
134
+ self.readonly = 1
135
+
136
+ def load_seek(self, pos: int) -> None:
137
+ if isinstance(self._fp, DeferredError):
138
+ raise self._fp.ex
139
+ self._fp.seek(pos)
140
+
141
+ def seek(self, frame: int) -> None:
142
+ if not self._seek_check(frame):
143
+ return
144
+ if isinstance(self._fp, DeferredError):
145
+ raise self._fp.ex
146
+ self.fp = self._fp
147
+ self.offset = self.__mpoffsets[frame]
148
+
149
+ original_exif = self.info.get("exif")
150
+ if "exif" in self.info:
151
+ del self.info["exif"]
152
+
153
+ self.fp.seek(self.offset + 2) # skip SOI marker
154
+ if not self.fp.read(2):
155
+ msg = "No data found for frame"
156
+ raise ValueError(msg)
157
+ self.fp.seek(self.offset)
158
+ JpegImagePlugin.JpegImageFile._open(self)
159
+ if self.info.get("exif") != original_exif:
160
+ self._reload_exif()
161
+
162
+ self.tile = [
163
+ ImageFile._Tile("jpeg", (0, 0) + self.size, self.offset, self.tile[0][-1])
164
+ ]
165
+ self.__frame = frame
166
+
167
+ def tell(self) -> int:
168
+ return self.__frame
169
+
170
+ @staticmethod
171
+ def adopt(
172
+ jpeg_instance: JpegImagePlugin.JpegImageFile,
173
+ mpheader: dict[int, Any] | None = None,
174
+ ) -> MpoImageFile:
175
+ """
176
+ Transform the instance of JpegImageFile into
177
+ an instance of MpoImageFile.
178
+ After the call, the JpegImageFile is extended
179
+ to be an MpoImageFile.
180
+
181
+ This is essentially useful when opening a JPEG
182
+ file that reveals itself as an MPO, to avoid
183
+ double call to _open.
184
+ """
185
+ jpeg_instance.__class__ = MpoImageFile
186
+ mpo_instance = cast(MpoImageFile, jpeg_instance)
187
+ mpo_instance._after_jpeg_open(mpheader)
188
+ return mpo_instance
189
+
190
+
191
+ # ---------------------------------------------------------------------
192
+ # Registry stuff
193
+
194
+ # Note that since MPO shares a factory with JPEG, we do not need to do a
195
+ # separate registration for it here.
196
+ # Image.register_open(MpoImageFile.format,
197
+ # JpegImagePlugin.jpeg_factory, _accept)
198
+ Image.register_save(MpoImageFile.format, _save)
199
+ Image.register_save_all(MpoImageFile.format, _save_all)
200
+
201
+ Image.register_extension(MpoImageFile.format, ".mpo")
202
+
203
+ Image.register_mime(MpoImageFile.format, "image/mpo")
@@ -0,0 +1,200 @@
1
+ #
2
+ # The Python Imaging Library.
3
+ #
4
+ # MSP file handling
5
+ #
6
+ # This is the format used by the Paint program in Windows 1 and 2.
7
+ #
8
+ # History:
9
+ # 95-09-05 fl Created
10
+ # 97-01-03 fl Read/write MSP images
11
+ # 17-02-21 es Fixed RLE interpretation
12
+ #
13
+ # Copyright (c) Secret Labs AB 1997.
14
+ # Copyright (c) Fredrik Lundh 1995-97.
15
+ # Copyright (c) Eric Soroos 2017.
16
+ #
17
+ # See the README file for information on usage and redistribution.
18
+ #
19
+ # More info on this format: https://archive.org/details/gg243631
20
+ # Page 313:
21
+ # Figure 205. Windows Paint Version 1: "DanM" Format
22
+ # Figure 206. Windows Paint Version 2: "LinS" Format. Used in Windows V2.03
23
+ #
24
+ # See also: https://www.fileformat.info/format/mspaint/egff.htm
25
+ from __future__ import annotations
26
+
27
+ import io
28
+ import struct
29
+ from typing import IO
30
+
31
+ from . import Image, ImageFile
32
+ from ._binary import i16le as i16
33
+ from ._binary import o16le as o16
34
+
35
+ #
36
+ # read MSP files
37
+
38
+
39
+ def _accept(prefix: bytes) -> bool:
40
+ return prefix.startswith((b"DanM", b"LinS"))
41
+
42
+
43
+ ##
44
+ # Image plugin for Windows MSP images. This plugin supports both
45
+ # uncompressed (Windows 1.0).
46
+
47
+
48
+ class MspImageFile(ImageFile.ImageFile):
49
+ format = "MSP"
50
+ format_description = "Windows Paint"
51
+
52
+ def _open(self) -> None:
53
+ # Header
54
+ assert self.fp is not None
55
+
56
+ s = self.fp.read(32)
57
+ if not _accept(s):
58
+ msg = "not an MSP file"
59
+ raise SyntaxError(msg)
60
+
61
+ # Header checksum
62
+ checksum = 0
63
+ for i in range(0, 32, 2):
64
+ checksum = checksum ^ i16(s, i)
65
+ if checksum != 0:
66
+ msg = "bad MSP checksum"
67
+ raise SyntaxError(msg)
68
+
69
+ self._mode = "1"
70
+ self._size = i16(s, 4), i16(s, 6)
71
+
72
+ if s.startswith(b"DanM"):
73
+ self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 32, "1")]
74
+ else:
75
+ self.tile = [ImageFile._Tile("MSP", (0, 0) + self.size, 32)]
76
+
77
+
78
+ class MspDecoder(ImageFile.PyDecoder):
79
+ # The algo for the MSP decoder is from
80
+ # https://www.fileformat.info/format/mspaint/egff.htm
81
+ # cc-by-attribution -- That page references is taken from the
82
+ # Encyclopedia of Graphics File Formats and is licensed by
83
+ # O'Reilly under the Creative Common/Attribution license
84
+ #
85
+ # For RLE encoded files, the 32byte header is followed by a scan
86
+ # line map, encoded as one 16bit word of encoded byte length per
87
+ # line.
88
+ #
89
+ # NOTE: the encoded length of the line can be 0. This was not
90
+ # handled in the previous version of this encoder, and there's no
91
+ # mention of how to handle it in the documentation. From the few
92
+ # examples I've seen, I've assumed that it is a fill of the
93
+ # background color, in this case, white.
94
+ #
95
+ #
96
+ # Pseudocode of the decoder:
97
+ # Read a BYTE value as the RunType
98
+ # If the RunType value is zero
99
+ # Read next byte as the RunCount
100
+ # Read the next byte as the RunValue
101
+ # Write the RunValue byte RunCount times
102
+ # If the RunType value is non-zero
103
+ # Use this value as the RunCount
104
+ # Read and write the next RunCount bytes literally
105
+ #
106
+ # e.g.:
107
+ # 0x00 03 ff 05 00 01 02 03 04
108
+ # would yield the bytes:
109
+ # 0xff ff ff 00 01 02 03 04
110
+ #
111
+ # which are then interpreted as a bit packed mode '1' image
112
+
113
+ _pulls_fd = True
114
+
115
+ def decode(self, buffer: Image.DecoderInput) -> tuple[int, int]:
116
+ assert self.fd is not None
117
+
118
+ img = io.BytesIO()
119
+ blank_line = bytearray((0xFF,) * ((self.state.xsize + 7) // 8))
120
+ try:
121
+ self.fd.seek(32)
122
+ rowmap = struct.unpack_from(
123
+ f"<{self.state.ysize}H", self.fd.read(self.state.ysize * 2)
124
+ )
125
+ except struct.error as e:
126
+ msg = "Truncated MSP file in row map"
127
+ raise OSError(msg) from e
128
+
129
+ for x, rowlen in enumerate(rowmap):
130
+ try:
131
+ if rowlen == 0:
132
+ img.write(blank_line)
133
+ continue
134
+ row = self.fd.read(rowlen)
135
+ if len(row) != rowlen:
136
+ msg = f"Truncated MSP file, expected {rowlen} bytes on row {x}"
137
+ raise OSError(msg)
138
+ idx = 0
139
+ while idx < rowlen:
140
+ runtype = row[idx]
141
+ idx += 1
142
+ if runtype == 0:
143
+ runcount, runval = struct.unpack_from("Bc", row, idx)
144
+ img.write(runval * runcount)
145
+ idx += 2
146
+ else:
147
+ runcount = runtype
148
+ img.write(row[idx : idx + runcount])
149
+ idx += runcount
150
+
151
+ except struct.error as e:
152
+ msg = f"Corrupted MSP file in row {x}"
153
+ raise OSError(msg) from e
154
+
155
+ self.set_as_raw(img.getvalue(), "1")
156
+
157
+ return -1, 0
158
+
159
+
160
+ Image.register_decoder("MSP", MspDecoder)
161
+
162
+
163
+ #
164
+ # write MSP files (uncompressed only)
165
+
166
+
167
+ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
168
+ if im.mode != "1":
169
+ msg = f"cannot write mode {im.mode} as MSP"
170
+ raise OSError(msg)
171
+
172
+ # create MSP header
173
+ header = [0] * 16
174
+
175
+ header[0], header[1] = i16(b"Da"), i16(b"nM") # version 1
176
+ header[2], header[3] = im.size
177
+ header[4], header[5] = 1, 1
178
+ header[6], header[7] = 1, 1
179
+ header[8], header[9] = im.size
180
+
181
+ checksum = 0
182
+ for h in header:
183
+ checksum = checksum ^ h
184
+ header[12] = checksum # FIXME: is this the right field?
185
+
186
+ # header
187
+ for h in header:
188
+ fp.write(o16(h))
189
+
190
+ # image body
191
+ ImageFile._save(im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 32, "1")])
192
+
193
+
194
+ #
195
+ # registry
196
+
197
+ Image.register_open(MspImageFile.format, MspImageFile, _accept)
198
+ Image.register_save(MspImageFile.format, _save)
199
+
200
+ Image.register_extension(MspImageFile.format, ".msp")
@@ -0,0 +1,238 @@
1
+ #
2
+ # The Python Imaging Library
3
+ # $Id$
4
+ #
5
+ # Simple PostScript graphics interface
6
+ #
7
+ # History:
8
+ # 1996-04-20 fl Created
9
+ # 1999-01-10 fl Added gsave/grestore to image method
10
+ # 2005-05-04 fl Fixed floating point issue in image (from Eric Etheridge)
11
+ #
12
+ # Copyright (c) 1997-2005 by Secret Labs AB. All rights reserved.
13
+ # Copyright (c) 1996 by Fredrik Lundh.
14
+ #
15
+ # See the README file for information on usage and redistribution.
16
+ #
17
+ from __future__ import annotations
18
+
19
+ import sys
20
+ from typing import IO
21
+
22
+ from . import EpsImagePlugin
23
+
24
+ TYPE_CHECKING = False
25
+
26
+
27
+ ##
28
+ # Simple PostScript graphics interface.
29
+
30
+
31
+ class PSDraw:
32
+ """
33
+ Sets up printing to the given file. If ``fp`` is omitted,
34
+ ``sys.stdout.buffer`` is assumed.
35
+ """
36
+
37
+ def __init__(self, fp: IO[bytes] | None = None) -> None:
38
+ if not fp:
39
+ fp = sys.stdout.buffer
40
+ self.fp = fp
41
+
42
+ def begin_document(self, id: str | None = None) -> None:
43
+ """Set up printing of a document. (Write PostScript DSC header.)"""
44
+ # FIXME: incomplete
45
+ self.fp.write(
46
+ b"%!PS-Adobe-3.0\n"
47
+ b"save\n"
48
+ b"/showpage { } def\n"
49
+ b"%%EndComments\n"
50
+ b"%%BeginDocument\n"
51
+ )
52
+ # self.fp.write(ERROR_PS) # debugging!
53
+ self.fp.write(EDROFF_PS)
54
+ self.fp.write(VDI_PS)
55
+ self.fp.write(b"%%EndProlog\n")
56
+ self.isofont: dict[bytes, int] = {}
57
+
58
+ def end_document(self) -> None:
59
+ """Ends printing. (Write PostScript DSC footer.)"""
60
+ self.fp.write(b"%%EndDocument\nrestore showpage\n%%End\n")
61
+ if hasattr(self.fp, "flush"):
62
+ self.fp.flush()
63
+
64
+ def setfont(self, font: str, size: int) -> None:
65
+ """
66
+ Selects which font to use.
67
+
68
+ :param font: A PostScript font name
69
+ :param size: Size in points.
70
+ """
71
+ font_bytes = bytes(font, "UTF-8")
72
+ if font_bytes not in self.isofont:
73
+ # reencode font
74
+ self.fp.write(
75
+ b"/PSDraw-%s ISOLatin1Encoding /%s E\n" % (font_bytes, font_bytes)
76
+ )
77
+ self.isofont[font_bytes] = 1
78
+ # rough
79
+ self.fp.write(b"/F0 %d /PSDraw-%s F\n" % (size, font_bytes))
80
+
81
+ def line(self, xy0: tuple[int, int], xy1: tuple[int, int]) -> None:
82
+ """
83
+ Draws a line between the two points. Coordinates are given in
84
+ PostScript point coordinates (72 points per inch, (0, 0) is the lower
85
+ left corner of the page).
86
+ """
87
+ self.fp.write(b"%d %d %d %d Vl\n" % (*xy0, *xy1))
88
+
89
+ def rectangle(self, box: tuple[int, int, int, int]) -> None:
90
+ """
91
+ Draws a rectangle.
92
+
93
+ :param box: A tuple of four integers, specifying left, bottom, width and
94
+ height.
95
+ """
96
+ self.fp.write(b"%d %d M 0 %d %d Vr\n" % box)
97
+
98
+ def text(self, xy: tuple[int, int], text: str) -> None:
99
+ """
100
+ Draws text at the given position. You must use
101
+ :py:meth:`~PIL.PSDraw.PSDraw.setfont` before calling this method.
102
+ """
103
+ # The font is loaded as ISOLatin1Encoding, so use latin-1 here.
104
+ text_bytes = bytes(text, "latin-1")
105
+ text_bytes = b"\\(".join(text_bytes.split(b"("))
106
+ text_bytes = b"\\)".join(text_bytes.split(b")"))
107
+ self.fp.write(b"%d %d M (%s) S\n" % (xy + (text_bytes,)))
108
+
109
+ if TYPE_CHECKING:
110
+ from . import Image
111
+
112
+ def image(
113
+ self, box: tuple[int, int, int, int], im: Image.Image, dpi: int | None = None
114
+ ) -> None:
115
+ """Draw a PIL image, centered in the given box."""
116
+ # default resolution depends on mode
117
+ if not dpi:
118
+ if im.mode == "1":
119
+ dpi = 200 # fax
120
+ else:
121
+ dpi = 100 # grayscale
122
+ # image size (on paper)
123
+ x = im.size[0] * 72 / dpi
124
+ y = im.size[1] * 72 / dpi
125
+ # max allowed size
126
+ xmax = float(box[2] - box[0])
127
+ ymax = float(box[3] - box[1])
128
+ if x > xmax:
129
+ y = y * xmax / x
130
+ x = xmax
131
+ if y > ymax:
132
+ x = x * ymax / y
133
+ y = ymax
134
+ dx = (xmax - x) / 2 + box[0]
135
+ dy = (ymax - y) / 2 + box[1]
136
+ self.fp.write(b"gsave\n%f %f translate\n" % (dx, dy))
137
+ if (x, y) != im.size:
138
+ # EpsImagePlugin._save prints the image at (0,0,xsize,ysize)
139
+ sx = x / im.size[0]
140
+ sy = y / im.size[1]
141
+ self.fp.write(b"%f %f scale\n" % (sx, sy))
142
+ EpsImagePlugin._save(im, self.fp, "", 0)
143
+ self.fp.write(b"\ngrestore\n")
144
+
145
+
146
+ # --------------------------------------------------------------------
147
+ # PostScript driver
148
+
149
+ #
150
+ # EDROFF.PS -- PostScript driver for Edroff 2
151
+ #
152
+ # History:
153
+ # 94-01-25 fl: created (edroff 2.04)
154
+ #
155
+ # Copyright (c) Fredrik Lundh 1994.
156
+ #
157
+
158
+
159
+ EDROFF_PS = b"""\
160
+ /S { show } bind def
161
+ /P { moveto show } bind def
162
+ /M { moveto } bind def
163
+ /X { 0 rmoveto } bind def
164
+ /Y { 0 exch rmoveto } bind def
165
+ /E { findfont
166
+ dup maxlength dict begin
167
+ {
168
+ 1 index /FID ne { def } { pop pop } ifelse
169
+ } forall
170
+ /Encoding exch def
171
+ dup /FontName exch def
172
+ currentdict end definefont pop
173
+ } bind def
174
+ /F { findfont exch scalefont dup setfont
175
+ [ exch /setfont cvx ] cvx bind def
176
+ } bind def
177
+ """
178
+
179
+ #
180
+ # VDI.PS -- PostScript driver for VDI meta commands
181
+ #
182
+ # History:
183
+ # 94-01-25 fl: created (edroff 2.04)
184
+ #
185
+ # Copyright (c) Fredrik Lundh 1994.
186
+ #
187
+
188
+ VDI_PS = b"""\
189
+ /Vm { moveto } bind def
190
+ /Va { newpath arcn stroke } bind def
191
+ /Vl { moveto lineto stroke } bind def
192
+ /Vc { newpath 0 360 arc closepath } bind def
193
+ /Vr { exch dup 0 rlineto
194
+ exch dup 0 exch rlineto
195
+ exch neg 0 rlineto
196
+ 0 exch neg rlineto
197
+ setgray fill } bind def
198
+ /Tm matrix def
199
+ /Ve { Tm currentmatrix pop
200
+ translate scale newpath 0 0 .5 0 360 arc closepath
201
+ Tm setmatrix
202
+ } bind def
203
+ /Vf { currentgray exch setgray fill setgray } bind def
204
+ """
205
+
206
+ #
207
+ # ERROR.PS -- Error handler
208
+ #
209
+ # History:
210
+ # 89-11-21 fl: created (pslist 1.10)
211
+ #
212
+
213
+ ERROR_PS = b"""\
214
+ /landscape false def
215
+ /errorBUF 200 string def
216
+ /errorNL { currentpoint 10 sub exch pop 72 exch moveto } def
217
+ errordict begin /handleerror {
218
+ initmatrix /Courier findfont 10 scalefont setfont
219
+ newpath 72 720 moveto $error begin /newerror false def
220
+ (PostScript Error) show errorNL errorNL
221
+ (Error: ) show
222
+ /errorname load errorBUF cvs show errorNL errorNL
223
+ (Command: ) show
224
+ /command load dup type /stringtype ne { errorBUF cvs } if show
225
+ errorNL errorNL
226
+ (VMstatus: ) show
227
+ vmstatus errorBUF cvs show ( bytes available, ) show
228
+ errorBUF cvs show ( bytes used at level ) show
229
+ errorBUF cvs show errorNL errorNL
230
+ (Operand stargck: ) show errorNL /ostargck load {
231
+ dup type /stringtype ne { errorBUF cvs } if 72 0 rmoveto show errorNL
232
+ } forall errorNL
233
+ (Execution stargck: ) show errorNL /estargck load {
234
+ dup type /stringtype ne { errorBUF cvs } if 72 0 rmoveto show errorNL
235
+ } forall
236
+ end showpage
237
+ } def end
238
+ """
@@ -0,0 +1,54 @@
1
+ #
2
+ # Python Imaging Library
3
+ # $Id$
4
+ #
5
+ # stuff to read simple, teragon-style palette files
6
+ #
7
+ # History:
8
+ # 97-08-23 fl Created
9
+ #
10
+ # Copyright (c) Secret Labs AB 1997.
11
+ # Copyright (c) Fredrik Lundh 1997.
12
+ #
13
+ # See the README file for information on usage and redistribution.
14
+ #
15
+ from __future__ import annotations
16
+
17
+ from typing import IO
18
+
19
+ from ._binary import o8
20
+
21
+
22
+ class PaletteFile:
23
+ """File handler for Teragon-style palette files."""
24
+
25
+ rawmode = "RGB"
26
+
27
+ def __init__(self, fp: IO[bytes]) -> None:
28
+ palette = [o8(i) * 3 for i in range(256)]
29
+
30
+ while True:
31
+ s = fp.readline()
32
+
33
+ if not s:
34
+ break
35
+ if s.startswith(b"#"):
36
+ continue
37
+ if len(s) > 100:
38
+ msg = "bad palette file"
39
+ raise SyntaxError(msg)
40
+
41
+ v = [int(x) for x in s.split()]
42
+ try:
43
+ [i, r, g, b] = v
44
+ except ValueError:
45
+ [i, r] = v
46
+ g = b = r
47
+
48
+ if 0 <= i <= 255:
49
+ palette[i] = o8(r) + o8(g) + o8(b)
50
+
51
+ self.palette = b"".join(palette)
52
+
53
+ def getpalette(self) -> tuple[bytes, str]:
54
+ return self.palette, self.rawmode