From 931f5f9c275f7bd034a5788ef3822afaf8ab92ec Mon Sep 17 00:00:00 2001 From: Bastian Machek <16717398+bmachek@users.noreply.github.com> Date: Tue, 27 Jun 2023 19:18:47 +0200 Subject: [PATCH] Feature: support barcode upscaling for better detection of small barcodes (#3655) --- docs/configuration.md | 21 +++++++++ paperless.conf.example | 2 + src/documents/barcodes.py | 12 ++++- .../barcode-qr-asn-000123-upscale-dpi.pdf | Bin 0 -> 39348 bytes src/documents/tests/test_barcodes.py | 41 ++++++++++++++++++ src/paperless/settings.py | 10 +++++ 6 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 src/documents/tests/samples/barcodes/barcode-qr-asn-000123-upscale-dpi.pdf diff --git a/docs/configuration.md b/docs/configuration.md index d3874256f..722db8a4b 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1095,6 +1095,27 @@ barcode. Defaults to "ASN" +`PAPERLESS_CONSUMER_BARCODE_UPSCALE=` + +: Defines the upscale factor used in barcode detection. +Improves the detection of small barcodes, i.e. with a value of 1.5 by +upscaling the document beforce the detection process. Upscaling will +only take place if value is bigger than 1.0. Otherwise upscaling will +not be performed to save resources. Try using in combination with +PAPERLESS_CONSUMER_BARCODE_DPI set to a value higher than default. + + Defaults to 0.0 + +`PAPERLESS_CONSUMER_BARCODE_DPI=` + +: During barcode detection every page from a PDF document needs +to be converted to an image. A dpi value can be specified in the +conversion process. Default is 300. If the detection of small barcodes +fails a bigger dpi value i.e. 600 can fix the issue. Try using in +combination with PAPERLESS_CONSUMER_BARCODE_UPSCALE bigger than 1.0. + + Defaults to "300" + ## Binaries There are a few external software packages that Paperless expects to diff --git a/paperless.conf.example b/paperless.conf.example index 6bd70697e..9b168db0c 100644 --- a/paperless.conf.example +++ b/paperless.conf.example @@ -66,6 +66,8 @@ #PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS=false #PAPERLESS_CONSUMER_ENABLE_BARCODES=false #PAPERLESS_CONSUMER_BARCODE_STRING=PATCHT +#PAPERLESS_CONSUMER_BARCODE_UPSCALE=0.0 +#PAPERLESS_CONSUMER_BARCODE_DPI=300 #PAPERLESS_PRE_CONSUME_SCRIPT=/path/to/an/arbitrary/script.sh #PAPERLESS_POST_CONSUME_SCRIPT=/path/to/an/arbitrary/script.sh #PAPERLESS_FILENAME_DATE_ORDER=YMD diff --git a/src/documents/barcodes.py b/src/documents/barcodes.py index f3d59bc5b..3650593ae 100644 --- a/src/documents/barcodes.py +++ b/src/documents/barcodes.py @@ -203,11 +203,21 @@ class BarcodeReader: try: pages_from_path = convert_from_path( self.pdf_file, - dpi=300, + dpi=settings.CONSUMER_BARCODE_DPI, output_folder=self.temp_dir.name, ) for current_page_number, page in enumerate(pages_from_path): + factor = settings.CONSUMER_BARCODE_UPSCALE + if factor > 1.0: + logger.debug( + f"Upscaling image by {factor} for better barcode detection", + ) + x, y = page.size + page = page.resize( + (int(round(x * factor)), (int(round(y * factor)))), + ) + for barcode_value in reader(page): self.barcodes.append( Barcode(current_page_number, barcode_value), diff --git a/src/documents/tests/samples/barcodes/barcode-qr-asn-000123-upscale-dpi.pdf b/src/documents/tests/samples/barcodes/barcode-qr-asn-000123-upscale-dpi.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3d6d8eacbee9710b667bf216ac39c2df083df3a0 GIT binary patch literal 39348 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 TV-tnN#l^%4+1Zt05W@cfwc`1x literal 0 HcmV?d00001 diff --git a/src/documents/tests/test_barcodes.py b/src/documents/tests/test_barcodes.py index eda97554d..70f7807cc 100644 --- a/src/documents/tests/test_barcodes.py +++ b/src/documents/tests/test_barcodes.py @@ -906,6 +906,47 @@ class TestAsnBarcode(DirectoriesMixin, TestCase): input_doc, ) + @override_settings(CONSUMER_BARCODE_SCANNER="PYZBAR") + def test_scan_file_for_qrcode_without_upscale(self): + """ + 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 + """ + + test_file = self.BARCODE_SAMPLE_DIR / "barcode-qr-asn-000123-upscale-dpi.pdf" + + with BarcodeReader(test_file, "application/pdf") as reader: + 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): + """ + 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, + when you cannot switch to zxing (aarch64 build problems of zxing) + THEN: + - ASN 123 is detected + """ + + test_file = self.BARCODE_SAMPLE_DIR / "barcode-qr-asn-000123-upscale-dpi.pdf" + + with BarcodeReader(test_file, "application/pdf") as reader: + reader.detect() + self.assertEqual(len(reader.barcodes), 1) + self.assertEqual(reader.asn, 123) + @pytest.mark.skipif( not HAS_ZXING_LIB, diff --git a/src/paperless/settings.py b/src/paperless/settings.py index ab33e6b1a..2b7a32091 100644 --- a/src/paperless/settings.py +++ b/src/paperless/settings.py @@ -781,6 +781,16 @@ CONSUMER_ASN_BARCODE_PREFIX: Final[str] = os.getenv( ) +CONSUMER_BARCODE_UPSCALE: Final[float] = float( + os.getenv("PAPERLESS_CONSUMER_BARCODE_UPSCALE", 0.0), +) + + +CONSUMER_BARCODE_DPI: Final[str] = int( + os.getenv("PAPERLESS_CONSUMER_BARCODE_DPI", 300), +) + + OCR_PAGES = int(os.getenv("PAPERLESS_OCR_PAGES", 0)) # The default language that tesseract will attempt to use when parsing