diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 4aa9d56e7..c5bd4ec6c 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -64,8 +64,6 @@ ARG RUNTIME_PACKAGES="\ libmagic1 \ media-types \ zlib1g \ - # Barcode splitter - libzbar0 \ poppler-utils \ htop \ sudo" diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 0cd9a445e..1d4481a96 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -69,7 +69,6 @@ updates: patterns: - "ocrmypdf" - "pdf2image" - - "pyzbar" - "zxing-cpp" - "tika-client" - "gotenberg-client" diff --git a/.github/workflows/ci-backend.yml b/.github/workflows/ci-backend.yml index a4ffa06dc..85d1fe3a9 100644 --- a/.github/workflows/ci-backend.yml +++ b/.github/workflows/ci-backend.yml @@ -55,7 +55,7 @@ jobs: run: | sudo apt-get update -qq sudo apt-get install -qq --no-install-recommends \ - unpaper tesseract-ocr imagemagick ghostscript libzbar0 poppler-utils + unpaper tesseract-ocr imagemagick ghostscript poppler-utils - name: Configure ImageMagick run: | sudo cp docker/rootfs/etc/ImageMagick-6/paperless-policy.xml /etc/ImageMagick-6/policy.xml diff --git a/.mypy-baseline.txt b/.mypy-baseline.txt index 1f63f2023..1226f16a8 100644 --- a/.mypy-baseline.txt +++ b/.mypy-baseline.txt @@ -20,7 +20,6 @@ src/documents/admin.py:0: error: Skipping analyzing "auditlog.models": module is src/documents/admin.py:0: error: Skipping analyzing "treenode.admin": module is installed, but missing library stubs or py.typed marker [import-untyped] src/documents/barcodes.py:0: error: "Image" has no attribute "filename" [attr-defined] src/documents/barcodes.py:0: error: Cannot find implementation or library stub for module named "zxingcpp" [import-not-found] -src/documents/barcodes.py:0: error: Skipping analyzing "pyzbar": module is installed, but missing library stubs or py.typed marker [import-untyped] src/documents/bulk_download.py:0: error: Return type "None" of "add_document" incompatible with return type "Never" in supertype "BulkArchiveStrategy" [override] src/documents/bulk_download.py:0: error: Return type "None" of "add_document" incompatible with return type "Never" in supertype "BulkArchiveStrategy" [override] src/documents/bulk_download.py:0: error: Return type "None" of "add_document" incompatible with return type "Never" in supertype "BulkArchiveStrategy" [override] diff --git a/Dockerfile b/Dockerfile index d8c87a812..d0c377050 100644 --- a/Dockerfile +++ b/Dockerfile @@ -154,8 +154,6 @@ ARG RUNTIME_PACKAGES="\ libmagic1 \ media-types \ zlib1g \ - # Barcode splitter - libzbar0 \ poppler-utils" # Install basic runtime packages. diff --git a/docs/advanced_usage.md b/docs/advanced_usage.md index 638544005..6d0ec2b41 100644 --- a/docs/advanced_usage.md +++ b/docs/advanced_usage.md @@ -774,7 +774,6 @@ At this time, the library utilized for detection of barcodes supports the follow - QR Code - SQ Code -You may check for updates on the [zbar library homepage](https://github.com/mchehab/zbar). For usage in Paperless, the type of barcode does not matter, only the contents of it. For how to enable barcode usage, see [the configuration](configuration.md#barcodes). diff --git a/docs/configuration.md b/docs/configuration.md index 32d56408f..10b20fe9a 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1222,14 +1222,6 @@ using Python's `re.match()`, which anchors at the start of the filename. The default ignores are `[.stfolder, .stversions, .localized, @eaDir, .Spotlight-V100, .Trashes, __MACOSX]` and cannot be overridden. -#### [`PAPERLESS_CONSUMER_BARCODE_SCANNER=`](#PAPERLESS_CONSUMER_BARCODE_SCANNER) {#PAPERLESS_CONSUMER_BARCODE_SCANNER} - -: Sets the barcode scanner used for barcode functionality. - - Currently, "PYZBAR" (the default) or "ZXING" might be selected. - If you have problems that your Barcodes/QR-Codes are not detected - (especially with bad scan quality and/or small codes), try the other one. - #### [`PAPERLESS_PRE_CONSUME_SCRIPT=`](#PAPERLESS_PRE_CONSUME_SCRIPT) {#PAPERLESS_PRE_CONSUME_SCRIPT} : After some initial validation, Paperless can trigger an arbitrary diff --git a/docs/setup.md b/docs/setup.md index 13cf6a63d..2b83049c4 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -207,13 +207,12 @@ are released, dependency support is confirmed, etc. - `libpq-dev` for PostgreSQL - `libmagic-dev` for mime type detection - `mariadb-client` for MariaDB compile time - - `libzbar0` for barcode detection - `poppler-utils` for barcode detection Use this list for your preferred package management: ``` - python3 python3-pip python3-dev imagemagick fonts-liberation gnupg libpq-dev default-libmysqlclient-dev pkg-config libmagic-dev libzbar0 poppler-utils + python3 python3-pip python3-dev imagemagick fonts-liberation gnupg libpq-dev default-libmysqlclient-dev pkg-config libmagic-dev poppler-utils ``` These dependencies are required for OCRmyPDF, which is used for text diff --git a/pyproject.toml b/pyproject.toml index 04c2b0793..030c724f9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,7 +68,6 @@ dependencies = [ "python-gnupg~=0.5.4", "python-ipware~=3.0.0", "python-magic~=0.4.27", - "pyzbar~=0.1.9", "rapidfuzz~=3.14.0", "redis[hiredis]~=5.2.1", "regex>=2025.9.18", diff --git a/src/documents/barcodes.py b/src/documents/barcodes.py index 668b77547..31ef052c4 100644 --- a/src/documents/barcodes.py +++ b/src/documents/barcodes.py @@ -28,8 +28,6 @@ from documents.utils import maybe_override_pixel_limit from paperless.config import BarcodeConfig if TYPE_CHECKING: - from collections.abc import Callable - from PIL import Image logger = logging.getLogger("paperless.barcodes") @@ -262,26 +260,6 @@ class BarcodePlugin(ConsumeTaskPlugin): return barcodes - @staticmethod - def read_barcodes_pyzbar(image: Image.Image) -> list[str]: - barcodes = [] - - from pyzbar import pyzbar - - # Decode the barcode image - detected_barcodes = pyzbar.decode(image) - - # Traverse through all the detected barcodes in image - for barcode in detected_barcodes: - if barcode.data: - decoded_barcode = barcode.data.decode("utf-8") - barcodes.append(decoded_barcode) - logger.debug( - f"Barcode of type {barcode.type} found: {decoded_barcode}", - ) - - return barcodes - def detect(self) -> None: """ Scan all pages of the PDF as images, updating barcodes and the pages @@ -294,14 +272,6 @@ class BarcodePlugin(ConsumeTaskPlugin): # No op if not a TIFF self.convert_from_tiff_to_pdf() - # Choose the library for reading - if settings.CONSUMER_BARCODE_SCANNER == "PYZBAR": - reader: Callable[[Image.Image], list[str]] = self.read_barcodes_pyzbar - logger.debug("Scanning for barcodes using PYZBAR") - else: - reader = self.read_barcodes_zxing - logger.debug("Scanning for barcodes using ZXING") - try: # Read number of pages from pdf with Pdf.open(self.pdf_file) as pdf: @@ -349,7 +319,7 @@ class BarcodePlugin(ConsumeTaskPlugin): ) # Detect barcodes - for barcode_value in reader(page): + for barcode_value in self.read_barcodes_zxing(page): self.barcodes.append( Barcode(current_page_number, barcode_value, self.settings), ) diff --git a/src/documents/tests/test_barcodes.py b/src/documents/tests/test_barcodes.py index d7dab5a2d..fca1e4908 100644 --- a/src/documents/tests/test_barcodes.py +++ b/src/documents/tests/test_barcodes.py @@ -4,7 +4,6 @@ from contextlib import contextmanager from pathlib import Path from unittest import mock -import pytest from django.conf import settings from django.test import TestCase from django.test import override_settings @@ -25,13 +24,6 @@ from documents.tests.utils import FileSystemAssertsMixin from documents.tests.utils import SampleDirMixin from paperless.models import ApplicationConfiguration -try: - import zxingcpp # noqa: F401 - - HAS_ZXING_LIB = True -except ImportError: - HAS_ZXING_LIB = False - class GetReaderPluginMixin: @contextmanager @@ -48,7 +40,6 @@ class GetReaderPluginMixin: reader.cleanup() -@override_settings(CONSUMER_BARCODE_SCANNER="PYZBAR") class TestBarcode( DirectoriesMixin, FileSystemAssertsMixin, @@ -606,7 +597,6 @@ class TestBarcode( self.assertDictEqual(separator_page_numbers, {0: False}) -@override_settings(CONSUMER_BARCODE_SCANNER="PYZBAR") class TestBarcodeNewConsume( DirectoriesMixin, FileSystemAssertsMixin, @@ -784,14 +774,12 @@ class TestAsnBarcode(DirectoriesMixin, SampleDirMixin, GetReaderPluginMixin, Tes self.assertEqual(document.archive_serial_number, 123) - @override_settings(CONSUMER_BARCODE_SCANNER="PYZBAR") def test_scan_file_for_qrcode_without_upscale(self) -> None: """ GIVEN: - A printed and scanned PDF document with a rather small QR code WHEN: - ASN barcode detection is run with default settings - - pyzbar is used for detection, as zxing would behave differently, and detect the QR code THEN: - ASN is not detected """ @@ -802,7 +790,6 @@ class TestAsnBarcode(DirectoriesMixin, SampleDirMixin, GetReaderPluginMixin, Tes reader.detect() self.assertEqual(len(reader.barcodes), 0) - @override_settings(CONSUMER_BARCODE_SCANNER="PYZBAR") @override_settings(CONSUMER_BARCODE_DPI=600) @override_settings(CONSUMER_BARCODE_UPSCALE=1.5) def test_scan_file_for_qrcode_with_upscale(self) -> None: @@ -810,9 +797,7 @@ class TestAsnBarcode(DirectoriesMixin, SampleDirMixin, GetReaderPluginMixin, Tes GIVEN: - A printed and scanned PDF document with a rather small QR code WHEN: - - ASN barcode detection is run with 600dpi and an upscale factor of 1.5 and pyzbar - - pyzbar is used for detection, as zxing would behave differently. - Upscaling is a workaround for detection problems with pyzbar, + - ASN barcode detection is run with 600dpi and an upscale factor of 1.5 when you cannot switch to zxing (aarch64 build problems of zxing) THEN: - ASN 123 is detected @@ -826,24 +811,6 @@ class TestAsnBarcode(DirectoriesMixin, SampleDirMixin, GetReaderPluginMixin, Tes self.assertEqual(reader.asn, 123) -@pytest.mark.skipif( - not HAS_ZXING_LIB, - reason="No zxingcpp", -) -@override_settings(CONSUMER_BARCODE_SCANNER="ZXING") -class TestBarcodeZxing(TestBarcode): - pass - - -@pytest.mark.skipif( - not HAS_ZXING_LIB, - reason="No zxingcpp", -) -@override_settings(CONSUMER_BARCODE_SCANNER="ZXING") -class TestAsnBarcodesZxing(TestAsnBarcode): - pass - - class TestTagBarcode(DirectoriesMixin, SampleDirMixin, GetReaderPluginMixin, TestCase): @contextmanager def get_reader(self, filepath: Path) -> BarcodePlugin: diff --git a/src/paperless/checks.py b/src/paperless/checks.py index 29d35f76b..7df85d146 100644 --- a/src/paperless/checks.py +++ b/src/paperless/checks.py @@ -167,17 +167,6 @@ def settings_values_check(app_configs, **kwargs): ) return msgs - def _barcode_scanner_validate(): - """ - Validates the barcode scanner type - """ - msgs = [] - if settings.CONSUMER_BARCODE_SCANNER not in ["PYZBAR", "ZXING"]: - msgs.append( - Error(f'Invalid Barcode Scanner "{settings.CONSUMER_BARCODE_SCANNER}"'), - ) - return msgs - def _email_certificate_validate(): msgs = [] # Existence checks @@ -195,7 +184,6 @@ def settings_values_check(app_configs, **kwargs): return ( _ocrmypdf_settings_check() + _timezone_validate() - + _barcode_scanner_validate() + _email_certificate_validate() ) diff --git a/src/paperless/settings.py b/src/paperless/settings.py index 490727e8f..910d206c1 100644 --- a/src/paperless/settings.py +++ b/src/paperless/settings.py @@ -1106,11 +1106,6 @@ CONSUMER_BARCODE_STRING: Final[str] = os.getenv( "PATCHT", ) -CONSUMER_BARCODE_SCANNER: Final[str] = os.getenv( - "PAPERLESS_CONSUMER_BARCODE_SCANNER", - "PYZBAR", -).upper() - CONSUMER_ENABLE_ASN_BARCODE: Final[bool] = __get_boolean( "PAPERLESS_CONSUMER_ENABLE_ASN_BARCODE", ) diff --git a/src/paperless/tests/test_checks.py b/src/paperless/tests/test_checks.py index 30fdde182..25bb07d22 100644 --- a/src/paperless/tests/test_checks.py +++ b/src/paperless/tests/test_checks.py @@ -206,11 +206,6 @@ class TestBarcodeSettingsChecks(DirectoriesMixin, TestCase): self.assertIn('Invalid Barcode Scanner ""', msg.msg) - @override_settings(CONSUMER_BARCODE_SCANNER="PYZBAR") - def test_barcode_scanner_valid(self) -> None: - msgs = settings_values_check(None) - self.assertEqual(len(msgs), 0) - class TestEmailCertSettingsChecks(DirectoriesMixin, FileSystemAssertsMixin, TestCase): @override_settings(EMAIL_CERTIFICATE_FILE=Path("/tmp/not_actually_here.pem")) diff --git a/uv.lock b/uv.lock index 2ff50455b..b601fcd30 100644 --- a/uv.lock +++ b/uv.lock @@ -3073,7 +3073,6 @@ dependencies = [ { name = "python-gnupg", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, { name = "python-ipware", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, { name = "python-magic", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, - { name = "pyzbar", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, { name = "rapidfuzz", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, { name = "redis", extra = ["hiredis"], marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, { name = "regex", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, @@ -3226,7 +3225,6 @@ requires-dist = [ { name = "python-gnupg", specifier = "~=0.5.4" }, { name = "python-ipware", specifier = "~=3.0.0" }, { name = "python-magic", specifier = "~=0.4.27" }, - { name = "pyzbar", specifier = "~=0.1.9" }, { name = "rapidfuzz", specifier = "~=3.14.0" }, { name = "redis", extras = ["hiredis"], specifier = "~=5.2.1" }, { name = "regex", specifier = ">=2025.9.18" }, @@ -4279,14 +4277,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, ] -[[package]] -name = "pyzbar" -version = "0.1.9" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/24/81ebe6a1c00760471a3028a23cbe0b94e5fa2926e5ba47adc895920887bc/pyzbar-0.1.9-py2.py3-none-any.whl", hash = "sha256:4559628b8192feb25766d954b36a3753baaf5c97c03135aec7e4a026036b475d", size = 32560, upload-time = "2022-03-15T14:53:40.637Z" }, -] - [[package]] name = "qrcode" version = "8.2"