commit for feature developing invert-replace color of a pdf for stirl… (#1982)
commit for feature developing invert-replace color of a pdf for stirling PDF
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
package stirling.software.SPDF.utils.misc;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.pdfbox.Loader;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||
import org.apache.pdfbox.pdmodel.PDPageTree;
|
||||
import org.apache.pdfbox.pdmodel.font.*;
|
||||
import org.apache.pdfbox.text.TextPosition;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import stirling.software.SPDF.model.api.misc.HighContrastColorCombination;
|
||||
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert;
|
||||
|
||||
public class CustomColorReplaceStrategy extends ReplaceAndInvertColorStrategy {
|
||||
|
||||
private String textColor;
|
||||
private String backgroundColor;
|
||||
private HighContrastColorCombination highContrastColorCombination;
|
||||
|
||||
public CustomColorReplaceStrategy(
|
||||
MultipartFile file,
|
||||
ReplaceAndInvert replaceAndInvert,
|
||||
String textColor,
|
||||
String backgroundColor,
|
||||
HighContrastColorCombination highContrastColorCombination) {
|
||||
super(file, replaceAndInvert);
|
||||
this.textColor = textColor;
|
||||
this.backgroundColor = backgroundColor;
|
||||
this.highContrastColorCombination = highContrastColorCombination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStreamResource replace() throws IOException {
|
||||
|
||||
// If ReplaceAndInvert is HighContrastColor option, then get the colors of text and
|
||||
// background from static
|
||||
if (replaceAndInvert == ReplaceAndInvert.HIGH_CONTRAST_COLOR) {
|
||||
String[] colors =
|
||||
HighContrastColorReplaceDecider.getColors(
|
||||
replaceAndInvert, highContrastColorCombination);
|
||||
this.textColor = colors[0];
|
||||
this.backgroundColor = colors[1];
|
||||
}
|
||||
|
||||
// Create a temporary file, with the original filename from the multipart file
|
||||
File file = File.createTempFile("temp", getFileInput().getOriginalFilename());
|
||||
|
||||
// Transfer the content of the multipart file to the file
|
||||
getFileInput().transferTo(file);
|
||||
|
||||
try (PDDocument document = Loader.loadPDF(file)) {
|
||||
|
||||
PDPageTree pages = document.getPages();
|
||||
|
||||
for (PDPage page : pages) {
|
||||
|
||||
PdfTextStripperCustom pdfTextStripperCustom = new PdfTextStripperCustom();
|
||||
// Get text positions
|
||||
List<List<TextPosition>> charactersByArticle =
|
||||
pdfTextStripperCustom.processPageCustom(page);
|
||||
|
||||
// Begin a new content stream
|
||||
PDPageContentStream contentStream =
|
||||
new PDPageContentStream(
|
||||
document, page, PDPageContentStream.AppendMode.APPEND, true, true);
|
||||
|
||||
// Set the new text color
|
||||
contentStream.setNonStrokingColor(Color.decode(this.textColor));
|
||||
|
||||
// Draw the text with the new color
|
||||
for (List<TextPosition> textPositions : charactersByArticle) {
|
||||
for (TextPosition text : textPositions) {
|
||||
// Move to the text position
|
||||
contentStream.beginText();
|
||||
contentStream.newLineAtOffset(
|
||||
text.getX(), page.getMediaBox().getHeight() - text.getY());
|
||||
PDFont font = null;
|
||||
String unicodeText = text.getUnicode();
|
||||
try {
|
||||
font = PDFontFactory.createFont(text.getFont().getCOSObject());
|
||||
} catch (IOException io) {
|
||||
System.out.println("Primary font not found, using fallback font.");
|
||||
font = new PDType1Font(Standard14Fonts.FontName.HELVETICA);
|
||||
}
|
||||
// if a character is not supported by font, then look for supported font
|
||||
try {
|
||||
byte[] bytes = font.encode(unicodeText);
|
||||
} catch (IOException io) {
|
||||
System.out.println("text could not be encoded ");
|
||||
font = checkSupportedFontForCharacter(unicodeText);
|
||||
} catch (IllegalArgumentException ie) {
|
||||
System.out.println("text not supported by font ");
|
||||
font = checkSupportedFontForCharacter(unicodeText);
|
||||
} finally {
|
||||
// if any other font is not supported, then replace default character *
|
||||
if (font == null) {
|
||||
font = new PDType1Font(Standard14Fonts.FontName.HELVETICA);
|
||||
unicodeText = "*";
|
||||
}
|
||||
}
|
||||
contentStream.setFont(font, text.getFontSize());
|
||||
contentStream.showText(unicodeText);
|
||||
contentStream.endText();
|
||||
}
|
||||
}
|
||||
// Close the content stream
|
||||
contentStream.close();
|
||||
// Use a content stream to overlay the background color
|
||||
try (PDPageContentStream contentStreamBg =
|
||||
new PDPageContentStream(
|
||||
document,
|
||||
page,
|
||||
PDPageContentStream.AppendMode.PREPEND,
|
||||
true,
|
||||
true)) {
|
||||
// Set background color (e.g., light yellow)
|
||||
contentStreamBg.setNonStrokingColor(Color.decode(this.backgroundColor));
|
||||
contentStreamBg.addRect(
|
||||
0, 0, page.getMediaBox().getWidth(), page.getMediaBox().getHeight());
|
||||
contentStreamBg.fill();
|
||||
}
|
||||
}
|
||||
// Save the modified PDF to a ByteArrayOutputStream
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
document.save(byteArrayOutputStream);
|
||||
document.close();
|
||||
|
||||
// Prepare the modified PDF for download
|
||||
ByteArrayInputStream inputStream =
|
||||
new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
|
||||
InputStreamResource resource = new InputStreamResource(inputStream);
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
|
||||
private PDFont checkSupportedFontForCharacter(String unicodeText) {
|
||||
|
||||
Set<String> fonts = Standard14Fonts.getNames();
|
||||
for (String font : fonts) {
|
||||
Standard14Fonts.FontName fontName = Standard14Fonts.getMappedFontName(font);
|
||||
PDFont currentFont = new PDType1Font(fontName);
|
||||
try {
|
||||
byte[] bytes = currentFont.encode(unicodeText);
|
||||
return currentFont;
|
||||
} catch (IOException io) {
|
||||
System.out.println("text could not be encoded ");
|
||||
} catch (IllegalArgumentException ie) {
|
||||
System.out.println("text not supported by font ");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package stirling.software.SPDF.utils.misc;
|
||||
|
||||
import stirling.software.SPDF.model.api.misc.HighContrastColorCombination;
|
||||
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert;
|
||||
|
||||
public class HighContrastColorReplaceDecider {
|
||||
|
||||
// To decide the text and background colors for High contrast color option for replace-invert
|
||||
// color feature
|
||||
public static String[] getColors(
|
||||
ReplaceAndInvert replaceAndInvert,
|
||||
HighContrastColorCombination highContrastColorCombination) {
|
||||
|
||||
if (highContrastColorCombination == HighContrastColorCombination.BLACK_TEXT_ON_WHITE) {
|
||||
return new String[] {"0", "16777215"};
|
||||
} else if (highContrastColorCombination
|
||||
== HighContrastColorCombination.GREEN_TEXT_ON_BLACK) {
|
||||
return new String[] {"65280", "0"};
|
||||
} else if (highContrastColorCombination
|
||||
== HighContrastColorCombination.WHITE_TEXT_ON_BLACK) {
|
||||
return new String[] {"16777215", "0"};
|
||||
} else if (highContrastColorCombination
|
||||
== HighContrastColorCombination.YELLOW_TEXT_ON_BLACK) {
|
||||
|
||||
return new String[] {"16776960", "0"};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package stirling.software.SPDF.utils.misc;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.apache.pdfbox.Loader;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert;
|
||||
|
||||
public class InvertFullColorStrategy extends ReplaceAndInvertColorStrategy {
|
||||
|
||||
public InvertFullColorStrategy(MultipartFile file, ReplaceAndInvert replaceAndInvert) {
|
||||
super(file, replaceAndInvert);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStreamResource replace() throws IOException {
|
||||
|
||||
// Create a temporary file, with the original filename from the multipart file
|
||||
File file = File.createTempFile("temp", getFileInput().getOriginalFilename());
|
||||
|
||||
// Transfer the content of the multipart file to the file
|
||||
getFileInput().transferTo(file);
|
||||
|
||||
// Load the uploaded PDF
|
||||
PDDocument document = Loader.loadPDF(file);
|
||||
|
||||
// Render each page and invert colors
|
||||
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
||||
for (int page = 0; page < document.getNumberOfPages(); page++) {
|
||||
BufferedImage image =
|
||||
pdfRenderer.renderImageWithDPI(page, 300); // Render page at 300 DPI
|
||||
|
||||
// Invert the colors
|
||||
invertImageColors(image);
|
||||
|
||||
// Create a new PDPage from the inverted image
|
||||
PDPage pdPage = document.getPage(page);
|
||||
PDImageXObject pdImage =
|
||||
PDImageXObject.createFromFileByContent(
|
||||
convertToBufferedImageTpFile(image), document);
|
||||
|
||||
PDPageContentStream contentStream =
|
||||
new PDPageContentStream(
|
||||
document, pdPage, PDPageContentStream.AppendMode.OVERWRITE, true);
|
||||
contentStream.drawImage(
|
||||
pdImage,
|
||||
0,
|
||||
0,
|
||||
pdPage.getMediaBox().getWidth(),
|
||||
pdPage.getMediaBox().getHeight());
|
||||
contentStream.close();
|
||||
}
|
||||
|
||||
// Save the modified PDF to a ByteArrayOutputStream
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
document.save(byteArrayOutputStream);
|
||||
document.close();
|
||||
|
||||
// Prepare the modified PDF for download
|
||||
ByteArrayInputStream inputStream =
|
||||
new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
|
||||
InputStreamResource resource = new InputStreamResource(inputStream);
|
||||
return resource;
|
||||
}
|
||||
|
||||
// Method to invert image colors
|
||||
private void invertImageColors(BufferedImage image) {
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
int rgba = image.getRGB(x, y);
|
||||
Color color = new Color(rgba, true);
|
||||
Color invertedColor =
|
||||
new Color(
|
||||
255 - color.getRed(),
|
||||
255 - color.getGreen(),
|
||||
255 - color.getBlue());
|
||||
image.setRGB(x, y, invertedColor.getRGB());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method to convert BufferedImage to InputStream
|
||||
private File convertToBufferedImageTpFile(BufferedImage image) throws IOException {
|
||||
File file = new File("image.png");
|
||||
ImageIO.write(image, "png", file);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package stirling.software.SPDF.utils.misc;
|
||||
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.text.PDFTextStripperByArea;
|
||||
import org.apache.pdfbox.text.TextPosition;
|
||||
|
||||
public class PdfTextStripperCustom extends PDFTextStripperByArea {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @throws IOException If there is an error loading properties.
|
||||
*/
|
||||
public PdfTextStripperCustom() throws IOException {}
|
||||
|
||||
// To process the page text using stripper and returns the TextPosition and its values
|
||||
public List<List<TextPosition>> processPageCustom(PDPage page) throws IOException {
|
||||
|
||||
addRegion(
|
||||
"wholePage",
|
||||
new Rectangle2D.Float(
|
||||
page.getMediaBox().getLowerLeftX(),
|
||||
page.getMediaBox().getLowerLeftY(),
|
||||
page.getMediaBox().getWidth(),
|
||||
page.getMediaBox().getHeight()));
|
||||
extractRegions(page);
|
||||
|
||||
List<List<TextPosition>> textPositions = getCharactersByArticle();
|
||||
|
||||
return textPositions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package stirling.software.SPDF.utils.misc;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import lombok.Data;
|
||||
import stirling.software.SPDF.model.api.PDFFile;
|
||||
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert;
|
||||
|
||||
@Data
|
||||
// @EqualsAndHashCode(callSuper = true)
|
||||
public abstract class ReplaceAndInvertColorStrategy extends PDFFile {
|
||||
|
||||
protected ReplaceAndInvert replaceAndInvert;
|
||||
|
||||
public ReplaceAndInvertColorStrategy(MultipartFile file, ReplaceAndInvert replaceAndInvert) {
|
||||
setFileInput(file);
|
||||
setReplaceAndInvert(replaceAndInvert);
|
||||
}
|
||||
|
||||
public abstract InputStreamResource replace() throws IOException;
|
||||
}
|
||||
Reference in New Issue
Block a user