This is an automated email from the ASF dual-hosted git repository.

tballison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tika.git


The following commit(s) were added to refs/heads/main by this push:
     new b7e329a9ce TIKA-4862 - add compression/image quality setting to 
PDFBoxRenderer (#3103)
b7e329a9ce is described below

commit b7e329a9cebf8fe885be7a4b30cd0d150952d73f
Author: Tim Allison <[email protected]>
AuthorDate: Mon Aug 31 09:46:21 2026 -0400

    TIKA-4862 - add compression/image quality setting to PDFBoxRenderer (#3103)
---
 CHANGES.txt                                        |  7 +-
 .../java/org/apache/tika/parser/pdf/OcrConfig.java |  7 +-
 .../tika/renderer/pdf/pdfbox/PDFBoxRenderer.java   | 22 ++++++-
 .../renderer/pdf/pdfbox/PDFBoxRendererTest.java    | 75 ++++++++++++++++++++++
 4 files changed, 105 insertions(+), 6 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index cfc2c66ea6..595ca638b8 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,10 +1,9 @@
 Release 4.1.0 - unreleased
 
+   * Allow image compression settings in PDFBox-based renderer (TIKA-4862).
+     
    * The tika-server full and tika-grpc Docker images set OMP_THREAD_LIMIT=1:
-     the distro tesseract links OpenMP and runs up to 4 threads per OCR
-     process, which oversubscribes the CPU under forked parse workers;
-     single-threaded tesseract with process-level parallelism is the
-     tesseract project's guidance for servers (TIKA-XXXX).
+     to avoid oversubscribing the CPU under forked parse workers (TIKA-4863).
 
    * embedded-limits maxDepth counts embedding levels again instead of the
      parsers a parse passes through; with AutoDetectParser over DefaultParser
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/main/java/org/apache/tika/parser/pdf/OcrConfig.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/main/java/org/apache/tika/parser/pdf/OcrConfig.java
index 45454b7275..0b54b7b5a2 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/main/java/org/apache/tika/parser/pdf/OcrConfig.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/main/java/org/apache/tika/parser/pdf/OcrConfig.java
@@ -121,7 +121,12 @@ public class OcrConfig implements Serializable {
     private int dpi = 300;
     private ImageType imageType = ImageType.GRAY;
     private ImageFormat imageFormat = ImageFormat.PNG;
-    private float imageQuality = 1.0f;
+    /**
+     * Compression quality handed to ImageIO when writing rendered pages. For 
PNG this is
+     * an inverted effort knob, not fidelity: 1.0 writes an uncompressed file, 
0.0 spends
+     * ~10x the time of 0.5 for a few percent smaller output. PNG is always 
lossless.
+     */
+    private float imageQuality = 0.5f;
 
     /**
      * Maximum total pixels (width &times; height) allowed for a rendered
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/main/java/org/apache/tika/renderer/pdf/pdfbox/PDFBoxRenderer.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/main/java/org/apache/tika/renderer/pdf/pdfbox/PDFBoxRenderer.java
index 4307342458..3e26a13dda 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/main/java/org/apache/tika/renderer/pdf/pdfbox/PDFBoxRenderer.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/main/java/org/apache/tika/renderer/pdf/pdfbox/PDFBoxRenderer.java
@@ -90,6 +90,13 @@ public class PDFBoxRenderer implements PDDocumentRenderer {
     private ImageType defaultImageType = ImageType.GRAY;
     private String defaultImageFormatName = "png";
 
+    /**
+     * ImageIO's "compression quality"; for PNG it is an inverted effort knob:
+     * 1.0 writes an uncompressed file, 0.0 spends ~10x the time of the 
default for a
+     * few percent smaller output. 0.5 is both fast and small.
+     */
+    private float defaultImageQuality = 0.5f;
+
 
     @Override
     public RenderResults render(TikaInputStream tis, Metadata metadata, 
ParseContext parseContext,
@@ -185,7 +192,8 @@ public class PDFBoxRenderer implements PDDocumentRenderer {
             metadata.set(PDFBOX_RENDERING_TIME_MS, renderingElapsed);
             start = System.currentTimeMillis();
             try (OutputStream os = Files.newOutputStream(tmpFile)) {
-                ImageIOUtil.writeImage(image, 
getImageFormatName(parseContext), os, getDPI(parseContext));
+                ImageIOUtil.writeImage(image, 
getImageFormatName(parseContext), os, getDPI(parseContext),
+                        getImageQuality(parseContext));
             }
             long elapsedWrite = System.currentTimeMillis() - start;
             metadata.set(PDFBOX_IMAGE_WRITING_TIME_MS, elapsedWrite);
@@ -216,6 +224,18 @@ public class PDFBoxRenderer implements PDDocumentRenderer {
         this.defaultImageFormatName = imageFormatName;
     }
 
+    public void setImageQuality(float imageQuality) {
+        this.defaultImageQuality = imageQuality;
+    }
+
+    protected float getImageQuality(ParseContext parseContext) {
+        PDFParserConfig pdfParserConfig = 
parseContext.get(PDFParserConfig.class);
+        if (pdfParserConfig == null) {
+            return defaultImageQuality;
+        }
+        return pdfParserConfig.getOcr().getImageQuality();
+    }
+
     protected int getDPI(ParseContext parseContext) {
         PDFParserConfig pdfParserConfig = 
parseContext.get(PDFParserConfig.class);
         if (pdfParserConfig == null) {
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/test/java/org/apache/tika/renderer/pdf/pdfbox/PDFBoxRendererTest.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/test/java/org/apache/tika/renderer/pdf/pdfbox/PDFBoxRendererTest.java
new file mode 100644
index 0000000000..0bcf1dc396
--- /dev/null
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/test/java/org/apache/tika/renderer/pdf/pdfbox/PDFBoxRendererTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.renderer.pdf.pdfbox;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.InputStream;
+
+import org.junit.jupiter.api.Test;
+
+import org.apache.tika.io.TikaInputStream;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.parser.ParseContext;
+import org.apache.tika.parser.pdf.PDFParserConfig;
+import org.apache.tika.renderer.PageBasedRenderResults;
+import org.apache.tika.renderer.PageRangeRequest;
+import org.apache.tika.renderer.RenderResult;
+
+public class PDFBoxRendererTest {
+
+    private long renderedPngBytes(ParseContext context) throws Exception {
+        PDFBoxRenderer renderer = new PDFBoxRenderer();
+        try (InputStream is = 
getClass().getResourceAsStream("/test-documents/testPDF.pdf");
+             TikaInputStream tis = TikaInputStream.get(is)) {
+            assertNotNull(is);
+            PageBasedRenderResults results = (PageBasedRenderResults) 
renderer.render(
+                    tis, new Metadata(), context, new PageRangeRequest(1, 1));
+            RenderResult r = results.getResults().get(0);
+            assertEquals(RenderResult.STATUS.SUCCESS, r.getStatus());
+            try (TikaInputStream img = r.getInputStream()) {
+                byte[] b = img.readAllBytes();
+                assertEquals((byte) 0x89, b[0]);
+                assertEquals((byte) 'P', b[1]);
+                results.close();
+                return b.length;
+            }
+        }
+    }
+
+    @Test
+    public void testPngCompressedByDefault() throws Exception {
+        // letter page, 300 dpi gray: raw raster ~8.5 MB; compressed must be 
far smaller
+        long bytes = renderedPngBytes(new ParseContext());
+        assertTrue(bytes < 2_000_000, "default render should be a compressed 
PNG, got " + bytes);
+    }
+
+    @Test
+    public void testImageQualityConfigurable() throws Exception {
+        // ImageIO's PNG "quality" 1.0 = uncompressed; proves the config 
reaches the writer
+        PDFParserConfig config = new PDFParserConfig();
+        config.getOcr().setImageQuality(1.0f);
+        ParseContext context = new ParseContext();
+        context.set(PDFParserConfig.class, config);
+        long uncompressed = renderedPngBytes(context);
+        long compressed = renderedPngBytes(new ParseContext());
+        assertTrue(uncompressed > compressed * 4,
+                "quality 1.0 should be far larger: " + uncompressed + " vs " + 
compressed);
+    }
+}

Reply via email to