Merge branch 'RED-8212' into 'master'

RED-8212: fix tables for ocred documents

Closes RED-8212

See merge request redactmanager/commons/pdftron-logic-commons!19
This commit is contained in:
Kilian Schüttler 2024-01-23 10:50:09 +01:00
commit ab4a4619bc

View File

@ -8,13 +8,9 @@ import java.awt.geom.Rectangle2D;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import com.pdftron.common.PDFNetException; import com.pdftron.common.PDFNetException;
import com.pdftron.pdf.ColorPt; import com.pdftron.pdf.ColorPt;
@ -55,16 +51,17 @@ public class InvisibleElementRemovalService {
* -Any Text set to clipping with its many interactions with other elements * -Any Text set to clipping with its many interactions with other elements
* *
* @param pdfFile The PDF file to process * @param pdfFile The PDF file to process
* @param removePaths If this flag is set, invisible path elements will be removed
* @param delta If this flag is set only the removed Elements will be written to the output file. * @param delta If this flag is set only the removed Elements will be written to the output file.
* The Elements are red if they are removed by clipping path, blue for transparency, and a green bounding box for overlap. * The Elements are red if they are removed by clipping path, blue for transparency, and a green bounding box for overlap.
* @param out OutputStream to write the resulting file to * @param out OutputStream to write the resulting file to
**/ **/
@SneakyThrows @SneakyThrows
public void removeInvisibleElements(InputStream pdfFile, OutputStream out, boolean delta) { public void removeInvisibleElements(InputStream pdfFile, OutputStream out, boolean delta, boolean removePaths) {
PDFDoc pdfDoc = new PDFDoc(pdfFile); PDFDoc pdfDoc = new PDFDoc(pdfFile);
execute(pdfDoc, delta); execute(pdfDoc, delta, removePaths);
try { try {
pdfDoc.save(out, SDFDoc.SaveMode.LINEARIZED, null); pdfDoc.save(out, SDFDoc.SaveMode.LINEARIZED, null);
@ -79,17 +76,36 @@ public class InvisibleElementRemovalService {
/** /**
* This method is similar to {@link #removeInvisibleElements(InputStream, OutputStream, boolean)}, just with a PDFDoc. * This method is equal to {@link #removeInvisibleElements(InputStream, OutputStream, boolean, boolean)}, with removePaths == true.
*/
@SneakyThrows
public void removeInvisibleElements(InputStream pdfFile, OutputStream out, boolean delta) {
removeInvisibleElements(pdfFile, out, delta, true);
}
/**
* This method is similar to {@link #removeInvisibleElements(InputStream, OutputStream, boolean, boolean)}, just with a PDFDoc.
*/
@SneakyThrows
public void removeInvisibleElements(PDFDoc pdfDoc, boolean removePaths, boolean delta) {
execute(pdfDoc, delta, removePaths);
}
/**
* This method is equal to {@link #removeInvisibleElements(PDFDoc, boolean, boolean)}, with removePaths == true.
*/ */
@SneakyThrows @SneakyThrows
public void removeInvisibleElements(PDFDoc pdfDoc, boolean delta) { public void removeInvisibleElements(PDFDoc pdfDoc, boolean delta) {
execute(pdfDoc, delta); execute(pdfDoc, delta, true);
} }
@SneakyThrows @SneakyThrows
private void execute(PDFDoc pdfDoc, boolean delta) { private void execute(PDFDoc pdfDoc, boolean delta, boolean removePaths) {
log.info("Start removing invisible Elements"); log.info("Start removing invisible Elements");
ElementWriter writer = new ElementWriter(); ElementWriter writer = new ElementWriter();
@ -105,6 +121,7 @@ public class InvisibleElementRemovalService {
InvisibleElementRemovalContext context = InvisibleElementRemovalContext.builder() InvisibleElementRemovalContext context = InvisibleElementRemovalContext.builder()
.reader(reader) .reader(reader)
.clippingPathStack(new ClippingPathStack(page.getMediaBox())) .clippingPathStack(new ClippingPathStack(page.getMediaBox()))
.removePaths(removePaths)
.delta(delta) .delta(delta)
.overlappedElements(new ArrayList<>()) .overlappedElements(new ArrayList<>())
.visibleElements(new ArrayList<>()) .visibleElements(new ArrayList<>())
@ -297,11 +314,11 @@ public class InvisibleElementRemovalService {
context.visibleElements().removeAll(currentOverlappedElements); context.visibleElements().removeAll(currentOverlappedElements);
} }
context.visibleElements().add(ElementFeatureFactory.extractFeatures(pathElement)); context.visibleElements().add(ElementFeatureFactory.extractFeatures(pathElement));
if (!context.delta()) { if (!context.delta() || !context.removePaths()) {
writer.writeElement(pathElement); writer.writeElement(pathElement);
} }
} }
if (context.delta() && !inClippingPath) { if (context.delta() && !inClippingPath && context.removePaths()) {
pathElement.getGState().setFillColorSpace(ColorSpace.createDeviceRGB()); pathElement.getGState().setFillColorSpace(ColorSpace.createDeviceRGB());
pathElement.getGState().setFillColor(new ColorPt(1, 0, 0)); pathElement.getGState().setFillColor(new ColorPt(1, 0, 0));
pathElement.getGState().setStrokeColorSpace(ColorSpace.createDeviceRGB()); pathElement.getGState().setStrokeColorSpace(ColorSpace.createDeviceRGB());
@ -336,7 +353,22 @@ public class InvisibleElementRemovalService {
for (Element element = context.reader().next(); element != null; element = context.reader().next()) { for (Element element = context.reader().next(); element != null; element = context.reader().next()) {
switch (element.getType()) { switch (element.getType()) {
case Element.e_form -> processFormOverlappedElements(writer, element, context); case Element.e_form -> processFormOverlappedElements(writer, element, context);
case Element.e_path, Element.e_image, Element.e_inline_image, Element.e_text -> { case Element.e_image, Element.e_inline_image, Element.e_text -> removeOverlappedElement(writer, context, element);
case Element.e_path -> {
if (context.removePaths()) {
removeOverlappedElement(writer, context, element);
} else {
writer.writeElement(element);
}
}
default -> writer.writeElement(element);
}
}
}
private static void removeOverlappedElement(ElementWriter writer, InvisibleElementRemovalContext context, Element element) throws PDFNetException {
boolean anyMatch = false; boolean anyMatch = false;
for (ElementFeatures elementToRemove : context.overlappedElements()) { for (ElementFeatures elementToRemove : context.overlappedElements()) {
if (elementToRemove.almostMatches(element)) { if (elementToRemove.almostMatches(element)) {
@ -357,10 +389,6 @@ public class InvisibleElementRemovalService {
writer.writeGStateChanges(element); writer.writeGStateChanges(element);
} }
} }
default -> writer.writeElement(element);
}
}
}
private void processFormOverlappedElements(ElementWriter writer, Element formElement, InvisibleElementRemovalContext context) throws PDFNetException { private void processFormOverlappedElements(ElementWriter writer, Element formElement, InvisibleElementRemovalContext context) throws PDFNetException {
@ -490,6 +518,7 @@ public class InvisibleElementRemovalService {
@Builder @Builder
private record InvisibleElementRemovalContext( private record InvisibleElementRemovalContext(
boolean removePaths,
boolean delta, boolean delta,
ElementReader reader, ElementReader reader,
ClippingPathStack clippingPathStack, ClippingPathStack clippingPathStack,