mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-10-23 16:18:55 +00:00
Chore: Drop ImageMagik as a dependency (#14440)
* Mark the thumbnail constants Final * Comment each pdftoppm option * Feature/Chore: Replaces all usages of ImageMagik's convert binary with a simple Pillow based helper This removes ImageMagik as a dependency entirly and all documentation is cleaned up from it. We no longer need to install it, have a policy for it to allow PDFs and no longer shell out to it either. * Fix: Save WebP images losslessly when removing the alpha channel Pillow's default WebP save is lossy, so a WebP with an alpha channel came back from remove_alpha_channel with slightly shifted pixel values before it reached OCR. Save WebP lossless; other formats are unchanged. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a05afd654c
commit
c089bba32c
14 files changed
+151
-169
No files matched your search
@@ -9,11 +9,13 @@ from pathlib import Path
|
||||
from subprocess import CompletedProcess
|
||||
from subprocess import run
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import Any
|
||||
from typing import Generic
|
||||
from typing import TypeVar
|
||||
|
||||
from django.conf import settings
|
||||
from PIL import Image
|
||||
from PIL import ImageSequence
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from django.db.models import Model
|
||||
@@ -128,6 +130,32 @@ def maybe_override_pixel_limit() -> None:
|
||||
Image.MAX_IMAGE_PIXELS = pixel_count
|
||||
|
||||
|
||||
def remove_alpha_channel(source: Path, dest: Path) -> Path:
|
||||
"""
|
||||
Writes a copy of the image with its alpha channel dropped, keeping the
|
||||
format, every frame, the DPI and any ICC profile.
|
||||
|
||||
The channel is dropped, not composited, so transparent pixels keep their
|
||||
underlying color. Returns dest.
|
||||
"""
|
||||
with Image.open(source) as im:
|
||||
image_format = im.format
|
||||
opaque_mode = "L" if im.mode == "LA" else "RGB"
|
||||
frames = [frame.convert(opaque_mode) for frame in ImageSequence.Iterator(im)]
|
||||
save_kwargs: dict[str, Any] = {}
|
||||
if "dpi" in im.info:
|
||||
save_kwargs["dpi"] = im.info["dpi"]
|
||||
if "icc_profile" in im.info:
|
||||
save_kwargs["icc_profile"] = im.info["icc_profile"]
|
||||
if image_format == "WEBP":
|
||||
save_kwargs["lossless"] = True
|
||||
if len(frames) > 1:
|
||||
save_kwargs["save_all"] = True
|
||||
save_kwargs["append_images"] = frames[1:]
|
||||
frames[0].save(dest, format=image_format, **save_kwargs)
|
||||
return dest
|
||||
|
||||
|
||||
def run_subprocess(
|
||||
arguments: list[str],
|
||||
env: dict[str, str] | None = None,
|
||||
|
||||
Reference in new issue
Block a user