Roshan1162003 commited on
Commit
4608b26
·
verified ·
1 Parent(s): 0edb558

Upload folder using huggingface_hub

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +196 -0
  2. app.py +110 -0
  3. fine_tuned_model/feature_extractor/preprocessor_config.json +27 -0
  4. fine_tuned_model/logs/dreambooth/1750848551.8584013/events.out.tfevents.1750848551.ef0460d8cbbe.10247.1 +3 -0
  5. fine_tuned_model/logs/dreambooth/1750848551.8677673/hparams.yml +60 -0
  6. fine_tuned_model/logs/dreambooth/1750848665.145276/events.out.tfevents.1750848665.ef0460d8cbbe.10782.1 +3 -0
  7. fine_tuned_model/logs/dreambooth/1750848665.1627958/hparams.yml +60 -0
  8. fine_tuned_model/logs/dreambooth/events.out.tfevents.1750848551.ef0460d8cbbe.10247.0 +3 -0
  9. fine_tuned_model/logs/dreambooth/events.out.tfevents.1750848665.ef0460d8cbbe.10782.0 +3 -0
  10. fine_tuned_model/model_index.json +38 -0
  11. fine_tuned_model/safety_checker/config.json +46 -0
  12. fine_tuned_model/safety_checker/model.safetensors +3 -0
  13. fine_tuned_model/scheduler/scheduler_config.json +15 -0
  14. fine_tuned_model/text_encoder/config.json +24 -0
  15. fine_tuned_model/text_encoder/model.safetensors +3 -0
  16. fine_tuned_model/tokenizer/merges.txt +0 -0
  17. fine_tuned_model/tokenizer/special_tokens_map.json +30 -0
  18. fine_tuned_model/tokenizer/tokenizer_config.json +31 -0
  19. fine_tuned_model/tokenizer/vocab.json +0 -0
  20. fine_tuned_model/unet/config.json +68 -0
  21. fine_tuned_model/unet/diffusion_pytorch_model.safetensors +3 -0
  22. fine_tuned_model/vae/config.json +38 -0
  23. fine_tuned_model/vae/diffusion_pytorch_model.safetensors +3 -0
  24. generate_images_local.py +48 -0
  25. requirements.txt +7 -0
  26. templates/index.html +601 -0
  27. venv/Lib/site-packages/MarkupSafe-3.0.2.dist-info/INSTALLER +1 -0
  28. venv/Lib/site-packages/MarkupSafe-3.0.2.dist-info/LICENSE.txt +28 -0
  29. venv/Lib/site-packages/MarkupSafe-3.0.2.dist-info/METADATA +92 -0
  30. venv/Lib/site-packages/MarkupSafe-3.0.2.dist-info/RECORD +14 -0
  31. venv/Lib/site-packages/MarkupSafe-3.0.2.dist-info/WHEEL +5 -0
  32. venv/Lib/site-packages/MarkupSafe-3.0.2.dist-info/top_level.txt +1 -0
  33. venv/Lib/site-packages/PIL/AvifImagePlugin.py +292 -0
  34. venv/Lib/site-packages/PIL/BdfFontFile.py +122 -0
  35. venv/Lib/site-packages/PIL/BlpImagePlugin.py +497 -0
  36. venv/Lib/site-packages/PIL/BmpImagePlugin.py +515 -0
  37. venv/Lib/site-packages/PIL/BufrStubImagePlugin.py +75 -0
  38. venv/Lib/site-packages/PIL/ContainerIO.py +173 -0
  39. venv/Lib/site-packages/PIL/CurImagePlugin.py +75 -0
  40. venv/Lib/site-packages/PIL/DcxImagePlugin.py +83 -0
  41. venv/Lib/site-packages/PIL/DdsImagePlugin.py +624 -0
  42. venv/Lib/site-packages/PIL/EpsImagePlugin.py +476 -0
  43. venv/Lib/site-packages/PIL/ExifTags.py +382 -0
  44. venv/Lib/site-packages/PIL/FitsImagePlugin.py +152 -0
  45. venv/Lib/site-packages/PIL/FliImagePlugin.py +178 -0
  46. venv/Lib/site-packages/PIL/FontFile.py +134 -0
  47. venv/Lib/site-packages/PIL/FpxImagePlugin.py +257 -0
  48. venv/Lib/site-packages/PIL/FtexImagePlugin.py +114 -0
  49. venv/Lib/site-packages/PIL/GbrImagePlugin.py +103 -0
  50. venv/Lib/site-packages/PIL/GdImageFile.py +102 -0
.gitattributes CHANGED
@@ -33,3 +33,199 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ venv/Lib/site-packages/__pycache__/typing_extensions.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
37
+ venv/Lib/site-packages/accelerate/__pycache__/accelerator.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
38
+ venv/Lib/site-packages/accelerate/utils/__pycache__/dataclasses.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
39
+ venv/Lib/site-packages/charset_normalizer/md__mypyc.cp310-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
40
+ venv/Lib/site-packages/diffusers/loaders/__pycache__/lora_pipeline.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
41
+ venv/Lib/site-packages/diffusers/models/__pycache__/attention_processor.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
42
+ venv/Lib/site-packages/functorch/_C.cp310-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
43
+ venv/Lib/site-packages/huggingface_hub/__pycache__/hf_api.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
44
+ venv/Lib/site-packages/huggingface_hub/inference/__pycache__/_client.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
45
+ venv/Lib/site-packages/huggingface_hub/inference/_generated/__pycache__/_async_client.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
46
+ venv/Lib/site-packages/idna/__pycache__/idnadata.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
47
+ venv/Lib/site-packages/idna/__pycache__/uts46data.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
48
+ venv/Lib/site-packages/mpmath/__pycache__/function_docs.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
49
+ venv/Lib/site-packages/numpy/_core/__pycache__/_add_newdocs.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
50
+ venv/Lib/site-packages/numpy/_core/__pycache__/fromnumeric.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
51
+ venv/Lib/site-packages/numpy/_core/_multiarray_umath.cp310-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
52
+ venv/Lib/site-packages/numpy/_core/_simd.cp310-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
53
+ venv/Lib/site-packages/numpy/_core/lib/npymath.lib filter=lfs diff=lfs merge=lfs -text
54
+ venv/Lib/site-packages/numpy/_core/tests/__pycache__/test_multiarray.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
55
+ venv/Lib/site-packages/numpy/_core/tests/__pycache__/test_numeric.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
56
+ venv/Lib/site-packages/numpy/_core/tests/__pycache__/test_regression.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
57
+ venv/Lib/site-packages/numpy/_core/tests/__pycache__/test_ufunc.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
58
+ venv/Lib/site-packages/numpy/_core/tests/__pycache__/test_umath.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
59
+ venv/Lib/site-packages/numpy/fft/_pocketfft_umath.cp310-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
60
+ venv/Lib/site-packages/numpy/lib/__pycache__/_function_base_impl.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
61
+ venv/Lib/site-packages/numpy/lib/tests/__pycache__/test_function_base.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
62
+ venv/Lib/site-packages/numpy/linalg/__pycache__/_linalg.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
63
+ venv/Lib/site-packages/numpy/linalg/_umath_linalg.cp310-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
64
+ venv/Lib/site-packages/numpy/ma/__pycache__/core.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
65
+ venv/Lib/site-packages/numpy/ma/tests/__pycache__/test_core.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
66
+ venv/Lib/site-packages/numpy/random/_bounded_integers.cp310-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
67
+ venv/Lib/site-packages/numpy/random/_common.cp310-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
68
+ venv/Lib/site-packages/numpy/random/_generator.cp310-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
69
+ venv/Lib/site-packages/numpy/random/bit_generator.cp310-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
70
+ venv/Lib/site-packages/numpy/random/lib/npyrandom.lib filter=lfs diff=lfs merge=lfs -text
71
+ venv/Lib/site-packages/numpy/random/mtrand.cp310-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
72
+ venv/Lib/site-packages/numpy.libs/libscipy_openblas64_-13e2df515630b4a41f92893938845698.dll filter=lfs diff=lfs merge=lfs -text
73
+ venv/Lib/site-packages/numpy.libs/msvcp140-263139962577ecda4cd9469ca360a746.dll filter=lfs diff=lfs merge=lfs -text
74
+ venv/Lib/site-packages/PIL/__pycache__/Image.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
75
+ venv/Lib/site-packages/PIL/_imaging.cp310-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
76
+ venv/Lib/site-packages/PIL/_imagingcms.cp310-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
77
+ venv/Lib/site-packages/PIL/_imagingft.cp310-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
78
+ venv/Lib/site-packages/PIL/_webp.cp310-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
79
+ venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/johabfreq.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
80
+ venv/Lib/site-packages/pip/_vendor/distlib/t64-arm.exe filter=lfs diff=lfs merge=lfs -text
81
+ venv/Lib/site-packages/pip/_vendor/distlib/t64.exe filter=lfs diff=lfs merge=lfs -text
82
+ venv/Lib/site-packages/pip/_vendor/distlib/w64-arm.exe filter=lfs diff=lfs merge=lfs -text
83
+ venv/Lib/site-packages/pip/_vendor/distlib/w64.exe filter=lfs diff=lfs merge=lfs -text
84
+ venv/Lib/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
85
+ venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/core.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
86
+ venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
87
+ venv/Lib/site-packages/pkg_resources/__pycache__/__init__.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
88
+ venv/Lib/site-packages/pkg_resources/_vendor/more_itertools/__pycache__/more.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
89
+ venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/core.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
90
+ venv/Lib/site-packages/regex/__pycache__/_regex_core.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
91
+ venv/Lib/site-packages/regex/__pycache__/test_regex.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
92
+ venv/Lib/site-packages/regex/_regex.cp310-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
93
+ venv/Lib/site-packages/safetensors/_safetensors_rust.pyd filter=lfs diff=lfs merge=lfs -text
94
+ venv/Lib/site-packages/setuptools/_vendor/more_itertools/__pycache__/more.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
95
+ venv/Lib/site-packages/setuptools/_vendor/pyparsing/__pycache__/core.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
96
+ venv/Lib/site-packages/setuptools/cli-arm64.exe filter=lfs diff=lfs merge=lfs -text
97
+ venv/Lib/site-packages/setuptools/gui-arm64.exe filter=lfs diff=lfs merge=lfs -text
98
+ venv/Lib/site-packages/sympy/combinatorics/__pycache__/perm_groups.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
99
+ venv/Lib/site-packages/sympy/core/__pycache__/expr.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
100
+ venv/Lib/site-packages/sympy/core/__pycache__/function.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
101
+ venv/Lib/site-packages/sympy/core/__pycache__/numbers.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
102
+ venv/Lib/site-packages/sympy/core/tests/__pycache__/test_args.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
103
+ venv/Lib/site-packages/sympy/logic/__pycache__/boolalg.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
104
+ venv/Lib/site-packages/sympy/matrices/__pycache__/matrixbase.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
105
+ venv/Lib/site-packages/sympy/matrices/tests/__pycache__/test_matrices.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
106
+ venv/Lib/site-packages/sympy/matrices/tests/__pycache__/test_matrixbase.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
107
+ venv/Lib/site-packages/sympy/parsing/latex/_antlr/__pycache__/latexparser.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
108
+ venv/Lib/site-packages/sympy/physics/continuum_mechanics/__pycache__/beam.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
109
+ venv/Lib/site-packages/sympy/physics/control/__pycache__/lti.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
110
+ venv/Lib/site-packages/sympy/physics/quantum/tests/__pycache__/test_spin.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
111
+ venv/Lib/site-packages/sympy/polys/__pycache__/polyquinticconst.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
112
+ venv/Lib/site-packages/sympy/polys/__pycache__/polytools.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
113
+ venv/Lib/site-packages/sympy/polys/benchmarks/__pycache__/bench_solvers.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
114
+ venv/Lib/site-packages/sympy/polys/matrices/__pycache__/domainmatrix.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
115
+ venv/Lib/site-packages/sympy/polys/tests/__pycache__/test_polytools.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
116
+ venv/Lib/site-packages/sympy/printing/__pycache__/latex.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
117
+ venv/Lib/site-packages/sympy/printing/pretty/tests/__pycache__/test_pretty.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
118
+ venv/Lib/site-packages/sympy/printing/tests/__pycache__/test_latex.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
119
+ venv/Lib/site-packages/sympy/solvers/__pycache__/solvers.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
120
+ venv/Lib/site-packages/sympy/solvers/__pycache__/solveset.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
121
+ venv/Lib/site-packages/sympy/solvers/diophantine/__pycache__/diophantine.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
122
+ venv/Lib/site-packages/sympy/solvers/ode/__pycache__/ode.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
123
+ venv/Lib/site-packages/sympy/solvers/ode/__pycache__/single.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
124
+ venv/Lib/site-packages/sympy/solvers/ode/tests/__pycache__/test_systems.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
125
+ venv/Lib/site-packages/sympy/solvers/tests/__pycache__/test_solvers.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
126
+ venv/Lib/site-packages/sympy/solvers/tests/__pycache__/test_solveset.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
127
+ venv/Lib/site-packages/sympy/stats/__pycache__/crv_types.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
128
+ venv/Lib/site-packages/sympy/tensor/__pycache__/tensor.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
129
+ venv/Lib/site-packages/sympy/utilities/tests/__pycache__/test_wester.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
130
+ venv/Lib/site-packages/tokenizers/tokenizers.pyd filter=lfs diff=lfs merge=lfs -text
131
+ venv/Lib/site-packages/torch/__pycache__/_meta_registrations.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
132
+ venv/Lib/site-packages/torch/__pycache__/_tensor_docs.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
133
+ venv/Lib/site-packages/torch/__pycache__/_torch_docs.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
134
+ venv/Lib/site-packages/torch/__pycache__/overrides.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
135
+ venv/Lib/site-packages/torch/_decomp/__pycache__/decompositions.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
136
+ venv/Lib/site-packages/torch/_dynamo/__pycache__/symbolic_convert.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
137
+ venv/Lib/site-packages/torch/_dynamo/__pycache__/trace_rules.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
138
+ venv/Lib/site-packages/torch/_dynamo/__pycache__/utils.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
139
+ venv/Lib/site-packages/torch/_inductor/__pycache__/ir.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
140
+ venv/Lib/site-packages/torch/_inductor/__pycache__/lowering.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
141
+ venv/Lib/site-packages/torch/_inductor/__pycache__/scheduler.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
142
+ venv/Lib/site-packages/torch/_inductor/codegen/__pycache__/cpp.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
143
+ venv/Lib/site-packages/torch/_inductor/codegen/__pycache__/triton.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
144
+ venv/Lib/site-packages/torch/_refs/__pycache__/__init__.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
145
+ venv/Lib/site-packages/torch/bin/asmjit.dll filter=lfs diff=lfs merge=lfs -text
146
+ venv/Lib/site-packages/torch/bin/fbgemm.dll filter=lfs diff=lfs merge=lfs -text
147
+ venv/Lib/site-packages/torch/bin/protoc.exe filter=lfs diff=lfs merge=lfs -text
148
+ venv/Lib/site-packages/torch/distributed/__pycache__/distributed_c10d.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
149
+ venv/Lib/site-packages/torch/fx/experimental/__pycache__/symbolic_shapes.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
150
+ venv/Lib/site-packages/torch/lib/asmjit.dll filter=lfs diff=lfs merge=lfs -text
151
+ venv/Lib/site-packages/torch/lib/asmjit.lib filter=lfs diff=lfs merge=lfs -text
152
+ venv/Lib/site-packages/torch/lib/c10.dll filter=lfs diff=lfs merge=lfs -text
153
+ venv/Lib/site-packages/torch/lib/c10.lib filter=lfs diff=lfs merge=lfs -text
154
+ venv/Lib/site-packages/torch/lib/cpuinfo.lib filter=lfs diff=lfs merge=lfs -text
155
+ venv/Lib/site-packages/torch/lib/dnnl.lib filter=lfs diff=lfs merge=lfs -text
156
+ venv/Lib/site-packages/torch/lib/fbgemm.dll filter=lfs diff=lfs merge=lfs -text
157
+ venv/Lib/site-packages/torch/lib/fbgemm.lib filter=lfs diff=lfs merge=lfs -text
158
+ venv/Lib/site-packages/torch/lib/fmt.lib filter=lfs diff=lfs merge=lfs -text
159
+ venv/Lib/site-packages/torch/lib/kineto.lib filter=lfs diff=lfs merge=lfs -text
160
+ venv/Lib/site-packages/torch/lib/libiomp5md.dll filter=lfs diff=lfs merge=lfs -text
161
+ venv/Lib/site-packages/torch/lib/libprotobuf-lite.lib filter=lfs diff=lfs merge=lfs -text
162
+ venv/Lib/site-packages/torch/lib/libprotobuf.lib filter=lfs diff=lfs merge=lfs -text
163
+ venv/Lib/site-packages/torch/lib/libprotoc.lib filter=lfs diff=lfs merge=lfs -text
164
+ venv/Lib/site-packages/torch/lib/microkernels-prod.lib filter=lfs diff=lfs merge=lfs -text
165
+ venv/Lib/site-packages/torch/lib/pthreadpool.lib filter=lfs diff=lfs merge=lfs -text
166
+ venv/Lib/site-packages/torch/lib/sleef.lib filter=lfs diff=lfs merge=lfs -text
167
+ venv/Lib/site-packages/torch/lib/torch_cpu.dll filter=lfs diff=lfs merge=lfs -text
168
+ venv/Lib/site-packages/torch/lib/torch_cpu.lib filter=lfs diff=lfs merge=lfs -text
169
+ venv/Lib/site-packages/torch/lib/torch_python.dll filter=lfs diff=lfs merge=lfs -text
170
+ venv/Lib/site-packages/torch/lib/torch_python.lib filter=lfs diff=lfs merge=lfs -text
171
+ venv/Lib/site-packages/torch/lib/uv.dll filter=lfs diff=lfs merge=lfs -text
172
+ venv/Lib/site-packages/torch/lib/XNNPACK.lib filter=lfs diff=lfs merge=lfs -text
173
+ venv/Lib/site-packages/torch/linalg/__pycache__/__init__.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
174
+ venv/Lib/site-packages/torch/nn/__pycache__/functional.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
175
+ venv/Lib/site-packages/torch/onnx/__pycache__/symbolic_opset9.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
176
+ venv/Lib/site-packages/torch/sparse/__pycache__/_triton_ops_meta.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
177
+ venv/Lib/site-packages/torch/testing/_internal/__pycache__/common_methods_invocations.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
178
+ venv/Lib/site-packages/torch/testing/_internal/__pycache__/common_nn.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
179
+ venv/Lib/site-packages/torch/testing/_internal/__pycache__/common_quantization.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
180
+ venv/Lib/site-packages/torch/testing/_internal/__pycache__/common_utils.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
181
+ venv/Lib/site-packages/torch/testing/_internal/distributed/__pycache__/distributed_test.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
182
+ venv/Lib/site-packages/torch/testing/_internal/distributed/rpc/__pycache__/rpc_test.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
183
+ venv/Lib/site-packages/torch/testing/_internal/generated/__pycache__/annotated_fn_args.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
184
+ venv/Lib/site-packages/torch/utils/hipify/__pycache__/cuda_to_hip_mappings.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
185
+ venv/Lib/site-packages/torchvision/_C.pyd filter=lfs diff=lfs merge=lfs -text
186
+ venv/Lib/site-packages/torchvision/image.pyd filter=lfs diff=lfs merge=lfs -text
187
+ venv/Lib/site-packages/torchvision/jpeg8.dll filter=lfs diff=lfs merge=lfs -text
188
+ venv/Lib/site-packages/torchvision/libjpeg.dll filter=lfs diff=lfs merge=lfs -text
189
+ venv/Lib/site-packages/torchvision/libpng16.dll filter=lfs diff=lfs merge=lfs -text
190
+ venv/Lib/site-packages/torchvision/libwebp.dll filter=lfs diff=lfs merge=lfs -text
191
+ venv/Lib/site-packages/transformers/__pycache__/modeling_outputs.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
192
+ venv/Lib/site-packages/transformers/__pycache__/modeling_tf_utils.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
193
+ venv/Lib/site-packages/transformers/__pycache__/modeling_utils.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
194
+ venv/Lib/site-packages/transformers/__pycache__/testing_utils.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
195
+ venv/Lib/site-packages/transformers/__pycache__/tokenization_utils_base.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
196
+ venv/Lib/site-packages/transformers/__pycache__/trainer.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
197
+ venv/Lib/site-packages/transformers/__pycache__/training_args.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
198
+ venv/Lib/site-packages/transformers/generation/__pycache__/logits_process.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
199
+ venv/Lib/site-packages/transformers/generation/__pycache__/tf_utils.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
200
+ venv/Lib/site-packages/transformers/generation/__pycache__/utils.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
201
+ venv/Lib/site-packages/transformers/models/oneformer/__pycache__/modeling_oneformer.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
202
+ venv/Lib/site-packages/transformers/models/perceiver/__pycache__/modeling_perceiver.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
203
+ venv/Lib/site-packages/transformers/models/qwen2_5_omni/__pycache__/modeling_qwen2_5_omni.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
204
+ venv/Lib/site-packages/transformers/models/qwen2_5_omni/__pycache__/modular_qwen2_5_omni.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
205
+ venv/Lib/site-packages/transformers/models/seamless_m4t/__pycache__/modeling_seamless_m4t.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
206
+ venv/Lib/site-packages/transformers/models/seamless_m4t_v2/__pycache__/modeling_seamless_m4t_v2.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
207
+ venv/Lib/site-packages/transformers/models/speecht5/__pycache__/modeling_speecht5.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
208
+ venv/Lib/site-packages/yaml/_yaml.cp310-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
209
+ venv/Scripts/accelerate-config.exe filter=lfs diff=lfs merge=lfs -text
210
+ venv/Scripts/accelerate-estimate-memory.exe filter=lfs diff=lfs merge=lfs -text
211
+ venv/Scripts/accelerate-launch.exe filter=lfs diff=lfs merge=lfs -text
212
+ venv/Scripts/accelerate-merge-weights.exe filter=lfs diff=lfs merge=lfs -text
213
+ venv/Scripts/accelerate.exe filter=lfs diff=lfs merge=lfs -text
214
+ venv/Scripts/diffusers-cli.exe filter=lfs diff=lfs merge=lfs -text
215
+ venv/Scripts/f2py.exe filter=lfs diff=lfs merge=lfs -text
216
+ venv/Scripts/flask.exe filter=lfs diff=lfs merge=lfs -text
217
+ venv/Scripts/huggingface-cli.exe filter=lfs diff=lfs merge=lfs -text
218
+ venv/Scripts/isympy.exe filter=lfs diff=lfs merge=lfs -text
219
+ venv/Scripts/normalizer.exe filter=lfs diff=lfs merge=lfs -text
220
+ venv/Scripts/numpy-config.exe filter=lfs diff=lfs merge=lfs -text
221
+ venv/Scripts/pip.exe filter=lfs diff=lfs merge=lfs -text
222
+ venv/Scripts/pip3.10.exe filter=lfs diff=lfs merge=lfs -text
223
+ venv/Scripts/pip3.exe filter=lfs diff=lfs merge=lfs -text
224
+ venv/Scripts/python.exe filter=lfs diff=lfs merge=lfs -text
225
+ venv/Scripts/pythonw.exe filter=lfs diff=lfs merge=lfs -text
226
+ venv/Scripts/tiny-agents.exe filter=lfs diff=lfs merge=lfs -text
227
+ venv/Scripts/torchfrtrace.exe filter=lfs diff=lfs merge=lfs -text
228
+ venv/Scripts/torchrun.exe filter=lfs diff=lfs merge=lfs -text
229
+ venv/Scripts/tqdm.exe filter=lfs diff=lfs merge=lfs -text
230
+ venv/Scripts/transformers-cli.exe filter=lfs diff=lfs merge=lfs -text
231
+ venv/Scripts/transformers.exe filter=lfs diff=lfs merge=lfs -text
app.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template, request, jsonify
2
+ import os
3
+ import torch
4
+ from diffusers import StableDiffusionPipeline
5
+ from PIL import Image
6
+ import re
7
+ import time
8
+
9
+ app = Flask(__name__)
10
+
11
+ # Define paths
12
+ MODEL_PATH = "Roshan1162003/fine_tuned_model" # Replace with your HF model repository ID
13
+ STATIC_IMAGES_PATH = os.path.join("static", "images")
14
+ os.makedirs(STATIC_IMAGES_PATH, exist_ok=True)
15
+
16
+ # Restricted terms for prompt filtering
17
+ RESTRICTED_TERMS = [
18
+ "crime", "abuse", "violence", "illegal", "explicit", "nsfw",
19
+ "offensive", "hate", "nude", "porn", "gore", "drug"
20
+ ]
21
+
22
+ # Load the fine-tuned model
23
+ pipe = None
24
+ if torch.cuda.is_available():
25
+ pipe = StableDiffusionPipeline.from_pretrained(
26
+ MODEL_PATH,
27
+ torch_dtype=torch.float16,
28
+ use_safetensors=True,
29
+ use_auth_token=os.getenv("HF_TOKEN") # Use HF_TOKEN from environment
30
+ ).to("cuda")
31
+ else:
32
+ pipe = StableDiffusionPipeline.from_pretrained(
33
+ MODEL_PATH,
34
+ torch_dtype=torch.float32,
35
+ use_safetensors=True,
36
+ use_auth_token=os.getenv("HF_TOKEN")
37
+ )
38
+ print("Model loaded successfully")
39
+
40
+ # Aspect ratio to resolution mapping
41
+ ASPECT_RATIOS = {
42
+ "1:1": (512, 512),
43
+ "4:3": (512, 384),
44
+ "16:9": (512, 288)
45
+ }
46
+
47
+ def is_prompt_safe(prompt):
48
+ """Check if prompt contains restricted terms."""
49
+ prompt_lower = prompt.lower()
50
+ for term in RESTRICTED_TERMS:
51
+ if re.search(r'\b' + re.escape(term) + r'\b', prompt_lower):
52
+ return False
53
+ return True
54
+
55
+ @app.route("/", methods=["GET"])
56
+ def index():
57
+ return render_template("index.html")
58
+
59
+ @app.route("/generate", methods=["POST"])
60
+ def generate():
61
+ try:
62
+ # Get form data
63
+ prompt = request.form.get("prompt", "").strip()
64
+ num_images = int(request.form.get("num_images", 1))
65
+ aspect_ratio = request.form.get("aspect_ratio", "1:1")
66
+ model_name = request.form.get("model", "stable_diffusion")
67
+
68
+ # Validate inputs
69
+ if not prompt:
70
+ return jsonify({"error": "Prompt is required"}), 400
71
+ if model_name != "stable_diffusion":
72
+ return jsonify({"error": "Selected model is locked"}), 400
73
+ if num_images < 1 or num_images > 5:
74
+ return jsonify({"error": "Number of images must be between 1 and 5"}), 400
75
+ if aspect_ratio not in ASPECT_RATIOS:
76
+ return jsonify({"error": "Invalid aspect ratio"}), 400
77
+
78
+ # Check for restricted terms
79
+ if not is_prompt_safe(prompt):
80
+ return jsonify({
81
+ "error": "You are violating the regulation policy terms and conditions due to restricted terms in the prompt."
82
+ }), 400
83
+
84
+ # Get resolution for aspect ratio
85
+ width, height = ASPECT_RATIOS[aspect_ratio]
86
+
87
+ # Generate images
88
+ image_paths = []
89
+ for i in range(num_images):
90
+ image = pipe(
91
+ prompt,
92
+ width=width,
93
+ height=height,
94
+ num_inference_steps=50,
95
+ guidance_scale=7.5,
96
+ seed=42 + i
97
+ ).images[0]
98
+ # Save image
99
+ timestamp = int(time.time() * 1000)
100
+ image_path = os.path.join(STATIC_IMAGES_PATH, f"generated_{timestamp}_{i}.png")
101
+ image.save(image_path)
102
+ image_paths.append(image_path.replace("static/", ""))
103
+
104
+ return jsonify({"images": image_paths})
105
+
106
+ except Exception as e:
107
+ return jsonify({"error": str(e)}), 500
108
+
109
+ if __name__ == "__main__":
110
+ app.run(host="0.0.0.0", port=7860, debug=False)
fine_tuned_model/feature_extractor/preprocessor_config.json ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "crop_size": {
3
+ "height": 224,
4
+ "width": 224
5
+ },
6
+ "do_center_crop": true,
7
+ "do_convert_rgb": true,
8
+ "do_normalize": true,
9
+ "do_rescale": true,
10
+ "do_resize": true,
11
+ "image_mean": [
12
+ 0.48145466,
13
+ 0.4578275,
14
+ 0.40821073
15
+ ],
16
+ "image_processor_type": "CLIPImageProcessor",
17
+ "image_std": [
18
+ 0.26862954,
19
+ 0.26130258,
20
+ 0.27577711
21
+ ],
22
+ "resample": 3,
23
+ "rescale_factor": 0.00392156862745098,
24
+ "size": {
25
+ "shortest_edge": 224
26
+ }
27
+ }
fine_tuned_model/logs/dreambooth/1750848551.8584013/events.out.tfevents.1750848551.ef0460d8cbbe.10247.1 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3ca33c1ef789bffba275eb0d743db8c97f597a7b8788c49b0c2dc42a46ad3bcb
3
+ size 2956
fine_tuned_model/logs/dreambooth/1750848551.8677673/hparams.yml ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ adam_beta1: 0.9
2
+ adam_beta2: 0.999
3
+ adam_epsilon: 1.0e-08
4
+ adam_weight_decay: 0.01
5
+ allow_tf32: false
6
+ center_crop: false
7
+ checkpointing_steps: 200
8
+ checkpoints_total_limit: null
9
+ class_data_dir: null
10
+ class_labels_conditioning: null
11
+ class_prompt: null
12
+ dataloader_num_workers: 0
13
+ enable_xformers_memory_efficient_attention: false
14
+ gradient_accumulation_steps: 1
15
+ gradient_checkpointing: true
16
+ hub_model_id: null
17
+ hub_token: null
18
+ instance_data_dir: /content/drive/MyDrive/Datasets/combined
19
+ instance_prompt: a person
20
+ learning_rate: 5.0e-06
21
+ local_rank: -1
22
+ logging_dir: logs
23
+ lr_num_cycles: 1
24
+ lr_power: 1.0
25
+ lr_scheduler: constant
26
+ lr_warmup_steps: 500
27
+ max_grad_norm: 1.0
28
+ max_train_steps: 800
29
+ mixed_precision: fp16
30
+ num_class_images: 100
31
+ num_train_epochs: 58
32
+ num_validation_images: 4
33
+ offset_noise: false
34
+ output_dir: /content/drive/MyDrive/Datasets/fine_tuned_model
35
+ pre_compute_text_embeddings: false
36
+ pretrained_model_name_or_path: /content/stable-diffusion-v1-5
37
+ prior_generation_precision: null
38
+ prior_loss_weight: 1.0
39
+ push_to_hub: false
40
+ report_to: tensorboard
41
+ resolution: 512
42
+ resume_from_checkpoint: null
43
+ revision: null
44
+ sample_batch_size: 4
45
+ scale_lr: false
46
+ seed: 42
47
+ set_grads_to_none: false
48
+ skip_save_text_encoder: false
49
+ snr_gamma: null
50
+ text_encoder_use_attention_mask: false
51
+ tokenizer_max_length: null
52
+ tokenizer_name: null
53
+ train_batch_size: 1
54
+ train_text_encoder: true
55
+ use_8bit_adam: true
56
+ validation_prompt: '[V1], founder of this'
57
+ validation_scheduler: DPMSolverMultistepScheduler
58
+ validation_steps: 100
59
+ variant: null
60
+ with_prior_preservation: false
fine_tuned_model/logs/dreambooth/1750848665.145276/events.out.tfevents.1750848665.ef0460d8cbbe.10782.1 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6c61cc8f294da973070e135da111c308dcdd62876a09f7cc56e34c3d0ce1ece2
3
+ size 2956
fine_tuned_model/logs/dreambooth/1750848665.1627958/hparams.yml ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ adam_beta1: 0.9
2
+ adam_beta2: 0.999
3
+ adam_epsilon: 1.0e-08
4
+ adam_weight_decay: 0.01
5
+ allow_tf32: false
6
+ center_crop: false
7
+ checkpointing_steps: 200
8
+ checkpoints_total_limit: null
9
+ class_data_dir: null
10
+ class_labels_conditioning: null
11
+ class_prompt: null
12
+ dataloader_num_workers: 0
13
+ enable_xformers_memory_efficient_attention: false
14
+ gradient_accumulation_steps: 1
15
+ gradient_checkpointing: true
16
+ hub_model_id: null
17
+ hub_token: null
18
+ instance_data_dir: /content/drive/MyDrive/Datasets/combined
19
+ instance_prompt: a person
20
+ learning_rate: 5.0e-06
21
+ local_rank: -1
22
+ logging_dir: logs
23
+ lr_num_cycles: 1
24
+ lr_power: 1.0
25
+ lr_scheduler: constant
26
+ lr_warmup_steps: 500
27
+ max_grad_norm: 1.0
28
+ max_train_steps: 800
29
+ mixed_precision: fp16
30
+ num_class_images: 100
31
+ num_train_epochs: 62
32
+ num_validation_images: 4
33
+ offset_noise: false
34
+ output_dir: /content/drive/MyDrive/Datasets/fine_tuned_model
35
+ pre_compute_text_embeddings: false
36
+ pretrained_model_name_or_path: /content/stable-diffusion-v1-5
37
+ prior_generation_precision: null
38
+ prior_loss_weight: 1.0
39
+ push_to_hub: false
40
+ report_to: tensorboard
41
+ resolution: 512
42
+ resume_from_checkpoint: null
43
+ revision: null
44
+ sample_batch_size: 4
45
+ scale_lr: false
46
+ seed: 42
47
+ set_grads_to_none: false
48
+ skip_save_text_encoder: false
49
+ snr_gamma: null
50
+ text_encoder_use_attention_mask: false
51
+ tokenizer_max_length: null
52
+ tokenizer_name: null
53
+ train_batch_size: 1
54
+ train_text_encoder: true
55
+ use_8bit_adam: true
56
+ validation_prompt: '[V1], founder of this'
57
+ validation_scheduler: DPMSolverMultistepScheduler
58
+ validation_steps: 100
59
+ variant: null
60
+ with_prior_preservation: false
fine_tuned_model/logs/dreambooth/events.out.tfevents.1750848551.ef0460d8cbbe.10247.0 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d806b28987ac0fb6dbd5622f8e4cea4b365f3a51fef2a13d6c0b7cea7c34d163
3
+ size 662
fine_tuned_model/logs/dreambooth/events.out.tfevents.1750848665.ef0460d8cbbe.10782.0 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e62a110b4cb8da08b408839248a821bf30caba4ad1d4bbdeb1e5cad62d67185d
3
+ size 11888579
fine_tuned_model/model_index.json ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_class_name": "StableDiffusionPipeline",
3
+ "_diffusers_version": "0.34.0",
4
+ "_name_or_path": "/content/stable-diffusion-v1-5",
5
+ "feature_extractor": [
6
+ "transformers",
7
+ "CLIPImageProcessor"
8
+ ],
9
+ "image_encoder": [
10
+ null,
11
+ null
12
+ ],
13
+ "requires_safety_checker": true,
14
+ "safety_checker": [
15
+ "stable_diffusion",
16
+ "StableDiffusionSafetyChecker"
17
+ ],
18
+ "scheduler": [
19
+ "diffusers",
20
+ "PNDMScheduler"
21
+ ],
22
+ "text_encoder": [
23
+ "transformers",
24
+ "CLIPTextModel"
25
+ ],
26
+ "tokenizer": [
27
+ "transformers",
28
+ "CLIPTokenizer"
29
+ ],
30
+ "unet": [
31
+ "diffusers",
32
+ "UNet2DConditionModel"
33
+ ],
34
+ "vae": [
35
+ "diffusers",
36
+ "AutoencoderKL"
37
+ ]
38
+ }
fine_tuned_model/safety_checker/config.json ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "StableDiffusionSafetyChecker"
4
+ ],
5
+ "initializer_factor": 1.0,
6
+ "logit_scale_init_value": 2.6592,
7
+ "model_type": "clip",
8
+ "projection_dim": 768,
9
+ "text_config": {
10
+ "attention_dropout": 0.0,
11
+ "dropout": 0.0,
12
+ "hidden_act": "quick_gelu",
13
+ "hidden_size": 768,
14
+ "initializer_factor": 1.0,
15
+ "initializer_range": 0.02,
16
+ "intermediate_size": 3072,
17
+ "layer_norm_eps": 1e-05,
18
+ "max_position_embeddings": 77,
19
+ "model_type": "clip_text_model",
20
+ "num_attention_heads": 12,
21
+ "num_hidden_layers": 12,
22
+ "projection_dim": 512,
23
+ "torch_dtype": "float32",
24
+ "vocab_size": 49408
25
+ },
26
+ "torch_dtype": "float32",
27
+ "transformers_version": "4.52.4",
28
+ "vision_config": {
29
+ "attention_dropout": 0.0,
30
+ "dropout": 0.0,
31
+ "hidden_act": "quick_gelu",
32
+ "hidden_size": 1024,
33
+ "image_size": 224,
34
+ "initializer_factor": 1.0,
35
+ "initializer_range": 0.02,
36
+ "intermediate_size": 4096,
37
+ "layer_norm_eps": 1e-05,
38
+ "model_type": "clip_vision_model",
39
+ "num_attention_heads": 16,
40
+ "num_channels": 3,
41
+ "num_hidden_layers": 24,
42
+ "patch_size": 14,
43
+ "projection_dim": 512,
44
+ "torch_dtype": "float32"
45
+ }
46
+ }
fine_tuned_model/safety_checker/model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fb351a5ded815c3ff744968ad9c6b218d071b9d313d04f35e813b84b4c0ffde8
3
+ size 1215979664
fine_tuned_model/scheduler/scheduler_config.json ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_class_name": "PNDMScheduler",
3
+ "_diffusers_version": "0.34.0",
4
+ "beta_end": 0.012,
5
+ "beta_schedule": "scaled_linear",
6
+ "beta_start": 0.00085,
7
+ "clip_sample": false,
8
+ "num_train_timesteps": 1000,
9
+ "prediction_type": "epsilon",
10
+ "set_alpha_to_one": false,
11
+ "skip_prk_steps": true,
12
+ "steps_offset": 1,
13
+ "timestep_spacing": "leading",
14
+ "trained_betas": null
15
+ }
fine_tuned_model/text_encoder/config.json ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "CLIPTextModel"
4
+ ],
5
+ "attention_dropout": 0.0,
6
+ "bos_token_id": 0,
7
+ "dropout": 0.0,
8
+ "eos_token_id": 2,
9
+ "hidden_act": "quick_gelu",
10
+ "hidden_size": 768,
11
+ "initializer_factor": 1.0,
12
+ "initializer_range": 0.02,
13
+ "intermediate_size": 3072,
14
+ "layer_norm_eps": 1e-05,
15
+ "max_position_embeddings": 77,
16
+ "model_type": "clip_text_model",
17
+ "num_attention_heads": 12,
18
+ "num_hidden_layers": 12,
19
+ "pad_token_id": 1,
20
+ "projection_dim": 768,
21
+ "torch_dtype": "float32",
22
+ "transformers_version": "4.52.4",
23
+ "vocab_size": 49408
24
+ }
fine_tuned_model/text_encoder/model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2ccf8b79952f31abbb532203b476c2ab45a45580d79e8813f1fb4d59c5d3abac
3
+ size 492265168
fine_tuned_model/tokenizer/merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
fine_tuned_model/tokenizer/special_tokens_map.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bos_token": {
3
+ "content": "<|startoftext|>",
4
+ "lstrip": false,
5
+ "normalized": true,
6
+ "rstrip": false,
7
+ "single_word": false
8
+ },
9
+ "eos_token": {
10
+ "content": "<|endoftext|>",
11
+ "lstrip": false,
12
+ "normalized": true,
13
+ "rstrip": false,
14
+ "single_word": false
15
+ },
16
+ "pad_token": {
17
+ "content": "<|endoftext|>",
18
+ "lstrip": false,
19
+ "normalized": true,
20
+ "rstrip": false,
21
+ "single_word": false
22
+ },
23
+ "unk_token": {
24
+ "content": "<|endoftext|>",
25
+ "lstrip": false,
26
+ "normalized": true,
27
+ "rstrip": false,
28
+ "single_word": false
29
+ }
30
+ }
fine_tuned_model/tokenizer/tokenizer_config.json ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": false,
3
+ "added_tokens_decoder": {
4
+ "49406": {
5
+ "content": "<|startoftext|>",
6
+ "lstrip": false,
7
+ "normalized": true,
8
+ "rstrip": false,
9
+ "single_word": false,
10
+ "special": true
11
+ },
12
+ "49407": {
13
+ "content": "<|endoftext|>",
14
+ "lstrip": false,
15
+ "normalized": true,
16
+ "rstrip": false,
17
+ "single_word": false,
18
+ "special": true
19
+ }
20
+ },
21
+ "bos_token": "<|startoftext|>",
22
+ "clean_up_tokenization_spaces": false,
23
+ "do_lower_case": true,
24
+ "eos_token": "<|endoftext|>",
25
+ "errors": "replace",
26
+ "extra_special_tokens": {},
27
+ "model_max_length": 77,
28
+ "pad_token": "<|endoftext|>",
29
+ "tokenizer_class": "CLIPTokenizer",
30
+ "unk_token": "<|endoftext|>"
31
+ }
fine_tuned_model/tokenizer/vocab.json ADDED
The diff for this file is too large to render. See raw diff
 
fine_tuned_model/unet/config.json ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_class_name": "UNet2DConditionModel",
3
+ "_diffusers_version": "0.34.0",
4
+ "_name_or_path": "/content/stable-diffusion-v1-5",
5
+ "act_fn": "silu",
6
+ "addition_embed_type": null,
7
+ "addition_embed_type_num_heads": 64,
8
+ "addition_time_embed_dim": null,
9
+ "attention_head_dim": 8,
10
+ "attention_type": "default",
11
+ "block_out_channels": [
12
+ 320,
13
+ 640,
14
+ 1280,
15
+ 1280
16
+ ],
17
+ "center_input_sample": false,
18
+ "class_embed_type": null,
19
+ "class_embeddings_concat": false,
20
+ "conv_in_kernel": 3,
21
+ "conv_out_kernel": 3,
22
+ "cross_attention_dim": 768,
23
+ "cross_attention_norm": null,
24
+ "down_block_types": [
25
+ "CrossAttnDownBlock2D",
26
+ "CrossAttnDownBlock2D",
27
+ "CrossAttnDownBlock2D",
28
+ "DownBlock2D"
29
+ ],
30
+ "downsample_padding": 1,
31
+ "dropout": 0.0,
32
+ "dual_cross_attention": false,
33
+ "encoder_hid_dim": null,
34
+ "encoder_hid_dim_type": null,
35
+ "flip_sin_to_cos": true,
36
+ "freq_shift": 0,
37
+ "in_channels": 4,
38
+ "layers_per_block": 2,
39
+ "mid_block_only_cross_attention": null,
40
+ "mid_block_scale_factor": 1,
41
+ "mid_block_type": "UNetMidBlock2DCrossAttn",
42
+ "norm_eps": 1e-05,
43
+ "norm_num_groups": 32,
44
+ "num_attention_heads": null,
45
+ "num_class_embeds": null,
46
+ "only_cross_attention": false,
47
+ "out_channels": 4,
48
+ "projection_class_embeddings_input_dim": null,
49
+ "resnet_out_scale_factor": 1.0,
50
+ "resnet_skip_time_act": false,
51
+ "resnet_time_scale_shift": "default",
52
+ "reverse_transformer_layers_per_block": null,
53
+ "sample_size": 64,
54
+ "time_cond_proj_dim": null,
55
+ "time_embedding_act_fn": null,
56
+ "time_embedding_dim": null,
57
+ "time_embedding_type": "positional",
58
+ "timestep_post_act": null,
59
+ "transformer_layers_per_block": 1,
60
+ "up_block_types": [
61
+ "UpBlock2D",
62
+ "CrossAttnUpBlock2D",
63
+ "CrossAttnUpBlock2D",
64
+ "CrossAttnUpBlock2D"
65
+ ],
66
+ "upcast_attention": false,
67
+ "use_linear_projection": false
68
+ }
fine_tuned_model/unet/diffusion_pytorch_model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b6f41dcfb8a3accf30d55cd8ea7b1cf66c093bc102268046a3f7e768444af2b0
3
+ size 3438167536
fine_tuned_model/vae/config.json ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_class_name": "AutoencoderKL",
3
+ "_diffusers_version": "0.34.0",
4
+ "_name_or_path": "/content/stable-diffusion-v1-5/vae",
5
+ "act_fn": "silu",
6
+ "block_out_channels": [
7
+ 128,
8
+ 256,
9
+ 512,
10
+ 512
11
+ ],
12
+ "down_block_types": [
13
+ "DownEncoderBlock2D",
14
+ "DownEncoderBlock2D",
15
+ "DownEncoderBlock2D",
16
+ "DownEncoderBlock2D"
17
+ ],
18
+ "force_upcast": true,
19
+ "in_channels": 3,
20
+ "latent_channels": 4,
21
+ "latents_mean": null,
22
+ "latents_std": null,
23
+ "layers_per_block": 2,
24
+ "mid_block_add_attention": true,
25
+ "norm_num_groups": 32,
26
+ "out_channels": 3,
27
+ "sample_size": 512,
28
+ "scaling_factor": 0.18215,
29
+ "shift_factor": null,
30
+ "up_block_types": [
31
+ "UpDecoderBlock2D",
32
+ "UpDecoderBlock2D",
33
+ "UpDecoderBlock2D",
34
+ "UpDecoderBlock2D"
35
+ ],
36
+ "use_post_quant_conv": true,
37
+ "use_quant_conv": true
38
+ }
fine_tuned_model/vae/diffusion_pytorch_model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b4d2b5932bb4151e54e694fd31ccf51fca908223c9485bd56cd0e1d83ad94c49
3
+ size 334643268
generate_images_local.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from diffusers import StableDiffusionPipeline
3
+ import torch
4
+
5
+ # Define paths (update to your local path)
6
+ model_path = "./fine_tuned_model" # Replace with actual path, e.g., C:/Users/YourName/fine_tuned_model
7
+ output_dir = "generated_images"
8
+
9
+ # Create output directory
10
+ os.makedirs(output_dir, exist_ok=True)
11
+
12
+ # Load the fine-tuned model
13
+ print("Loading fine-tuned model...")
14
+ pipe = StableDiffusionPipeline.from_pretrained(
15
+ model_path,
16
+ torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
17
+ use_safetensors=True
18
+ )
19
+
20
+ # Move to GPU if available
21
+ if torch.cuda.is_available():
22
+ pipe = pipe.to("cuda")
23
+ print("Using GPU for inference")
24
+ else:
25
+ print("Using CPU for inference")
26
+
27
+ # Define prompts
28
+ prompts = [
29
+ "[V1], founder of this",
30
+ "[V2], most decent and cute innocent girl of ECE from 2025 batch in ALIET"
31
+ ]
32
+
33
+ # Generate images
34
+ for i, prompt in enumerate(prompts):
35
+ print(f"Generating image for prompt: {prompt}")
36
+ image = pipe(
37
+ prompt,
38
+ num_inference_steps=50,
39
+ guidance_scale=7.5,
40
+ seed=42 # Fixed seed for reproducibility
41
+ ).images[0]
42
+ # Save image
43
+ image_path = os.path.join(output_dir, f"generated_image_{i+1}.png")
44
+ image.save(image_path)
45
+ print(f"Saved image to {image_path}")
46
+
47
+ # List generated images
48
+ print("Generated images:", os.listdir(output_dir))
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ flask==3.0.3
2
+ torch==2.3.0
3
+ diffusers==0.34.0
4
+ transformers==4.52.0
5
+ accelerate==0.33.0
6
+ safetensors==0.4.5
7
+ pillow==10.4.0
templates/index.html ADDED
@@ -0,0 +1,601 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>AI Image Studio - Professional Text-to-Image Generator</title>
7
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
8
+ <style>
9
+ * {
10
+ margin: 0;
11
+ padding: 0;
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ body {
16
+ font-family: 'Segoe UI', Tango, Geneva, Verdana, sans-serif;
17
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
18
+ min-height: 100vh;
19
+ padding: 20px;
20
+ line-height: 1.6;
21
+ }
22
+
23
+ .main-container {
24
+ max-width: 1200px;
25
+ margin: 0 auto;
26
+ }
27
+
28
+ /* Header */
29
+ .header {
30
+ text-align: center;
31
+ margin-bottom: 40px;
32
+ color: white;
33
+ }
34
+
35
+ .header h1 {
36
+ font-size: 3rem;
37
+ font-weight: 300;
38
+ margin-bottom: 10px;
39
+ letter-spacing: -1px;
40
+ }
41
+
42
+ .header .subtitle {
43
+ font-size: 1.2rem;
44
+ opacity: 0.9;
45
+ font-weight: 300;
46
+ }
47
+
48
+ /* Main Content Grid */
49
+ .content-grid {
50
+ display: grid;
51
+ grid-template-columns: 1fr 1fr;
52
+ gap: 30px;
53
+ align-items: start;
54
+ }
55
+
56
+ /* Control Panel */
57
+ .control-panel {
58
+ background: white;
59
+ border-radius: 16px;
60
+ padding: 32px;
61
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
62
+ backdrop-filter: blur(10px);
63
+ }
64
+
65
+ .panel-title {
66
+ font-size: 1.5rem;
67
+ font-weight: 600;
68
+ color: #2d3748;
69
+ margin-bottom: 24px;
70
+ display: flex;
71
+ align-items: center;
72
+ gap: 12px;
73
+ }
74
+
75
+ .form-group {
76
+ margin-bottom: 24px;
77
+ }
78
+
79
+ .form-label {
80
+ display: block;
81
+ font-size: 0.875rem;
82
+ font-weight: 600;
83
+ color: #4a5568;
84
+ margin-bottom: 8px;
85
+ text-transform: uppercase;
86
+ letter-spacing: 0.5px;
87
+ }
88
+
89
+ .form-input, .form-select, .form-textarea {
90
+ width: 100%;
91
+ padding: 14px 16px;
92
+ border: 2px solid #e2e8f0;
93
+ border-radius: 12px;
94
+ font-size: 1rem;
95
+ transition: all 0.3s ease;
96
+ background: #f8fafc;
97
+ }
98
+
99
+ .form-input:focus, .form-select:focus, .form-textarea:focus {
100
+ outline: none;
101
+ border-color: #667eea;
102
+ background: white;
103
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
104
+ }
105
+
106
+ .form-textarea {
107
+ min-height: 120px;
108
+ resize: vertical;
109
+ font-family: inherit;
110
+ }
111
+
112
+ .form-select {
113
+ cursor: pointer;
114
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e");
115
+ background-position: right 12px center;
116
+ background-repeat: no-repeat;
117
+ background-size: 16px;
118
+ padding-right: 40px;
119
+ appearance: none;
120
+ }
121
+
122
+ .form-row {
123
+ display: grid;
124
+ grid-template-columns: 1fr 1fr;
125
+ gap: 16px;
126
+ }
127
+
128
+ /* Generate Button */
129
+ .generate-btn {
130
+ width: 100%;
131
+ padding: 16px 24px;
132
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
133
+ color: white;
134
+ border: none;
135
+ border-radius: 12px;
136
+ font-size: 1.1rem;
137
+ font-weight: 600;
138
+ cursor: pointer;
139
+ transition: all 0.3s ease;
140
+ display: flex;
141
+ align-items: center;
142
+ justify-content: center;
143
+ gap: 12px;
144
+ margin-top: 8px;
145
+ }
146
+
147
+ .generate-btn:hover {
148
+ transform: translateY(-2px);
149
+ box-shadow: 0 12px 24px rgba(102, 126, 234, 0.3);
150
+ }
151
+
152
+ .generate-btn:active {
153
+ transform: translateY(0);
154
+ }
155
+
156
+ .generate-btn:disabled {
157
+ opacity: 0.6;
158
+ cursor: not-allowed;
159
+ transform: none;
160
+ }
161
+
162
+ /* Results Panel */
163
+ .results-panel {
164
+ background: white;
165
+ border-radius: 16px;
166
+ padding: 32px;
167
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
168
+ min-height: 400px;
169
+ display: flex;
170
+ flex-direction: column;
171
+ }
172
+
173
+ .results-header {
174
+ display: flex;
175
+ align-items: center;
176
+ justify-content: space-between;
177
+ margin-bottom: 24px;
178
+ }
179
+
180
+ .results-title {
181
+ font-size: 1.5rem;
182
+ font-weight: 600;
183
+ color: #2d3748;
184
+ display: flex;
185
+ align-items: center;
186
+ gap: 12px;
187
+ }
188
+
189
+ .results-count {
190
+ background: #667eea;
191
+ color: white;
192
+ padding: 4px 12px;
193
+ border-radius: 20px;
194
+ font-size: 0.875rem;
195
+ font-weight: 600;
196
+ }
197
+
198
+ /* Gallery */
199
+ .gallery {
200
+ display: grid;
201
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
202
+ gap: 20px;
203
+ flex: 1;
204
+ }
205
+
206
+ .gallery-item {
207
+ position: relative;
208
+ border-radius: 12px;
209
+ overflow: hidden;
210
+ background: #f8fafc;
211
+ aspect-ratio: 1;
212
+ cursor: pointer;
213
+ transition: all 0.3s ease;
214
+ }
215
+
216
+ .gallery-item:hover {
217
+ transform: translateY(-4px);
218
+ box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
219
+ }
220
+
221
+ .gallery-item img {
222
+ width: 100%;
223
+ height: 100%;
224
+ object-fit: cover;
225
+ transition: transform 0.3s ease;
226
+ }
227
+
228
+ .gallery-item:hover img {
229
+ transform: scale(1.05);
230
+ }
231
+
232
+ .gallery-overlay {
233
+ position: absolute;
234
+ top: 0;
235
+ left: 0;
236
+ right: 0;
237
+ bottom: 0;
238
+ background: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.7));
239
+ opacity: 0;
240
+ transition: opacity 0.3s ease;
241
+ display: flex;
242
+ align-items: flex-end;
243
+ padding: 16px;
244
+ }
245
+
246
+ .gallery-item:hover .gallery-overlay {
247
+ opacity: 1;
248
+ }
249
+
250
+ .gallery-actions {
251
+ display: flex;
252
+ gap: 8px;
253
+ }
254
+
255
+ .gallery-action {
256
+ background: rgba(255, 255, 255, 0.2);
257
+ backdrop-filter: blur(10px);
258
+ border: none;
259
+ color: white;
260
+ padding: 8px;
261
+ border-radius: 8px;
262
+ cursor: pointer;
263
+ transition: all 0.3s ease;
264
+ }
265
+
266
+ .gallery-action:hover {
267
+ background: rgba(255, 255, 255, 0.3);
268
+ }
269
+
270
+ /* Empty State */
271
+ .empty-state {
272
+ display: flex;
273
+ flex-direction: column;
274
+ align-items: center;
275
+ justify-content: center;
276
+ flex: 1;
277
+ color: #a0aec0;
278
+ text-align: center;
279
+ }
280
+
281
+ .empty-state i {
282
+ font-size: 4rem;
283
+ margin-bottom: 16px;
284
+ opacity: 0.5;
285
+ }
286
+
287
+ .empty-state h3 {
288
+ font-size: 1.25rem;
289
+ margin-bottom: 8px;
290
+ color: #718096;
291
+ }
292
+
293
+ .empty-state p {
294
+ font-size: 0.875rem;
295
+ }
296
+
297
+ /* Loading State */
298
+ .loading {
299
+ display: flex;
300
+ flex-direction: column;
301
+ align-items: center;
302
+ justify-content: center;
303
+ flex: 1;
304
+ color: #667eea;
305
+ }
306
+
307
+ .loading-spinner {
308
+ width: 40px;
309
+ height: 40px;
310
+ border: 3px solid #e2e8f0;
311
+ border-top: 3px solid #667eea;
312
+ border-radius: 50%;
313
+ animation: spin 1s linear infinite;
314
+ margin-bottom: 16px;
315
+ }
316
+
317
+ @keyframes spin {
318
+ 0% { transform: rotate(0deg); }
319
+ 100% { transform: rotate(360deg); }
320
+ }
321
+
322
+ /* Error Message */
323
+ .error-message {
324
+ background: #fed7d7;
325
+ color: #c53030;
326
+ padding: 12px 16px;
327
+ border-radius: 8px;
328
+ margin-bottom: 16px;
329
+ border: 1px solid #feb2b2;
330
+ display: flex;
331
+ align-items: center;
332
+ gap: 8px;
333
+ }
334
+
335
+ /* Responsive Design */
336
+ @media (max-width: 768px) {
337
+ .content-grid {
338
+ grid-template-columns: 1fr;
339
+ gap: 20px;
340
+ }
341
+
342
+ .header h1 {
343
+ font-size: 2rem;
344
+ }
345
+
346
+ .control-panel, .results-panel {
347
+ padding: 24px;
348
+ }
349
+
350
+ .form-row {
351
+ grid-template-columns: 1fr;
352
+ }
353
+
354
+ .gallery {
355
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
356
+ gap: 16px;
357
+ }
358
+ }
359
+
360
+ /* Additional Professional Touches */
361
+ .badge {
362
+ display: inline-flex;
363
+ align-items: center;
364
+ padding: 4px 8px;
365
+ background: #edf2f7;
366
+ color: #4a5568;
367
+ border-radius: 6px;
368
+ font-size: 0.75rem;
369
+ font-weight: 600;
370
+ text-transform: uppercase;
371
+ letter-spacing: 0.5px;
372
+ }
373
+
374
+ .divider {
375
+ height: 1px;
376
+ background: #e2e8f0;
377
+ margin: 24px 0;
378
+ }
379
+ </style>
380
+ </head>
381
+ <body>
382
+ <div class="main-container">
383
+ <!-- Header -->
384
+ <div class="header">
385
+ <h1>AI Image Studio</h1>
386
+ <p class="subtitle">Transform your ideas into stunning visuals with advanced AI technology</p>
387
+ </div>
388
+
389
+ <!-- Main Content -->
390
+ <div class="content-grid">
391
+ <!-- Control Panel -->
392
+ <div class="control-panel">
393
+ <h2 class="panel-title">
394
+ <i class="fas fa-magic"></i>
395
+ Generate Images
396
+ </h2>
397
+
398
+ <form id="generate-form">
399
+ <div class="form-group">
400
+ <label class="form-label" for="prompt">
401
+ <i class="fas fa-pen"></i> Prompt Description
402
+ </label>
403
+ <textarea
404
+ id="prompt"
405
+ name="prompt"
406
+ class="form-textarea"
407
+ required
408
+ placeholder="Describe the image you want to create... (e.g., A serene landscape with mountains at sunset, digital art style)"
409
+ ></textarea>
410
+ </div>
411
+
412
+ <div class="form-row">
413
+ <div class="form-group">
414
+ <label class="form-label" for="num_images">
415
+ <i class="fas fa-images"></i> Quantity
416
+ </label>
417
+ <select id="num_images" name="num_images" class="form-select">
418
+ <option value="1">1 Image</option>
419
+ <option value="2">2 Images</option>
420
+ <option value="3">3 Images</option>
421
+ <option value="4">4 Images</option>
422
+ <option value="5">5 Images</option>
423
+ </select>
424
+ </div>
425
+
426
+ <div class="form-group">
427
+ <label class="form-label" for="aspect_ratio">
428
+ <i class="fas fa-expand-arrows-alt"></i> Aspect Ratio
429
+ </label>
430
+ <select id="aspect_ratio" name="aspect_ratio" class="form-select">
431
+ <option value="1:1">1:1 Square</option>
432
+ <option value="4:3">4:3 Standard</option>
433
+ <option value="16:9">16:9 Widescreen</option>
434
+ </select>
435
+ </div>
436
+ </div>
437
+
438
+ <div class="form-group">
439
+ <label class="form-label" for="model">
440
+ <i class="fas fa-brain"></i> AI Model
441
+ </label>
442
+ <select id="model" name="model" class="form-select">
443
+ <option value="stable_diffusion">Stable Diffusion</option>
444
+ <option value="locked_model" disabled>Premium Model (Coming Soon)</option>
445
+ </select>
446
+ </div>
447
+
448
+ <div class="divider"></div>
449
+
450
+ <button type="submit" class="generate-btn">
451
+ <i class="fas fa-rocket"></i>
452
+ Generate Images
453
+ </button>
454
+ </form>
455
+
456
+ <div id="error-message"></div>
457
+ </div>
458
+
459
+ <!-- Results Panel -->
460
+ <div class="results-panel">
461
+ <div class="results-header">
462
+ <h2 class="results-title">
463
+ <i class="fas fa-images"></i>
464
+ Generated Images
465
+ </h2>
466
+ <div class="results-count" id="results-count" style="display: none;">0</div>
467
+ </div>
468
+
469
+ <div id="gallery-content">
470
+ <div class="empty-state">
471
+ <i class="fas fa-image"></i>
472
+ <h3>Ready to Create</h3>
473
+ <p>Enter a prompt and click generate to see your AI-created images appear here</p>
474
+ </div>
475
+ </div>
476
+ </div>
477
+ </div>
478
+ </div>
479
+
480
+ <script>
481
+ document.getElementById("generate-form").addEventListener("submit", async (e) => {
482
+ e.preventDefault();
483
+
484
+ const formData = new FormData(e.target);
485
+ const errorDiv = document.getElementById("error-message");
486
+ const galleryContent = document.getElementById("gallery-content");
487
+ const resultsCount = document.getElementById("results-count");
488
+ const generateBtn = document.querySelector(".generate-btn");
489
+
490
+ // Clear previous state
491
+ errorDiv.innerHTML = "";
492
+ resultsCount.style.display = "none";
493
+
494
+ // Show loading state
495
+ generateBtn.disabled = true;
496
+ generateBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Generating...';
497
+
498
+ galleryContent.innerHTML = `
499
+ <div class="loading">
500
+ <div class="loading-spinner"></div>
501
+ <h3>Creating your images...</h3>
502
+ <p>This may take a few moments</p>
503
+ </div>
504
+ `;
505
+
506
+ try {
507
+ const response = await fetch("/generate", {
508
+ method: "POST",
509
+ body: formData
510
+ });
511
+ const data = await response.json();
512
+
513
+ if (data.error) {
514
+ errorDiv.innerHTML = `
515
+ <div class="error-message">
516
+ <i class="fas fa-exclamation-triangle"></i>
517
+ ${data.error}
518
+ </div>
519
+ `;
520
+ galleryContent.innerHTML = `
521
+ <div class="empty-state">
522
+ <i class="fas fa-exclamation-triangle"></i>
523
+ <h3>Generation Failed</h3>
524
+ <p>Please check your prompt and try again</p>
525
+ </div>
526
+ `;
527
+ } else {
528
+ // Show results
529
+ const gallery = document.createElement("div");
530
+ gallery.className = "gallery";
531
+
532
+ data.images.forEach((imgPath, index) => {
533
+ const galleryItem = document.createElement("div");
534
+ galleryItem.className = "gallery-item";
535
+ galleryItem.innerHTML = `
536
+ <img src="/${imgPath}" alt="Generated Image ${index + 1}" loading="lazy">
537
+ <div class="gallery-overlay">
538
+ <div class="gallery-actions">
539
+ <button class="gallery-action" onclick="downloadImage('/${imgPath}')" title="Download">
540
+ <i class="fas fa-download"></i>
541
+ </button>
542
+ </div>
543
+ </div>
544
+ `;
545
+ gallery.appendChild(galleryItem);
546
+ });
547
+
548
+ galleryContent.innerHTML = "";
549
+ galleryContent.appendChild(gallery);
550
+
551
+ // Update results count
552
+ resultsCount.textContent = data.images.length;
553
+ resultsCount.style.display = "block";
554
+ }
555
+ } catch (err) {
556
+ errorDiv.innerHTML = `
557
+ <div class="error-message">
558
+ <i class="fas fa-exclamation-triangle"></i>
559
+ Network error occurred. Please check your connection and try again.
560
+ </div>
561
+ `;
562
+ galleryContent.innerHTML = `
563
+ <div class="empty-state">
564
+ <i class="fas fa-wifi"></i>
565
+ <h3>Connection Error</h3>
566
+ <p>Please check your internet connection and try again</p>
567
+ </div>
568
+ `;
569
+ } finally {
570
+ // Reset button
571
+ generateBtn.disabled = false;
572
+ generateBtn.innerHTML = '<i class="fas fa-rocket"></i> Generate Images';
573
+ }
574
+ });
575
+
576
+ // Download function
577
+ function downloadImage(src) {
578
+ const link = document.createElement('a');
579
+ link.href = src;
580
+ link.download = `ai-generated-image-${Date.now()}.png`;
581
+ document.body.appendChild(link);
582
+ link.click();
583
+ document.body.removeChild(link);
584
+ }
585
+
586
+ // Add some interactive polish
587
+ document.addEventListener('DOMContentLoaded', function() {
588
+ // Add subtle animation to form elements
589
+ const formElements = document.querySelectorAll('.form-input, .form-select, .form-textarea');
590
+ formElements.forEach(element => {
591
+ element.addEventListener('focus', function() {
592
+ this.parentElement.style.transform = 'translateY(-2px)';
593
+ });
594
+ element.addEventListener('blur', function() {
595
+ this.parentElement.style.transform = 'translateY(0)';
596
+ });
597
+ });
598
+ });
599
+ </script>
600
+ </body>
601
+ </html>
venv/Lib/site-packages/MarkupSafe-3.0.2.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
venv/Lib/site-packages/MarkupSafe-3.0.2.dist-info/LICENSE.txt ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright 2010 Pallets
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions are
5
+ met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright
8
+ notice, this list of conditions and the following disclaimer.
9
+
10
+ 2. Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+
14
+ 3. Neither the name of the copyright holder nor the names of its
15
+ contributors may be used to endorse or promote products derived from
16
+ this software without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
venv/Lib/site-packages/MarkupSafe-3.0.2.dist-info/METADATA ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.1
2
+ Name: MarkupSafe
3
+ Version: 3.0.2
4
+ Summary: Safely add untrusted strings to HTML/XML markup.
5
+ Maintainer-email: Pallets <contact@palletsprojects.com>
6
+ License: Copyright 2010 Pallets
7
+
8
+ Redistribution and use in source and binary forms, with or without
9
+ modification, are permitted provided that the following conditions are
10
+ met:
11
+
12
+ 1. Redistributions of source code must retain the above copyright
13
+ notice, this list of conditions and the following disclaimer.
14
+
15
+ 2. Redistributions in binary form must reproduce the above copyright
16
+ notice, this list of conditions and the following disclaimer in the
17
+ documentation and/or other materials provided with the distribution.
18
+
19
+ 3. Neither the name of the copyright holder nor the names of its
20
+ contributors may be used to endorse or promote products derived from
21
+ this software without specific prior written permission.
22
+
23
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
+
35
+ Project-URL: Donate, https://palletsprojects.com/donate
36
+ Project-URL: Documentation, https://markupsafe.palletsprojects.com/
37
+ Project-URL: Changes, https://markupsafe.palletsprojects.com/changes/
38
+ Project-URL: Source, https://github.com/pallets/markupsafe/
39
+ Project-URL: Chat, https://discord.gg/pallets
40
+ Classifier: Development Status :: 5 - Production/Stable
41
+ Classifier: Environment :: Web Environment
42
+ Classifier: Intended Audience :: Developers
43
+ Classifier: License :: OSI Approved :: BSD License
44
+ Classifier: Operating System :: OS Independent
45
+ Classifier: Programming Language :: Python
46
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
47
+ Classifier: Topic :: Text Processing :: Markup :: HTML
48
+ Classifier: Typing :: Typed
49
+ Requires-Python: >=3.9
50
+ Description-Content-Type: text/markdown
51
+ License-File: LICENSE.txt
52
+
53
+ # MarkupSafe
54
+
55
+ MarkupSafe implements a text object that escapes characters so it is
56
+ safe to use in HTML and XML. Characters that have special meanings are
57
+ replaced so that they display as the actual characters. This mitigates
58
+ injection attacks, meaning untrusted user input can safely be displayed
59
+ on a page.
60
+
61
+
62
+ ## Examples
63
+
64
+ ```pycon
65
+ >>> from markupsafe import Markup, escape
66
+
67
+ >>> # escape replaces special characters and wraps in Markup
68
+ >>> escape("<script>alert(document.cookie);</script>")
69
+ Markup('&lt;script&gt;alert(document.cookie);&lt;/script&gt;')
70
+
71
+ >>> # wrap in Markup to mark text "safe" and prevent escaping
72
+ >>> Markup("<strong>Hello</strong>")
73
+ Markup('<strong>hello</strong>')
74
+
75
+ >>> escape(Markup("<strong>Hello</strong>"))
76
+ Markup('<strong>hello</strong>')
77
+
78
+ >>> # Markup is a str subclass
79
+ >>> # methods and operators escape their arguments
80
+ >>> template = Markup("Hello <em>{name}</em>")
81
+ >>> template.format(name='"World"')
82
+ Markup('Hello <em>&#34;World&#34;</em>')
83
+ ```
84
+
85
+ ## Donate
86
+
87
+ The Pallets organization develops and supports MarkupSafe and other
88
+ popular packages. In order to grow the community of contributors and
89
+ users, and allow the maintainers to devote more time to the projects,
90
+ [please donate today][].
91
+
92
+ [please donate today]: https://palletsprojects.com/donate
venv/Lib/site-packages/MarkupSafe-3.0.2.dist-info/RECORD ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MarkupSafe-3.0.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
2
+ MarkupSafe-3.0.2.dist-info/LICENSE.txt,sha256=RjHsDbX9kKVH4zaBcmTGeYIUM4FG-KyUtKV_lu6MnsQ,1503
3
+ MarkupSafe-3.0.2.dist-info/METADATA,sha256=nhoabjupBG41j_JxPCJ3ylgrZ6Fx8oMCFbiLF9Kafqc,4067
4
+ MarkupSafe-3.0.2.dist-info/RECORD,,
5
+ MarkupSafe-3.0.2.dist-info/WHEEL,sha256=IqiWNwTSPPvorR7mTezuRY2eqj__44JKKkjOiewDX64,101
6
+ MarkupSafe-3.0.2.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11
7
+ markupsafe/__init__.py,sha256=pREerPwvinB62tNCMOwqxBS2YHV6R52Wcq1d-rB4Z5o,13609
8
+ markupsafe/__pycache__/__init__.cpython-310.pyc,,
9
+ markupsafe/__pycache__/_native.cpython-310.pyc,,
10
+ markupsafe/_native.py,sha256=2ptkJ40yCcp9kq3L1NqpgjfpZB-obniYKFFKUOkHh4Q,218
11
+ markupsafe/_speedups.c,sha256=SglUjn40ti9YgQAO--OgkSyv9tXq9vvaHyVhQows4Ok,4353
12
+ markupsafe/_speedups.cp310-win_amd64.pyd,sha256=RTvh-UzJTX7J_4j-A5jZmnqwRKBe0pQiDPd_j60jft8,13312
13
+ markupsafe/_speedups.pyi,sha256=LSDmXYOefH4HVpAXuL8sl7AttLw0oXh1njVoVZp2wqQ,42
14
+ markupsafe/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
venv/Lib/site-packages/MarkupSafe-3.0.2.dist-info/WHEEL ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.2.0)
3
+ Root-Is-Purelib: false
4
+ Tag: cp310-cp310-win_amd64
5
+
venv/Lib/site-packages/MarkupSafe-3.0.2.dist-info/top_level.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ markupsafe
venv/Lib/site-packages/PIL/AvifImagePlugin.py ADDED
@@ -0,0 +1,292 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from io import BytesIO
5
+ from typing import IO
6
+
7
+ from . import ExifTags, Image, ImageFile
8
+
9
+ try:
10
+ from . import _avif
11
+
12
+ SUPPORTED = True
13
+ except ImportError:
14
+ SUPPORTED = False
15
+
16
+ # Decoder options as module globals, until there is a way to pass parameters
17
+ # to Image.open (see https://github.com/python-pillow/Pillow/issues/569)
18
+ DECODE_CODEC_CHOICE = "auto"
19
+ # Decoding is only affected by this for libavif **0.8.4** or greater.
20
+ DEFAULT_MAX_THREADS = 0
21
+
22
+
23
+ def get_codec_version(codec_name: str) -> str | None:
24
+ versions = _avif.codec_versions()
25
+ for version in versions.split(", "):
26
+ if version.split(" [")[0] == codec_name:
27
+ return version.split(":")[-1].split(" ")[0]
28
+ return None
29
+
30
+
31
+ def _accept(prefix: bytes) -> bool | str:
32
+ if prefix[4:8] != b"ftyp":
33
+ return False
34
+ major_brand = prefix[8:12]
35
+ if major_brand in (
36
+ # coding brands
37
+ b"avif",
38
+ b"avis",
39
+ # We accept files with AVIF container brands; we can't yet know if
40
+ # the ftyp box has the correct compatible brands, but if it doesn't
41
+ # then the plugin will raise a SyntaxError which Pillow will catch
42
+ # before moving on to the next plugin that accepts the file.
43
+ #
44
+ # Also, because this file might not actually be an AVIF file, we
45
+ # don't raise an error if AVIF support isn't properly compiled.
46
+ b"mif1",
47
+ b"msf1",
48
+ ):
49
+ if not SUPPORTED:
50
+ return (
51
+ "image file could not be identified because AVIF support not installed"
52
+ )
53
+ return True
54
+ return False
55
+
56
+
57
+ def _get_default_max_threads() -> int:
58
+ if DEFAULT_MAX_THREADS:
59
+ return DEFAULT_MAX_THREADS
60
+ if hasattr(os, "sched_getaffinity"):
61
+ return len(os.sched_getaffinity(0))
62
+ else:
63
+ return os.cpu_count() or 1
64
+
65
+
66
+ class AvifImageFile(ImageFile.ImageFile):
67
+ format = "AVIF"
68
+ format_description = "AVIF image"
69
+ __frame = -1
70
+
71
+ def _open(self) -> None:
72
+ if not SUPPORTED:
73
+ msg = "image file could not be opened because AVIF support not installed"
74
+ raise SyntaxError(msg)
75
+
76
+ if DECODE_CODEC_CHOICE != "auto" and not _avif.decoder_codec_available(
77
+ DECODE_CODEC_CHOICE
78
+ ):
79
+ msg = "Invalid opening codec"
80
+ raise ValueError(msg)
81
+ self._decoder = _avif.AvifDecoder(
82
+ self.fp.read(),
83
+ DECODE_CODEC_CHOICE,
84
+ _get_default_max_threads(),
85
+ )
86
+
87
+ # Get info from decoder
88
+ self._size, self.n_frames, self._mode, icc, exif, exif_orientation, xmp = (
89
+ self._decoder.get_info()
90
+ )
91
+ self.is_animated = self.n_frames > 1
92
+
93
+ if icc:
94
+ self.info["icc_profile"] = icc
95
+ if xmp:
96
+ self.info["xmp"] = xmp
97
+
98
+ if exif_orientation != 1 or exif:
99
+ exif_data = Image.Exif()
100
+ if exif:
101
+ exif_data.load(exif)
102
+ original_orientation = exif_data.get(ExifTags.Base.Orientation, 1)
103
+ else:
104
+ original_orientation = 1
105
+ if exif_orientation != original_orientation:
106
+ exif_data[ExifTags.Base.Orientation] = exif_orientation
107
+ exif = exif_data.tobytes()
108
+ if exif:
109
+ self.info["exif"] = exif
110
+ self.seek(0)
111
+
112
+ def seek(self, frame: int) -> None:
113
+ if not self._seek_check(frame):
114
+ return
115
+
116
+ # Set tile
117
+ self.__frame = frame
118
+ self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 0, self.mode)]
119
+
120
+ def load(self) -> Image.core.PixelAccess | None:
121
+ if self.tile:
122
+ # We need to load the image data for this frame
123
+ data, timescale, pts_in_timescales, duration_in_timescales = (
124
+ self._decoder.get_frame(self.__frame)
125
+ )
126
+ self.info["timestamp"] = round(1000 * (pts_in_timescales / timescale))
127
+ self.info["duration"] = round(1000 * (duration_in_timescales / timescale))
128
+
129
+ if self.fp and self._exclusive_fp:
130
+ self.fp.close()
131
+ self.fp = BytesIO(data)
132
+
133
+ return super().load()
134
+
135
+ def load_seek(self, pos: int) -> None:
136
+ pass
137
+
138
+ def tell(self) -> int:
139
+ return self.__frame
140
+
141
+
142
+ def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
143
+ _save(im, fp, filename, save_all=True)
144
+
145
+
146
+ def _save(
147
+ im: Image.Image, fp: IO[bytes], filename: str | bytes, save_all: bool = False
148
+ ) -> None:
149
+ info = im.encoderinfo.copy()
150
+ if save_all:
151
+ append_images = list(info.get("append_images", []))
152
+ else:
153
+ append_images = []
154
+
155
+ total = 0
156
+ for ims in [im] + append_images:
157
+ total += getattr(ims, "n_frames", 1)
158
+
159
+ quality = info.get("quality", 75)
160
+ if not isinstance(quality, int) or quality < 0 or quality > 100:
161
+ msg = "Invalid quality setting"
162
+ raise ValueError(msg)
163
+
164
+ duration = info.get("duration", 0)
165
+ subsampling = info.get("subsampling", "4:2:0")
166
+ speed = info.get("speed", 6)
167
+ max_threads = info.get("max_threads", _get_default_max_threads())
168
+ codec = info.get("codec", "auto")
169
+ if codec != "auto" and not _avif.encoder_codec_available(codec):
170
+ msg = "Invalid saving codec"
171
+ raise ValueError(msg)
172
+ range_ = info.get("range", "full")
173
+ tile_rows_log2 = info.get("tile_rows", 0)
174
+ tile_cols_log2 = info.get("tile_cols", 0)
175
+ alpha_premultiplied = bool(info.get("alpha_premultiplied", False))
176
+ autotiling = bool(info.get("autotiling", tile_rows_log2 == tile_cols_log2 == 0))
177
+
178
+ icc_profile = info.get("icc_profile", im.info.get("icc_profile"))
179
+ exif_orientation = 1
180
+ if exif := info.get("exif"):
181
+ if isinstance(exif, Image.Exif):
182
+ exif_data = exif
183
+ else:
184
+ exif_data = Image.Exif()
185
+ exif_data.load(exif)
186
+ if ExifTags.Base.Orientation in exif_data:
187
+ exif_orientation = exif_data.pop(ExifTags.Base.Orientation)
188
+ exif = exif_data.tobytes() if exif_data else b""
189
+ elif isinstance(exif, Image.Exif):
190
+ exif = exif_data.tobytes()
191
+
192
+ xmp = info.get("xmp")
193
+
194
+ if isinstance(xmp, str):
195
+ xmp = xmp.encode("utf-8")
196
+
197
+ advanced = info.get("advanced")
198
+ if advanced is not None:
199
+ if isinstance(advanced, dict):
200
+ advanced = advanced.items()
201
+ try:
202
+ advanced = tuple(advanced)
203
+ except TypeError:
204
+ invalid = True
205
+ else:
206
+ invalid = any(not isinstance(v, tuple) or len(v) != 2 for v in advanced)
207
+ if invalid:
208
+ msg = (
209
+ "advanced codec options must be a dict of key-value string "
210
+ "pairs or a series of key-value two-tuples"
211
+ )
212
+ raise ValueError(msg)
213
+
214
+ # Setup the AVIF encoder
215
+ enc = _avif.AvifEncoder(
216
+ im.size,
217
+ subsampling,
218
+ quality,
219
+ speed,
220
+ max_threads,
221
+ codec,
222
+ range_,
223
+ tile_rows_log2,
224
+ tile_cols_log2,
225
+ alpha_premultiplied,
226
+ autotiling,
227
+ icc_profile or b"",
228
+ exif or b"",
229
+ exif_orientation,
230
+ xmp or b"",
231
+ advanced,
232
+ )
233
+
234
+ # Add each frame
235
+ frame_idx = 0
236
+ frame_duration = 0
237
+ cur_idx = im.tell()
238
+ is_single_frame = total == 1
239
+ try:
240
+ for ims in [im] + append_images:
241
+ # Get number of frames in this image
242
+ nfr = getattr(ims, "n_frames", 1)
243
+
244
+ for idx in range(nfr):
245
+ ims.seek(idx)
246
+
247
+ # Make sure image mode is supported
248
+ frame = ims
249
+ rawmode = ims.mode
250
+ if ims.mode not in {"RGB", "RGBA"}:
251
+ rawmode = "RGBA" if ims.has_transparency_data else "RGB"
252
+ frame = ims.convert(rawmode)
253
+
254
+ # Update frame duration
255
+ if isinstance(duration, (list, tuple)):
256
+ frame_duration = duration[frame_idx]
257
+ else:
258
+ frame_duration = duration
259
+
260
+ # Append the frame to the animation encoder
261
+ enc.add(
262
+ frame.tobytes("raw", rawmode),
263
+ frame_duration,
264
+ frame.size,
265
+ rawmode,
266
+ is_single_frame,
267
+ )
268
+
269
+ # Update frame index
270
+ frame_idx += 1
271
+
272
+ if not save_all:
273
+ break
274
+
275
+ finally:
276
+ im.seek(cur_idx)
277
+
278
+ # Get the final output from the encoder
279
+ data = enc.finish()
280
+ if data is None:
281
+ msg = "cannot write file as AVIF (encoder returned None)"
282
+ raise OSError(msg)
283
+
284
+ fp.write(data)
285
+
286
+
287
+ Image.register_open(AvifImageFile.format, AvifImageFile, _accept)
288
+ if SUPPORTED:
289
+ Image.register_save(AvifImageFile.format, _save)
290
+ Image.register_save_all(AvifImageFile.format, _save_all)
291
+ Image.register_extensions(AvifImageFile.format, [".avif", ".avifs"])
292
+ Image.register_mime(AvifImageFile.format, "image/avif")
venv/Lib/site-packages/PIL/BdfFontFile.py ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # The Python Imaging Library
3
+ # $Id$
4
+ #
5
+ # bitmap distribution font (bdf) file parser
6
+ #
7
+ # history:
8
+ # 1996-05-16 fl created (as bdf2pil)
9
+ # 1997-08-25 fl converted to FontFile driver
10
+ # 2001-05-25 fl removed bogus __init__ call
11
+ # 2002-11-20 fl robustification (from Kevin Cazabon, Dmitry Vasiliev)
12
+ # 2003-04-22 fl more robustification (from Graham Dumpleton)
13
+ #
14
+ # Copyright (c) 1997-2003 by Secret Labs AB.
15
+ # Copyright (c) 1997-2003 by Fredrik Lundh.
16
+ #
17
+ # See the README file for information on usage and redistribution.
18
+ #
19
+
20
+ """
21
+ Parse X Bitmap Distribution Format (BDF)
22
+ """
23
+ from __future__ import annotations
24
+
25
+ from typing import BinaryIO
26
+
27
+ from . import FontFile, Image
28
+
29
+
30
+ def bdf_char(
31
+ f: BinaryIO,
32
+ ) -> (
33
+ tuple[
34
+ str,
35
+ int,
36
+ tuple[tuple[int, int], tuple[int, int, int, int], tuple[int, int, int, int]],
37
+ Image.Image,
38
+ ]
39
+ | None
40
+ ):
41
+ # skip to STARTCHAR
42
+ while True:
43
+ s = f.readline()
44
+ if not s:
45
+ return None
46
+ if s.startswith(b"STARTCHAR"):
47
+ break
48
+ id = s[9:].strip().decode("ascii")
49
+
50
+ # load symbol properties
51
+ props = {}
52
+ while True:
53
+ s = f.readline()
54
+ if not s or s.startswith(b"BITMAP"):
55
+ break
56
+ i = s.find(b" ")
57
+ props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii")
58
+
59
+ # load bitmap
60
+ bitmap = bytearray()
61
+ while True:
62
+ s = f.readline()
63
+ if not s or s.startswith(b"ENDCHAR"):
64
+ break
65
+ bitmap += s[:-1]
66
+
67
+ # The word BBX
68
+ # followed by the width in x (BBw), height in y (BBh),
69
+ # and x and y displacement (BBxoff0, BByoff0)
70
+ # of the lower left corner from the origin of the character.
71
+ width, height, x_disp, y_disp = (int(p) for p in props["BBX"].split())
72
+
73
+ # The word DWIDTH
74
+ # followed by the width in x and y of the character in device pixels.
75
+ dwx, dwy = (int(p) for p in props["DWIDTH"].split())
76
+
77
+ bbox = (
78
+ (dwx, dwy),
79
+ (x_disp, -y_disp - height, width + x_disp, -y_disp),
80
+ (0, 0, width, height),
81
+ )
82
+
83
+ try:
84
+ im = Image.frombytes("1", (width, height), bitmap, "hex", "1")
85
+ except ValueError:
86
+ # deal with zero-width characters
87
+ im = Image.new("1", (width, height))
88
+
89
+ return id, int(props["ENCODING"]), bbox, im
90
+
91
+
92
+ class BdfFontFile(FontFile.FontFile):
93
+ """Font file plugin for the X11 BDF format."""
94
+
95
+ def __init__(self, fp: BinaryIO) -> None:
96
+ super().__init__()
97
+
98
+ s = fp.readline()
99
+ if not s.startswith(b"STARTFONT 2.1"):
100
+ msg = "not a valid BDF file"
101
+ raise SyntaxError(msg)
102
+
103
+ props = {}
104
+ comments = []
105
+
106
+ while True:
107
+ s = fp.readline()
108
+ if not s or s.startswith(b"ENDPROPERTIES"):
109
+ break
110
+ i = s.find(b" ")
111
+ props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii")
112
+ if s[:i] in [b"COMMENT", b"COPYRIGHT"]:
113
+ if s.find(b"LogicalFontDescription") < 0:
114
+ comments.append(s[i + 1 : -1].decode("ascii"))
115
+
116
+ while True:
117
+ c = bdf_char(fp)
118
+ if not c:
119
+ break
120
+ id, ch, (xy, dst, src), im = c
121
+ if 0 <= ch < len(self.glyph):
122
+ self.glyph[ch] = xy, dst, src, im
venv/Lib/site-packages/PIL/BlpImagePlugin.py ADDED
@@ -0,0 +1,497 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Blizzard Mipmap Format (.blp)
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
+ BLP1 files, used mostly in Warcraft III, are not fully supported.
10
+ All types of BLP2 files used in World of Warcraft are supported.
11
+
12
+ The BLP file structure consists of a header, up to 16 mipmaps of the
13
+ texture
14
+
15
+ Texture sizes must be powers of two, though the two dimensions do
16
+ not have to be equal; 512x256 is valid, but 512x200 is not.
17
+ The first mipmap (mipmap #0) is the full size image; each subsequent
18
+ mipmap halves both dimensions. The final mipmap should be 1x1.
19
+
20
+ BLP files come in many different flavours:
21
+ * JPEG-compressed (type == 0) - only supported for BLP1.
22
+ * RAW images (type == 1, encoding == 1). Each mipmap is stored as an
23
+ array of 8-bit values, one per pixel, left to right, top to bottom.
24
+ Each value is an index to the palette.
25
+ * DXT-compressed (type == 1, encoding == 2):
26
+ - DXT1 compression is used if alpha_encoding == 0.
27
+ - An additional alpha bit is used if alpha_depth == 1.
28
+ - DXT3 compression is used if alpha_encoding == 1.
29
+ - DXT5 compression is used if alpha_encoding == 7.
30
+ """
31
+
32
+ from __future__ import annotations
33
+
34
+ import abc
35
+ import os
36
+ import struct
37
+ from enum import IntEnum
38
+ from io import BytesIO
39
+ from typing import IO
40
+
41
+ from . import Image, ImageFile
42
+
43
+
44
+ class Format(IntEnum):
45
+ JPEG = 0
46
+
47
+
48
+ class Encoding(IntEnum):
49
+ UNCOMPRESSED = 1
50
+ DXT = 2
51
+ UNCOMPRESSED_RAW_BGRA = 3
52
+
53
+
54
+ class AlphaEncoding(IntEnum):
55
+ DXT1 = 0
56
+ DXT3 = 1
57
+ DXT5 = 7
58
+
59
+
60
+ def unpack_565(i: int) -> tuple[int, int, int]:
61
+ return ((i >> 11) & 0x1F) << 3, ((i >> 5) & 0x3F) << 2, (i & 0x1F) << 3
62
+
63
+
64
+ def decode_dxt1(
65
+ data: bytes, alpha: bool = False
66
+ ) -> tuple[bytearray, bytearray, bytearray, bytearray]:
67
+ """
68
+ input: one "row" of data (i.e. will produce 4*width pixels)
69
+ """
70
+
71
+ blocks = len(data) // 8 # number of blocks in row
72
+ ret = (bytearray(), bytearray(), bytearray(), bytearray())
73
+
74
+ for block_index in range(blocks):
75
+ # Decode next 8-byte block.
76
+ idx = block_index * 8
77
+ color0, color1, bits = struct.unpack_from("<HHI", data, idx)
78
+
79
+ r0, g0, b0 = unpack_565(color0)
80
+ r1, g1, b1 = unpack_565(color1)
81
+
82
+ # Decode this block into 4x4 pixels
83
+ # Accumulate the results onto our 4 row accumulators
84
+ for j in range(4):
85
+ for i in range(4):
86
+ # get next control op and generate a pixel
87
+
88
+ control = bits & 3
89
+ bits = bits >> 2
90
+
91
+ a = 0xFF
92
+ if control == 0:
93
+ r, g, b = r0, g0, b0
94
+ elif control == 1:
95
+ r, g, b = r1, g1, b1
96
+ elif control == 2:
97
+ if color0 > color1:
98
+ r = (2 * r0 + r1) // 3
99
+ g = (2 * g0 + g1) // 3
100
+ b = (2 * b0 + b1) // 3
101
+ else:
102
+ r = (r0 + r1) // 2
103
+ g = (g0 + g1) // 2
104
+ b = (b0 + b1) // 2
105
+ elif control == 3:
106
+ if color0 > color1:
107
+ r = (2 * r1 + r0) // 3
108
+ g = (2 * g1 + g0) // 3
109
+ b = (2 * b1 + b0) // 3
110
+ else:
111
+ r, g, b, a = 0, 0, 0, 0
112
+
113
+ if alpha:
114
+ ret[j].extend([r, g, b, a])
115
+ else:
116
+ ret[j].extend([r, g, b])
117
+
118
+ return ret
119
+
120
+
121
+ def decode_dxt3(data: bytes) -> tuple[bytearray, bytearray, bytearray, bytearray]:
122
+ """
123
+ input: one "row" of data (i.e. will produce 4*width pixels)
124
+ """
125
+
126
+ blocks = len(data) // 16 # number of blocks in row
127
+ ret = (bytearray(), bytearray(), bytearray(), bytearray())
128
+
129
+ for block_index in range(blocks):
130
+ idx = block_index * 16
131
+ block = data[idx : idx + 16]
132
+ # Decode next 16-byte block.
133
+ bits = struct.unpack_from("<8B", block)
134
+ color0, color1 = struct.unpack_from("<HH", block, 8)
135
+
136
+ (code,) = struct.unpack_from("<I", block, 12)
137
+
138
+ r0, g0, b0 = unpack_565(color0)
139
+ r1, g1, b1 = unpack_565(color1)
140
+
141
+ for j in range(4):
142
+ high = False # Do we want the higher bits?
143
+ for i in range(4):
144
+ alphacode_index = (4 * j + i) // 2
145
+ a = bits[alphacode_index]
146
+ if high:
147
+ high = False
148
+ a >>= 4
149
+ else:
150
+ high = True
151
+ a &= 0xF
152
+ a *= 17 # We get a value between 0 and 15
153
+
154
+ color_code = (code >> 2 * (4 * j + i)) & 0x03
155
+
156
+ if color_code == 0:
157
+ r, g, b = r0, g0, b0
158
+ elif color_code == 1:
159
+ r, g, b = r1, g1, b1
160
+ elif color_code == 2:
161
+ r = (2 * r0 + r1) // 3
162
+ g = (2 * g0 + g1) // 3
163
+ b = (2 * b0 + b1) // 3
164
+ elif color_code == 3:
165
+ r = (2 * r1 + r0) // 3
166
+ g = (2 * g1 + g0) // 3
167
+ b = (2 * b1 + b0) // 3
168
+
169
+ ret[j].extend([r, g, b, a])
170
+
171
+ return ret
172
+
173
+
174
+ def decode_dxt5(data: bytes) -> tuple[bytearray, bytearray, bytearray, bytearray]:
175
+ """
176
+ input: one "row" of data (i.e. will produce 4 * width pixels)
177
+ """
178
+
179
+ blocks = len(data) // 16 # number of blocks in row
180
+ ret = (bytearray(), bytearray(), bytearray(), bytearray())
181
+
182
+ for block_index in range(blocks):
183
+ idx = block_index * 16
184
+ block = data[idx : idx + 16]
185
+ # Decode next 16-byte block.
186
+ a0, a1 = struct.unpack_from("<BB", block)
187
+
188
+ bits = struct.unpack_from("<6B", block, 2)
189
+ alphacode1 = bits[2] | (bits[3] << 8) | (bits[4] << 16) | (bits[5] << 24)
190
+ alphacode2 = bits[0] | (bits[1] << 8)
191
+
192
+ color0, color1 = struct.unpack_from("<HH", block, 8)
193
+
194
+ (code,) = struct.unpack_from("<I", block, 12)
195
+
196
+ r0, g0, b0 = unpack_565(color0)
197
+ r1, g1, b1 = unpack_565(color1)
198
+
199
+ for j in range(4):
200
+ for i in range(4):
201
+ # get next control op and generate a pixel
202
+ alphacode_index = 3 * (4 * j + i)
203
+
204
+ if alphacode_index <= 12:
205
+ alphacode = (alphacode2 >> alphacode_index) & 0x07
206
+ elif alphacode_index == 15:
207
+ alphacode = (alphacode2 >> 15) | ((alphacode1 << 1) & 0x06)
208
+ else: # alphacode_index >= 18 and alphacode_index <= 45
209
+ alphacode = (alphacode1 >> (alphacode_index - 16)) & 0x07
210
+
211
+ if alphacode == 0:
212
+ a = a0
213
+ elif alphacode == 1:
214
+ a = a1
215
+ elif a0 > a1:
216
+ a = ((8 - alphacode) * a0 + (alphacode - 1) * a1) // 7
217
+ elif alphacode == 6:
218
+ a = 0
219
+ elif alphacode == 7:
220
+ a = 255
221
+ else:
222
+ a = ((6 - alphacode) * a0 + (alphacode - 1) * a1) // 5
223
+
224
+ color_code = (code >> 2 * (4 * j + i)) & 0x03
225
+
226
+ if color_code == 0:
227
+ r, g, b = r0, g0, b0
228
+ elif color_code == 1:
229
+ r, g, b = r1, g1, b1
230
+ elif color_code == 2:
231
+ r = (2 * r0 + r1) // 3
232
+ g = (2 * g0 + g1) // 3
233
+ b = (2 * b0 + b1) // 3
234
+ elif color_code == 3:
235
+ r = (2 * r1 + r0) // 3
236
+ g = (2 * g1 + g0) // 3
237
+ b = (2 * b1 + b0) // 3
238
+
239
+ ret[j].extend([r, g, b, a])
240
+
241
+ return ret
242
+
243
+
244
+ class BLPFormatError(NotImplementedError):
245
+ pass
246
+
247
+
248
+ def _accept(prefix: bytes) -> bool:
249
+ return prefix.startswith((b"BLP1", b"BLP2"))
250
+
251
+
252
+ class BlpImageFile(ImageFile.ImageFile):
253
+ """
254
+ Blizzard Mipmap Format
255
+ """
256
+
257
+ format = "BLP"
258
+ format_description = "Blizzard Mipmap Format"
259
+
260
+ def _open(self) -> None:
261
+ self.magic = self.fp.read(4)
262
+ if not _accept(self.magic):
263
+ msg = f"Bad BLP magic {repr(self.magic)}"
264
+ raise BLPFormatError(msg)
265
+
266
+ compression = struct.unpack("<i", self.fp.read(4))[0]
267
+ if self.magic == b"BLP1":
268
+ alpha = struct.unpack("<I", self.fp.read(4))[0] != 0
269
+ else:
270
+ encoding = struct.unpack("<b", self.fp.read(1))[0]
271
+ alpha = struct.unpack("<b", self.fp.read(1))[0] != 0
272
+ alpha_encoding = struct.unpack("<b", self.fp.read(1))[0]
273
+ self.fp.seek(1, os.SEEK_CUR) # mips
274
+
275
+ self._size = struct.unpack("<II", self.fp.read(8))
276
+
277
+ args: tuple[int, int, bool] | tuple[int, int, bool, int]
278
+ if self.magic == b"BLP1":
279
+ encoding = struct.unpack("<i", self.fp.read(4))[0]
280
+ self.fp.seek(4, os.SEEK_CUR) # subtype
281
+
282
+ args = (compression, encoding, alpha)
283
+ offset = 28
284
+ else:
285
+ args = (compression, encoding, alpha, alpha_encoding)
286
+ offset = 20
287
+
288
+ decoder = self.magic.decode()
289
+
290
+ self._mode = "RGBA" if alpha else "RGB"
291
+ self.tile = [ImageFile._Tile(decoder, (0, 0) + self.size, offset, args)]
292
+
293
+
294
+ class _BLPBaseDecoder(abc.ABC, ImageFile.PyDecoder):
295
+ _pulls_fd = True
296
+
297
+ def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
298
+ try:
299
+ self._read_header()
300
+ self._load()
301
+ except struct.error as e:
302
+ msg = "Truncated BLP file"
303
+ raise OSError(msg) from e
304
+ return -1, 0
305
+
306
+ @abc.abstractmethod
307
+ def _load(self) -> None:
308
+ pass
309
+
310
+ def _read_header(self) -> None:
311
+ self._offsets = struct.unpack("<16I", self._safe_read(16 * 4))
312
+ self._lengths = struct.unpack("<16I", self._safe_read(16 * 4))
313
+
314
+ def _safe_read(self, length: int) -> bytes:
315
+ assert self.fd is not None
316
+ return ImageFile._safe_read(self.fd, length)
317
+
318
+ def _read_palette(self) -> list[tuple[int, int, int, int]]:
319
+ ret = []
320
+ for i in range(256):
321
+ try:
322
+ b, g, r, a = struct.unpack("<4B", self._safe_read(4))
323
+ except struct.error:
324
+ break
325
+ ret.append((b, g, r, a))
326
+ return ret
327
+
328
+ def _read_bgra(
329
+ self, palette: list[tuple[int, int, int, int]], alpha: bool
330
+ ) -> bytearray:
331
+ data = bytearray()
332
+ _data = BytesIO(self._safe_read(self._lengths[0]))
333
+ while True:
334
+ try:
335
+ (offset,) = struct.unpack("<B", _data.read(1))
336
+ except struct.error:
337
+ break
338
+ b, g, r, a = palette[offset]
339
+ d: tuple[int, ...] = (r, g, b)
340
+ if alpha:
341
+ d += (a,)
342
+ data.extend(d)
343
+ return data
344
+
345
+
346
+ class BLP1Decoder(_BLPBaseDecoder):
347
+ def _load(self) -> None:
348
+ self._compression, self._encoding, alpha = self.args
349
+
350
+ if self._compression == Format.JPEG:
351
+ self._decode_jpeg_stream()
352
+
353
+ elif self._compression == 1:
354
+ if self._encoding in (4, 5):
355
+ palette = self._read_palette()
356
+ data = self._read_bgra(palette, alpha)
357
+ self.set_as_raw(data)
358
+ else:
359
+ msg = f"Unsupported BLP encoding {repr(self._encoding)}"
360
+ raise BLPFormatError(msg)
361
+ else:
362
+ msg = f"Unsupported BLP compression {repr(self._encoding)}"
363
+ raise BLPFormatError(msg)
364
+
365
+ def _decode_jpeg_stream(self) -> None:
366
+ from .JpegImagePlugin import JpegImageFile
367
+
368
+ (jpeg_header_size,) = struct.unpack("<I", self._safe_read(4))
369
+ jpeg_header = self._safe_read(jpeg_header_size)
370
+ assert self.fd is not None
371
+ self._safe_read(self._offsets[0] - self.fd.tell()) # What IS this?
372
+ data = self._safe_read(self._lengths[0])
373
+ data = jpeg_header + data
374
+ image = JpegImageFile(BytesIO(data))
375
+ Image._decompression_bomb_check(image.size)
376
+ if image.mode == "CMYK":
377
+ args = image.tile[0].args
378
+ assert isinstance(args, tuple)
379
+ image.tile = [image.tile[0]._replace(args=(args[0], "CMYK"))]
380
+ self.set_as_raw(image.convert("RGB").tobytes(), "BGR")
381
+
382
+
383
+ class BLP2Decoder(_BLPBaseDecoder):
384
+ def _load(self) -> None:
385
+ self._compression, self._encoding, alpha, self._alpha_encoding = self.args
386
+
387
+ palette = self._read_palette()
388
+
389
+ assert self.fd is not None
390
+ self.fd.seek(self._offsets[0])
391
+
392
+ if self._compression == 1:
393
+ # Uncompressed or DirectX compression
394
+
395
+ if self._encoding == Encoding.UNCOMPRESSED:
396
+ data = self._read_bgra(palette, alpha)
397
+
398
+ elif self._encoding == Encoding.DXT:
399
+ data = bytearray()
400
+ if self._alpha_encoding == AlphaEncoding.DXT1:
401
+ linesize = (self.state.xsize + 3) // 4 * 8
402
+ for yb in range((self.state.ysize + 3) // 4):
403
+ for d in decode_dxt1(self._safe_read(linesize), alpha):
404
+ data += d
405
+
406
+ elif self._alpha_encoding == AlphaEncoding.DXT3:
407
+ linesize = (self.state.xsize + 3) // 4 * 16
408
+ for yb in range((self.state.ysize + 3) // 4):
409
+ for d in decode_dxt3(self._safe_read(linesize)):
410
+ data += d
411
+
412
+ elif self._alpha_encoding == AlphaEncoding.DXT5:
413
+ linesize = (self.state.xsize + 3) // 4 * 16
414
+ for yb in range((self.state.ysize + 3) // 4):
415
+ for d in decode_dxt5(self._safe_read(linesize)):
416
+ data += d
417
+ else:
418
+ msg = f"Unsupported alpha encoding {repr(self._alpha_encoding)}"
419
+ raise BLPFormatError(msg)
420
+ else:
421
+ msg = f"Unknown BLP encoding {repr(self._encoding)}"
422
+ raise BLPFormatError(msg)
423
+
424
+ else:
425
+ msg = f"Unknown BLP compression {repr(self._compression)}"
426
+ raise BLPFormatError(msg)
427
+
428
+ self.set_as_raw(data)
429
+
430
+
431
+ class BLPEncoder(ImageFile.PyEncoder):
432
+ _pushes_fd = True
433
+
434
+ def _write_palette(self) -> bytes:
435
+ data = b""
436
+ assert self.im is not None
437
+ palette = self.im.getpalette("RGBA", "RGBA")
438
+ for i in range(len(palette) // 4):
439
+ r, g, b, a = palette[i * 4 : (i + 1) * 4]
440
+ data += struct.pack("<4B", b, g, r, a)
441
+ while len(data) < 256 * 4:
442
+ data += b"\x00" * 4
443
+ return data
444
+
445
+ def encode(self, bufsize: int) -> tuple[int, int, bytes]:
446
+ palette_data = self._write_palette()
447
+
448
+ offset = 20 + 16 * 4 * 2 + len(palette_data)
449
+ data = struct.pack("<16I", offset, *((0,) * 15))
450
+
451
+ assert self.im is not None
452
+ w, h = self.im.size
453
+ data += struct.pack("<16I", w * h, *((0,) * 15))
454
+
455
+ data += palette_data
456
+
457
+ for y in range(h):
458
+ for x in range(w):
459
+ data += struct.pack("<B", self.im.getpixel((x, y)))
460
+
461
+ return len(data), 0, data
462
+
463
+
464
+ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
465
+ if im.mode != "P":
466
+ msg = "Unsupported BLP image mode"
467
+ raise ValueError(msg)
468
+
469
+ magic = b"BLP1" if im.encoderinfo.get("blp_version") == "BLP1" else b"BLP2"
470
+ fp.write(magic)
471
+
472
+ assert im.palette is not None
473
+ fp.write(struct.pack("<i", 1)) # Uncompressed or DirectX compression
474
+
475
+ alpha_depth = 1 if im.palette.mode == "RGBA" else 0
476
+ if magic == b"BLP1":
477
+ fp.write(struct.pack("<L", alpha_depth))
478
+ else:
479
+ fp.write(struct.pack("<b", Encoding.UNCOMPRESSED))
480
+ fp.write(struct.pack("<b", alpha_depth))
481
+ fp.write(struct.pack("<b", 0)) # alpha encoding
482
+ fp.write(struct.pack("<b", 0)) # mips
483
+ fp.write(struct.pack("<II", *im.size))
484
+ if magic == b"BLP1":
485
+ fp.write(struct.pack("<i", 5))
486
+ fp.write(struct.pack("<i", 0))
487
+
488
+ ImageFile._save(im, fp, [ImageFile._Tile("BLP", (0, 0) + im.size, 0, im.mode)])
489
+
490
+
491
+ Image.register_open(BlpImageFile.format, BlpImageFile, _accept)
492
+ Image.register_extension(BlpImageFile.format, ".blp")
493
+ Image.register_decoder("BLP1", BLP1Decoder)
494
+ Image.register_decoder("BLP2", BLP2Decoder)
495
+
496
+ Image.register_save(BlpImageFile.format, _save)
497
+ Image.register_encoder("BLP", BLPEncoder)
venv/Lib/site-packages/PIL/BmpImagePlugin.py ADDED
@@ -0,0 +1,515 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # The Python Imaging Library.
3
+ # $Id$
4
+ #
5
+ # BMP file handler
6
+ #
7
+ # Windows (and OS/2) native bitmap storage format.
8
+ #
9
+ # history:
10
+ # 1995-09-01 fl Created
11
+ # 1996-04-30 fl Added save
12
+ # 1997-08-27 fl Fixed save of 1-bit images
13
+ # 1998-03-06 fl Load P images as L where possible
14
+ # 1998-07-03 fl Load P images as 1 where possible
15
+ # 1998-12-29 fl Handle small palettes
16
+ # 2002-12-30 fl Fixed load of 1-bit palette images
17
+ # 2003-04-21 fl Fixed load of 1-bit monochrome images
18
+ # 2003-04-23 fl Added limited support for BI_BITFIELDS compression
19
+ #
20
+ # Copyright (c) 1997-2003 by Secret Labs AB
21
+ # Copyright (c) 1995-2003 by Fredrik Lundh
22
+ #
23
+ # See the README file for information on usage and redistribution.
24
+ #
25
+ from __future__ import annotations
26
+
27
+ import os
28
+ from typing import IO, Any
29
+
30
+ from . import Image, ImageFile, ImagePalette
31
+ from ._binary import i16le as i16
32
+ from ._binary import i32le as i32
33
+ from ._binary import o8
34
+ from ._binary import o16le as o16
35
+ from ._binary import o32le as o32
36
+
37
+ #
38
+ # --------------------------------------------------------------------
39
+ # Read BMP file
40
+
41
+ BIT2MODE = {
42
+ # bits => mode, rawmode
43
+ 1: ("P", "P;1"),
44
+ 4: ("P", "P;4"),
45
+ 8: ("P", "P"),
46
+ 16: ("RGB", "BGR;15"),
47
+ 24: ("RGB", "BGR"),
48
+ 32: ("RGB", "BGRX"),
49
+ }
50
+
51
+ USE_RAW_ALPHA = False
52
+
53
+
54
+ def _accept(prefix: bytes) -> bool:
55
+ return prefix.startswith(b"BM")
56
+
57
+
58
+ def _dib_accept(prefix: bytes) -> bool:
59
+ return i32(prefix) in [12, 40, 52, 56, 64, 108, 124]
60
+
61
+
62
+ # =============================================================================
63
+ # Image plugin for the Windows BMP format.
64
+ # =============================================================================
65
+ class BmpImageFile(ImageFile.ImageFile):
66
+ """Image plugin for the Windows Bitmap format (BMP)"""
67
+
68
+ # ------------------------------------------------------------- Description
69
+ format_description = "Windows Bitmap"
70
+ format = "BMP"
71
+
72
+ # -------------------------------------------------- BMP Compression values
73
+ COMPRESSIONS = {"RAW": 0, "RLE8": 1, "RLE4": 2, "BITFIELDS": 3, "JPEG": 4, "PNG": 5}
74
+ for k, v in COMPRESSIONS.items():
75
+ vars()[k] = v
76
+
77
+ def _bitmap(self, header: int = 0, offset: int = 0) -> None:
78
+ """Read relevant info about the BMP"""
79
+ read, seek = self.fp.read, self.fp.seek
80
+ if header:
81
+ seek(header)
82
+ # read bmp header size @offset 14 (this is part of the header size)
83
+ file_info: dict[str, bool | int | tuple[int, ...]] = {
84
+ "header_size": i32(read(4)),
85
+ "direction": -1,
86
+ }
87
+
88
+ # -------------------- If requested, read header at a specific position
89
+ # read the rest of the bmp header, without its size
90
+ assert isinstance(file_info["header_size"], int)
91
+ header_data = ImageFile._safe_read(self.fp, file_info["header_size"] - 4)
92
+
93
+ # ------------------------------- Windows Bitmap v2, IBM OS/2 Bitmap v1
94
+ # ----- This format has different offsets because of width/height types
95
+ # 12: BITMAPCOREHEADER/OS21XBITMAPHEADER
96
+ if file_info["header_size"] == 12:
97
+ file_info["width"] = i16(header_data, 0)
98
+ file_info["height"] = i16(header_data, 2)
99
+ file_info["planes"] = i16(header_data, 4)
100
+ file_info["bits"] = i16(header_data, 6)
101
+ file_info["compression"] = self.COMPRESSIONS["RAW"]
102
+ file_info["palette_padding"] = 3
103
+
104
+ # --------------------------------------------- Windows Bitmap v3 to v5
105
+ # 40: BITMAPINFOHEADER
106
+ # 52: BITMAPV2HEADER
107
+ # 56: BITMAPV3HEADER
108
+ # 64: BITMAPCOREHEADER2/OS22XBITMAPHEADER
109
+ # 108: BITMAPV4HEADER
110
+ # 124: BITMAPV5HEADER
111
+ elif file_info["header_size"] in (40, 52, 56, 64, 108, 124):
112
+ file_info["y_flip"] = header_data[7] == 0xFF
113
+ file_info["direction"] = 1 if file_info["y_flip"] else -1
114
+ file_info["width"] = i32(header_data, 0)
115
+ file_info["height"] = (
116
+ i32(header_data, 4)
117
+ if not file_info["y_flip"]
118
+ else 2**32 - i32(header_data, 4)
119
+ )
120
+ file_info["planes"] = i16(header_data, 8)
121
+ file_info["bits"] = i16(header_data, 10)
122
+ file_info["compression"] = i32(header_data, 12)
123
+ # byte size of pixel data
124
+ file_info["data_size"] = i32(header_data, 16)
125
+ file_info["pixels_per_meter"] = (
126
+ i32(header_data, 20),
127
+ i32(header_data, 24),
128
+ )
129
+ file_info["colors"] = i32(header_data, 28)
130
+ file_info["palette_padding"] = 4
131
+ assert isinstance(file_info["pixels_per_meter"], tuple)
132
+ self.info["dpi"] = tuple(x / 39.3701 for x in file_info["pixels_per_meter"])
133
+ if file_info["compression"] == self.COMPRESSIONS["BITFIELDS"]:
134
+ masks = ["r_mask", "g_mask", "b_mask"]
135
+ if len(header_data) >= 48:
136
+ if len(header_data) >= 52:
137
+ masks.append("a_mask")
138
+ else:
139
+ file_info["a_mask"] = 0x0
140
+ for idx, mask in enumerate(masks):
141
+ file_info[mask] = i32(header_data, 36 + idx * 4)
142
+ else:
143
+ # 40 byte headers only have the three components in the
144
+ # bitfields masks, ref:
145
+ # https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx
146
+ # See also
147
+ # https://github.com/python-pillow/Pillow/issues/1293
148
+ # There is a 4th component in the RGBQuad, in the alpha
149
+ # location, but it is listed as a reserved component,
150
+ # and it is not generally an alpha channel
151
+ file_info["a_mask"] = 0x0
152
+ for mask in masks:
153
+ file_info[mask] = i32(read(4))
154
+ assert isinstance(file_info["r_mask"], int)
155
+ assert isinstance(file_info["g_mask"], int)
156
+ assert isinstance(file_info["b_mask"], int)
157
+ assert isinstance(file_info["a_mask"], int)
158
+ file_info["rgb_mask"] = (
159
+ file_info["r_mask"],
160
+ file_info["g_mask"],
161
+ file_info["b_mask"],
162
+ )
163
+ file_info["rgba_mask"] = (
164
+ file_info["r_mask"],
165
+ file_info["g_mask"],
166
+ file_info["b_mask"],
167
+ file_info["a_mask"],
168
+ )
169
+ else:
170
+ msg = f"Unsupported BMP header type ({file_info['header_size']})"
171
+ raise OSError(msg)
172
+
173
+ # ------------------ Special case : header is reported 40, which
174
+ # ---------------------- is shorter than real size for bpp >= 16
175
+ assert isinstance(file_info["width"], int)
176
+ assert isinstance(file_info["height"], int)
177
+ self._size = file_info["width"], file_info["height"]
178
+
179
+ # ------- If color count was not found in the header, compute from bits
180
+ assert isinstance(file_info["bits"], int)
181
+ file_info["colors"] = (
182
+ file_info["colors"]
183
+ if file_info.get("colors", 0)
184
+ else (1 << file_info["bits"])
185
+ )
186
+ assert isinstance(file_info["colors"], int)
187
+ if offset == 14 + file_info["header_size"] and file_info["bits"] <= 8:
188
+ offset += 4 * file_info["colors"]
189
+
190
+ # ---------------------- Check bit depth for unusual unsupported values
191
+ self._mode, raw_mode = BIT2MODE.get(file_info["bits"], ("", ""))
192
+ if not self.mode:
193
+ msg = f"Unsupported BMP pixel depth ({file_info['bits']})"
194
+ raise OSError(msg)
195
+
196
+ # ---------------- Process BMP with Bitfields compression (not palette)
197
+ decoder_name = "raw"
198
+ if file_info["compression"] == self.COMPRESSIONS["BITFIELDS"]:
199
+ SUPPORTED: dict[int, list[tuple[int, ...]]] = {
200
+ 32: [
201
+ (0xFF0000, 0xFF00, 0xFF, 0x0),
202
+ (0xFF000000, 0xFF0000, 0xFF00, 0x0),
203
+ (0xFF000000, 0xFF00, 0xFF, 0x0),
204
+ (0xFF000000, 0xFF0000, 0xFF00, 0xFF),
205
+ (0xFF, 0xFF00, 0xFF0000, 0xFF000000),
206
+ (0xFF0000, 0xFF00, 0xFF, 0xFF000000),
207
+ (0xFF000000, 0xFF00, 0xFF, 0xFF0000),
208
+ (0x0, 0x0, 0x0, 0x0),
209
+ ],
210
+ 24: [(0xFF0000, 0xFF00, 0xFF)],
211
+ 16: [(0xF800, 0x7E0, 0x1F), (0x7C00, 0x3E0, 0x1F)],
212
+ }
213
+ MASK_MODES = {
214
+ (32, (0xFF0000, 0xFF00, 0xFF, 0x0)): "BGRX",
215
+ (32, (0xFF000000, 0xFF0000, 0xFF00, 0x0)): "XBGR",
216
+ (32, (0xFF000000, 0xFF00, 0xFF, 0x0)): "BGXR",
217
+ (32, (0xFF000000, 0xFF0000, 0xFF00, 0xFF)): "ABGR",
218
+ (32, (0xFF, 0xFF00, 0xFF0000, 0xFF000000)): "RGBA",
219
+ (32, (0xFF0000, 0xFF00, 0xFF, 0xFF000000)): "BGRA",
220
+ (32, (0xFF000000, 0xFF00, 0xFF, 0xFF0000)): "BGAR",
221
+ (32, (0x0, 0x0, 0x0, 0x0)): "BGRA",
222
+ (24, (0xFF0000, 0xFF00, 0xFF)): "BGR",
223
+ (16, (0xF800, 0x7E0, 0x1F)): "BGR;16",
224
+ (16, (0x7C00, 0x3E0, 0x1F)): "BGR;15",
225
+ }
226
+ if file_info["bits"] in SUPPORTED:
227
+ if (
228
+ file_info["bits"] == 32
229
+ and file_info["rgba_mask"] in SUPPORTED[file_info["bits"]]
230
+ ):
231
+ assert isinstance(file_info["rgba_mask"], tuple)
232
+ raw_mode = MASK_MODES[(file_info["bits"], file_info["rgba_mask"])]
233
+ self._mode = "RGBA" if "A" in raw_mode else self.mode
234
+ elif (
235
+ file_info["bits"] in (24, 16)
236
+ and file_info["rgb_mask"] in SUPPORTED[file_info["bits"]]
237
+ ):
238
+ assert isinstance(file_info["rgb_mask"], tuple)
239
+ raw_mode = MASK_MODES[(file_info["bits"], file_info["rgb_mask"])]
240
+ else:
241
+ msg = "Unsupported BMP bitfields layout"
242
+ raise OSError(msg)
243
+ else:
244
+ msg = "Unsupported BMP bitfields layout"
245
+ raise OSError(msg)
246
+ elif file_info["compression"] == self.COMPRESSIONS["RAW"]:
247
+ if file_info["bits"] == 32 and (
248
+ header == 22 or USE_RAW_ALPHA # 32-bit .cur offset
249
+ ):
250
+ raw_mode, self._mode = "BGRA", "RGBA"
251
+ elif file_info["compression"] in (
252
+ self.COMPRESSIONS["RLE8"],
253
+ self.COMPRESSIONS["RLE4"],
254
+ ):
255
+ decoder_name = "bmp_rle"
256
+ else:
257
+ msg = f"Unsupported BMP compression ({file_info['compression']})"
258
+ raise OSError(msg)
259
+
260
+ # --------------- Once the header is processed, process the palette/LUT
261
+ if self.mode == "P": # Paletted for 1, 4 and 8 bit images
262
+ # ---------------------------------------------------- 1-bit images
263
+ if not (0 < file_info["colors"] <= 65536):
264
+ msg = f"Unsupported BMP Palette size ({file_info['colors']})"
265
+ raise OSError(msg)
266
+ else:
267
+ assert isinstance(file_info["palette_padding"], int)
268
+ padding = file_info["palette_padding"]
269
+ palette = read(padding * file_info["colors"])
270
+ grayscale = True
271
+ indices = (
272
+ (0, 255)
273
+ if file_info["colors"] == 2
274
+ else list(range(file_info["colors"]))
275
+ )
276
+
277
+ # ----------------- Check if grayscale and ignore palette if so
278
+ for ind, val in enumerate(indices):
279
+ rgb = palette[ind * padding : ind * padding + 3]
280
+ if rgb != o8(val) * 3:
281
+ grayscale = False
282
+
283
+ # ------- If all colors are gray, white or black, ditch palette
284
+ if grayscale:
285
+ self._mode = "1" if file_info["colors"] == 2 else "L"
286
+ raw_mode = self.mode
287
+ else:
288
+ self._mode = "P"
289
+ self.palette = ImagePalette.raw(
290
+ "BGRX" if padding == 4 else "BGR", palette
291
+ )
292
+
293
+ # ---------------------------- Finally set the tile data for the plugin
294
+ self.info["compression"] = file_info["compression"]
295
+ args: list[Any] = [raw_mode]
296
+ if decoder_name == "bmp_rle":
297
+ args.append(file_info["compression"] == self.COMPRESSIONS["RLE4"])
298
+ else:
299
+ assert isinstance(file_info["width"], int)
300
+ args.append(((file_info["width"] * file_info["bits"] + 31) >> 3) & (~3))
301
+ args.append(file_info["direction"])
302
+ self.tile = [
303
+ ImageFile._Tile(
304
+ decoder_name,
305
+ (0, 0, file_info["width"], file_info["height"]),
306
+ offset or self.fp.tell(),
307
+ tuple(args),
308
+ )
309
+ ]
310
+
311
+ def _open(self) -> None:
312
+ """Open file, check magic number and read header"""
313
+ # read 14 bytes: magic number, filesize, reserved, header final offset
314
+ head_data = self.fp.read(14)
315
+ # choke if the file does not have the required magic bytes
316
+ if not _accept(head_data):
317
+ msg = "Not a BMP file"
318
+ raise SyntaxError(msg)
319
+ # read the start position of the BMP image data (u32)
320
+ offset = i32(head_data, 10)
321
+ # load bitmap information (offset=raster info)
322
+ self._bitmap(offset=offset)
323
+
324
+
325
+ class BmpRleDecoder(ImageFile.PyDecoder):
326
+ _pulls_fd = True
327
+
328
+ def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
329
+ assert self.fd is not None
330
+ rle4 = self.args[1]
331
+ data = bytearray()
332
+ x = 0
333
+ dest_length = self.state.xsize * self.state.ysize
334
+ while len(data) < dest_length:
335
+ pixels = self.fd.read(1)
336
+ byte = self.fd.read(1)
337
+ if not pixels or not byte:
338
+ break
339
+ num_pixels = pixels[0]
340
+ if num_pixels:
341
+ # encoded mode
342
+ if x + num_pixels > self.state.xsize:
343
+ # Too much data for row
344
+ num_pixels = max(0, self.state.xsize - x)
345
+ if rle4:
346
+ first_pixel = o8(byte[0] >> 4)
347
+ second_pixel = o8(byte[0] & 0x0F)
348
+ for index in range(num_pixels):
349
+ if index % 2 == 0:
350
+ data += first_pixel
351
+ else:
352
+ data += second_pixel
353
+ else:
354
+ data += byte * num_pixels
355
+ x += num_pixels
356
+ else:
357
+ if byte[0] == 0:
358
+ # end of line
359
+ while len(data) % self.state.xsize != 0:
360
+ data += b"\x00"
361
+ x = 0
362
+ elif byte[0] == 1:
363
+ # end of bitmap
364
+ break
365
+ elif byte[0] == 2:
366
+ # delta
367
+ bytes_read = self.fd.read(2)
368
+ if len(bytes_read) < 2:
369
+ break
370
+ right, up = self.fd.read(2)
371
+ data += b"\x00" * (right + up * self.state.xsize)
372
+ x = len(data) % self.state.xsize
373
+ else:
374
+ # absolute mode
375
+ if rle4:
376
+ # 2 pixels per byte
377
+ byte_count = byte[0] // 2
378
+ bytes_read = self.fd.read(byte_count)
379
+ for byte_read in bytes_read:
380
+ data += o8(byte_read >> 4)
381
+ data += o8(byte_read & 0x0F)
382
+ else:
383
+ byte_count = byte[0]
384
+ bytes_read = self.fd.read(byte_count)
385
+ data += bytes_read
386
+ if len(bytes_read) < byte_count:
387
+ break
388
+ x += byte[0]
389
+
390
+ # align to 16-bit word boundary
391
+ if self.fd.tell() % 2 != 0:
392
+ self.fd.seek(1, os.SEEK_CUR)
393
+ rawmode = "L" if self.mode == "L" else "P"
394
+ self.set_as_raw(bytes(data), rawmode, (0, self.args[-1]))
395
+ return -1, 0
396
+
397
+
398
+ # =============================================================================
399
+ # Image plugin for the DIB format (BMP alias)
400
+ # =============================================================================
401
+ class DibImageFile(BmpImageFile):
402
+ format = "DIB"
403
+ format_description = "Windows Bitmap"
404
+
405
+ def _open(self) -> None:
406
+ self._bitmap()
407
+
408
+
409
+ #
410
+ # --------------------------------------------------------------------
411
+ # Write BMP file
412
+
413
+
414
+ SAVE = {
415
+ "1": ("1", 1, 2),
416
+ "L": ("L", 8, 256),
417
+ "P": ("P", 8, 256),
418
+ "RGB": ("BGR", 24, 0),
419
+ "RGBA": ("BGRA", 32, 0),
420
+ }
421
+
422
+
423
+ def _dib_save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
424
+ _save(im, fp, filename, False)
425
+
426
+
427
+ def _save(
428
+ im: Image.Image, fp: IO[bytes], filename: str | bytes, bitmap_header: bool = True
429
+ ) -> None:
430
+ try:
431
+ rawmode, bits, colors = SAVE[im.mode]
432
+ except KeyError as e:
433
+ msg = f"cannot write mode {im.mode} as BMP"
434
+ raise OSError(msg) from e
435
+
436
+ info = im.encoderinfo
437
+
438
+ dpi = info.get("dpi", (96, 96))
439
+
440
+ # 1 meter == 39.3701 inches
441
+ ppm = tuple(int(x * 39.3701 + 0.5) for x in dpi)
442
+
443
+ stride = ((im.size[0] * bits + 7) // 8 + 3) & (~3)
444
+ header = 40 # or 64 for OS/2 version 2
445
+ image = stride * im.size[1]
446
+
447
+ if im.mode == "1":
448
+ palette = b"".join(o8(i) * 4 for i in (0, 255))
449
+ elif im.mode == "L":
450
+ palette = b"".join(o8(i) * 4 for i in range(256))
451
+ elif im.mode == "P":
452
+ palette = im.im.getpalette("RGB", "BGRX")
453
+ colors = len(palette) // 4
454
+ else:
455
+ palette = None
456
+
457
+ # bitmap header
458
+ if bitmap_header:
459
+ offset = 14 + header + colors * 4
460
+ file_size = offset + image
461
+ if file_size > 2**32 - 1:
462
+ msg = "File size is too large for the BMP format"
463
+ raise ValueError(msg)
464
+ fp.write(
465
+ b"BM" # file type (magic)
466
+ + o32(file_size) # file size
467
+ + o32(0) # reserved
468
+ + o32(offset) # image data offset
469
+ )
470
+
471
+ # bitmap info header
472
+ fp.write(
473
+ o32(header) # info header size
474
+ + o32(im.size[0]) # width
475
+ + o32(im.size[1]) # height
476
+ + o16(1) # planes
477
+ + o16(bits) # depth
478
+ + o32(0) # compression (0=uncompressed)
479
+ + o32(image) # size of bitmap
480
+ + o32(ppm[0]) # resolution
481
+ + o32(ppm[1]) # resolution
482
+ + o32(colors) # colors used
483
+ + o32(colors) # colors important
484
+ )
485
+
486
+ fp.write(b"\0" * (header - 40)) # padding (for OS/2 format)
487
+
488
+ if palette:
489
+ fp.write(palette)
490
+
491
+ ImageFile._save(
492
+ im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, (rawmode, stride, -1))]
493
+ )
494
+
495
+
496
+ #
497
+ # --------------------------------------------------------------------
498
+ # Registry
499
+
500
+
501
+ Image.register_open(BmpImageFile.format, BmpImageFile, _accept)
502
+ Image.register_save(BmpImageFile.format, _save)
503
+
504
+ Image.register_extension(BmpImageFile.format, ".bmp")
505
+
506
+ Image.register_mime(BmpImageFile.format, "image/bmp")
507
+
508
+ Image.register_decoder("bmp_rle", BmpRleDecoder)
509
+
510
+ Image.register_open(DibImageFile.format, DibImageFile, _dib_accept)
511
+ Image.register_save(DibImageFile.format, _dib_save)
512
+
513
+ Image.register_extension(DibImageFile.format, ".dib")
514
+
515
+ Image.register_mime(DibImageFile.format, "image/bmp")
venv/Lib/site-packages/PIL/BufrStubImagePlugin.py ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # The Python Imaging Library
3
+ # $Id$
4
+ #
5
+ # BUFR stub adapter
6
+ #
7
+ # Copyright (c) 1996-2003 by Fredrik Lundh
8
+ #
9
+ # See the README file for information on usage and redistribution.
10
+ #
11
+ from __future__ import annotations
12
+
13
+ import os
14
+ from typing import IO
15
+
16
+ from . import Image, ImageFile
17
+
18
+ _handler = None
19
+
20
+
21
+ def register_handler(handler: ImageFile.StubHandler | None) -> None:
22
+ """
23
+ Install application-specific BUFR image handler.
24
+
25
+ :param handler: Handler object.
26
+ """
27
+ global _handler
28
+ _handler = handler
29
+
30
+
31
+ # --------------------------------------------------------------------
32
+ # Image adapter
33
+
34
+
35
+ def _accept(prefix: bytes) -> bool:
36
+ return prefix.startswith((b"BUFR", b"ZCZC"))
37
+
38
+
39
+ class BufrStubImageFile(ImageFile.StubImageFile):
40
+ format = "BUFR"
41
+ format_description = "BUFR"
42
+
43
+ def _open(self) -> None:
44
+ if not _accept(self.fp.read(4)):
45
+ msg = "Not a BUFR file"
46
+ raise SyntaxError(msg)
47
+
48
+ self.fp.seek(-4, os.SEEK_CUR)
49
+
50
+ # make something up
51
+ self._mode = "F"
52
+ self._size = 1, 1
53
+
54
+ loader = self._load()
55
+ if loader:
56
+ loader.open(self)
57
+
58
+ def _load(self) -> ImageFile.StubHandler | None:
59
+ return _handler
60
+
61
+
62
+ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
63
+ if _handler is None or not hasattr(_handler, "save"):
64
+ msg = "BUFR save handler not installed"
65
+ raise OSError(msg)
66
+ _handler.save(im, fp, filename)
67
+
68
+
69
+ # --------------------------------------------------------------------
70
+ # Registry
71
+
72
+ Image.register_open(BufrStubImageFile.format, BufrStubImageFile, _accept)
73
+ Image.register_save(BufrStubImageFile.format, _save)
74
+
75
+ Image.register_extension(BufrStubImageFile.format, ".bufr")
venv/Lib/site-packages/PIL/ContainerIO.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # The Python Imaging Library.
3
+ # $Id$
4
+ #
5
+ # a class to read from a container file
6
+ #
7
+ # History:
8
+ # 1995-06-18 fl Created
9
+ # 1995-09-07 fl Added readline(), readlines()
10
+ #
11
+ # Copyright (c) 1997-2001 by Secret Labs AB
12
+ # Copyright (c) 1995 by Fredrik Lundh
13
+ #
14
+ # See the README file for information on usage and redistribution.
15
+ #
16
+ from __future__ import annotations
17
+
18
+ import io
19
+ from collections.abc import Iterable
20
+ from typing import IO, AnyStr, NoReturn
21
+
22
+
23
+ class ContainerIO(IO[AnyStr]):
24
+ """
25
+ A file object that provides read access to a part of an existing
26
+ file (for example a TAR file).
27
+ """
28
+
29
+ def __init__(self, file: IO[AnyStr], offset: int, length: int) -> None:
30
+ """
31
+ Create file object.
32
+
33
+ :param file: Existing file.
34
+ :param offset: Start of region, in bytes.
35
+ :param length: Size of region, in bytes.
36
+ """
37
+ self.fh: IO[AnyStr] = file
38
+ self.pos = 0
39
+ self.offset = offset
40
+ self.length = length
41
+ self.fh.seek(offset)
42
+
43
+ ##
44
+ # Always false.
45
+
46
+ def isatty(self) -> bool:
47
+ return False
48
+
49
+ def seekable(self) -> bool:
50
+ return True
51
+
52
+ def seek(self, offset: int, mode: int = io.SEEK_SET) -> int:
53
+ """
54
+ Move file pointer.
55
+
56
+ :param offset: Offset in bytes.
57
+ :param mode: Starting position. Use 0 for beginning of region, 1
58
+ for current offset, and 2 for end of region. You cannot move
59
+ the pointer outside the defined region.
60
+ :returns: Offset from start of region, in bytes.
61
+ """
62
+ if mode == 1:
63
+ self.pos = self.pos + offset
64
+ elif mode == 2:
65
+ self.pos = self.length + offset
66
+ else:
67
+ self.pos = offset
68
+ # clamp
69
+ self.pos = max(0, min(self.pos, self.length))
70
+ self.fh.seek(self.offset + self.pos)
71
+ return self.pos
72
+
73
+ def tell(self) -> int:
74
+ """
75
+ Get current file pointer.
76
+
77
+ :returns: Offset from start of region, in bytes.
78
+ """
79
+ return self.pos
80
+
81
+ def readable(self) -> bool:
82
+ return True
83
+
84
+ def read(self, n: int = -1) -> AnyStr:
85
+ """
86
+ Read data.
87
+
88
+ :param n: Number of bytes to read. If omitted, zero or negative,
89
+ read until end of region.
90
+ :returns: An 8-bit string.
91
+ """
92
+ if n > 0:
93
+ n = min(n, self.length - self.pos)
94
+ else:
95
+ n = self.length - self.pos
96
+ if n <= 0: # EOF
97
+ return b"" if "b" in self.fh.mode else "" # type: ignore[return-value]
98
+ self.pos = self.pos + n
99
+ return self.fh.read(n)
100
+
101
+ def readline(self, n: int = -1) -> AnyStr:
102
+ """
103
+ Read a line of text.
104
+
105
+ :param n: Number of bytes to read. If omitted, zero or negative,
106
+ read until end of line.
107
+ :returns: An 8-bit string.
108
+ """
109
+ s: AnyStr = b"" if "b" in self.fh.mode else "" # type: ignore[assignment]
110
+ newline_character = b"\n" if "b" in self.fh.mode else "\n"
111
+ while True:
112
+ c = self.read(1)
113
+ if not c:
114
+ break
115
+ s = s + c
116
+ if c == newline_character or len(s) == n:
117
+ break
118
+ return s
119
+
120
+ def readlines(self, n: int | None = -1) -> list[AnyStr]:
121
+ """
122
+ Read multiple lines of text.
123
+
124
+ :param n: Number of lines to read. If omitted, zero, negative or None,
125
+ read until end of region.
126
+ :returns: A list of 8-bit strings.
127
+ """
128
+ lines = []
129
+ while True:
130
+ s = self.readline()
131
+ if not s:
132
+ break
133
+ lines.append(s)
134
+ if len(lines) == n:
135
+ break
136
+ return lines
137
+
138
+ def writable(self) -> bool:
139
+ return False
140
+
141
+ def write(self, b: AnyStr) -> NoReturn:
142
+ raise NotImplementedError()
143
+
144
+ def writelines(self, lines: Iterable[AnyStr]) -> NoReturn:
145
+ raise NotImplementedError()
146
+
147
+ def truncate(self, size: int | None = None) -> int:
148
+ raise NotImplementedError()
149
+
150
+ def __enter__(self) -> ContainerIO[AnyStr]:
151
+ return self
152
+
153
+ def __exit__(self, *args: object) -> None:
154
+ self.close()
155
+
156
+ def __iter__(self) -> ContainerIO[AnyStr]:
157
+ return self
158
+
159
+ def __next__(self) -> AnyStr:
160
+ line = self.readline()
161
+ if not line:
162
+ msg = "end of region"
163
+ raise StopIteration(msg)
164
+ return line
165
+
166
+ def fileno(self) -> int:
167
+ return self.fh.fileno()
168
+
169
+ def flush(self) -> None:
170
+ self.fh.flush()
171
+
172
+ def close(self) -> None:
173
+ self.fh.close()
venv/Lib/site-packages/PIL/CurImagePlugin.py ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # The Python Imaging Library.
3
+ # $Id$
4
+ #
5
+ # Windows Cursor support for PIL
6
+ #
7
+ # notes:
8
+ # uses BmpImagePlugin.py to read the bitmap data.
9
+ #
10
+ # history:
11
+ # 96-05-27 fl Created
12
+ #
13
+ # Copyright (c) Secret Labs AB 1997.
14
+ # Copyright (c) Fredrik Lundh 1996.
15
+ #
16
+ # See the README file for information on usage and redistribution.
17
+ #
18
+ from __future__ import annotations
19
+
20
+ from . import BmpImagePlugin, Image, ImageFile
21
+ from ._binary import i16le as i16
22
+ from ._binary import i32le as i32
23
+
24
+ #
25
+ # --------------------------------------------------------------------
26
+
27
+
28
+ def _accept(prefix: bytes) -> bool:
29
+ return prefix.startswith(b"\0\0\2\0")
30
+
31
+
32
+ ##
33
+ # Image plugin for Windows Cursor files.
34
+
35
+
36
+ class CurImageFile(BmpImagePlugin.BmpImageFile):
37
+ format = "CUR"
38
+ format_description = "Windows Cursor"
39
+
40
+ def _open(self) -> None:
41
+ offset = self.fp.tell()
42
+
43
+ # check magic
44
+ s = self.fp.read(6)
45
+ if not _accept(s):
46
+ msg = "not a CUR file"
47
+ raise SyntaxError(msg)
48
+
49
+ # pick the largest cursor in the file
50
+ m = b""
51
+ for i in range(i16(s, 4)):
52
+ s = self.fp.read(16)
53
+ if not m:
54
+ m = s
55
+ elif s[0] > m[0] and s[1] > m[1]:
56
+ m = s
57
+ if not m:
58
+ msg = "No cursors were found"
59
+ raise TypeError(msg)
60
+
61
+ # load as bitmap
62
+ self._bitmap(i32(m, 12) + offset)
63
+
64
+ # patch up the bitmap height
65
+ self._size = self.size[0], self.size[1] // 2
66
+ d, e, o, a = self.tile[0]
67
+ self.tile[0] = ImageFile._Tile(d, (0, 0) + self.size, o, a)
68
+
69
+
70
+ #
71
+ # --------------------------------------------------------------------
72
+
73
+ Image.register_open(CurImageFile.format, CurImageFile, _accept)
74
+
75
+ Image.register_extension(CurImageFile.format, ".cur")
venv/Lib/site-packages/PIL/DcxImagePlugin.py ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # The Python Imaging Library.
3
+ # $Id$
4
+ #
5
+ # DCX file handling
6
+ #
7
+ # DCX is a container file format defined by Intel, commonly used
8
+ # for fax applications. Each DCX file consists of a directory
9
+ # (a list of file offsets) followed by a set of (usually 1-bit)
10
+ # PCX files.
11
+ #
12
+ # History:
13
+ # 1995-09-09 fl Created
14
+ # 1996-03-20 fl Properly derived from PcxImageFile.
15
+ # 1998-07-15 fl Renamed offset attribute to avoid name clash
16
+ # 2002-07-30 fl Fixed file handling
17
+ #
18
+ # Copyright (c) 1997-98 by Secret Labs AB.
19
+ # Copyright (c) 1995-96 by Fredrik Lundh.
20
+ #
21
+ # See the README file for information on usage and redistribution.
22
+ #
23
+ from __future__ import annotations
24
+
25
+ from . import Image
26
+ from ._binary import i32le as i32
27
+ from ._util import DeferredError
28
+ from .PcxImagePlugin import PcxImageFile
29
+
30
+ MAGIC = 0x3ADE68B1 # QUIZ: what's this value, then?
31
+
32
+
33
+ def _accept(prefix: bytes) -> bool:
34
+ return len(prefix) >= 4 and i32(prefix) == MAGIC
35
+
36
+
37
+ ##
38
+ # Image plugin for the Intel DCX format.
39
+
40
+
41
+ class DcxImageFile(PcxImageFile):
42
+ format = "DCX"
43
+ format_description = "Intel DCX"
44
+ _close_exclusive_fp_after_loading = False
45
+
46
+ def _open(self) -> None:
47
+ # Header
48
+ s = self.fp.read(4)
49
+ if not _accept(s):
50
+ msg = "not a DCX file"
51
+ raise SyntaxError(msg)
52
+
53
+ # Component directory
54
+ self._offset = []
55
+ for i in range(1024):
56
+ offset = i32(self.fp.read(4))
57
+ if not offset:
58
+ break
59
+ self._offset.append(offset)
60
+
61
+ self._fp = self.fp
62
+ self.frame = -1
63
+ self.n_frames = len(self._offset)
64
+ self.is_animated = self.n_frames > 1
65
+ self.seek(0)
66
+
67
+ def seek(self, frame: int) -> None:
68
+ if not self._seek_check(frame):
69
+ return
70
+ if isinstance(self._fp, DeferredError):
71
+ raise self._fp.ex
72
+ self.frame = frame
73
+ self.fp = self._fp
74
+ self.fp.seek(self._offset[frame])
75
+ PcxImageFile._open(self)
76
+
77
+ def tell(self) -> int:
78
+ return self.frame
79
+
80
+
81
+ Image.register_open(DcxImageFile.format, DcxImageFile, _accept)
82
+
83
+ Image.register_extension(DcxImageFile.format, ".dcx")
venv/Lib/site-packages/PIL/DdsImagePlugin.py ADDED
@@ -0,0 +1,624 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ A Pillow loader for .dds files (S3TC-compressed aka DXTC)
3
+ Jerome Leclanche <jerome@leclan.ch>
4
+
5
+ Documentation:
6
+ https://web.archive.org/web/20170802060935/http://oss.sgi.com/projects/ogl-sample/registry/EXT/texture_compression_s3tc.txt
7
+
8
+ The contents of this file are hereby released in the public domain (CC0)
9
+ Full text of the CC0 license:
10
+ https://creativecommons.org/publicdomain/zero/1.0/
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import io
16
+ import struct
17
+ import sys
18
+ from enum import IntEnum, IntFlag
19
+ from typing import IO
20
+
21
+ from . import Image, ImageFile, ImagePalette
22
+ from ._binary import i32le as i32
23
+ from ._binary import o8
24
+ from ._binary import o32le as o32
25
+
26
+ # Magic ("DDS ")
27
+ DDS_MAGIC = 0x20534444
28
+
29
+
30
+ # DDS flags
31
+ class DDSD(IntFlag):
32
+ CAPS = 0x1
33
+ HEIGHT = 0x2
34
+ WIDTH = 0x4
35
+ PITCH = 0x8
36
+ PIXELFORMAT = 0x1000
37
+ MIPMAPCOUNT = 0x20000
38
+ LINEARSIZE = 0x80000
39
+ DEPTH = 0x800000
40
+
41
+
42
+ # DDS caps
43
+ class DDSCAPS(IntFlag):
44
+ COMPLEX = 0x8
45
+ TEXTURE = 0x1000
46
+ MIPMAP = 0x400000
47
+
48
+
49
+ class DDSCAPS2(IntFlag):
50
+ CUBEMAP = 0x200
51
+ CUBEMAP_POSITIVEX = 0x400
52
+ CUBEMAP_NEGATIVEX = 0x800
53
+ CUBEMAP_POSITIVEY = 0x1000
54
+ CUBEMAP_NEGATIVEY = 0x2000
55
+ CUBEMAP_POSITIVEZ = 0x4000
56
+ CUBEMAP_NEGATIVEZ = 0x8000
57
+ VOLUME = 0x200000
58
+
59
+
60
+ # Pixel Format
61
+ class DDPF(IntFlag):
62
+ ALPHAPIXELS = 0x1
63
+ ALPHA = 0x2
64
+ FOURCC = 0x4
65
+ PALETTEINDEXED8 = 0x20
66
+ RGB = 0x40
67
+ LUMINANCE = 0x20000
68
+
69
+
70
+ # dxgiformat.h
71
+ class DXGI_FORMAT(IntEnum):
72
+ UNKNOWN = 0
73
+ R32G32B32A32_TYPELESS = 1
74
+ R32G32B32A32_FLOAT = 2
75
+ R32G32B32A32_UINT = 3
76
+ R32G32B32A32_SINT = 4
77
+ R32G32B32_TYPELESS = 5
78
+ R32G32B32_FLOAT = 6
79
+ R32G32B32_UINT = 7
80
+ R32G32B32_SINT = 8
81
+ R16G16B16A16_TYPELESS = 9
82
+ R16G16B16A16_FLOAT = 10
83
+ R16G16B16A16_UNORM = 11
84
+ R16G16B16A16_UINT = 12
85
+ R16G16B16A16_SNORM = 13
86
+ R16G16B16A16_SINT = 14
87
+ R32G32_TYPELESS = 15
88
+ R32G32_FLOAT = 16
89
+ R32G32_UINT = 17
90
+ R32G32_SINT = 18
91
+ R32G8X24_TYPELESS = 19
92
+ D32_FLOAT_S8X24_UINT = 20
93
+ R32_FLOAT_X8X24_TYPELESS = 21
94
+ X32_TYPELESS_G8X24_UINT = 22
95
+ R10G10B10A2_TYPELESS = 23
96
+ R10G10B10A2_UNORM = 24
97
+ R10G10B10A2_UINT = 25
98
+ R11G11B10_FLOAT = 26
99
+ R8G8B8A8_TYPELESS = 27
100
+ R8G8B8A8_UNORM = 28
101
+ R8G8B8A8_UNORM_SRGB = 29
102
+ R8G8B8A8_UINT = 30
103
+ R8G8B8A8_SNORM = 31
104
+ R8G8B8A8_SINT = 32
105
+ R16G16_TYPELESS = 33
106
+ R16G16_FLOAT = 34
107
+ R16G16_UNORM = 35
108
+ R16G16_UINT = 36
109
+ R16G16_SNORM = 37
110
+ R16G16_SINT = 38
111
+ R32_TYPELESS = 39
112
+ D32_FLOAT = 40
113
+ R32_FLOAT = 41
114
+ R32_UINT = 42
115
+ R32_SINT = 43
116
+ R24G8_TYPELESS = 44
117
+ D24_UNORM_S8_UINT = 45
118
+ R24_UNORM_X8_TYPELESS = 46
119
+ X24_TYPELESS_G8_UINT = 47
120
+ R8G8_TYPELESS = 48
121
+ R8G8_UNORM = 49
122
+ R8G8_UINT = 50
123
+ R8G8_SNORM = 51
124
+ R8G8_SINT = 52
125
+ R16_TYPELESS = 53
126
+ R16_FLOAT = 54
127
+ D16_UNORM = 55
128
+ R16_UNORM = 56
129
+ R16_UINT = 57
130
+ R16_SNORM = 58
131
+ R16_SINT = 59
132
+ R8_TYPELESS = 60
133
+ R8_UNORM = 61
134
+ R8_UINT = 62
135
+ R8_SNORM = 63
136
+ R8_SINT = 64
137
+ A8_UNORM = 65
138
+ R1_UNORM = 66
139
+ R9G9B9E5_SHAREDEXP = 67
140
+ R8G8_B8G8_UNORM = 68
141
+ G8R8_G8B8_UNORM = 69
142
+ BC1_TYPELESS = 70
143
+ BC1_UNORM = 71
144
+ BC1_UNORM_SRGB = 72
145
+ BC2_TYPELESS = 73
146
+ BC2_UNORM = 74
147
+ BC2_UNORM_SRGB = 75
148
+ BC3_TYPELESS = 76
149
+ BC3_UNORM = 77
150
+ BC3_UNORM_SRGB = 78
151
+ BC4_TYPELESS = 79
152
+ BC4_UNORM = 80
153
+ BC4_SNORM = 81
154
+ BC5_TYPELESS = 82
155
+ BC5_UNORM = 83
156
+ BC5_SNORM = 84
157
+ B5G6R5_UNORM = 85
158
+ B5G5R5A1_UNORM = 86
159
+ B8G8R8A8_UNORM = 87
160
+ B8G8R8X8_UNORM = 88
161
+ R10G10B10_XR_BIAS_A2_UNORM = 89
162
+ B8G8R8A8_TYPELESS = 90
163
+ B8G8R8A8_UNORM_SRGB = 91
164
+ B8G8R8X8_TYPELESS = 92
165
+ B8G8R8X8_UNORM_SRGB = 93
166
+ BC6H_TYPELESS = 94
167
+ BC6H_UF16 = 95
168
+ BC6H_SF16 = 96
169
+ BC7_TYPELESS = 97
170
+ BC7_UNORM = 98
171
+ BC7_UNORM_SRGB = 99
172
+ AYUV = 100
173
+ Y410 = 101
174
+ Y416 = 102
175
+ NV12 = 103
176
+ P010 = 104
177
+ P016 = 105
178
+ OPAQUE_420 = 106
179
+ YUY2 = 107
180
+ Y210 = 108
181
+ Y216 = 109
182
+ NV11 = 110
183
+ AI44 = 111
184
+ IA44 = 112
185
+ P8 = 113
186
+ A8P8 = 114
187
+ B4G4R4A4_UNORM = 115
188
+ P208 = 130
189
+ V208 = 131
190
+ V408 = 132
191
+ SAMPLER_FEEDBACK_MIN_MIP_OPAQUE = 189
192
+ SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE = 190
193
+
194
+
195
+ class D3DFMT(IntEnum):
196
+ UNKNOWN = 0
197
+ R8G8B8 = 20
198
+ A8R8G8B8 = 21
199
+ X8R8G8B8 = 22
200
+ R5G6B5 = 23
201
+ X1R5G5B5 = 24
202
+ A1R5G5B5 = 25
203
+ A4R4G4B4 = 26
204
+ R3G3B2 = 27
205
+ A8 = 28
206
+ A8R3G3B2 = 29
207
+ X4R4G4B4 = 30
208
+ A2B10G10R10 = 31
209
+ A8B8G8R8 = 32
210
+ X8B8G8R8 = 33
211
+ G16R16 = 34
212
+ A2R10G10B10 = 35
213
+ A16B16G16R16 = 36
214
+ A8P8 = 40
215
+ P8 = 41
216
+ L8 = 50
217
+ A8L8 = 51
218
+ A4L4 = 52
219
+ V8U8 = 60
220
+ L6V5U5 = 61
221
+ X8L8V8U8 = 62
222
+ Q8W8V8U8 = 63
223
+ V16U16 = 64
224
+ A2W10V10U10 = 67
225
+ D16_LOCKABLE = 70
226
+ D32 = 71
227
+ D15S1 = 73
228
+ D24S8 = 75
229
+ D24X8 = 77
230
+ D24X4S4 = 79
231
+ D16 = 80
232
+ D32F_LOCKABLE = 82
233
+ D24FS8 = 83
234
+ D32_LOCKABLE = 84
235
+ S8_LOCKABLE = 85
236
+ L16 = 81
237
+ VERTEXDATA = 100
238
+ INDEX16 = 101
239
+ INDEX32 = 102
240
+ Q16W16V16U16 = 110
241
+ R16F = 111
242
+ G16R16F = 112
243
+ A16B16G16R16F = 113
244
+ R32F = 114
245
+ G32R32F = 115
246
+ A32B32G32R32F = 116
247
+ CxV8U8 = 117
248
+ A1 = 118
249
+ A2B10G10R10_XR_BIAS = 119
250
+ BINARYBUFFER = 199
251
+
252
+ UYVY = i32(b"UYVY")
253
+ R8G8_B8G8 = i32(b"RGBG")
254
+ YUY2 = i32(b"YUY2")
255
+ G8R8_G8B8 = i32(b"GRGB")
256
+ DXT1 = i32(b"DXT1")
257
+ DXT2 = i32(b"DXT2")
258
+ DXT3 = i32(b"DXT3")
259
+ DXT4 = i32(b"DXT4")
260
+ DXT5 = i32(b"DXT5")
261
+ DX10 = i32(b"DX10")
262
+ BC4S = i32(b"BC4S")
263
+ BC4U = i32(b"BC4U")
264
+ BC5S = i32(b"BC5S")
265
+ BC5U = i32(b"BC5U")
266
+ ATI1 = i32(b"ATI1")
267
+ ATI2 = i32(b"ATI2")
268
+ MULTI2_ARGB8 = i32(b"MET1")
269
+
270
+
271
+ # Backward compatibility layer
272
+ module = sys.modules[__name__]
273
+ for item in DDSD:
274
+ assert item.name is not None
275
+ setattr(module, f"DDSD_{item.name}", item.value)
276
+ for item1 in DDSCAPS:
277
+ assert item1.name is not None
278
+ setattr(module, f"DDSCAPS_{item1.name}", item1.value)
279
+ for item2 in DDSCAPS2:
280
+ assert item2.name is not None
281
+ setattr(module, f"DDSCAPS2_{item2.name}", item2.value)
282
+ for item3 in DDPF:
283
+ assert item3.name is not None
284
+ setattr(module, f"DDPF_{item3.name}", item3.value)
285
+
286
+ DDS_FOURCC = DDPF.FOURCC
287
+ DDS_RGB = DDPF.RGB
288
+ DDS_RGBA = DDPF.RGB | DDPF.ALPHAPIXELS
289
+ DDS_LUMINANCE = DDPF.LUMINANCE
290
+ DDS_LUMINANCEA = DDPF.LUMINANCE | DDPF.ALPHAPIXELS
291
+ DDS_ALPHA = DDPF.ALPHA
292
+ DDS_PAL8 = DDPF.PALETTEINDEXED8
293
+
294
+ DDS_HEADER_FLAGS_TEXTURE = DDSD.CAPS | DDSD.HEIGHT | DDSD.WIDTH | DDSD.PIXELFORMAT
295
+ DDS_HEADER_FLAGS_MIPMAP = DDSD.MIPMAPCOUNT
296
+ DDS_HEADER_FLAGS_VOLUME = DDSD.DEPTH
297
+ DDS_HEADER_FLAGS_PITCH = DDSD.PITCH
298
+ DDS_HEADER_FLAGS_LINEARSIZE = DDSD.LINEARSIZE
299
+
300
+ DDS_HEIGHT = DDSD.HEIGHT
301
+ DDS_WIDTH = DDSD.WIDTH
302
+
303
+ DDS_SURFACE_FLAGS_TEXTURE = DDSCAPS.TEXTURE
304
+ DDS_SURFACE_FLAGS_MIPMAP = DDSCAPS.COMPLEX | DDSCAPS.MIPMAP
305
+ DDS_SURFACE_FLAGS_CUBEMAP = DDSCAPS.COMPLEX
306
+
307
+ DDS_CUBEMAP_POSITIVEX = DDSCAPS2.CUBEMAP | DDSCAPS2.CUBEMAP_POSITIVEX
308
+ DDS_CUBEMAP_NEGATIVEX = DDSCAPS2.CUBEMAP | DDSCAPS2.CUBEMAP_NEGATIVEX
309
+ DDS_CUBEMAP_POSITIVEY = DDSCAPS2.CUBEMAP | DDSCAPS2.CUBEMAP_POSITIVEY
310
+ DDS_CUBEMAP_NEGATIVEY = DDSCAPS2.CUBEMAP | DDSCAPS2.CUBEMAP_NEGATIVEY
311
+ DDS_CUBEMAP_POSITIVEZ = DDSCAPS2.CUBEMAP | DDSCAPS2.CUBEMAP_POSITIVEZ
312
+ DDS_CUBEMAP_NEGATIVEZ = DDSCAPS2.CUBEMAP | DDSCAPS2.CUBEMAP_NEGATIVEZ
313
+
314
+ DXT1_FOURCC = D3DFMT.DXT1
315
+ DXT3_FOURCC = D3DFMT.DXT3
316
+ DXT5_FOURCC = D3DFMT.DXT5
317
+
318
+ DXGI_FORMAT_R8G8B8A8_TYPELESS = DXGI_FORMAT.R8G8B8A8_TYPELESS
319
+ DXGI_FORMAT_R8G8B8A8_UNORM = DXGI_FORMAT.R8G8B8A8_UNORM
320
+ DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = DXGI_FORMAT.R8G8B8A8_UNORM_SRGB
321
+ DXGI_FORMAT_BC5_TYPELESS = DXGI_FORMAT.BC5_TYPELESS
322
+ DXGI_FORMAT_BC5_UNORM = DXGI_FORMAT.BC5_UNORM
323
+ DXGI_FORMAT_BC5_SNORM = DXGI_FORMAT.BC5_SNORM
324
+ DXGI_FORMAT_BC6H_UF16 = DXGI_FORMAT.BC6H_UF16
325
+ DXGI_FORMAT_BC6H_SF16 = DXGI_FORMAT.BC6H_SF16
326
+ DXGI_FORMAT_BC7_TYPELESS = DXGI_FORMAT.BC7_TYPELESS
327
+ DXGI_FORMAT_BC7_UNORM = DXGI_FORMAT.BC7_UNORM
328
+ DXGI_FORMAT_BC7_UNORM_SRGB = DXGI_FORMAT.BC7_UNORM_SRGB
329
+
330
+
331
+ class DdsImageFile(ImageFile.ImageFile):
332
+ format = "DDS"
333
+ format_description = "DirectDraw Surface"
334
+
335
+ def _open(self) -> None:
336
+ if not _accept(self.fp.read(4)):
337
+ msg = "not a DDS file"
338
+ raise SyntaxError(msg)
339
+ (header_size,) = struct.unpack("<I", self.fp.read(4))
340
+ if header_size != 124:
341
+ msg = f"Unsupported header size {repr(header_size)}"
342
+ raise OSError(msg)
343
+ header_bytes = self.fp.read(header_size - 4)
344
+ if len(header_bytes) != 120:
345
+ msg = f"Incomplete header: {len(header_bytes)} bytes"
346
+ raise OSError(msg)
347
+ header = io.BytesIO(header_bytes)
348
+
349
+ flags, height, width = struct.unpack("<3I", header.read(12))
350
+ self._size = (width, height)
351
+ extents = (0, 0) + self.size
352
+
353
+ pitch, depth, mipmaps = struct.unpack("<3I", header.read(12))
354
+ struct.unpack("<11I", header.read(44)) # reserved
355
+
356
+ # pixel format
357
+ pfsize, pfflags, fourcc, bitcount = struct.unpack("<4I", header.read(16))
358
+ n = 0
359
+ rawmode = None
360
+ if pfflags & DDPF.RGB:
361
+ # Texture contains uncompressed RGB data
362
+ if pfflags & DDPF.ALPHAPIXELS:
363
+ self._mode = "RGBA"
364
+ mask_count = 4
365
+ else:
366
+ self._mode = "RGB"
367
+ mask_count = 3
368
+
369
+ masks = struct.unpack(f"<{mask_count}I", header.read(mask_count * 4))
370
+ self.tile = [ImageFile._Tile("dds_rgb", extents, 0, (bitcount, masks))]
371
+ return
372
+ elif pfflags & DDPF.LUMINANCE:
373
+ if bitcount == 8:
374
+ self._mode = "L"
375
+ elif bitcount == 16 and pfflags & DDPF.ALPHAPIXELS:
376
+ self._mode = "LA"
377
+ else:
378
+ msg = f"Unsupported bitcount {bitcount} for {pfflags}"
379
+ raise OSError(msg)
380
+ elif pfflags & DDPF.PALETTEINDEXED8:
381
+ self._mode = "P"
382
+ self.palette = ImagePalette.raw("RGBA", self.fp.read(1024))
383
+ self.palette.mode = "RGBA"
384
+ elif pfflags & DDPF.FOURCC:
385
+ offset = header_size + 4
386
+ if fourcc == D3DFMT.DXT1:
387
+ self._mode = "RGBA"
388
+ self.pixel_format = "DXT1"
389
+ n = 1
390
+ elif fourcc == D3DFMT.DXT3:
391
+ self._mode = "RGBA"
392
+ self.pixel_format = "DXT3"
393
+ n = 2
394
+ elif fourcc == D3DFMT.DXT5:
395
+ self._mode = "RGBA"
396
+ self.pixel_format = "DXT5"
397
+ n = 3
398
+ elif fourcc in (D3DFMT.BC4U, D3DFMT.ATI1):
399
+ self._mode = "L"
400
+ self.pixel_format = "BC4"
401
+ n = 4
402
+ elif fourcc == D3DFMT.BC5S:
403
+ self._mode = "RGB"
404
+ self.pixel_format = "BC5S"
405
+ n = 5
406
+ elif fourcc in (D3DFMT.BC5U, D3DFMT.ATI2):
407
+ self._mode = "RGB"
408
+ self.pixel_format = "BC5"
409
+ n = 5
410
+ elif fourcc == D3DFMT.DX10:
411
+ offset += 20
412
+ # ignoring flags which pertain to volume textures and cubemaps
413
+ (dxgi_format,) = struct.unpack("<I", self.fp.read(4))
414
+ self.fp.read(16)
415
+ if dxgi_format in (
416
+ DXGI_FORMAT.BC1_UNORM,
417
+ DXGI_FORMAT.BC1_TYPELESS,
418
+ ):
419
+ self._mode = "RGBA"
420
+ self.pixel_format = "BC1"
421
+ n = 1
422
+ elif dxgi_format in (DXGI_FORMAT.BC2_TYPELESS, DXGI_FORMAT.BC2_UNORM):
423
+ self._mode = "RGBA"
424
+ self.pixel_format = "BC2"
425
+ n = 2
426
+ elif dxgi_format in (DXGI_FORMAT.BC3_TYPELESS, DXGI_FORMAT.BC3_UNORM):
427
+ self._mode = "RGBA"
428
+ self.pixel_format = "BC3"
429
+ n = 3
430
+ elif dxgi_format in (DXGI_FORMAT.BC4_TYPELESS, DXGI_FORMAT.BC4_UNORM):
431
+ self._mode = "L"
432
+ self.pixel_format = "BC4"
433
+ n = 4
434
+ elif dxgi_format in (DXGI_FORMAT.BC5_TYPELESS, DXGI_FORMAT.BC5_UNORM):
435
+ self._mode = "RGB"
436
+ self.pixel_format = "BC5"
437
+ n = 5
438
+ elif dxgi_format == DXGI_FORMAT.BC5_SNORM:
439
+ self._mode = "RGB"
440
+ self.pixel_format = "BC5S"
441
+ n = 5
442
+ elif dxgi_format == DXGI_FORMAT.BC6H_UF16:
443
+ self._mode = "RGB"
444
+ self.pixel_format = "BC6H"
445
+ n = 6
446
+ elif dxgi_format == DXGI_FORMAT.BC6H_SF16:
447
+ self._mode = "RGB"
448
+ self.pixel_format = "BC6HS"
449
+ n = 6
450
+ elif dxgi_format in (
451
+ DXGI_FORMAT.BC7_TYPELESS,
452
+ DXGI_FORMAT.BC7_UNORM,
453
+ DXGI_FORMAT.BC7_UNORM_SRGB,
454
+ ):
455
+ self._mode = "RGBA"
456
+ self.pixel_format = "BC7"
457
+ n = 7
458
+ if dxgi_format == DXGI_FORMAT.BC7_UNORM_SRGB:
459
+ self.info["gamma"] = 1 / 2.2
460
+ elif dxgi_format in (
461
+ DXGI_FORMAT.R8G8B8A8_TYPELESS,
462
+ DXGI_FORMAT.R8G8B8A8_UNORM,
463
+ DXGI_FORMAT.R8G8B8A8_UNORM_SRGB,
464
+ ):
465
+ self._mode = "RGBA"
466
+ if dxgi_format == DXGI_FORMAT.R8G8B8A8_UNORM_SRGB:
467
+ self.info["gamma"] = 1 / 2.2
468
+ else:
469
+ msg = f"Unimplemented DXGI format {dxgi_format}"
470
+ raise NotImplementedError(msg)
471
+ else:
472
+ msg = f"Unimplemented pixel format {repr(fourcc)}"
473
+ raise NotImplementedError(msg)
474
+ else:
475
+ msg = f"Unknown pixel format flags {pfflags}"
476
+ raise NotImplementedError(msg)
477
+
478
+ if n:
479
+ self.tile = [
480
+ ImageFile._Tile("bcn", extents, offset, (n, self.pixel_format))
481
+ ]
482
+ else:
483
+ self.tile = [ImageFile._Tile("raw", extents, 0, rawmode or self.mode)]
484
+
485
+ def load_seek(self, pos: int) -> None:
486
+ pass
487
+
488
+
489
+ class DdsRgbDecoder(ImageFile.PyDecoder):
490
+ _pulls_fd = True
491
+
492
+ def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
493
+ assert self.fd is not None
494
+ bitcount, masks = self.args
495
+
496
+ # Some masks will be padded with zeros, e.g. R 0b11 G 0b1100
497
+ # Calculate how many zeros each mask is padded with
498
+ mask_offsets = []
499
+ # And the maximum value of each channel without the padding
500
+ mask_totals = []
501
+ for mask in masks:
502
+ offset = 0
503
+ if mask != 0:
504
+ while mask >> (offset + 1) << (offset + 1) == mask:
505
+ offset += 1
506
+ mask_offsets.append(offset)
507
+ mask_totals.append(mask >> offset)
508
+
509
+ data = bytearray()
510
+ bytecount = bitcount // 8
511
+ dest_length = self.state.xsize * self.state.ysize * len(masks)
512
+ while len(data) < dest_length:
513
+ value = int.from_bytes(self.fd.read(bytecount), "little")
514
+ for i, mask in enumerate(masks):
515
+ masked_value = value & mask
516
+ # Remove the zero padding, and scale it to 8 bits
517
+ data += o8(
518
+ int(((masked_value >> mask_offsets[i]) / mask_totals[i]) * 255)
519
+ )
520
+ self.set_as_raw(data)
521
+ return -1, 0
522
+
523
+
524
+ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
525
+ if im.mode not in ("RGB", "RGBA", "L", "LA"):
526
+ msg = f"cannot write mode {im.mode} as DDS"
527
+ raise OSError(msg)
528
+
529
+ flags = DDSD.CAPS | DDSD.HEIGHT | DDSD.WIDTH | DDSD.PIXELFORMAT
530
+ bitcount = len(im.getbands()) * 8
531
+ pixel_format = im.encoderinfo.get("pixel_format")
532
+ args: tuple[int] | str
533
+ if pixel_format:
534
+ codec_name = "bcn"
535
+ flags |= DDSD.LINEARSIZE
536
+ pitch = (im.width + 3) * 4
537
+ rgba_mask = [0, 0, 0, 0]
538
+ pixel_flags = DDPF.FOURCC
539
+ if pixel_format == "DXT1":
540
+ fourcc = D3DFMT.DXT1
541
+ args = (1,)
542
+ elif pixel_format == "DXT3":
543
+ fourcc = D3DFMT.DXT3
544
+ args = (2,)
545
+ elif pixel_format == "DXT5":
546
+ fourcc = D3DFMT.DXT5
547
+ args = (3,)
548
+ else:
549
+ fourcc = D3DFMT.DX10
550
+ if pixel_format == "BC2":
551
+ args = (2,)
552
+ dxgi_format = DXGI_FORMAT.BC2_TYPELESS
553
+ elif pixel_format == "BC3":
554
+ args = (3,)
555
+ dxgi_format = DXGI_FORMAT.BC3_TYPELESS
556
+ elif pixel_format == "BC5":
557
+ args = (5,)
558
+ dxgi_format = DXGI_FORMAT.BC5_TYPELESS
559
+ if im.mode != "RGB":
560
+ msg = "only RGB mode can be written as BC5"
561
+ raise OSError(msg)
562
+ else:
563
+ msg = f"cannot write pixel format {pixel_format}"
564
+ raise OSError(msg)
565
+ else:
566
+ codec_name = "raw"
567
+ flags |= DDSD.PITCH
568
+ pitch = (im.width * bitcount + 7) // 8
569
+
570
+ alpha = im.mode[-1] == "A"
571
+ if im.mode[0] == "L":
572
+ pixel_flags = DDPF.LUMINANCE
573
+ args = im.mode
574
+ if alpha:
575
+ rgba_mask = [0x000000FF, 0x000000FF, 0x000000FF]
576
+ else:
577
+ rgba_mask = [0xFF000000, 0xFF000000, 0xFF000000]
578
+ else:
579
+ pixel_flags = DDPF.RGB
580
+ args = im.mode[::-1]
581
+ rgba_mask = [0x00FF0000, 0x0000FF00, 0x000000FF]
582
+
583
+ if alpha:
584
+ r, g, b, a = im.split()
585
+ im = Image.merge("RGBA", (a, r, g, b))
586
+ if alpha:
587
+ pixel_flags |= DDPF.ALPHAPIXELS
588
+ rgba_mask.append(0xFF000000 if alpha else 0)
589
+
590
+ fourcc = D3DFMT.UNKNOWN
591
+ fp.write(
592
+ o32(DDS_MAGIC)
593
+ + struct.pack(
594
+ "<7I",
595
+ 124, # header size
596
+ flags, # flags
597
+ im.height,
598
+ im.width,
599
+ pitch,
600
+ 0, # depth
601
+ 0, # mipmaps
602
+ )
603
+ + struct.pack("11I", *((0,) * 11)) # reserved
604
+ # pfsize, pfflags, fourcc, bitcount
605
+ + struct.pack("<4I", 32, pixel_flags, fourcc, bitcount)
606
+ + struct.pack("<4I", *rgba_mask) # dwRGBABitMask
607
+ + struct.pack("<5I", DDSCAPS.TEXTURE, 0, 0, 0, 0)
608
+ )
609
+ if fourcc == D3DFMT.DX10:
610
+ fp.write(
611
+ # dxgi_format, 2D resource, misc, array size, straight alpha
612
+ struct.pack("<5I", dxgi_format, 3, 0, 0, 1)
613
+ )
614
+ ImageFile._save(im, fp, [ImageFile._Tile(codec_name, (0, 0) + im.size, 0, args)])
615
+
616
+
617
+ def _accept(prefix: bytes) -> bool:
618
+ return prefix.startswith(b"DDS ")
619
+
620
+
621
+ Image.register_open(DdsImageFile.format, DdsImageFile, _accept)
622
+ Image.register_decoder("dds_rgb", DdsRgbDecoder)
623
+ Image.register_save(DdsImageFile.format, _save)
624
+ Image.register_extension(DdsImageFile.format, ".dds")
venv/Lib/site-packages/PIL/EpsImagePlugin.py ADDED
@@ -0,0 +1,476 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # The Python Imaging Library.
3
+ # $Id$
4
+ #
5
+ # EPS file handling
6
+ #
7
+ # History:
8
+ # 1995-09-01 fl Created (0.1)
9
+ # 1996-05-18 fl Don't choke on "atend" fields, Ghostscript interface (0.2)
10
+ # 1996-08-22 fl Don't choke on floating point BoundingBox values
11
+ # 1996-08-23 fl Handle files from Macintosh (0.3)
12
+ # 2001-02-17 fl Use 're' instead of 'regex' (Python 2.1) (0.4)
13
+ # 2003-09-07 fl Check gs.close status (from Federico Di Gregorio) (0.5)
14
+ # 2014-05-07 e Handling of EPS with binary preview and fixed resolution
15
+ # resizing
16
+ #
17
+ # Copyright (c) 1997-2003 by Secret Labs AB.
18
+ # Copyright (c) 1995-2003 by Fredrik Lundh
19
+ #
20
+ # See the README file for information on usage and redistribution.
21
+ #
22
+ from __future__ import annotations
23
+
24
+ import io
25
+ import os
26
+ import re
27
+ import subprocess
28
+ import sys
29
+ import tempfile
30
+ from typing import IO
31
+
32
+ from . import Image, ImageFile
33
+ from ._binary import i32le as i32
34
+
35
+ # --------------------------------------------------------------------
36
+
37
+
38
+ split = re.compile(r"^%%([^:]*):[ \t]*(.*)[ \t]*$")
39
+ field = re.compile(r"^%[%!\w]([^:]*)[ \t]*$")
40
+
41
+ gs_binary: str | bool | None = None
42
+ gs_windows_binary = None
43
+
44
+
45
+ def has_ghostscript() -> bool:
46
+ global gs_binary, gs_windows_binary
47
+ if gs_binary is None:
48
+ if sys.platform.startswith("win"):
49
+ if gs_windows_binary is None:
50
+ import shutil
51
+
52
+ for binary in ("gswin32c", "gswin64c", "gs"):
53
+ if shutil.which(binary) is not None:
54
+ gs_windows_binary = binary
55
+ break
56
+ else:
57
+ gs_windows_binary = False
58
+ gs_binary = gs_windows_binary
59
+ else:
60
+ try:
61
+ subprocess.check_call(["gs", "--version"], stdout=subprocess.DEVNULL)
62
+ gs_binary = "gs"
63
+ except OSError:
64
+ gs_binary = False
65
+ return gs_binary is not False
66
+
67
+
68
+ def Ghostscript(
69
+ tile: list[ImageFile._Tile],
70
+ size: tuple[int, int],
71
+ fp: IO[bytes],
72
+ scale: int = 1,
73
+ transparency: bool = False,
74
+ ) -> Image.core.ImagingCore:
75
+ """Render an image using Ghostscript"""
76
+ global gs_binary
77
+ if not has_ghostscript():
78
+ msg = "Unable to locate Ghostscript on paths"
79
+ raise OSError(msg)
80
+ assert isinstance(gs_binary, str)
81
+
82
+ # Unpack decoder tile
83
+ args = tile[0].args
84
+ assert isinstance(args, tuple)
85
+ length, bbox = args
86
+
87
+ # Hack to support hi-res rendering
88
+ scale = int(scale) or 1
89
+ width = size[0] * scale
90
+ height = size[1] * scale
91
+ # resolution is dependent on bbox and size
92
+ res_x = 72.0 * width / (bbox[2] - bbox[0])
93
+ res_y = 72.0 * height / (bbox[3] - bbox[1])
94
+
95
+ out_fd, outfile = tempfile.mkstemp()
96
+ os.close(out_fd)
97
+
98
+ infile_temp = None
99
+ if hasattr(fp, "name") and os.path.exists(fp.name):
100
+ infile = fp.name
101
+ else:
102
+ in_fd, infile_temp = tempfile.mkstemp()
103
+ os.close(in_fd)
104
+ infile = infile_temp
105
+
106
+ # Ignore length and offset!
107
+ # Ghostscript can read it
108
+ # Copy whole file to read in Ghostscript
109
+ with open(infile_temp, "wb") as f:
110
+ # fetch length of fp
111
+ fp.seek(0, io.SEEK_END)
112
+ fsize = fp.tell()
113
+ # ensure start position
114
+ # go back
115
+ fp.seek(0)
116
+ lengthfile = fsize
117
+ while lengthfile > 0:
118
+ s = fp.read(min(lengthfile, 100 * 1024))
119
+ if not s:
120
+ break
121
+ lengthfile -= len(s)
122
+ f.write(s)
123
+
124
+ if transparency:
125
+ # "RGBA"
126
+ device = "pngalpha"
127
+ else:
128
+ # "pnmraw" automatically chooses between
129
+ # PBM ("1"), PGM ("L"), and PPM ("RGB").
130
+ device = "pnmraw"
131
+
132
+ # Build Ghostscript command
133
+ command = [
134
+ gs_binary,
135
+ "-q", # quiet mode
136
+ f"-g{width:d}x{height:d}", # set output geometry (pixels)
137
+ f"-r{res_x:f}x{res_y:f}", # set input DPI (dots per inch)
138
+ "-dBATCH", # exit after processing
139
+ "-dNOPAUSE", # don't pause between pages
140
+ "-dSAFER", # safe mode
141
+ f"-sDEVICE={device}",
142
+ f"-sOutputFile={outfile}", # output file
143
+ # adjust for image origin
144
+ "-c",
145
+ f"{-bbox[0]} {-bbox[1]} translate",
146
+ "-f",
147
+ infile, # input file
148
+ # showpage (see https://bugs.ghostscript.com/show_bug.cgi?id=698272)
149
+ "-c",
150
+ "showpage",
151
+ ]
152
+
153
+ # push data through Ghostscript
154
+ try:
155
+ startupinfo = None
156
+ if sys.platform.startswith("win"):
157
+ startupinfo = subprocess.STARTUPINFO()
158
+ startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
159
+ subprocess.check_call(command, startupinfo=startupinfo)
160
+ with Image.open(outfile) as out_im:
161
+ out_im.load()
162
+ return out_im.im.copy()
163
+ finally:
164
+ try:
165
+ os.unlink(outfile)
166
+ if infile_temp:
167
+ os.unlink(infile_temp)
168
+ except OSError:
169
+ pass
170
+
171
+
172
+ def _accept(prefix: bytes) -> bool:
173
+ return prefix.startswith(b"%!PS") or (
174
+ len(prefix) >= 4 and i32(prefix) == 0xC6D3D0C5
175
+ )
176
+
177
+
178
+ ##
179
+ # Image plugin for Encapsulated PostScript. This plugin supports only
180
+ # a few variants of this format.
181
+
182
+
183
+ class EpsImageFile(ImageFile.ImageFile):
184
+ """EPS File Parser for the Python Imaging Library"""
185
+
186
+ format = "EPS"
187
+ format_description = "Encapsulated Postscript"
188
+
189
+ mode_map = {1: "L", 2: "LAB", 3: "RGB", 4: "CMYK"}
190
+
191
+ def _open(self) -> None:
192
+ (length, offset) = self._find_offset(self.fp)
193
+
194
+ # go to offset - start of "%!PS"
195
+ self.fp.seek(offset)
196
+
197
+ self._mode = "RGB"
198
+
199
+ # When reading header comments, the first comment is used.
200
+ # When reading trailer comments, the last comment is used.
201
+ bounding_box: list[int] | None = None
202
+ imagedata_size: tuple[int, int] | None = None
203
+
204
+ byte_arr = bytearray(255)
205
+ bytes_mv = memoryview(byte_arr)
206
+ bytes_read = 0
207
+ reading_header_comments = True
208
+ reading_trailer_comments = False
209
+ trailer_reached = False
210
+
211
+ def check_required_header_comments() -> None:
212
+ """
213
+ The EPS specification requires that some headers exist.
214
+ This should be checked when the header comments formally end,
215
+ when image data starts, or when the file ends, whichever comes first.
216
+ """
217
+ if "PS-Adobe" not in self.info:
218
+ msg = 'EPS header missing "%!PS-Adobe" comment'
219
+ raise SyntaxError(msg)
220
+ if "BoundingBox" not in self.info:
221
+ msg = 'EPS header missing "%%BoundingBox" comment'
222
+ raise SyntaxError(msg)
223
+
224
+ def read_comment(s: str) -> bool:
225
+ nonlocal bounding_box, reading_trailer_comments
226
+ try:
227
+ m = split.match(s)
228
+ except re.error as e:
229
+ msg = "not an EPS file"
230
+ raise SyntaxError(msg) from e
231
+
232
+ if not m:
233
+ return False
234
+
235
+ k, v = m.group(1, 2)
236
+ self.info[k] = v
237
+ if k == "BoundingBox":
238
+ if v == "(atend)":
239
+ reading_trailer_comments = True
240
+ elif not bounding_box or (trailer_reached and reading_trailer_comments):
241
+ try:
242
+ # Note: The DSC spec says that BoundingBox
243
+ # fields should be integers, but some drivers
244
+ # put floating point values there anyway.
245
+ bounding_box = [int(float(i)) for i in v.split()]
246
+ except Exception:
247
+ pass
248
+ return True
249
+
250
+ while True:
251
+ byte = self.fp.read(1)
252
+ if byte == b"":
253
+ # if we didn't read a byte we must be at the end of the file
254
+ if bytes_read == 0:
255
+ if reading_header_comments:
256
+ check_required_header_comments()
257
+ break
258
+ elif byte in b"\r\n":
259
+ # if we read a line ending character, ignore it and parse what
260
+ # we have already read. if we haven't read any other characters,
261
+ # continue reading
262
+ if bytes_read == 0:
263
+ continue
264
+ else:
265
+ # ASCII/hexadecimal lines in an EPS file must not exceed
266
+ # 255 characters, not including line ending characters
267
+ if bytes_read >= 255:
268
+ # only enforce this for lines starting with a "%",
269
+ # otherwise assume it's binary data
270
+ if byte_arr[0] == ord("%"):
271
+ msg = "not an EPS file"
272
+ raise SyntaxError(msg)
273
+ else:
274
+ if reading_header_comments:
275
+ check_required_header_comments()
276
+ reading_header_comments = False
277
+ # reset bytes_read so we can keep reading
278
+ # data until the end of the line
279
+ bytes_read = 0
280
+ byte_arr[bytes_read] = byte[0]
281
+ bytes_read += 1
282
+ continue
283
+
284
+ if reading_header_comments:
285
+ # Load EPS header
286
+
287
+ # if this line doesn't start with a "%",
288
+ # or does start with "%%EndComments",
289
+ # then we've reached the end of the header/comments
290
+ if byte_arr[0] != ord("%") or bytes_mv[:13] == b"%%EndComments":
291
+ check_required_header_comments()
292
+ reading_header_comments = False
293
+ continue
294
+
295
+ s = str(bytes_mv[:bytes_read], "latin-1")
296
+ if not read_comment(s):
297
+ m = field.match(s)
298
+ if m:
299
+ k = m.group(1)
300
+ if k.startswith("PS-Adobe"):
301
+ self.info["PS-Adobe"] = k[9:]
302
+ else:
303
+ self.info[k] = ""
304
+ elif s[0] == "%":
305
+ # handle non-DSC PostScript comments that some
306
+ # tools mistakenly put in the Comments section
307
+ pass
308
+ else:
309
+ msg = "bad EPS header"
310
+ raise OSError(msg)
311
+ elif bytes_mv[:11] == b"%ImageData:":
312
+ # Check for an "ImageData" descriptor
313
+ # https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577413_pgfId-1035096
314
+
315
+ # If we've already read an "ImageData" descriptor,
316
+ # don't read another one.
317
+ if imagedata_size:
318
+ bytes_read = 0
319
+ continue
320
+
321
+ # Values:
322
+ # columns
323
+ # rows
324
+ # bit depth (1 or 8)
325
+ # mode (1: L, 2: LAB, 3: RGB, 4: CMYK)
326
+ # number of padding channels
327
+ # block size (number of bytes per row per channel)
328
+ # binary/ascii (1: binary, 2: ascii)
329
+ # data start identifier (the image data follows after a single line
330
+ # consisting only of this quoted value)
331
+ image_data_values = byte_arr[11:bytes_read].split(None, 7)
332
+ columns, rows, bit_depth, mode_id = (
333
+ int(value) for value in image_data_values[:4]
334
+ )
335
+
336
+ if bit_depth == 1:
337
+ self._mode = "1"
338
+ elif bit_depth == 8:
339
+ try:
340
+ self._mode = self.mode_map[mode_id]
341
+ except ValueError:
342
+ break
343
+ else:
344
+ break
345
+
346
+ # Parse the columns and rows after checking the bit depth and mode
347
+ # in case the bit depth and/or mode are invalid.
348
+ imagedata_size = columns, rows
349
+ elif bytes_mv[:5] == b"%%EOF":
350
+ break
351
+ elif trailer_reached and reading_trailer_comments:
352
+ # Load EPS trailer
353
+ s = str(bytes_mv[:bytes_read], "latin-1")
354
+ read_comment(s)
355
+ elif bytes_mv[:9] == b"%%Trailer":
356
+ trailer_reached = True
357
+ bytes_read = 0
358
+
359
+ # A "BoundingBox" is always required,
360
+ # even if an "ImageData" descriptor size exists.
361
+ if not bounding_box:
362
+ msg = "cannot determine EPS bounding box"
363
+ raise OSError(msg)
364
+
365
+ # An "ImageData" size takes precedence over the "BoundingBox".
366
+ self._size = imagedata_size or (
367
+ bounding_box[2] - bounding_box[0],
368
+ bounding_box[3] - bounding_box[1],
369
+ )
370
+
371
+ self.tile = [
372
+ ImageFile._Tile("eps", (0, 0) + self.size, offset, (length, bounding_box))
373
+ ]
374
+
375
+ def _find_offset(self, fp: IO[bytes]) -> tuple[int, int]:
376
+ s = fp.read(4)
377
+
378
+ if s == b"%!PS":
379
+ # for HEAD without binary preview
380
+ fp.seek(0, io.SEEK_END)
381
+ length = fp.tell()
382
+ offset = 0
383
+ elif i32(s) == 0xC6D3D0C5:
384
+ # FIX for: Some EPS file not handled correctly / issue #302
385
+ # EPS can contain binary data
386
+ # or start directly with latin coding
387
+ # more info see:
388
+ # https://web.archive.org/web/20160528181353/http://partners.adobe.com/public/developer/en/ps/5002.EPSF_Spec.pdf
389
+ s = fp.read(8)
390
+ offset = i32(s)
391
+ length = i32(s, 4)
392
+ else:
393
+ msg = "not an EPS file"
394
+ raise SyntaxError(msg)
395
+
396
+ return length, offset
397
+
398
+ def load(
399
+ self, scale: int = 1, transparency: bool = False
400
+ ) -> Image.core.PixelAccess | None:
401
+ # Load EPS via Ghostscript
402
+ if self.tile:
403
+ self.im = Ghostscript(self.tile, self.size, self.fp, scale, transparency)
404
+ self._mode = self.im.mode
405
+ self._size = self.im.size
406
+ self.tile = []
407
+ return Image.Image.load(self)
408
+
409
+ def load_seek(self, pos: int) -> None:
410
+ # we can't incrementally load, so force ImageFile.parser to
411
+ # use our custom load method by defining this method.
412
+ pass
413
+
414
+
415
+ # --------------------------------------------------------------------
416
+
417
+
418
+ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes, eps: int = 1) -> None:
419
+ """EPS Writer for the Python Imaging Library."""
420
+
421
+ # make sure image data is available
422
+ im.load()
423
+
424
+ # determine PostScript image mode
425
+ if im.mode == "L":
426
+ operator = (8, 1, b"image")
427
+ elif im.mode == "RGB":
428
+ operator = (8, 3, b"false 3 colorimage")
429
+ elif im.mode == "CMYK":
430
+ operator = (8, 4, b"false 4 colorimage")
431
+ else:
432
+ msg = "image mode is not supported"
433
+ raise ValueError(msg)
434
+
435
+ if eps:
436
+ # write EPS header
437
+ fp.write(b"%!PS-Adobe-3.0 EPSF-3.0\n")
438
+ fp.write(b"%%Creator: PIL 0.1 EpsEncode\n")
439
+ # fp.write("%%CreationDate: %s"...)
440
+ fp.write(b"%%%%BoundingBox: 0 0 %d %d\n" % im.size)
441
+ fp.write(b"%%Pages: 1\n")
442
+ fp.write(b"%%EndComments\n")
443
+ fp.write(b"%%Page: 1 1\n")
444
+ fp.write(b"%%ImageData: %d %d " % im.size)
445
+ fp.write(b'%d %d 0 1 1 "%s"\n' % operator)
446
+
447
+ # image header
448
+ fp.write(b"gsave\n")
449
+ fp.write(b"10 dict begin\n")
450
+ fp.write(b"/buf %d string def\n" % (im.size[0] * operator[1]))
451
+ fp.write(b"%d %d scale\n" % im.size)
452
+ fp.write(b"%d %d 8\n" % im.size) # <= bits
453
+ fp.write(b"[%d 0 0 -%d 0 %d]\n" % (im.size[0], im.size[1], im.size[1]))
454
+ fp.write(b"{ currentfile buf readhexstring pop } bind\n")
455
+ fp.write(operator[2] + b"\n")
456
+ if hasattr(fp, "flush"):
457
+ fp.flush()
458
+
459
+ ImageFile._save(im, fp, [ImageFile._Tile("eps", (0, 0) + im.size)])
460
+
461
+ fp.write(b"\n%%%%EndBinary\n")
462
+ fp.write(b"grestore end\n")
463
+ if hasattr(fp, "flush"):
464
+ fp.flush()
465
+
466
+
467
+ # --------------------------------------------------------------------
468
+
469
+
470
+ Image.register_open(EpsImageFile.format, EpsImageFile, _accept)
471
+
472
+ Image.register_save(EpsImageFile.format, _save)
473
+
474
+ Image.register_extensions(EpsImageFile.format, [".ps", ".eps"])
475
+
476
+ Image.register_mime(EpsImageFile.format, "application/postscript")
venv/Lib/site-packages/PIL/ExifTags.py ADDED
@@ -0,0 +1,382 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # The Python Imaging Library.
3
+ # $Id$
4
+ #
5
+ # EXIF tags
6
+ #
7
+ # Copyright (c) 2003 by Secret Labs AB
8
+ #
9
+ # See the README file for information on usage and redistribution.
10
+ #
11
+
12
+ """
13
+ This module provides constants and clear-text names for various
14
+ well-known EXIF tags.
15
+ """
16
+ from __future__ import annotations
17
+
18
+ from enum import IntEnum
19
+
20
+
21
+ class Base(IntEnum):
22
+ # possibly incomplete
23
+ InteropIndex = 0x0001
24
+ ProcessingSoftware = 0x000B
25
+ NewSubfileType = 0x00FE
26
+ SubfileType = 0x00FF
27
+ ImageWidth = 0x0100
28
+ ImageLength = 0x0101
29
+ BitsPerSample = 0x0102
30
+ Compression = 0x0103
31
+ PhotometricInterpretation = 0x0106
32
+ Thresholding = 0x0107
33
+ CellWidth = 0x0108
34
+ CellLength = 0x0109
35
+ FillOrder = 0x010A
36
+ DocumentName = 0x010D
37
+ ImageDescription = 0x010E
38
+ Make = 0x010F
39
+ Model = 0x0110
40
+ StripOffsets = 0x0111
41
+ Orientation = 0x0112
42
+ SamplesPerPixel = 0x0115
43
+ RowsPerStrip = 0x0116
44
+ StripByteCounts = 0x0117
45
+ MinSampleValue = 0x0118
46
+ MaxSampleValue = 0x0119
47
+ XResolution = 0x011A
48
+ YResolution = 0x011B
49
+ PlanarConfiguration = 0x011C
50
+ PageName = 0x011D
51
+ FreeOffsets = 0x0120
52
+ FreeByteCounts = 0x0121
53
+ GrayResponseUnit = 0x0122
54
+ GrayResponseCurve = 0x0123
55
+ T4Options = 0x0124
56
+ T6Options = 0x0125
57
+ ResolutionUnit = 0x0128
58
+ PageNumber = 0x0129
59
+ TransferFunction = 0x012D
60
+ Software = 0x0131
61
+ DateTime = 0x0132
62
+ Artist = 0x013B
63
+ HostComputer = 0x013C
64
+ Predictor = 0x013D
65
+ WhitePoint = 0x013E
66
+ PrimaryChromaticities = 0x013F
67
+ ColorMap = 0x0140
68
+ HalftoneHints = 0x0141
69
+ TileWidth = 0x0142
70
+ TileLength = 0x0143
71
+ TileOffsets = 0x0144
72
+ TileByteCounts = 0x0145
73
+ SubIFDs = 0x014A
74
+ InkSet = 0x014C
75
+ InkNames = 0x014D
76
+ NumberOfInks = 0x014E
77
+ DotRange = 0x0150
78
+ TargetPrinter = 0x0151
79
+ ExtraSamples = 0x0152
80
+ SampleFormat = 0x0153
81
+ SMinSampleValue = 0x0154
82
+ SMaxSampleValue = 0x0155
83
+ TransferRange = 0x0156
84
+ ClipPath = 0x0157
85
+ XClipPathUnits = 0x0158
86
+ YClipPathUnits = 0x0159
87
+ Indexed = 0x015A
88
+ JPEGTables = 0x015B
89
+ OPIProxy = 0x015F
90
+ JPEGProc = 0x0200
91
+ JpegIFOffset = 0x0201
92
+ JpegIFByteCount = 0x0202
93
+ JpegRestartInterval = 0x0203
94
+ JpegLosslessPredictors = 0x0205
95
+ JpegPointTransforms = 0x0206
96
+ JpegQTables = 0x0207
97
+ JpegDCTables = 0x0208
98
+ JpegACTables = 0x0209
99
+ YCbCrCoefficients = 0x0211
100
+ YCbCrSubSampling = 0x0212
101
+ YCbCrPositioning = 0x0213
102
+ ReferenceBlackWhite = 0x0214
103
+ XMLPacket = 0x02BC
104
+ RelatedImageFileFormat = 0x1000
105
+ RelatedImageWidth = 0x1001
106
+ RelatedImageLength = 0x1002
107
+ Rating = 0x4746
108
+ RatingPercent = 0x4749
109
+ ImageID = 0x800D
110
+ CFARepeatPatternDim = 0x828D
111
+ BatteryLevel = 0x828F
112
+ Copyright = 0x8298
113
+ ExposureTime = 0x829A
114
+ FNumber = 0x829D
115
+ IPTCNAA = 0x83BB
116
+ ImageResources = 0x8649
117
+ ExifOffset = 0x8769
118
+ InterColorProfile = 0x8773
119
+ ExposureProgram = 0x8822
120
+ SpectralSensitivity = 0x8824
121
+ GPSInfo = 0x8825
122
+ ISOSpeedRatings = 0x8827
123
+ OECF = 0x8828
124
+ Interlace = 0x8829
125
+ TimeZoneOffset = 0x882A
126
+ SelfTimerMode = 0x882B
127
+ SensitivityType = 0x8830
128
+ StandardOutputSensitivity = 0x8831
129
+ RecommendedExposureIndex = 0x8832
130
+ ISOSpeed = 0x8833
131
+ ISOSpeedLatitudeyyy = 0x8834
132
+ ISOSpeedLatitudezzz = 0x8835
133
+ ExifVersion = 0x9000
134
+ DateTimeOriginal = 0x9003
135
+ DateTimeDigitized = 0x9004
136
+ OffsetTime = 0x9010
137
+ OffsetTimeOriginal = 0x9011
138
+ OffsetTimeDigitized = 0x9012
139
+ ComponentsConfiguration = 0x9101
140
+ CompressedBitsPerPixel = 0x9102
141
+ ShutterSpeedValue = 0x9201
142
+ ApertureValue = 0x9202
143
+ BrightnessValue = 0x9203
144
+ ExposureBiasValue = 0x9204
145
+ MaxApertureValue = 0x9205
146
+ SubjectDistance = 0x9206
147
+ MeteringMode = 0x9207
148
+ LightSource = 0x9208
149
+ Flash = 0x9209
150
+ FocalLength = 0x920A
151
+ Noise = 0x920D
152
+ ImageNumber = 0x9211
153
+ SecurityClassification = 0x9212
154
+ ImageHistory = 0x9213
155
+ TIFFEPStandardID = 0x9216
156
+ MakerNote = 0x927C
157
+ UserComment = 0x9286
158
+ SubsecTime = 0x9290
159
+ SubsecTimeOriginal = 0x9291
160
+ SubsecTimeDigitized = 0x9292
161
+ AmbientTemperature = 0x9400
162
+ Humidity = 0x9401
163
+ Pressure = 0x9402
164
+ WaterDepth = 0x9403
165
+ Acceleration = 0x9404
166
+ CameraElevationAngle = 0x9405
167
+ XPTitle = 0x9C9B
168
+ XPComment = 0x9C9C
169
+ XPAuthor = 0x9C9D
170
+ XPKeywords = 0x9C9E
171
+ XPSubject = 0x9C9F
172
+ FlashPixVersion = 0xA000
173
+ ColorSpace = 0xA001
174
+ ExifImageWidth = 0xA002
175
+ ExifImageHeight = 0xA003
176
+ RelatedSoundFile = 0xA004
177
+ ExifInteroperabilityOffset = 0xA005
178
+ FlashEnergy = 0xA20B
179
+ SpatialFrequencyResponse = 0xA20C
180
+ FocalPlaneXResolution = 0xA20E
181
+ FocalPlaneYResolution = 0xA20F
182
+ FocalPlaneResolutionUnit = 0xA210
183
+ SubjectLocation = 0xA214
184
+ ExposureIndex = 0xA215
185
+ SensingMethod = 0xA217
186
+ FileSource = 0xA300
187
+ SceneType = 0xA301
188
+ CFAPattern = 0xA302
189
+ CustomRendered = 0xA401
190
+ ExposureMode = 0xA402
191
+ WhiteBalance = 0xA403
192
+ DigitalZoomRatio = 0xA404
193
+ FocalLengthIn35mmFilm = 0xA405
194
+ SceneCaptureType = 0xA406
195
+ GainControl = 0xA407
196
+ Contrast = 0xA408
197
+ Saturation = 0xA409
198
+ Sharpness = 0xA40A
199
+ DeviceSettingDescription = 0xA40B
200
+ SubjectDistanceRange = 0xA40C
201
+ ImageUniqueID = 0xA420
202
+ CameraOwnerName = 0xA430
203
+ BodySerialNumber = 0xA431
204
+ LensSpecification = 0xA432
205
+ LensMake = 0xA433
206
+ LensModel = 0xA434
207
+ LensSerialNumber = 0xA435
208
+ CompositeImage = 0xA460
209
+ CompositeImageCount = 0xA461
210
+ CompositeImageExposureTimes = 0xA462
211
+ Gamma = 0xA500
212
+ PrintImageMatching = 0xC4A5
213
+ DNGVersion = 0xC612
214
+ DNGBackwardVersion = 0xC613
215
+ UniqueCameraModel = 0xC614
216
+ LocalizedCameraModel = 0xC615
217
+ CFAPlaneColor = 0xC616
218
+ CFALayout = 0xC617
219
+ LinearizationTable = 0xC618
220
+ BlackLevelRepeatDim = 0xC619
221
+ BlackLevel = 0xC61A
222
+ BlackLevelDeltaH = 0xC61B
223
+ BlackLevelDeltaV = 0xC61C
224
+ WhiteLevel = 0xC61D
225
+ DefaultScale = 0xC61E
226
+ DefaultCropOrigin = 0xC61F
227
+ DefaultCropSize = 0xC620
228
+ ColorMatrix1 = 0xC621
229
+ ColorMatrix2 = 0xC622
230
+ CameraCalibration1 = 0xC623
231
+ CameraCalibration2 = 0xC624
232
+ ReductionMatrix1 = 0xC625
233
+ ReductionMatrix2 = 0xC626
234
+ AnalogBalance = 0xC627
235
+ AsShotNeutral = 0xC628
236
+ AsShotWhiteXY = 0xC629
237
+ BaselineExposure = 0xC62A
238
+ BaselineNoise = 0xC62B
239
+ BaselineSharpness = 0xC62C
240
+ BayerGreenSplit = 0xC62D
241
+ LinearResponseLimit = 0xC62E
242
+ CameraSerialNumber = 0xC62F
243
+ LensInfo = 0xC630
244
+ ChromaBlurRadius = 0xC631
245
+ AntiAliasStrength = 0xC632
246
+ ShadowScale = 0xC633
247
+ DNGPrivateData = 0xC634
248
+ MakerNoteSafety = 0xC635
249
+ CalibrationIlluminant1 = 0xC65A
250
+ CalibrationIlluminant2 = 0xC65B
251
+ BestQualityScale = 0xC65C
252
+ RawDataUniqueID = 0xC65D
253
+ OriginalRawFileName = 0xC68B
254
+ OriginalRawFileData = 0xC68C
255
+ ActiveArea = 0xC68D
256
+ MaskedAreas = 0xC68E
257
+ AsShotICCProfile = 0xC68F
258
+ AsShotPreProfileMatrix = 0xC690
259
+ CurrentICCProfile = 0xC691
260
+ CurrentPreProfileMatrix = 0xC692
261
+ ColorimetricReference = 0xC6BF
262
+ CameraCalibrationSignature = 0xC6F3
263
+ ProfileCalibrationSignature = 0xC6F4
264
+ AsShotProfileName = 0xC6F6
265
+ NoiseReductionApplied = 0xC6F7
266
+ ProfileName = 0xC6F8
267
+ ProfileHueSatMapDims = 0xC6F9
268
+ ProfileHueSatMapData1 = 0xC6FA
269
+ ProfileHueSatMapData2 = 0xC6FB
270
+ ProfileToneCurve = 0xC6FC
271
+ ProfileEmbedPolicy = 0xC6FD
272
+ ProfileCopyright = 0xC6FE
273
+ ForwardMatrix1 = 0xC714
274
+ ForwardMatrix2 = 0xC715
275
+ PreviewApplicationName = 0xC716
276
+ PreviewApplicationVersion = 0xC717
277
+ PreviewSettingsName = 0xC718
278
+ PreviewSettingsDigest = 0xC719
279
+ PreviewColorSpace = 0xC71A
280
+ PreviewDateTime = 0xC71B
281
+ RawImageDigest = 0xC71C
282
+ OriginalRawFileDigest = 0xC71D
283
+ SubTileBlockSize = 0xC71E
284
+ RowInterleaveFactor = 0xC71F
285
+ ProfileLookTableDims = 0xC725
286
+ ProfileLookTableData = 0xC726
287
+ OpcodeList1 = 0xC740
288
+ OpcodeList2 = 0xC741
289
+ OpcodeList3 = 0xC74E
290
+ NoiseProfile = 0xC761
291
+
292
+
293
+ """Maps EXIF tags to tag names."""
294
+ TAGS = {
295
+ **{i.value: i.name for i in Base},
296
+ 0x920C: "SpatialFrequencyResponse",
297
+ 0x9214: "SubjectLocation",
298
+ 0x9215: "ExposureIndex",
299
+ 0x828E: "CFAPattern",
300
+ 0x920B: "FlashEnergy",
301
+ 0x9216: "TIFF/EPStandardID",
302
+ }
303
+
304
+
305
+ class GPS(IntEnum):
306
+ GPSVersionID = 0x00
307
+ GPSLatitudeRef = 0x01
308
+ GPSLatitude = 0x02
309
+ GPSLongitudeRef = 0x03
310
+ GPSLongitude = 0x04
311
+ GPSAltitudeRef = 0x05
312
+ GPSAltitude = 0x06
313
+ GPSTimeStamp = 0x07
314
+ GPSSatellites = 0x08
315
+ GPSStatus = 0x09
316
+ GPSMeasureMode = 0x0A
317
+ GPSDOP = 0x0B
318
+ GPSSpeedRef = 0x0C
319
+ GPSSpeed = 0x0D
320
+ GPSTrackRef = 0x0E
321
+ GPSTrack = 0x0F
322
+ GPSImgDirectionRef = 0x10
323
+ GPSImgDirection = 0x11
324
+ GPSMapDatum = 0x12
325
+ GPSDestLatitudeRef = 0x13
326
+ GPSDestLatitude = 0x14
327
+ GPSDestLongitudeRef = 0x15
328
+ GPSDestLongitude = 0x16
329
+ GPSDestBearingRef = 0x17
330
+ GPSDestBearing = 0x18
331
+ GPSDestDistanceRef = 0x19
332
+ GPSDestDistance = 0x1A
333
+ GPSProcessingMethod = 0x1B
334
+ GPSAreaInformation = 0x1C
335
+ GPSDateStamp = 0x1D
336
+ GPSDifferential = 0x1E
337
+ GPSHPositioningError = 0x1F
338
+
339
+
340
+ """Maps EXIF GPS tags to tag names."""
341
+ GPSTAGS = {i.value: i.name for i in GPS}
342
+
343
+
344
+ class Interop(IntEnum):
345
+ InteropIndex = 0x0001
346
+ InteropVersion = 0x0002
347
+ RelatedImageFileFormat = 0x1000
348
+ RelatedImageWidth = 0x1001
349
+ RelatedImageHeight = 0x1002
350
+
351
+
352
+ class IFD(IntEnum):
353
+ Exif = 0x8769
354
+ GPSInfo = 0x8825
355
+ MakerNote = 0x927C
356
+ Makernote = 0x927C # Deprecated
357
+ Interop = 0xA005
358
+ IFD1 = -1
359
+
360
+
361
+ class LightSource(IntEnum):
362
+ Unknown = 0x00
363
+ Daylight = 0x01
364
+ Fluorescent = 0x02
365
+ Tungsten = 0x03
366
+ Flash = 0x04
367
+ Fine = 0x09
368
+ Cloudy = 0x0A
369
+ Shade = 0x0B
370
+ DaylightFluorescent = 0x0C
371
+ DayWhiteFluorescent = 0x0D
372
+ CoolWhiteFluorescent = 0x0E
373
+ WhiteFluorescent = 0x0F
374
+ StandardLightA = 0x11
375
+ StandardLightB = 0x12
376
+ StandardLightC = 0x13
377
+ D55 = 0x14
378
+ D65 = 0x15
379
+ D75 = 0x16
380
+ D50 = 0x17
381
+ ISO = 0x18
382
+ Other = 0xFF
venv/Lib/site-packages/PIL/FitsImagePlugin.py ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # The Python Imaging Library
3
+ # $Id$
4
+ #
5
+ # FITS file handling
6
+ #
7
+ # Copyright (c) 1998-2003 by Fredrik Lundh
8
+ #
9
+ # See the README file for information on usage and redistribution.
10
+ #
11
+ from __future__ import annotations
12
+
13
+ import gzip
14
+ import math
15
+
16
+ from . import Image, ImageFile
17
+
18
+
19
+ def _accept(prefix: bytes) -> bool:
20
+ return prefix.startswith(b"SIMPLE")
21
+
22
+
23
+ class FitsImageFile(ImageFile.ImageFile):
24
+ format = "FITS"
25
+ format_description = "FITS"
26
+
27
+ def _open(self) -> None:
28
+ assert self.fp is not None
29
+
30
+ headers: dict[bytes, bytes] = {}
31
+ header_in_progress = False
32
+ decoder_name = ""
33
+ while True:
34
+ header = self.fp.read(80)
35
+ if not header:
36
+ msg = "Truncated FITS file"
37
+ raise OSError(msg)
38
+ keyword = header[:8].strip()
39
+ if keyword in (b"SIMPLE", b"XTENSION"):
40
+ header_in_progress = True
41
+ elif headers and not header_in_progress:
42
+ # This is now a data unit
43
+ break
44
+ elif keyword == b"END":
45
+ # Seek to the end of the header unit
46
+ self.fp.seek(math.ceil(self.fp.tell() / 2880) * 2880)
47
+ if not decoder_name:
48
+ decoder_name, offset, args = self._parse_headers(headers)
49
+
50
+ header_in_progress = False
51
+ continue
52
+
53
+ if decoder_name:
54
+ # Keep going to read past the headers
55
+ continue
56
+
57
+ value = header[8:].split(b"/")[0].strip()
58
+ if value.startswith(b"="):
59
+ value = value[1:].strip()
60
+ if not headers and (not _accept(keyword) or value != b"T"):
61
+ msg = "Not a FITS file"
62
+ raise SyntaxError(msg)
63
+ headers[keyword] = value
64
+
65
+ if not decoder_name:
66
+ msg = "No image data"
67
+ raise ValueError(msg)
68
+
69
+ offset += self.fp.tell() - 80
70
+ self.tile = [ImageFile._Tile(decoder_name, (0, 0) + self.size, offset, args)]
71
+
72
+ def _get_size(
73
+ self, headers: dict[bytes, bytes], prefix: bytes
74
+ ) -> tuple[int, int] | None:
75
+ naxis = int(headers[prefix + b"NAXIS"])
76
+ if naxis == 0:
77
+ return None
78
+
79
+ if naxis == 1:
80
+ return 1, int(headers[prefix + b"NAXIS1"])
81
+ else:
82
+ return int(headers[prefix + b"NAXIS1"]), int(headers[prefix + b"NAXIS2"])
83
+
84
+ def _parse_headers(
85
+ self, headers: dict[bytes, bytes]
86
+ ) -> tuple[str, int, tuple[str | int, ...]]:
87
+ prefix = b""
88
+ decoder_name = "raw"
89
+ offset = 0
90
+ if (
91
+ headers.get(b"XTENSION") == b"'BINTABLE'"
92
+ and headers.get(b"ZIMAGE") == b"T"
93
+ and headers[b"ZCMPTYPE"] == b"'GZIP_1 '"
94
+ ):
95
+ no_prefix_size = self._get_size(headers, prefix) or (0, 0)
96
+ number_of_bits = int(headers[b"BITPIX"])
97
+ offset = no_prefix_size[0] * no_prefix_size[1] * (number_of_bits // 8)
98
+
99
+ prefix = b"Z"
100
+ decoder_name = "fits_gzip"
101
+
102
+ size = self._get_size(headers, prefix)
103
+ if not size:
104
+ return "", 0, ()
105
+
106
+ self._size = size
107
+
108
+ number_of_bits = int(headers[prefix + b"BITPIX"])
109
+ if number_of_bits == 8:
110
+ self._mode = "L"
111
+ elif number_of_bits == 16:
112
+ self._mode = "I;16"
113
+ elif number_of_bits == 32:
114
+ self._mode = "I"
115
+ elif number_of_bits in (-32, -64):
116
+ self._mode = "F"
117
+
118
+ args: tuple[str | int, ...]
119
+ if decoder_name == "raw":
120
+ args = (self.mode, 0, -1)
121
+ else:
122
+ args = (number_of_bits,)
123
+ return decoder_name, offset, args
124
+
125
+
126
+ class FitsGzipDecoder(ImageFile.PyDecoder):
127
+ _pulls_fd = True
128
+
129
+ def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
130
+ assert self.fd is not None
131
+ value = gzip.decompress(self.fd.read())
132
+
133
+ rows = []
134
+ offset = 0
135
+ number_of_bits = min(self.args[0] // 8, 4)
136
+ for y in range(self.state.ysize):
137
+ row = bytearray()
138
+ for x in range(self.state.xsize):
139
+ row += value[offset + (4 - number_of_bits) : offset + 4]
140
+ offset += 4
141
+ rows.append(row)
142
+ self.set_as_raw(bytes([pixel for row in rows[::-1] for pixel in row]))
143
+ return -1, 0
144
+
145
+
146
+ # --------------------------------------------------------------------
147
+ # Registry
148
+
149
+ Image.register_open(FitsImageFile.format, FitsImageFile, _accept)
150
+ Image.register_decoder("fits_gzip", FitsGzipDecoder)
151
+
152
+ Image.register_extensions(FitsImageFile.format, [".fit", ".fits"])
venv/Lib/site-packages/PIL/FliImagePlugin.py ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # The Python Imaging Library.
3
+ # $Id$
4
+ #
5
+ # FLI/FLC file handling.
6
+ #
7
+ # History:
8
+ # 95-09-01 fl Created
9
+ # 97-01-03 fl Fixed parser, setup decoder tile
10
+ # 98-07-15 fl Renamed offset attribute to avoid name clash
11
+ #
12
+ # Copyright (c) Secret Labs AB 1997-98.
13
+ # Copyright (c) Fredrik Lundh 1995-97.
14
+ #
15
+ # See the README file for information on usage and redistribution.
16
+ #
17
+ from __future__ import annotations
18
+
19
+ import os
20
+
21
+ from . import Image, ImageFile, ImagePalette
22
+ from ._binary import i16le as i16
23
+ from ._binary import i32le as i32
24
+ from ._binary import o8
25
+ from ._util import DeferredError
26
+
27
+ #
28
+ # decoder
29
+
30
+
31
+ def _accept(prefix: bytes) -> bool:
32
+ return (
33
+ len(prefix) >= 6
34
+ and i16(prefix, 4) in [0xAF11, 0xAF12]
35
+ and i16(prefix, 14) in [0, 3] # flags
36
+ )
37
+
38
+
39
+ ##
40
+ # Image plugin for the FLI/FLC animation format. Use the <b>seek</b>
41
+ # method to load individual frames.
42
+
43
+
44
+ class FliImageFile(ImageFile.ImageFile):
45
+ format = "FLI"
46
+ format_description = "Autodesk FLI/FLC Animation"
47
+ _close_exclusive_fp_after_loading = False
48
+
49
+ def _open(self) -> None:
50
+ # HEAD
51
+ s = self.fp.read(128)
52
+ if not (_accept(s) and s[20:22] == b"\x00\x00"):
53
+ msg = "not an FLI/FLC file"
54
+ raise SyntaxError(msg)
55
+
56
+ # frames
57
+ self.n_frames = i16(s, 6)
58
+ self.is_animated = self.n_frames > 1
59
+
60
+ # image characteristics
61
+ self._mode = "P"
62
+ self._size = i16(s, 8), i16(s, 10)
63
+
64
+ # animation speed
65
+ duration = i32(s, 16)
66
+ magic = i16(s, 4)
67
+ if magic == 0xAF11:
68
+ duration = (duration * 1000) // 70
69
+ self.info["duration"] = duration
70
+
71
+ # look for palette
72
+ palette = [(a, a, a) for a in range(256)]
73
+
74
+ s = self.fp.read(16)
75
+
76
+ self.__offset = 128
77
+
78
+ if i16(s, 4) == 0xF100:
79
+ # prefix chunk; ignore it
80
+ self.__offset = self.__offset + i32(s)
81
+ self.fp.seek(self.__offset)
82
+ s = self.fp.read(16)
83
+
84
+ if i16(s, 4) == 0xF1FA:
85
+ # look for palette chunk
86
+ number_of_subchunks = i16(s, 6)
87
+ chunk_size: int | None = None
88
+ for _ in range(number_of_subchunks):
89
+ if chunk_size is not None:
90
+ self.fp.seek(chunk_size - 6, os.SEEK_CUR)
91
+ s = self.fp.read(6)
92
+ chunk_type = i16(s, 4)
93
+ if chunk_type in (4, 11):
94
+ self._palette(palette, 2 if chunk_type == 11 else 0)
95
+ break
96
+ chunk_size = i32(s)
97
+ if not chunk_size:
98
+ break
99
+
100
+ self.palette = ImagePalette.raw(
101
+ "RGB", b"".join(o8(r) + o8(g) + o8(b) for (r, g, b) in palette)
102
+ )
103
+
104
+ # set things up to decode first frame
105
+ self.__frame = -1
106
+ self._fp = self.fp
107
+ self.__rewind = self.fp.tell()
108
+ self.seek(0)
109
+
110
+ def _palette(self, palette: list[tuple[int, int, int]], shift: int) -> None:
111
+ # load palette
112
+
113
+ i = 0
114
+ for e in range(i16(self.fp.read(2))):
115
+ s = self.fp.read(2)
116
+ i = i + s[0]
117
+ n = s[1]
118
+ if n == 0:
119
+ n = 256
120
+ s = self.fp.read(n * 3)
121
+ for n in range(0, len(s), 3):
122
+ r = s[n] << shift
123
+ g = s[n + 1] << shift
124
+ b = s[n + 2] << shift
125
+ palette[i] = (r, g, b)
126
+ i += 1
127
+
128
+ def seek(self, frame: int) -> None:
129
+ if not self._seek_check(frame):
130
+ return
131
+ if frame < self.__frame:
132
+ self._seek(0)
133
+
134
+ for f in range(self.__frame + 1, frame + 1):
135
+ self._seek(f)
136
+
137
+ def _seek(self, frame: int) -> None:
138
+ if isinstance(self._fp, DeferredError):
139
+ raise self._fp.ex
140
+ if frame == 0:
141
+ self.__frame = -1
142
+ self._fp.seek(self.__rewind)
143
+ self.__offset = 128
144
+ else:
145
+ # ensure that the previous frame was loaded
146
+ self.load()
147
+
148
+ if frame != self.__frame + 1:
149
+ msg = f"cannot seek to frame {frame}"
150
+ raise ValueError(msg)
151
+ self.__frame = frame
152
+
153
+ # move to next frame
154
+ self.fp = self._fp
155
+ self.fp.seek(self.__offset)
156
+
157
+ s = self.fp.read(4)
158
+ if not s:
159
+ msg = "missing frame size"
160
+ raise EOFError(msg)
161
+
162
+ framesize = i32(s)
163
+
164
+ self.decodermaxblock = framesize
165
+ self.tile = [ImageFile._Tile("fli", (0, 0) + self.size, self.__offset)]
166
+
167
+ self.__offset += framesize
168
+
169
+ def tell(self) -> int:
170
+ return self.__frame
171
+
172
+
173
+ #
174
+ # registry
175
+
176
+ Image.register_open(FliImageFile.format, FliImageFile, _accept)
177
+
178
+ Image.register_extensions(FliImageFile.format, [".fli", ".flc"])
venv/Lib/site-packages/PIL/FontFile.py ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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, _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 = 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
+ self.bitmap = Image.new("1", (xsize, ysize))
93
+ self.metrics: list[
94
+ tuple[tuple[int, int], tuple[int, int, int, int], tuple[int, int, int, int]]
95
+ | None
96
+ ] = [None] * 256
97
+ x = y = 0
98
+ for i in range(256):
99
+ glyph = self[i]
100
+ if glyph:
101
+ d, dst, src, im = glyph
102
+ xx = src[2] - src[0]
103
+ x0, y0 = x, y
104
+ x = x + xx
105
+ if x > WIDTH:
106
+ x, y = 0, y + h
107
+ x0, y0 = x, y
108
+ x = xx
109
+ s = src[0] + x0, src[1] + y0, src[2] + x0, src[3] + y0
110
+ self.bitmap.paste(im.crop(src), s)
111
+ self.metrics[i] = d, dst, s
112
+
113
+ def save(self, filename: str) -> None:
114
+ """Save font"""
115
+
116
+ self.compile()
117
+
118
+ # font data
119
+ if not self.bitmap:
120
+ msg = "No bitmap created"
121
+ raise ValueError(msg)
122
+ self.bitmap.save(os.path.splitext(filename)[0] + ".pbm", "PNG")
123
+
124
+ # font metrics
125
+ with open(os.path.splitext(filename)[0] + ".pil", "wb") as fp:
126
+ fp.write(b"PILfont\n")
127
+ fp.write(f";;;;;;{self.ysize};\n".encode("ascii")) # HACK!!!
128
+ fp.write(b"DATA\n")
129
+ for id in range(256):
130
+ m = self.metrics[id]
131
+ if not m:
132
+ puti16(fp, (0,) * 10)
133
+ else:
134
+ puti16(fp, m[0] + m[1] + m[2])
venv/Lib/site-packages/PIL/FpxImagePlugin.py ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ try:
62
+ self.ole = olefile.OleFileIO(self.fp)
63
+ except OSError as e:
64
+ msg = "not an FPX file; invalid OLE file"
65
+ raise SyntaxError(msg) from e
66
+
67
+ root = self.ole.root
68
+ if not root or root.clsid != "56616700-C154-11CE-8553-00AA00A1F95B":
69
+ msg = "not an FPX file; bad root CLSID"
70
+ raise SyntaxError(msg)
71
+
72
+ self._open_index(1)
73
+
74
+ def _open_index(self, index: int = 1) -> None:
75
+ #
76
+ # get the Image Contents Property Set
77
+
78
+ prop = self.ole.getproperties(
79
+ [f"Data Object Store {index:06d}", "\005Image Contents"]
80
+ )
81
+
82
+ # size (highest resolution)
83
+
84
+ assert isinstance(prop[0x1000002], int)
85
+ assert isinstance(prop[0x1000003], int)
86
+ self._size = prop[0x1000002], prop[0x1000003]
87
+
88
+ size = max(self.size)
89
+ i = 1
90
+ while size > 64:
91
+ size = size // 2
92
+ i += 1
93
+ self.maxid = i - 1
94
+
95
+ # mode. instead of using a single field for this, flashpix
96
+ # requires you to specify the mode for each channel in each
97
+ # resolution subimage, and leaves it to the decoder to make
98
+ # sure that they all match. for now, we'll cheat and assume
99
+ # that this is always the case.
100
+
101
+ id = self.maxid << 16
102
+
103
+ s = prop[0x2000002 | id]
104
+
105
+ if not isinstance(s, bytes) or (bands := i32(s, 4)) > 4:
106
+ msg = "Invalid number of bands"
107
+ raise OSError(msg)
108
+
109
+ # note: for now, we ignore the "uncalibrated" flag
110
+ colors = tuple(i32(s, 8 + i * 4) & 0x7FFFFFFF for i in range(bands))
111
+
112
+ self._mode, self.rawmode = MODES[colors]
113
+
114
+ # load JPEG tables, if any
115
+ self.jpeg = {}
116
+ for i in range(256):
117
+ id = 0x3000001 | (i << 16)
118
+ if id in prop:
119
+ self.jpeg[i] = prop[id]
120
+
121
+ self._open_subimage(1, self.maxid)
122
+
123
+ def _open_subimage(self, index: int = 1, subimage: int = 0) -> None:
124
+ #
125
+ # setup tile descriptors for a given subimage
126
+
127
+ stream = [
128
+ f"Data Object Store {index:06d}",
129
+ f"Resolution {subimage:04d}",
130
+ "Subimage 0000 Header",
131
+ ]
132
+
133
+ fp = self.ole.openstream(stream)
134
+
135
+ # skip prefix
136
+ fp.read(28)
137
+
138
+ # header stream
139
+ s = fp.read(36)
140
+
141
+ size = i32(s, 4), i32(s, 8)
142
+ # tilecount = i32(s, 12)
143
+ tilesize = i32(s, 16), i32(s, 20)
144
+ # channels = i32(s, 24)
145
+ offset = i32(s, 28)
146
+ length = i32(s, 32)
147
+
148
+ if size != self.size:
149
+ msg = "subimage mismatch"
150
+ raise OSError(msg)
151
+
152
+ # get tile descriptors
153
+ fp.seek(28 + offset)
154
+ s = fp.read(i32(s, 12) * length)
155
+
156
+ x = y = 0
157
+ xsize, ysize = size
158
+ xtile, ytile = tilesize
159
+ self.tile = []
160
+
161
+ for i in range(0, len(s), length):
162
+ x1 = min(xsize, x + xtile)
163
+ y1 = min(ysize, y + ytile)
164
+
165
+ compression = i32(s, i + 8)
166
+
167
+ if compression == 0:
168
+ self.tile.append(
169
+ ImageFile._Tile(
170
+ "raw",
171
+ (x, y, x1, y1),
172
+ i32(s, i) + 28,
173
+ self.rawmode,
174
+ )
175
+ )
176
+
177
+ elif compression == 1:
178
+ # FIXME: the fill decoder is not implemented
179
+ self.tile.append(
180
+ ImageFile._Tile(
181
+ "fill",
182
+ (x, y, x1, y1),
183
+ i32(s, i) + 28,
184
+ (self.rawmode, s[12:16]),
185
+ )
186
+ )
187
+
188
+ elif compression == 2:
189
+ internal_color_conversion = s[14]
190
+ jpeg_tables = s[15]
191
+ rawmode = self.rawmode
192
+
193
+ if internal_color_conversion:
194
+ # The image is stored as usual (usually YCbCr).
195
+ if rawmode == "RGBA":
196
+ # For "RGBA", data is stored as YCbCrA based on
197
+ # negative RGB. The following trick works around
198
+ # this problem :
199
+ jpegmode, rawmode = "YCbCrK", "CMYK"
200
+ else:
201
+ jpegmode = None # let the decoder decide
202
+
203
+ else:
204
+ # The image is stored as defined by rawmode
205
+ jpegmode = rawmode
206
+
207
+ self.tile.append(
208
+ ImageFile._Tile(
209
+ "jpeg",
210
+ (x, y, x1, y1),
211
+ i32(s, i) + 28,
212
+ (rawmode, jpegmode),
213
+ )
214
+ )
215
+
216
+ # FIXME: jpeg tables are tile dependent; the prefix
217
+ # data must be placed in the tile descriptor itself!
218
+
219
+ if jpeg_tables:
220
+ self.tile_prefix = self.jpeg[jpeg_tables]
221
+
222
+ else:
223
+ msg = "unknown/invalid compression"
224
+ raise OSError(msg)
225
+
226
+ x = x + xtile
227
+ if x >= xsize:
228
+ x, y = 0, y + ytile
229
+ if y >= ysize:
230
+ break # isn't really required
231
+
232
+ self.stream = stream
233
+ self._fp = self.fp
234
+ self.fp = None
235
+
236
+ def load(self) -> Image.core.PixelAccess | None:
237
+ if not self.fp:
238
+ self.fp = self.ole.openstream(self.stream[:2] + ["Subimage 0000 Data"])
239
+
240
+ return ImageFile.ImageFile.load(self)
241
+
242
+ def close(self) -> None:
243
+ self.ole.close()
244
+ super().close()
245
+
246
+ def __exit__(self, *args: object) -> None:
247
+ self.ole.close()
248
+ super().__exit__()
249
+
250
+
251
+ #
252
+ # --------------------------------------------------------------------
253
+
254
+
255
+ Image.register_open(FpxImageFile.format, FpxImageFile, _accept)
256
+
257
+ Image.register_extension(FpxImageFile.format, ".fpx")
venv/Lib/site-packages/PIL/FtexImagePlugin.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ if not _accept(self.fp.read(4)):
76
+ msg = "not an FTEX file"
77
+ raise SyntaxError(msg)
78
+ struct.unpack("<i", self.fp.read(4)) # version
79
+ self._size = struct.unpack("<2i", self.fp.read(8))
80
+ mipmap_count, format_count = struct.unpack("<2i", self.fp.read(8))
81
+
82
+ # Only support single-format files.
83
+ # I don't know of any multi-format file.
84
+ assert format_count == 1
85
+
86
+ format, where = struct.unpack("<2i", self.fp.read(8))
87
+ self.fp.seek(where)
88
+ (mipmap_size,) = struct.unpack("<i", self.fp.read(4))
89
+
90
+ data = self.fp.read(mipmap_size)
91
+
92
+ if format == Format.DXT1:
93
+ self._mode = "RGBA"
94
+ self.tile = [ImageFile._Tile("bcn", (0, 0) + self.size, 0, (1,))]
95
+ elif format == Format.UNCOMPRESSED:
96
+ self._mode = "RGB"
97
+ self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 0, "RGB")]
98
+ else:
99
+ msg = f"Invalid texture compression format: {repr(format)}"
100
+ raise ValueError(msg)
101
+
102
+ self.fp.close()
103
+ self.fp = BytesIO(data)
104
+
105
+ def load_seek(self, pos: int) -> None:
106
+ pass
107
+
108
+
109
+ def _accept(prefix: bytes) -> bool:
110
+ return prefix.startswith(MAGIC)
111
+
112
+
113
+ Image.register_open(FtexImageFile.format, FtexImageFile, _accept)
114
+ Image.register_extensions(FtexImageFile.format, [".ftc", ".ftu"])
venv/Lib/site-packages/PIL/GbrImagePlugin.py ADDED
@@ -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
+ header_size = i32(self.fp.read(4))
46
+ if header_size < 20:
47
+ msg = "not a GIMP brush"
48
+ raise SyntaxError(msg)
49
+ version = i32(self.fp.read(4))
50
+ if version not in (1, 2):
51
+ msg = f"Unsupported GIMP brush version: {version}"
52
+ raise SyntaxError(msg)
53
+
54
+ width = i32(self.fp.read(4))
55
+ height = i32(self.fp.read(4))
56
+ color_depth = i32(self.fp.read(4))
57
+ if width <= 0 or height <= 0:
58
+ msg = "not a GIMP brush"
59
+ raise SyntaxError(msg)
60
+ if color_depth not in (1, 4):
61
+ msg = f"Unsupported GIMP brush color depth: {color_depth}"
62
+ raise SyntaxError(msg)
63
+
64
+ if version == 1:
65
+ comment_length = header_size - 20
66
+ else:
67
+ comment_length = header_size - 28
68
+ magic_number = self.fp.read(4)
69
+ if magic_number != b"GIMP":
70
+ msg = "not a GIMP brush, bad magic number"
71
+ raise SyntaxError(msg)
72
+ self.info["spacing"] = i32(self.fp.read(4))
73
+
74
+ comment = self.fp.read(comment_length)[:-1]
75
+
76
+ if color_depth == 1:
77
+ self._mode = "L"
78
+ else:
79
+ self._mode = "RGBA"
80
+
81
+ self._size = width, height
82
+
83
+ self.info["comment"] = comment
84
+
85
+ # Image might not be small
86
+ Image._decompression_bomb_check(self.size)
87
+
88
+ # Data is an uncompressed block of w * h * bytes/pixel
89
+ self._data_size = width * height * color_depth
90
+
91
+ def load(self) -> Image.core.PixelAccess | None:
92
+ if self._im is 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")
venv/Lib/site-packages/PIL/GdImageFile.py ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # The Python Imaging Library.
3
+ # $Id$
4
+ #
5
+ # GD file handling
6
+ #
7
+ # History:
8
+ # 1996-04-12 fl Created
9
+ #
10
+ # Copyright (c) 1997 by Secret Labs AB.
11
+ # Copyright (c) 1996 by Fredrik Lundh.
12
+ #
13
+ # See the README file for information on usage and redistribution.
14
+ #
15
+
16
+
17
+ """
18
+ .. note::
19
+ This format cannot be automatically recognized, so the
20
+ class is not registered for use with :py:func:`PIL.Image.open()`. To open a
21
+ gd file, use the :py:func:`PIL.GdImageFile.open()` function instead.
22
+
23
+ .. warning::
24
+ THE GD FORMAT IS NOT DESIGNED FOR DATA INTERCHANGE. This
25
+ implementation is provided for convenience and demonstrational
26
+ purposes only.
27
+ """
28
+ from __future__ import annotations
29
+
30
+ from typing import IO
31
+
32
+ from . import ImageFile, ImagePalette, UnidentifiedImageError
33
+ from ._binary import i16be as i16
34
+ from ._binary import i32be as i32
35
+ from ._typing import StrOrBytesPath
36
+
37
+
38
+ class GdImageFile(ImageFile.ImageFile):
39
+ """
40
+ Image plugin for the GD uncompressed format. Note that this format
41
+ is not supported by the standard :py:func:`PIL.Image.open()` function. To use
42
+ this plugin, you have to import the :py:mod:`PIL.GdImageFile` module and
43
+ use the :py:func:`PIL.GdImageFile.open()` function.
44
+ """
45
+
46
+ format = "GD"
47
+ format_description = "GD uncompressed images"
48
+
49
+ def _open(self) -> None:
50
+ # Header
51
+ assert self.fp is not None
52
+
53
+ s = self.fp.read(1037)
54
+
55
+ if i16(s) not in [65534, 65535]:
56
+ msg = "Not a valid GD 2.x .gd file"
57
+ raise SyntaxError(msg)
58
+
59
+ self._mode = "P"
60
+ self._size = i16(s, 2), i16(s, 4)
61
+
62
+ true_color = s[6]
63
+ true_color_offset = 2 if true_color else 0
64
+
65
+ # transparency index
66
+ tindex = i32(s, 7 + true_color_offset)
67
+ if tindex < 256:
68
+ self.info["transparency"] = tindex
69
+
70
+ self.palette = ImagePalette.raw(
71
+ "RGBX", s[7 + true_color_offset + 6 : 7 + true_color_offset + 6 + 256 * 4]
72
+ )
73
+
74
+ self.tile = [
75
+ ImageFile._Tile(
76
+ "raw",
77
+ (0, 0) + self.size,
78
+ 7 + true_color_offset + 6 + 256 * 4,
79
+ "L",
80
+ )
81
+ ]
82
+
83
+
84
+ def open(fp: StrOrBytesPath | IO[bytes], mode: str = "r") -> GdImageFile:
85
+ """
86
+ Load texture from a GD image file.
87
+
88
+ :param fp: GD file name, or an opened file handle.
89
+ :param mode: Optional mode. In this version, if the mode argument
90
+ is given, it must be "r".
91
+ :returns: An image instance.
92
+ :raises OSError: If the image could not be read.
93
+ """
94
+ if mode != "r":
95
+ msg = "bad mode"
96
+ raise ValueError(msg)
97
+
98
+ try:
99
+ return GdImageFile(fp)
100
+ except SyntaxError as e:
101
+ msg = "cannot identify this image file"
102
+ raise UnidentifiedImageError(msg) from e