@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.
- package/LICENSE +30 -0
- package/README.md +4 -0
- package/lib/python3.14/site-packages/PIL/AvifImagePlugin.py +295 -0
- package/lib/python3.14/site-packages/PIL/BdfFontFile.py +124 -0
- package/lib/python3.14/site-packages/PIL/BlpImagePlugin.py +498 -0
- package/lib/python3.14/site-packages/PIL/BmpImagePlugin.py +514 -0
- package/lib/python3.14/site-packages/PIL/BufrStubImagePlugin.py +72 -0
- package/lib/python3.14/site-packages/PIL/ContainerIO.py +173 -0
- package/lib/python3.14/site-packages/PIL/CurImagePlugin.py +103 -0
- package/lib/python3.14/site-packages/PIL/DcxImagePlugin.py +84 -0
- package/lib/python3.14/site-packages/PIL/DdsImagePlugin.py +632 -0
- package/lib/python3.14/site-packages/PIL/EpsImagePlugin.py +484 -0
- package/lib/python3.14/site-packages/PIL/ExifTags.py +384 -0
- package/lib/python3.14/site-packages/PIL/FitsImagePlugin.py +153 -0
- package/lib/python3.14/site-packages/PIL/FliImagePlugin.py +184 -0
- package/lib/python3.14/site-packages/PIL/FontFile.py +160 -0
- package/lib/python3.14/site-packages/PIL/FpxImagePlugin.py +262 -0
- package/lib/python3.14/site-packages/PIL/FtexImagePlugin.py +115 -0
- package/lib/python3.14/site-packages/PIL/GbrImagePlugin.py +103 -0
- package/lib/python3.14/site-packages/PIL/GdImageFile.py +104 -0
- package/lib/python3.14/site-packages/PIL/GifImagePlugin.py +1223 -0
- package/lib/python3.14/site-packages/PIL/GimpGradientFile.py +154 -0
- package/lib/python3.14/site-packages/PIL/GimpPaletteFile.py +75 -0
- package/lib/python3.14/site-packages/PIL/GribStubImagePlugin.py +72 -0
- package/lib/python3.14/site-packages/PIL/Hdf5StubImagePlugin.py +72 -0
- package/lib/python3.14/site-packages/PIL/IcnsImagePlugin.py +401 -0
- package/lib/python3.14/site-packages/PIL/IcoImagePlugin.py +396 -0
- package/lib/python3.14/site-packages/PIL/ImImagePlugin.py +390 -0
- package/lib/python3.14/site-packages/PIL/Image.py +4385 -0
- package/lib/python3.14/site-packages/PIL/ImageChops.py +311 -0
- package/lib/python3.14/site-packages/PIL/ImageCms.py +1078 -0
- package/lib/python3.14/site-packages/PIL/ImageColor.py +320 -0
- package/lib/python3.14/site-packages/PIL/ImageDraw.py +1002 -0
- package/lib/python3.14/site-packages/PIL/ImageDraw2.py +244 -0
- package/lib/python3.14/site-packages/PIL/ImageEnhance.py +113 -0
- package/lib/python3.14/site-packages/PIL/ImageFile.py +938 -0
- package/lib/python3.14/site-packages/PIL/ImageFilter.py +617 -0
- package/lib/python3.14/site-packages/PIL/ImageFont.py +1330 -0
- package/lib/python3.14/site-packages/PIL/ImageGrab.py +234 -0
- package/lib/python3.14/site-packages/PIL/ImageMath.py +314 -0
- package/lib/python3.14/site-packages/PIL/ImageMode.py +85 -0
- package/lib/python3.14/site-packages/PIL/ImageMorph.py +317 -0
- package/lib/python3.14/site-packages/PIL/ImageOps.py +749 -0
- package/lib/python3.14/site-packages/PIL/ImagePalette.py +290 -0
- package/lib/python3.14/site-packages/PIL/ImagePath.py +20 -0
- package/lib/python3.14/site-packages/PIL/ImageQt.py +219 -0
- package/lib/python3.14/site-packages/PIL/ImageSequence.py +88 -0
- package/lib/python3.14/site-packages/PIL/ImageShow.py +367 -0
- package/lib/python3.14/site-packages/PIL/ImageStat.py +167 -0
- package/lib/python3.14/site-packages/PIL/ImageText.py +509 -0
- package/lib/python3.14/site-packages/PIL/ImageTk.py +266 -0
- package/lib/python3.14/site-packages/PIL/ImageTransform.py +136 -0
- package/lib/python3.14/site-packages/PIL/ImageWin.py +247 -0
- package/lib/python3.14/site-packages/PIL/ImtImagePlugin.py +103 -0
- package/lib/python3.14/site-packages/PIL/IptcImagePlugin.py +226 -0
- package/lib/python3.14/site-packages/PIL/Jpeg2KImagePlugin.py +466 -0
- package/lib/python3.14/site-packages/PIL/JpegImagePlugin.py +889 -0
- package/lib/python3.14/site-packages/PIL/JpegPresets.py +242 -0
- package/lib/python3.14/site-packages/PIL/McIdasImagePlugin.py +78 -0
- package/lib/python3.14/site-packages/PIL/MicImagePlugin.py +103 -0
- package/lib/python3.14/site-packages/PIL/MpegImagePlugin.py +84 -0
- package/lib/python3.14/site-packages/PIL/MpoImagePlugin.py +203 -0
- package/lib/python3.14/site-packages/PIL/MspImagePlugin.py +200 -0
- package/lib/python3.14/site-packages/PIL/PSDraw.py +238 -0
- package/lib/python3.14/site-packages/PIL/PaletteFile.py +54 -0
- package/lib/python3.14/site-packages/PIL/PalmImagePlugin.py +217 -0
- package/lib/python3.14/site-packages/PIL/PcdImagePlugin.py +68 -0
- package/lib/python3.14/site-packages/PIL/PcfFontFile.py +256 -0
- package/lib/python3.14/site-packages/PIL/PcxImagePlugin.py +232 -0
- package/lib/python3.14/site-packages/PIL/PdfImagePlugin.py +315 -0
- package/lib/python3.14/site-packages/PIL/PdfParser.py +1092 -0
- package/lib/python3.14/site-packages/PIL/PixarImagePlugin.py +72 -0
- package/lib/python3.14/site-packages/PIL/PngImagePlugin.py +1578 -0
- package/lib/python3.14/site-packages/PIL/PpmImagePlugin.py +375 -0
- package/lib/python3.14/site-packages/PIL/PsdImagePlugin.py +339 -0
- package/lib/python3.14/site-packages/PIL/QoiImagePlugin.py +235 -0
- package/lib/python3.14/site-packages/PIL/SgiImagePlugin.py +231 -0
- package/lib/python3.14/site-packages/PIL/SpiderImagePlugin.py +332 -0
- package/lib/python3.14/site-packages/PIL/SunImagePlugin.py +145 -0
- package/lib/python3.14/site-packages/PIL/TarIO.py +61 -0
- package/lib/python3.14/site-packages/PIL/TgaImagePlugin.py +284 -0
- package/lib/python3.14/site-packages/PIL/TiffImagePlugin.py +2354 -0
- package/lib/python3.14/site-packages/PIL/TiffTags.py +566 -0
- package/lib/python3.14/site-packages/PIL/WalImageFile.py +129 -0
- package/lib/python3.14/site-packages/PIL/WebPImagePlugin.py +322 -0
- package/lib/python3.14/site-packages/PIL/WmfImagePlugin.py +183 -0
- package/lib/python3.14/site-packages/PIL/XVThumbImagePlugin.py +83 -0
- package/lib/python3.14/site-packages/PIL/XbmImagePlugin.py +98 -0
- package/lib/python3.14/site-packages/PIL/XpmImagePlugin.py +157 -0
- package/lib/python3.14/site-packages/PIL/__init__.py +87 -0
- package/lib/python3.14/site-packages/PIL/__main__.py +7 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/AvifImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/BdfFontFile.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/BlpImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/BmpImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/BufrStubImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ContainerIO.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/CurImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/DcxImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/DdsImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/EpsImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ExifTags.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/FitsImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/FliImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/FontFile.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/FpxImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/FtexImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/GbrImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/GdImageFile.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/GifImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/GimpGradientFile.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/GimpPaletteFile.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/GribStubImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/Hdf5StubImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/IcnsImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/IcoImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/Image.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageChops.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageCms.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageColor.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageDraw.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageDraw2.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageEnhance.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageFile.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageFilter.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageFont.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageGrab.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageMath.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageMode.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageMorph.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageOps.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImagePalette.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImagePath.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageQt.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageSequence.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageShow.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageStat.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageText.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageTk.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageTransform.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImageWin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/ImtImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/IptcImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/Jpeg2KImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/JpegImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/JpegPresets.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/McIdasImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/MicImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/MpegImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/MpoImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/MspImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/PSDraw.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/PaletteFile.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/PalmImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/PcdImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/PcfFontFile.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/PcxImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/PdfImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/PdfParser.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/PixarImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/PngImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/PpmImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/PsdImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/QoiImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/SgiImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/SpiderImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/SunImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/TarIO.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/TgaImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/TiffImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/TiffTags.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/WalImageFile.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/WebPImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/WmfImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/XVThumbImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/XbmImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/XpmImagePlugin.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/__init__.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/__main__.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/_binary.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/_deprecate.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/_tkinter_finder.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/_typing.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/_util.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/_version.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/features.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/__pycache__/report.cpython-314.pyc +0 -0
- package/lib/python3.14/site-packages/PIL/_avif.pyi +3 -0
- package/lib/python3.14/site-packages/PIL/_binary.py +113 -0
- package/lib/python3.14/site-packages/PIL/_deprecate.py +72 -0
- package/lib/python3.14/site-packages/PIL/_imaging.cpython-314-wasm32-wasix.so +0 -0
- package/lib/python3.14/site-packages/PIL/_imaging.pyi +31 -0
- package/lib/python3.14/site-packages/PIL/_imagingcms.pyi +143 -0
- package/lib/python3.14/site-packages/PIL/_imagingft.cpython-314-wasm32-wasix.so +0 -0
- package/lib/python3.14/site-packages/PIL/_imagingft.pyi +70 -0
- package/lib/python3.14/site-packages/PIL/_imagingmath.cpython-314-wasm32-wasix.so +0 -0
- package/lib/python3.14/site-packages/PIL/_imagingmath.pyi +3 -0
- package/lib/python3.14/site-packages/PIL/_imagingmorph.cpython-314-wasm32-wasix.so +0 -0
- package/lib/python3.14/site-packages/PIL/_imagingmorph.pyi +3 -0
- package/lib/python3.14/site-packages/PIL/_imagingtk.cpython-314-wasm32-wasix.so +0 -0
- package/lib/python3.14/site-packages/PIL/_imagingtk.pyi +3 -0
- package/lib/python3.14/site-packages/PIL/_tkinter_finder.py +20 -0
- package/lib/python3.14/site-packages/PIL/_typing.py +45 -0
- package/lib/python3.14/site-packages/PIL/_util.py +29 -0
- package/lib/python3.14/site-packages/PIL/_version.py +4 -0
- package/lib/python3.14/site-packages/PIL/_webp.pyi +3 -0
- package/lib/python3.14/site-packages/PIL/features.py +343 -0
- package/lib/python3.14/site-packages/PIL/py.typed +0 -0
- package/lib/python3.14/site-packages/PIL/report.py +5 -0
- package/lib/python3.14/site-packages/pillow-12.3.0.dist-info/METADATA +180 -0
- package/lib/python3.14/site-packages/pillow-12.3.0.dist-info/RECORD +117 -0
- package/lib/python3.14/site-packages/pillow-12.3.0.dist-info/WHEEL +5 -0
- package/lib/python3.14/site-packages/pillow-12.3.0.dist-info/licenses/LICENSE +30 -0
- package/lib/python3.14/site-packages/pillow-12.3.0.dist-info/top_level.txt +1 -0
- package/lib/python3.14/site-packages/pillow-12.3.0.dist-info/zip-safe +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#
|
|
2
|
+
# The Python Imaging Library
|
|
3
|
+
# $Id$
|
|
4
|
+
#
|
|
5
|
+
# base class for raster font file parsers
|
|
6
|
+
#
|
|
7
|
+
# history:
|
|
8
|
+
# 1997-06-05 fl created
|
|
9
|
+
# 1997-08-19 fl restrict image width
|
|
10
|
+
#
|
|
11
|
+
# Copyright (c) 1997-1998 by Secret Labs AB
|
|
12
|
+
# Copyright (c) 1997-1998 by Fredrik Lundh
|
|
13
|
+
#
|
|
14
|
+
# See the README file for information on usage and redistribution.
|
|
15
|
+
#
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
from typing import BinaryIO
|
|
20
|
+
|
|
21
|
+
from . import Image, ImageFont, _binary
|
|
22
|
+
|
|
23
|
+
WIDTH = 800
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def puti16(
|
|
27
|
+
fp: BinaryIO, values: tuple[int, int, int, int, int, int, int, int, int, int]
|
|
28
|
+
) -> None:
|
|
29
|
+
"""Write network order (big-endian) 16-bit sequence"""
|
|
30
|
+
for v in values:
|
|
31
|
+
if v < 0:
|
|
32
|
+
v += 65536
|
|
33
|
+
fp.write(_binary.o16be(v))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class FontFile:
|
|
37
|
+
"""Base class for raster font file handlers."""
|
|
38
|
+
|
|
39
|
+
bitmap: Image.Image | None = None
|
|
40
|
+
|
|
41
|
+
def __init__(self) -> None:
|
|
42
|
+
self.info: dict[bytes, bytes | int] = {}
|
|
43
|
+
self.glyph: list[
|
|
44
|
+
tuple[
|
|
45
|
+
tuple[int, int],
|
|
46
|
+
tuple[int, int, int, int],
|
|
47
|
+
tuple[int, int, int, int],
|
|
48
|
+
Image.Image,
|
|
49
|
+
]
|
|
50
|
+
| None
|
|
51
|
+
] = [None] * 256
|
|
52
|
+
|
|
53
|
+
def __getitem__(self, ix: int) -> (
|
|
54
|
+
tuple[
|
|
55
|
+
tuple[int, int],
|
|
56
|
+
tuple[int, int, int, int],
|
|
57
|
+
tuple[int, int, int, int],
|
|
58
|
+
Image.Image,
|
|
59
|
+
]
|
|
60
|
+
| None
|
|
61
|
+
):
|
|
62
|
+
return self.glyph[ix]
|
|
63
|
+
|
|
64
|
+
def compile(self) -> None:
|
|
65
|
+
"""Create metrics and bitmap"""
|
|
66
|
+
|
|
67
|
+
if self.bitmap:
|
|
68
|
+
return
|
|
69
|
+
|
|
70
|
+
# create bitmap large enough to hold all data
|
|
71
|
+
h = w = maxwidth = 0
|
|
72
|
+
lines = 1
|
|
73
|
+
for glyph in self.glyph:
|
|
74
|
+
if glyph:
|
|
75
|
+
d, dst, src, im = glyph
|
|
76
|
+
h = max(h, src[3] - src[1])
|
|
77
|
+
w += src[2] - src[0]
|
|
78
|
+
if w > WIDTH:
|
|
79
|
+
lines += 1
|
|
80
|
+
w = src[2] - src[0]
|
|
81
|
+
maxwidth = max(maxwidth, w)
|
|
82
|
+
|
|
83
|
+
xsize = maxwidth
|
|
84
|
+
ysize = lines * h
|
|
85
|
+
|
|
86
|
+
if xsize == 0 and ysize == 0:
|
|
87
|
+
return
|
|
88
|
+
|
|
89
|
+
self.ysize = h
|
|
90
|
+
|
|
91
|
+
# paste glyphs into bitmap
|
|
92
|
+
Image._decompression_bomb_check((xsize, ysize))
|
|
93
|
+
self.bitmap = Image.new("1", (xsize, ysize))
|
|
94
|
+
self.metrics: list[
|
|
95
|
+
tuple[tuple[int, int], tuple[int, int, int, int], tuple[int, int, int, int]]
|
|
96
|
+
| None
|
|
97
|
+
] = [None] * 256
|
|
98
|
+
x = y = 0
|
|
99
|
+
for i in range(256):
|
|
100
|
+
glyph = self[i]
|
|
101
|
+
if glyph:
|
|
102
|
+
d, dst, src, im = glyph
|
|
103
|
+
xx = src[2] - src[0]
|
|
104
|
+
x0, y0 = x, y
|
|
105
|
+
x = x + xx
|
|
106
|
+
if x > WIDTH:
|
|
107
|
+
x, y = 0, y + h
|
|
108
|
+
x0, y0 = x, y
|
|
109
|
+
x = xx
|
|
110
|
+
s = src[0] + x0, src[1] + y0, src[2] + x0, src[3] + y0
|
|
111
|
+
self.bitmap.paste(im.crop(src), s)
|
|
112
|
+
self.metrics[i] = d, dst, s
|
|
113
|
+
|
|
114
|
+
def _encode_metrics(self) -> bytes:
|
|
115
|
+
values: list[int] = []
|
|
116
|
+
for i in range(256):
|
|
117
|
+
m = self.metrics[i]
|
|
118
|
+
if m:
|
|
119
|
+
values.extend(m[0] + m[1] + m[2])
|
|
120
|
+
else:
|
|
121
|
+
values.extend((0,) * 10)
|
|
122
|
+
|
|
123
|
+
data = bytearray()
|
|
124
|
+
for v in values:
|
|
125
|
+
if v < 0:
|
|
126
|
+
v += 65536
|
|
127
|
+
data += _binary.o16be(v)
|
|
128
|
+
return bytes(data)
|
|
129
|
+
|
|
130
|
+
def save(self, filename: str) -> None:
|
|
131
|
+
"""Save font"""
|
|
132
|
+
|
|
133
|
+
self.compile()
|
|
134
|
+
|
|
135
|
+
# font data
|
|
136
|
+
if not self.bitmap:
|
|
137
|
+
msg = "No bitmap created"
|
|
138
|
+
raise ValueError(msg)
|
|
139
|
+
self.bitmap.save(os.path.splitext(filename)[0] + ".pbm", "PNG")
|
|
140
|
+
|
|
141
|
+
# font metrics
|
|
142
|
+
with open(os.path.splitext(filename)[0] + ".pil", "wb") as fp:
|
|
143
|
+
fp.write(b"PILfont\n")
|
|
144
|
+
fp.write(f";;;;;;{self.ysize};\n".encode("ascii")) # HACK!!!
|
|
145
|
+
fp.write(b"DATA\n")
|
|
146
|
+
fp.write(self._encode_metrics())
|
|
147
|
+
|
|
148
|
+
def to_imagefont(self) -> ImageFont.ImageFont:
|
|
149
|
+
"""Convert to ImageFont"""
|
|
150
|
+
|
|
151
|
+
self.compile()
|
|
152
|
+
|
|
153
|
+
# font data
|
|
154
|
+
if not self.bitmap:
|
|
155
|
+
msg = "No bitmap created"
|
|
156
|
+
raise ValueError(msg)
|
|
157
|
+
|
|
158
|
+
imagefont = ImageFont.ImageFont()
|
|
159
|
+
imagefont._load(self.bitmap, self._encode_metrics())
|
|
160
|
+
return imagefont
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
#
|
|
2
|
+
# THIS IS WORK IN PROGRESS
|
|
3
|
+
#
|
|
4
|
+
# The Python Imaging Library.
|
|
5
|
+
# $Id$
|
|
6
|
+
#
|
|
7
|
+
# FlashPix support for PIL
|
|
8
|
+
#
|
|
9
|
+
# History:
|
|
10
|
+
# 97-01-25 fl Created (reads uncompressed RGB images only)
|
|
11
|
+
#
|
|
12
|
+
# Copyright (c) Secret Labs AB 1997.
|
|
13
|
+
# Copyright (c) Fredrik Lundh 1997.
|
|
14
|
+
#
|
|
15
|
+
# See the README file for information on usage and redistribution.
|
|
16
|
+
#
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import olefile
|
|
20
|
+
|
|
21
|
+
from . import Image, ImageFile
|
|
22
|
+
from ._binary import i32le as i32
|
|
23
|
+
|
|
24
|
+
# we map from colour field tuples to (mode, rawmode) descriptors
|
|
25
|
+
MODES = {
|
|
26
|
+
# opacity
|
|
27
|
+
(0x00007FFE,): ("A", "L"),
|
|
28
|
+
# monochrome
|
|
29
|
+
(0x00010000,): ("L", "L"),
|
|
30
|
+
(0x00018000, 0x00017FFE): ("RGBA", "LA"),
|
|
31
|
+
# photo YCC
|
|
32
|
+
(0x00020000, 0x00020001, 0x00020002): ("RGB", "YCC;P"),
|
|
33
|
+
(0x00028000, 0x00028001, 0x00028002, 0x00027FFE): ("RGBA", "YCCA;P"),
|
|
34
|
+
# standard RGB (NIFRGB)
|
|
35
|
+
(0x00030000, 0x00030001, 0x00030002): ("RGB", "RGB"),
|
|
36
|
+
(0x00038000, 0x00038001, 0x00038002, 0x00037FFE): ("RGBA", "RGBA"),
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
#
|
|
41
|
+
# --------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _accept(prefix: bytes) -> bool:
|
|
45
|
+
return prefix.startswith(olefile.MAGIC)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
##
|
|
49
|
+
# Image plugin for the FlashPix images.
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class FpxImageFile(ImageFile.ImageFile):
|
|
53
|
+
format = "FPX"
|
|
54
|
+
format_description = "FlashPix"
|
|
55
|
+
|
|
56
|
+
def _open(self) -> None:
|
|
57
|
+
#
|
|
58
|
+
# read the OLE directory and see if this is a likely
|
|
59
|
+
# to be a FlashPix file
|
|
60
|
+
|
|
61
|
+
assert self.fp is not None
|
|
62
|
+
try:
|
|
63
|
+
self.ole = olefile.OleFileIO(self.fp)
|
|
64
|
+
except OSError as e:
|
|
65
|
+
msg = "not an FPX file; invalid OLE file"
|
|
66
|
+
raise SyntaxError(msg) from e
|
|
67
|
+
|
|
68
|
+
root = self.ole.root
|
|
69
|
+
if not root or root.clsid != "56616700-C154-11CE-8553-00AA00A1F95B":
|
|
70
|
+
msg = "not an FPX file; bad root CLSID"
|
|
71
|
+
raise SyntaxError(msg)
|
|
72
|
+
|
|
73
|
+
self._open_index(1)
|
|
74
|
+
|
|
75
|
+
def _open_index(self, index: int = 1) -> None:
|
|
76
|
+
#
|
|
77
|
+
# get the Image Contents Property Set
|
|
78
|
+
|
|
79
|
+
prop = self.ole.getproperties(
|
|
80
|
+
[f"Data Object Store {index:06d}", "\005Image Contents"]
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# size (highest resolution)
|
|
84
|
+
|
|
85
|
+
assert isinstance(prop[0x1000002], int)
|
|
86
|
+
assert isinstance(prop[0x1000003], int)
|
|
87
|
+
self._size = prop[0x1000002], prop[0x1000003]
|
|
88
|
+
|
|
89
|
+
size = max(self.size)
|
|
90
|
+
i = 1
|
|
91
|
+
while size > 64:
|
|
92
|
+
size = size // 2
|
|
93
|
+
i += 1
|
|
94
|
+
self.maxid = i - 1
|
|
95
|
+
|
|
96
|
+
# mode. instead of using a single field for this, flashpix
|
|
97
|
+
# requires you to specify the mode for each channel in each
|
|
98
|
+
# resolution subimage, and leaves it to the decoder to make
|
|
99
|
+
# sure that they all match. for now, we'll cheat and assume
|
|
100
|
+
# that this is always the case.
|
|
101
|
+
|
|
102
|
+
id = self.maxid << 16
|
|
103
|
+
|
|
104
|
+
s = prop[0x2000002 | id]
|
|
105
|
+
|
|
106
|
+
if not isinstance(s, bytes) or (bands := i32(s, 4)) > 4:
|
|
107
|
+
msg = "Invalid number of bands"
|
|
108
|
+
raise OSError(msg)
|
|
109
|
+
|
|
110
|
+
# note: for now, we ignore the "uncalibrated" flag
|
|
111
|
+
colors = tuple(i32(s, 8 + i * 4) & 0x7FFFFFFF for i in range(bands))
|
|
112
|
+
|
|
113
|
+
self._mode, self.rawmode = MODES[colors]
|
|
114
|
+
|
|
115
|
+
# load JPEG tables, if any
|
|
116
|
+
self.jpeg = {}
|
|
117
|
+
for i in range(256):
|
|
118
|
+
id = 0x3000001 | (i << 16)
|
|
119
|
+
if id in prop:
|
|
120
|
+
self.jpeg[i] = prop[id]
|
|
121
|
+
|
|
122
|
+
self._open_subimage(1, self.maxid)
|
|
123
|
+
|
|
124
|
+
def _open_subimage(self, index: int = 1, subimage: int = 0) -> None:
|
|
125
|
+
#
|
|
126
|
+
# setup tile descriptors for a given subimage
|
|
127
|
+
|
|
128
|
+
stream = [
|
|
129
|
+
f"Data Object Store {index:06d}",
|
|
130
|
+
f"Resolution {subimage:04d}",
|
|
131
|
+
"Subimage 0000 Header",
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
fp = self.ole.openstream(stream)
|
|
135
|
+
|
|
136
|
+
# skip prefix
|
|
137
|
+
fp.read(28)
|
|
138
|
+
|
|
139
|
+
# header stream
|
|
140
|
+
s = fp.read(36)
|
|
141
|
+
|
|
142
|
+
size = i32(s, 4), i32(s, 8)
|
|
143
|
+
# tilecount = i32(s, 12)
|
|
144
|
+
xtile, ytile = i32(s, 16), i32(s, 20)
|
|
145
|
+
if xtile != 64 or ytile != 64:
|
|
146
|
+
msg = "Tile must be 64 pixels by 64 pixels"
|
|
147
|
+
raise ValueError(msg)
|
|
148
|
+
|
|
149
|
+
# channels = i32(s, 24)
|
|
150
|
+
offset = i32(s, 28)
|
|
151
|
+
length = i32(s, 32)
|
|
152
|
+
|
|
153
|
+
if size != self.size:
|
|
154
|
+
msg = "subimage mismatch"
|
|
155
|
+
raise OSError(msg)
|
|
156
|
+
|
|
157
|
+
# get tile descriptors
|
|
158
|
+
fp.seek(28 + offset)
|
|
159
|
+
s = fp.read(i32(s, 12) * length)
|
|
160
|
+
|
|
161
|
+
x = y = 0
|
|
162
|
+
xsize, ysize = size
|
|
163
|
+
self.tile = []
|
|
164
|
+
|
|
165
|
+
for i in range(0, len(s), length):
|
|
166
|
+
x1 = min(xsize, x + xtile)
|
|
167
|
+
y1 = min(ysize, y + ytile)
|
|
168
|
+
|
|
169
|
+
compression = i32(s, i + 8)
|
|
170
|
+
|
|
171
|
+
if compression == 0:
|
|
172
|
+
self.tile.append(
|
|
173
|
+
ImageFile._Tile(
|
|
174
|
+
"raw",
|
|
175
|
+
(x, y, x1, y1),
|
|
176
|
+
i32(s, i) + 28,
|
|
177
|
+
self.rawmode,
|
|
178
|
+
)
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
elif compression == 1:
|
|
182
|
+
# FIXME: the fill decoder is not implemented
|
|
183
|
+
self.tile.append(
|
|
184
|
+
ImageFile._Tile(
|
|
185
|
+
"fill",
|
|
186
|
+
(x, y, x1, y1),
|
|
187
|
+
i32(s, i) + 28,
|
|
188
|
+
(self.rawmode, s[12:16]),
|
|
189
|
+
)
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
elif compression == 2:
|
|
193
|
+
internal_color_conversion = s[14]
|
|
194
|
+
jpeg_tables = s[15]
|
|
195
|
+
rawmode = self.rawmode
|
|
196
|
+
|
|
197
|
+
if internal_color_conversion:
|
|
198
|
+
# The image is stored as usual (usually YCbCr).
|
|
199
|
+
if rawmode == "RGBA":
|
|
200
|
+
# For "RGBA", data is stored as YCbCrA based on
|
|
201
|
+
# negative RGB. The following trick works around
|
|
202
|
+
# this problem :
|
|
203
|
+
jpegmode, rawmode = "YCbCrK", "CMYK"
|
|
204
|
+
else:
|
|
205
|
+
jpegmode = None # let the decoder decide
|
|
206
|
+
|
|
207
|
+
else:
|
|
208
|
+
# The image is stored as defined by rawmode
|
|
209
|
+
jpegmode = rawmode
|
|
210
|
+
|
|
211
|
+
self.tile.append(
|
|
212
|
+
ImageFile._Tile(
|
|
213
|
+
"jpeg",
|
|
214
|
+
(x, y, x1, y1),
|
|
215
|
+
i32(s, i) + 28,
|
|
216
|
+
(rawmode, jpegmode),
|
|
217
|
+
)
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# FIXME: jpeg tables are tile dependent; the prefix
|
|
221
|
+
# data must be placed in the tile descriptor itself!
|
|
222
|
+
|
|
223
|
+
if jpeg_tables:
|
|
224
|
+
self.tile_prefix = self.jpeg[jpeg_tables]
|
|
225
|
+
|
|
226
|
+
else:
|
|
227
|
+
msg = "unknown/invalid compression"
|
|
228
|
+
raise OSError(msg)
|
|
229
|
+
|
|
230
|
+
x += xtile
|
|
231
|
+
if x >= xsize:
|
|
232
|
+
x, y = 0, y + ytile
|
|
233
|
+
if y >= ysize:
|
|
234
|
+
break # isn't really required
|
|
235
|
+
|
|
236
|
+
assert self.fp is not None
|
|
237
|
+
self.stream = stream
|
|
238
|
+
self._fp = self.fp
|
|
239
|
+
self.fp = None
|
|
240
|
+
|
|
241
|
+
def load(self) -> Image.core.PixelAccess | None:
|
|
242
|
+
if not self.fp:
|
|
243
|
+
self.fp = self.ole.openstream(self.stream[:2] + ["Subimage 0000 Data"])
|
|
244
|
+
|
|
245
|
+
return ImageFile.ImageFile.load(self)
|
|
246
|
+
|
|
247
|
+
def close(self) -> None:
|
|
248
|
+
self.ole.close()
|
|
249
|
+
super().close()
|
|
250
|
+
|
|
251
|
+
def __exit__(self, *args: object) -> None:
|
|
252
|
+
self.ole.close()
|
|
253
|
+
super().__exit__()
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
#
|
|
257
|
+
# --------------------------------------------------------------------
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
Image.register_open(FpxImageFile.format, FpxImageFile, _accept)
|
|
261
|
+
|
|
262
|
+
Image.register_extension(FpxImageFile.format, ".fpx")
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A Pillow loader for .ftc and .ftu files (FTEX)
|
|
3
|
+
Jerome Leclanche <jerome@leclan.ch>
|
|
4
|
+
|
|
5
|
+
The contents of this file are hereby released in the public domain (CC0)
|
|
6
|
+
Full text of the CC0 license:
|
|
7
|
+
https://creativecommons.org/publicdomain/zero/1.0/
|
|
8
|
+
|
|
9
|
+
Independence War 2: Edge Of Chaos - Texture File Format - 16 October 2001
|
|
10
|
+
|
|
11
|
+
The textures used for 3D objects in Independence War 2: Edge Of Chaos are in a
|
|
12
|
+
packed custom format called FTEX. This file format uses file extensions FTC
|
|
13
|
+
and FTU.
|
|
14
|
+
* FTC files are compressed textures (using standard texture compression).
|
|
15
|
+
* FTU files are not compressed.
|
|
16
|
+
Texture File Format
|
|
17
|
+
The FTC and FTU texture files both use the same format. This
|
|
18
|
+
has the following structure:
|
|
19
|
+
{header}
|
|
20
|
+
{format_directory}
|
|
21
|
+
{data}
|
|
22
|
+
Where:
|
|
23
|
+
{header} = {
|
|
24
|
+
u32:magic,
|
|
25
|
+
u32:version,
|
|
26
|
+
u32:width,
|
|
27
|
+
u32:height,
|
|
28
|
+
u32:mipmap_count,
|
|
29
|
+
u32:format_count
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
* The "magic" number is "FTEX".
|
|
33
|
+
* "width" and "height" are the dimensions of the texture.
|
|
34
|
+
* "mipmap_count" is the number of mipmaps in the texture.
|
|
35
|
+
* "format_count" is the number of texture formats (different versions of the
|
|
36
|
+
same texture) in this file.
|
|
37
|
+
|
|
38
|
+
{format_directory} = format_count * { u32:format, u32:where }
|
|
39
|
+
|
|
40
|
+
The format value is 0 for DXT1 compressed textures and 1 for 24-bit RGB
|
|
41
|
+
uncompressed textures.
|
|
42
|
+
The texture data for a format starts at the position "where" in the file.
|
|
43
|
+
|
|
44
|
+
Each set of texture data in the file has the following structure:
|
|
45
|
+
{data} = format_count * { u32:mipmap_size, mipmap_size * { u8 } }
|
|
46
|
+
* "mipmap_size" is the number of bytes in that mip level. For compressed
|
|
47
|
+
textures this is the size of the texture data compressed with DXT1. For 24 bit
|
|
48
|
+
uncompressed textures, this is 3 * width * height. Following this are the image
|
|
49
|
+
bytes for that mipmap level.
|
|
50
|
+
|
|
51
|
+
Note: All data is stored in little-Endian (Intel) byte order.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
from __future__ import annotations
|
|
55
|
+
|
|
56
|
+
import struct
|
|
57
|
+
from enum import IntEnum
|
|
58
|
+
from io import BytesIO
|
|
59
|
+
|
|
60
|
+
from . import Image, ImageFile
|
|
61
|
+
|
|
62
|
+
MAGIC = b"FTEX"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class Format(IntEnum):
|
|
66
|
+
DXT1 = 0
|
|
67
|
+
UNCOMPRESSED = 1
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class FtexImageFile(ImageFile.ImageFile):
|
|
71
|
+
format = "FTEX"
|
|
72
|
+
format_description = "Texture File Format (IW2:EOC)"
|
|
73
|
+
|
|
74
|
+
def _open(self) -> None:
|
|
75
|
+
assert self.fp is not None
|
|
76
|
+
if not _accept(self.fp.read(4)):
|
|
77
|
+
msg = "not an FTEX file"
|
|
78
|
+
raise SyntaxError(msg)
|
|
79
|
+
struct.unpack("<i", self.fp.read(4)) # version
|
|
80
|
+
self._size = struct.unpack("<2i", self.fp.read(8))
|
|
81
|
+
mipmap_count, format_count = struct.unpack("<2i", self.fp.read(8))
|
|
82
|
+
|
|
83
|
+
# Only support single-format files.
|
|
84
|
+
# I don't know of any multi-format file.
|
|
85
|
+
assert format_count == 1
|
|
86
|
+
|
|
87
|
+
format, where = struct.unpack("<2i", self.fp.read(8))
|
|
88
|
+
self.fp.seek(where)
|
|
89
|
+
(mipmap_size,) = struct.unpack("<i", self.fp.read(4))
|
|
90
|
+
|
|
91
|
+
data = self.fp.read(mipmap_size)
|
|
92
|
+
|
|
93
|
+
if format == Format.DXT1:
|
|
94
|
+
self._mode = "RGBA"
|
|
95
|
+
self.tile = [ImageFile._Tile("bcn", (0, 0) + self.size, 0, (1,))]
|
|
96
|
+
elif format == Format.UNCOMPRESSED:
|
|
97
|
+
self._mode = "RGB"
|
|
98
|
+
self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 0, "RGB")]
|
|
99
|
+
else:
|
|
100
|
+
msg = f"Invalid texture compression format: {repr(format)}"
|
|
101
|
+
raise ValueError(msg)
|
|
102
|
+
|
|
103
|
+
self.fp.close()
|
|
104
|
+
self.fp = BytesIO(data)
|
|
105
|
+
|
|
106
|
+
def load_seek(self, pos: int) -> None:
|
|
107
|
+
pass
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _accept(prefix: bytes) -> bool:
|
|
111
|
+
return prefix.startswith(MAGIC)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
Image.register_open(FtexImageFile.format, FtexImageFile, _accept)
|
|
115
|
+
Image.register_extensions(FtexImageFile.format, [".ftc", ".ftu"])
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#
|
|
2
|
+
# The Python Imaging Library
|
|
3
|
+
#
|
|
4
|
+
# load a GIMP brush file
|
|
5
|
+
#
|
|
6
|
+
# History:
|
|
7
|
+
# 96-03-14 fl Created
|
|
8
|
+
# 16-01-08 es Version 2
|
|
9
|
+
#
|
|
10
|
+
# Copyright (c) Secret Labs AB 1997.
|
|
11
|
+
# Copyright (c) Fredrik Lundh 1996.
|
|
12
|
+
# Copyright (c) Eric Soroos 2016.
|
|
13
|
+
#
|
|
14
|
+
# See the README file for information on usage and redistribution.
|
|
15
|
+
#
|
|
16
|
+
#
|
|
17
|
+
# See https://github.com/GNOME/gimp/blob/mainline/devel-docs/gbr.txt for
|
|
18
|
+
# format documentation.
|
|
19
|
+
#
|
|
20
|
+
# This code Interprets version 1 and 2 .gbr files.
|
|
21
|
+
# Version 1 files are obsolete, and should not be used for new
|
|
22
|
+
# brushes.
|
|
23
|
+
# Version 2 files are saved by GIMP v2.8 (at least)
|
|
24
|
+
# Version 3 files have a format specifier of 18 for 16bit floats in
|
|
25
|
+
# the color depth field. This is currently unsupported by Pillow.
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
from . import Image, ImageFile
|
|
29
|
+
from ._binary import i32be as i32
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _accept(prefix: bytes) -> bool:
|
|
33
|
+
return len(prefix) >= 8 and i32(prefix, 0) >= 20 and i32(prefix, 4) in (1, 2)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
##
|
|
37
|
+
# Image plugin for the GIMP brush format.
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class GbrImageFile(ImageFile.ImageFile):
|
|
41
|
+
format = "GBR"
|
|
42
|
+
format_description = "GIMP brush file"
|
|
43
|
+
|
|
44
|
+
def _open(self) -> None:
|
|
45
|
+
assert self.fp is not None
|
|
46
|
+
header_size = i32(self.fp.read(4))
|
|
47
|
+
if header_size < 20:
|
|
48
|
+
msg = "not a GIMP brush"
|
|
49
|
+
raise SyntaxError(msg)
|
|
50
|
+
version = i32(self.fp.read(4))
|
|
51
|
+
if version not in (1, 2):
|
|
52
|
+
msg = f"Unsupported GIMP brush version: {version}"
|
|
53
|
+
raise SyntaxError(msg)
|
|
54
|
+
|
|
55
|
+
width = i32(self.fp.read(4))
|
|
56
|
+
height = i32(self.fp.read(4))
|
|
57
|
+
color_depth = i32(self.fp.read(4))
|
|
58
|
+
if width == 0 or height == 0:
|
|
59
|
+
msg = "not a GIMP brush"
|
|
60
|
+
raise SyntaxError(msg)
|
|
61
|
+
if color_depth not in (1, 4):
|
|
62
|
+
msg = f"Unsupported GIMP brush color depth: {color_depth}"
|
|
63
|
+
raise SyntaxError(msg)
|
|
64
|
+
|
|
65
|
+
if version == 1:
|
|
66
|
+
comment_length = header_size - 20
|
|
67
|
+
else:
|
|
68
|
+
comment_length = header_size - 28
|
|
69
|
+
magic_number = self.fp.read(4)
|
|
70
|
+
if magic_number != b"GIMP":
|
|
71
|
+
msg = "not a GIMP brush, bad magic number"
|
|
72
|
+
raise SyntaxError(msg)
|
|
73
|
+
self.info["spacing"] = i32(self.fp.read(4))
|
|
74
|
+
|
|
75
|
+
self.info["comment"] = self.fp.read(comment_length)[:-1]
|
|
76
|
+
|
|
77
|
+
if color_depth == 1:
|
|
78
|
+
self._mode = "L"
|
|
79
|
+
else:
|
|
80
|
+
self._mode = "RGBA"
|
|
81
|
+
|
|
82
|
+
self._size = width, height
|
|
83
|
+
|
|
84
|
+
# Image might not be small
|
|
85
|
+
Image._decompression_bomb_check(self.size)
|
|
86
|
+
|
|
87
|
+
# Data is an uncompressed block of w * h * bytes/pixel
|
|
88
|
+
self._data_size = width * height * color_depth
|
|
89
|
+
|
|
90
|
+
def load(self) -> Image.core.PixelAccess | None:
|
|
91
|
+
if self._im is None:
|
|
92
|
+
assert self.fp is not None
|
|
93
|
+
self.im = Image.core.new(self.mode, self.size)
|
|
94
|
+
self.frombytes(self.fp.read(self._data_size))
|
|
95
|
+
return Image.Image.load(self)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
#
|
|
99
|
+
# registry
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
Image.register_open(GbrImageFile.format, GbrImageFile, _accept)
|
|
103
|
+
Image.register_extension(GbrImageFile.format, ".gbr")
|