diff --git a/lpon_site/frontend/apps.py b/lpon_site/frontend/apps.py index 62e72da..cb5e374 100644 --- a/lpon_site/frontend/apps.py +++ b/lpon_site/frontend/apps.py @@ -5,6 +5,7 @@ from io import BytesIO from django.apps import AppConfig from django.core.files.base import ContentFile from PIL import Image as PILImage +import pillow_heif from lpon_site.settings import ( THUMBNAIL_WEBP_QUALITY, @@ -15,6 +16,9 @@ from lpon_site.settings import ( FILE_VALIDATORS, ) +# Регистрируем плагин HEIF в Pillow +pillow_heif.register_heif_opener() + # Получаем логгер для текущего модуля logger = logging.getLogger(__name__) @@ -36,10 +40,6 @@ class FrontendConfig(AppConfig): # ============================================================================== # Кастомная конфигурация для django-filer # - Патчинг MultiStorageFieldFile.save() для автоматической конвертации в WebP -# -# Все параметры конфигурации (MIME_TYPE_WHITELIST, FILER_WHITELIST_FOR_PATH_ACCESS и т.д.) -# определены в settings.py и импортируются оттуда. -# Удаление префикса filer_public_thumbnails/ достигается через THUMBNAIL_OPTIONS в settings.py # ============================================================================== class CustomFilerConfig(AppConfig): name = 'filer' @@ -47,7 +47,6 @@ class CustomFilerConfig(AppConfig): # ======================================================================== # Атрибуты конфигурации Django-Filer (импортированы из settings.py) - # Единое место правды - settings.py # ======================================================================== FILER_ENABLE_PERMISSIONS = FILER_ENABLE_PERMISSIONS FILER_UPLOADER_MAX_FILE_SIZE = FILER_UPLOADER_MAX_FILE_SIZE @@ -60,10 +59,10 @@ class CustomFilerConfig(AppConfig): def _convert_to_webp_if_needed(name: str, content): """ Преобразует загруженное изображение в WebP формат. - Поддерживает JPEG, PNG, BMP и TIFF. + Поддерживает JPEG, PNG, BMP, TIFF и HEIC/HEIF. """ _, original_ext = os.path.splitext(name) - if original_ext.lower() in [".jpg", ".jpeg", ".png", ".bmp", ".tiff"]: + if original_ext.lower() in [".jpg", ".jpeg", ".png", ".bmp", ".tiff", ".heic", ".heif"]: try: content.seek(0) img = PILImage.open(BytesIO(content.read())) @@ -111,4 +110,3 @@ class CustomFilerConfig(AppConfig): MultiStorageFieldFile.save = patched_save logger.info("MultiStorageFieldFile.save() patched successfully.") - diff --git a/lpon_site/lpon_site/settings.py b/lpon_site/lpon_site/settings.py index ef806fa..78b3693 100644 --- a/lpon_site/lpon_site/settings.py +++ b/lpon_site/lpon_site/settings.py @@ -211,15 +211,20 @@ FILER_MAX_IMAGE_PIXELS = 4096 * 4096 FILER_ENABLE_PERMISSIONS = DEBUG FILER_WHITELIST_FOR_PATH_ACCESS = ( - '.jpg', '.jpeg', '.png', '.gif', '.svg', '.webp', + '.jpg', '.jpeg', '.png', '.gif', '.svg', '.webp', ".heic", ".heif", '.doc', '.docx', '.pdf', '.txt', '.xls', '.xlsx', '.csv', ) MIME_TYPE_WHITELIST = ( - 'image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'image/webp', - 'application/pdf', 'application/msword', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'text/plain', 'application/vnd.ms-excel', - 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'image/jpeg', # .jpg / .jpeg + 'image/png', + 'image/gif', + 'image/svg+xml', + 'image/webp', + 'image/heic', 'image/heif', # форматы Apple HEIC/HEIF (без анимации + 'application/pdf', + 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', # .doc / .docx + 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', # .xls / .xlsx + 'text/plain', 'text/csv', ) FILE_VALIDATORS = {} diff --git a/poetry.lock b/poetry.lock index a68d2c2..6d7fd32 100644 --- a/poetry.lock +++ b/poetry.lock @@ -243,13 +243,13 @@ heif = ["pillow-heif"] [[package]] name = "django-polymorphic" -version = "4.11.4" +version = "4.11.5" description = "Seamless polymorphic inheritance for Django models." optional = false python-versions = "<4.0,>=3.10" files = [ - {file = "django_polymorphic-4.11.4-py3-none-any.whl", hash = "sha256:6093f38ca3c3d25e882d30e2b833f47f2155bd39b7c8c176a7e2e1fc78e6d29f"}, - {file = "django_polymorphic-4.11.4.tar.gz", hash = "sha256:2b9bd7c769d34f704465b453cb2ad74fa68b464d6de6091ed65bdfa30650c5f7"}, + {file = "django_polymorphic-4.11.5-py3-none-any.whl", hash = "sha256:8c65b5c109c057c51e059197b01765dd5e096b3fd393ee3038bffc294681b3be"}, + {file = "django_polymorphic-4.11.5.tar.gz", hash = "sha256:9a6fe66fab12cfe06aac81942d14670c6b0204aebd30ce9fb58fb53213c613eb"}, ] [package.dependencies] @@ -533,6 +533,72 @@ test-arrow = ["arro3-compute", "arro3-core", "nanoarrow", "pyarrow"] tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma (>=5)", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "trove-classifiers (>=2024.10.12)"] xmp = ["defusedxml"] +[[package]] +name = "pillow-heif" +version = "1.3.0" +description = "Python interface for libheif library" +optional = false +python-versions = ">=3.10" +files = [ + {file = "pillow_heif-1.3.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:0addc7d25133a2abd0149d1f1b8063808268c9ed75dc228c2196c90d56639a25"}, + {file = "pillow_heif-1.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e557b7082e785ff4505b2be258409fc3983162a3802f5438aa3177201d0e5a41"}, + {file = "pillow_heif-1.3.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e031f0036200da349cdac1328a3617a9d13b7f9145355c0a36306ce3b9f1d622"}, + {file = "pillow_heif-1.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d00218ce66aa74cddb5cb64e59a8867ed6722cc430b240d578ef3bc1307998a3"}, + {file = "pillow_heif-1.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4c4eef69c7caec0f41af13308bba5883bde751119f27a51c9a299b83852f3430"}, + {file = "pillow_heif-1.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:625b67f7000b3aae645e4aea4170a6f0bb9015577c69cf249c360b10e071e8a7"}, + {file = "pillow_heif-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:09a924fbb505674546973518b8906f499a56bb3332752a144bc272becd59c141"}, + {file = "pillow_heif-1.3.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:68bea3b9396fdd6c711e66fc645df92bbe53d48892909192ce9a30e4c619878a"}, + {file = "pillow_heif-1.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1a59db0091556d11ab26c2b34532b7992965520027ba0a64084771bcc9a31156"}, + {file = "pillow_heif-1.3.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b69cc05b4f22ac57f1fd8f5f7ae96ae7c752036659ea975ec5f5565efadd87f"}, + {file = "pillow_heif-1.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a5a9f26d9ece400f55ac006e2fed079392e44a550023c99122e281fcd72b7c06"}, + {file = "pillow_heif-1.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a25a58368222c388a96b111f4621423eac6fa07a0bbcb2ac5eaf624153cde04e"}, + {file = "pillow_heif-1.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6d3cdc335df30652ae9b07438e9898ce5cb5dbc47012fa14f93be1df9d446dc5"}, + {file = "pillow_heif-1.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:b5a1458bc11ca83cd72ec4a93f739ad3ae4315ae66766022ec16d12993a863a4"}, + {file = "pillow_heif-1.3.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:079abbcaeb42ef0849a33f35c1a96ccd431feb56b242a0d4f8435a1c8ca02c7d"}, + {file = "pillow_heif-1.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76c33f80ec111492642b98309db98516a7fba9677dcda9ec5fe9111b7e38d720"}, + {file = "pillow_heif-1.3.0-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:33b838d06e2fd730f806af5a76bfc4cd3de9d146d88d37572e40f7a4c4ff8221"}, + {file = "pillow_heif-1.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f92b387af891cf5d98f52e79eeaf51ee7955a54fe2deeec12bfb7519e41464b5"}, + {file = "pillow_heif-1.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f9f73246836f93f99343cbc3052b61d212d27e59ddf40262d494a1e3e54af31a"}, + {file = "pillow_heif-1.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:84c3816742c2e49176e651895e73c555b9c3b0f3561d60230242f3be0c9d272b"}, + {file = "pillow_heif-1.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:5f0db0bf49162fb1d73d13340a9576b3a2805bde026a9a40038bcc1a0878d710"}, + {file = "pillow_heif-1.3.0-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:641c50a064aa9ad6626a6b2b914b65855202f937d573d53838e344feb2e8c6d1"}, + {file = "pillow_heif-1.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9390dd7987887aa09779fbd88bbab715c732c9ad3a71d6707284035e3ca93379"}, + {file = "pillow_heif-1.3.0-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e8444ccb330015e1db930207d269886e4b6c666121cd9e5fdad88735950b09f"}, + {file = "pillow_heif-1.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d30054ccc97ecbe5ee3fa486a505ccc33bfbb27f005ad624ddb4c17b80ddd57"}, + {file = "pillow_heif-1.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dc1b9c9efdf8345d703118449ff69696d0827bdf28e3b52f82015f5714f7c23e"}, + {file = "pillow_heif-1.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee26b2155721e7f5f7b10fa93ca2ad3be59547c5c5e5d9d50e6ea17531b81d60"}, + {file = "pillow_heif-1.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:17ecbbadfe10ea12a65c1c12354dc1ed8ae1e5d1b7092ea753641b029f7d6f9e"}, + {file = "pillow_heif-1.3.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:8267a73d3b2d07a47a96428bd8cd4c406e1637a94f29d4c16ce08b31b8e50a07"}, + {file = "pillow_heif-1.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:36bbea7679467caa3a154db11c04f1ca2fa8591e886f06f40f7831c14b58d771"}, + {file = "pillow_heif-1.3.0-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea3a4b2de4b6c63407af72afdac901616807c6e6a030fe77851d227bca3727a"}, + {file = "pillow_heif-1.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05149bd26b08dae5af7a389af6db13cef4f12c7871db73d84e40a1f3c83b0142"}, + {file = "pillow_heif-1.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f8b7a50058fc3152f42b68aa2b30601249f61aa5c6c27876af076785c7051fd9"}, + {file = "pillow_heif-1.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:edb3ef437e8841475db14721f0529e600bb55c41b549ad1794a0831e28f33bac"}, + {file = "pillow_heif-1.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:bdd6695d5be0d98ae0e9a5f88fe26f1a6eca0a5b6d43d0a92a97f89fea5842f7"}, + {file = "pillow_heif-1.3.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:65c5d05cb7f5e1eadbe9c605ae3a4dd3ef953adb33e7d809d5fb56f8a6753588"}, + {file = "pillow_heif-1.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:dc177fbdf598770cad4afa99c082a30b9d090e60c39656904338717803ae59b2"}, + {file = "pillow_heif-1.3.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:71f88d180547bb5112b56310c8c5e338d8358320a402c80afabc6b2f39eadddb"}, + {file = "pillow_heif-1.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9acee893186bdde6140d30a7dc6d7c928e4ad3007989764f6e54a7a517faa332"}, + {file = "pillow_heif-1.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7cf893689132bec18f0c55a505da9ebf3a8feb33dd354fe2ac050f20f4f862e0"}, + {file = "pillow_heif-1.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:54404c9b6f0323114527579f54cc966b47206f99d943e47d73e1091ab0b9d2ba"}, + {file = "pillow_heif-1.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:18c7c35a9d98ed9eaaf2db601ee43425ebccc698801df9c008aa04e00756a22e"}, + {file = "pillow_heif-1.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:2723c4b85c5ad0420cb0b3e512ac0aa015e3c8b13013b4738816833aa431f919"}, + {file = "pillow_heif-1.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:6bdb197b43a629e2118fd33a9ebcf39abdabe5540b80d8862c53a7611edb42ab"}, + {file = "pillow_heif-1.3.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d433048bd23436afa2a33e08fc622712ec97fea1c230d5b5a0fafd5512628c8"}, + {file = "pillow_heif-1.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:142b307de087eba33d3174aa29a9669b65a7d006192ef8c98579920be3b56f64"}, + {file = "pillow_heif-1.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:633f5d7fbf60a489ba301fbba06e75539a5cd22ff0b036162db2167803416470"}, + {file = "pillow_heif-1.3.0.tar.gz", hash = "sha256:af8d2bda85e395677d5bb50d7bda3b5655c946cc95b913b5e7222fabacbb467f"}, +] + +[package.dependencies] +pillow = ">=11.1.0" + +[package.extras] +dev = ["coverage", "defusedxml", "numpy", "opencv-python (==4.13.0.92)", "packaging", "pre-commit", "pylint", "pympler", "pytest", "setuptools"] +docs = ["sphinx (>=4.4)", "sphinx-issues (>=3.0.1)", "sphinx-rtd-theme (>=1.0)"] +tests = ["defusedxml", "numpy", "packaging", "pympler", "pytest"] +tests-min = ["defusedxml", "packaging", "pytest"] + [[package]] name = "python-dotenv" version = "1.2.2" @@ -654,4 +720,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "e4e72f02a8c19fc9d396f6d0dd03ea91afbf63da3efc11a77f6e524f5acd9fcc" +content-hash = "8a4ac709434f2361f18fff48639d87ea7a0d44b9b6b3de3d99884a3b8814485c" diff --git a/pyproject.toml b/pyproject.toml index 62f8dcc..f957a1e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,7 @@ django = "^6.0" python-dotenv = "^1.0.0" django-environ = "^0.13.0" django-filer = "^3.4.4" +pillow-heif = "^1.3.0" [tool.poetry.group.dev.dependencies] django-extensions = "^3.2"