Save BufferedImages as TIFF - java

I´m trying to save a BufferedImage as TIFF. This works fine, but it's taking too long per TIFF, up to 5 sec. 5 sec might not sound like much, but if you want to save up to 20 images it´s too long.
Here is my code:
public void convertToTif() throws ConvertionFailedException {
final int dpi = 300;
try {
ImageOutputStream ios = null;
TIFFImageWriterSpi tiffspi = new TIFFImageWriterSpi();
ImageWriter writer = tiffspi.createWriterInstance();
// setup writer
ios = ImageIO.createImageOutputStream(this.tifFile);
writer.setOutput(ios);
BufferedImage tiffImage = create1BitTif(this.imageToConvert);
// get new Metadata
ImageTypeSpecifier imageType = ImageTypeSpecifier.createFromBufferedImageType(tiffImage.getType());
IIOMetadata imageMetadata = writer.getDefaultImageMetadata(imageType, null);
TIFFDirectory dir = TIFFDirectory.createFromMetadata(imageMetadata);
BaselineTIFFTagSet base = BaselineTIFFTagSet.getInstance();
TIFFTag tagXRes = base.getTag(BaselineTIFFTagSet.TAG_X_RESOLUTION);
TIFFTag tagYRes = base.getTag(BaselineTIFFTagSet.TAG_Y_RESOLUTION);
TIFFTag tagNewSubfile = base.getTag(BaselineTIFFTagSet.TAG_NEW_SUBFILE_TYPE);
TIFFTag tagBitsPerSample = base.getTag(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE);
TIFFTag tagResolutionUnit = base.getTag(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT);
// set X DPI
long[][] X_DPI = new long[][] { { dpi, 1 } };
TIFFField xDPI = new TIFFField(tagXRes, TIFFTag.TIFF_RATIONAL, 1, X_DPI);
// set Y DPI
long[][] Y_DPI = new long[][] { { dpi, 1 } };
TIFFField yDPI = new TIFFField(tagYRes, TIFFTag.TIFF_RATIONAL, 1, Y_DPI);
// setzt Photometric von BlackIsZero auf WhiteIsZero
TIFFField photometricInterpretationField = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION), BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO);
// setzt NewSubfileType auf 0
TIFFField newSubfile = new TIFFField(tagNewSubfile, 0);
// setzt BitsPerSample auf 1
TIFFField bitsPerSample = new TIFFField(tagBitsPerSample, 1);
// setzt ResolutionUnit auf 2
TIFFField resolutionUnit = new TIFFField(tagResolutionUnit, 2);
dir.addTIFFField(xDPI);
dir.addTIFFField(yDPI);
dir.addTIFFField(photometricInterpretationField);
dir.addTIFFField(newSubfile);
dir.addTIFFField(bitsPerSample);
dir.addTIFFField(resolutionUnit);
TIFFImageWriteParam param = (TIFFImageWriteParam) writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setTIFFCompressor(new TIFFT6Compressor());
param.setCompressionType("CCITT T.6");
param.setCompressionQuality(0.0f);
IIOMetadata streamMetadata = writer.getDefaultStreamMetadata(null);
String tiffMetadataFormatName = streamMetadata.getNativeMetadataFormatName();
IIOMetadataNode newTree = new IIOMetadataNode(tiffMetadataFormatName);
// create little endian
IIOMetadataNode endianNode = new IIOMetadataNode("ByteOrder");
endianNode.setAttribute("value", "LITTLE_ENDIAN");
newTree.appendChild(endianNode);
streamMetadata.setFromTree(tiffMetadataFormatName, newTree);
writer.prepareWriteSequence(streamMetadata);
writer.writeToSequence(new IIOImage(tiffImage, null, dir.getAsMetadata()), param);
ios.close();
} catch (IOException e) {
throw new ConvertionFailedException(e);
}
}

Related

add itext WaterMark to android java pdf

I need to add an itext watermark to my pdf android java pdf file
my sample current code for creating the pdf file:
File docsFolder = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS), "osary/estmara");
String currentDate = new SimpleDateFormat("dd-MM-yyyy_hh_mm_aaa", Locale.getDefault()).format(new Date());
String pdfname = myEstmaraa.getTalabId() + "_" + currentDate + ".pdf";
pdfFile = new File(docsFolder, pdfname);
OutputStream output = new FileOutputStream(pdfFile);
Document document = new Document(PageSize.A4);
document.setMargins(5, 5, 5, 5);
PdfWriter PdfWriters = PdfWriter.getInstance(document, output);
PdfWriters.createXmpMetadata();
PdfWriters.setTagged();
document.open();
//todo 2 preparing Header and directions and margin row 0
PdfPTable tableForRowZero = new PdfPTable(new float[]{1});
tableForRowZero.setSpacingBefore(5);
tableForRowZero.setRunDirection(PdfWriter.RUN_DIRECTION_RTL);
tableForRowZero.getDefaultCell().setFixedHeight(34);
tableForRowZero.setTotalWidth(PageSize.A4.getWidth());
tableForRowZero.setWidthPercentage(100);
tableForRowZero.setHeaderRows(0);
tableForRowZero.getDefaultCell().setVerticalAlignment(Element.ALIGN_MIDDLE);
cellss = new PdfPCell(new Phrase("رقم الاستمارة", FONT2));
cellss.setHorizontalAlignment(Element.ALIGN_CENTER);
cellss.setVerticalAlignment(Element.ALIGN_CENTER);
cellss.setBackgroundColor(BaseColor.GRAY);
tableForRowZero.addCell(cellss);
tableForRowZero.setHeaderRows(0);
cellss = new PdfPCell(new Phrase(String.valueOf(myEstmaraa.getTalabId()), FONT2));
cellss.setHorizontalAlignment(Element.ALIGN_CENTER);
cellss.setVerticalAlignment(Element.ALIGN_CENTER);
tableForRowZero.addCell(cellss);
document.add(tableForRowZero);
document.close();
i have tried this code but it for desktop java:
enter link description here
and the problem that i faced is this line:
PdfDocument pdfDoc = new PdfDocument(new PdfReader(SRC), new PdfWriter(dest));
when i change it to android i face a problem, i tried it like:
com.itextpdf.kernel.pdf.PdfDocument pdfDoc = new com.itextpdf.kernel.pdf.PdfDocument(new PdfReader(pdfFile.getPath()),new PdfWriter(pdfFile.getPath()));
it gives me this hint:
Cannot resolve constructor 'PdfWriter(java.lang.String)'
the code i tried to make watermark:
com.itextpdf.kernel.pdf.PdfDocument pdfDoc = new com.itextpdf.kernel.pdf.PdfDocument(new PdfReader(pdfFile.getPath()),new PdfWriter(pdfFile.getPath()));
PdfCanvas under = new PdfCanvas(pdfDoc.getFirstPage().newContentStreamBefore(), new PdfResources(), pdfDoc);
PdfFont font = PdfFontFactory.createFont(FontProgramFactory.createFont(StandardFonts.HELVETICA));
com.itextpdf.layout.element.Paragraph paragraph2 = new com.itextpdf.layout.element.Paragraph("This watermark is added UNDER the existing content")
.setFont(font)
.setFontSize(15);
Canvas canvasWatermark1 = new Canvas(under, pdfDoc.getDefaultPageSize())
.showTextAligned(paragraph2, 297, 550, 1, TextAlignment.CENTER, VerticalAlignment.TOP, 0);
canvasWatermark1.close();
PdfCanvas over = new PdfCanvas(pdfDoc.getFirstPage());
over.setFillColor(ColorConstants.BLACK);
paragraph2 = new com.itextpdf.layout.element.Paragraph("This watermark is added ON TOP OF the existing content")
.setFont(font)
.setFontSize(15);
Canvas canvasWatermark2 = new Canvas(over, pdfDoc.getDefaultPageSize())
.showTextAligned(paragraph2, 297, 500, 1, TextAlignment.CENTER, VerticalAlignment.TOP, 0);
canvasWatermark2.close();
paragraph2 = new com.itextpdf.layout.element.Paragraph("This TRANSPARENT watermark is added ON TOP OF the existing content")
.setFont(font)
.setFontSize(15);
over.saveState();
// Creating a dictionary that maps resource names to graphics state parameter dictionaries
PdfExtGState gs1 = new PdfExtGState();
gs1.setFillOpacity(0.5f);
over.setExtGState(gs1);
Canvas canvasWatermark3 = new Canvas(over, pdfDoc.getDefaultPageSize())
.showTextAligned(paragraph2, 297, 450, 1, TextAlignment.CENTER, VerticalAlignment.TOP, 0);
canvasWatermark3.close();
over.restoreState();
i tried also to add png image and set its opacity but it cover the content
try {
com.itextpdf.text.Image image1_emp_osary = null;
Drawable d_emp_osary = getResources().getDrawable(R.drawable.ketm_estmara);
BitmapDrawable bitDw_emp_osary = ((BitmapDrawable) d_emp_osary);
Bitmap bmp_emp_osary = bitDw_emp_osary.getBitmap();
ByteArrayOutputStream stream_emp_osary = new ByteArrayOutputStream();
bmp_emp_osary.compress(Bitmap.CompressFormat.PNG, 100, stream_emp_osary);
image1_emp_osary = com.itextpdf.text.Image.getInstance(stream_emp_osary.toByteArray());
image1_emp_osary.scaleToFit(200, 200);
image1_emp_osary.setAlignment(Element.ALIGN_BOTTOM);
image1_emp_osary.setSpacingBefore(200);
image1_emp_osary.setTransparency(new int[]{5, 5});
document.add(new Chunk(image1_emp_osary, 0, 200));
PdfContentByte canvas = PdfWriters.getDirectContentUnder();
PdfGState state = new PdfGState();
state.setFillOpacity(0.6f);
canvas.setGState(state);
canvas.addImage(image1_emp_osary);
canvas.restoreState();
} catch (Exception e) {
e.printStackTrace();
}
i have solved it,
the idea is:
1.we need to save the file with out water mark ,and that was easy:
File docsFolder = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS), "osary/estmara");
String currentDate = new SimpleDateFormat("dd-MM-yyyy_hh_mm_aaa", Locale.getDefault()).format(new Date());
String pdfname = myEstmaraa.getTalabId() + "_" + currentDate + ".pdf";
pdfFile = new File(docsFolder, pdfname);
OutputStream output = new FileOutputStream(pdfFile);
Document document = new Document(PageSize.A4);
document.setMargins(5, 5, 5, 5);
PdfWriter PdfWriters = PdfWriter.getInstance(document, output);
PdfWriters.createXmpMetadata();
PdfWriters.setTagged();
document.open();
//todo 2 preparing Header and directions and margin row 0
PdfPTable tableForRowZero = new PdfPTable(new float[]{1});
tableForRowZero.setSpacingBefore(5);
tableForRowZero.setRunDirection(PdfWriter.RUN_DIRECTION_RTL);
tableForRowZero.getDefaultCell().setFixedHeight(34);
tableForRowZero.setTotalWidth(PageSize.A4.getWidth());
tableForRowZero.setWidthPercentage(100);
tableForRowZero.setHeaderRows(0);
tableForRowZero.getDefaultCell().setVerticalAlignment(Element.ALIGN_MIDDLE);
cellss = new PdfPCell(new Phrase("رقم الاستمارة", FONT2));
cellss.setHorizontalAlignment(Element.ALIGN_CENTER);
cellss.setVerticalAlignment(Element.ALIGN_CENTER);
cellss.setBackgroundColor(BaseColor.GRAY);
tableForRowZero.addCell(cellss);
tableForRowZero.setHeaderRows(0);
cellss = new PdfPCell(new Phrase(String.valueOf(myEstmaraa.getTalabId()), FONT2));
cellss.setHorizontalAlignment(Element.ALIGN_CENTER);
cellss.setVerticalAlignment(Element.ALIGN_CENTER);
tableForRowZero.addCell(cellss);
document.add(tableForRowZero);
document.close();
2.we will open the file but we can not override it directly,
so:
a. we will save it in a temp file with the watermark and close it:
File tempFile = new File(docsFolder.getPath(), "temp.pdf");
com.itextpdf.kernel.pdf.PdfWriter TempWriter = new com.itextpdf.kernel.pdf.PdfWriter(tempFile);
String font = "/res/font/arialbd.ttf";
PdfFontFactory.register(font);
FontProgram fontProgram = FontProgramFactory.createFont(font, true);
PdfFont f = PdfFontFactory.createFont(fontProgram, PdfEncodings.IDENTITY_H);
LanguageProcessor languageProcessor = new ArabicLigaturizer();
com.itextpdf.kernel.pdf.PdfDocument tempPdfDoc = new com.itextpdf.kernel.pdf.PdfDocument(new PdfReader(pdfFile.getPath()), TempWriter);
com.itextpdf.layout.Document TempDoc = new com.itextpdf.layout.Document(tempPdfDoc);
com.itextpdf.layout.element.Paragraph paragraph0 = new com.itextpdf.layout.element.Paragraph(languageProcessor.process("الاستماره الالكترونية--الاستماره الالكترونية--الاستماره الالكترونية--الاستماره الالكترونية"))
.setFont(f).setBaseDirection(BaseDirection.RIGHT_TO_LEFT)
.setFontSize(15);
Drawable d_ketm_estmara = getResources().getDrawable(R.drawable.ketm_estmara);
Bitmap bitDw_estmara = ((BitmapDrawable) d_ketm_estmara).getBitmap();
ByteArrayOutputStream stream_estmara = new ByteArrayOutputStream();
bitDw_estmara.compress(Bitmap.CompressFormat.PNG, 100, stream_estmara);
byte[] data = stream_estmara.toByteArray();
ImageData img = ImageDataFactory.create(data);
PdfExtGState gs1 = new PdfExtGState().setFillOpacity(0.2f);
for (int i = 1; i <= tempPdfDoc.getNumberOfPages(); i++) {
PdfPage pdfPage = tempPdfDoc.getPage(i);
com.itextpdf.kernel.geom.Rectangle pageSize = pdfPage.getPageSize();
float x = (pageSize.getLeft() + pageSize.getRight()) / 2;
float y = (pageSize.getTop() + pageSize.getBottom()) / 3;
PdfCanvas over = new PdfCanvas(pdfPage);
over.saveState();
over.setExtGState(gs1);
TempDoc.showTextAligned(paragraph0, 300, 760, i, TextAlignment.CENTER, VerticalAlignment.TOP, 0);
float leftImage = 20;
float bottomImage = 120;
float rightImage = 550;
float topImage = 720;
over.addImageWithTransformationMatrix(img, rightImage, 0, 0, topImage, leftImage, bottomImage, true);
over.restoreState();
}
TempDoc.close();
tempPdfDoc.close();
b. we will open the temp file and save it with the old name:
com.itextpdf.kernel.pdf.PdfDocument pdfDoc = new com.itextpdf.kernel.pdf.PdfDocument(new PdfReader(tempFile.getPath()), new com.itextpdf.kernel.pdf.PdfWriter(new File(docsFolder.getPath(), pdfname)));
com.itextpdf.layout.Document doc = new com.itextpdf.layout.Document(pdfDoc);
doc.close();
pdfDoc.close();

Image file writes with double the size of actual

I'm trying to read a multi page tiff and blackout some content and then write it again.
Code :-
public void blackOut(File file, File outputTiff, String compressionType) throws IOException
{
ImageReader reader = getImageReader(file);
int pageCount = reader.getNumImages(true);
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(TIFF_FORMAT);
if (!writers.hasNext())
{
throw new RuntimeException(JAI_IMAGE_WRITER_MESSAGE);
}
ImageWriter writer = writers.next();
TIFFImageWriteParam tiffWriteParam = new TIFFImageWriteParam(Locale.US);
if (compressionType != null)
{
tiffWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
tiffWriteParam.setCompressionType(compressionType);
}
IIOMetadata streamMetadata = writer.getDefaultStreamMetadata(tiffWriteParam);
try (ImageOutputStream ios = ImageIO.createImageOutputStream(outputTiff))
{
writer.setOutput(ios);
int dpiX = 300;
int dpiY = 300;
for (int i = 0; i < pageCount; i++)
{
BufferedImage bufferedImage = reader.read(i);
Graphics2D g2d = bufferedImage.createGraphics();
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(10));
g2d.fillRect(X, Y, Width, Height);
g2d.dispose();
IIOImage iioImage = new IIOImage(bufferedImage, null, null);
ImageTypeSpecifier imageType = ImageTypeSpecifier.createFromRenderedImage(iioImage.getRenderedImage());
ImageWriteParam param = writer.getDefaultWriteParam();
IIOMetadata imageMetadata = writer.getDefaultImageMetadata(imageType, param);
imageMetadata = setDPIViaAPI(imageMetadata, dpiX, dpiY);
iioImage.setMetadata(imageMetadata);
if (i == 0)
{
IIOImage firstIioImage = iioImage;
writer.write(streamMetadata, firstIioImage, tiffWriteParam);
}
else
{
writer.writeInsert(i, iioImage, tiffWriteParam);
}
}
}
finally
{
writer.dispose();
}
}
private static IIOMetadata setDPIViaAPI(IIOMetadata imageMetadata, int dpiX, int dpiY)
throws IIOInvalidTreeException
{
// Derive the TIFFDirectory from the metadata.
TIFFDirectory dir = TIFFDirectory.createFromMetadata(imageMetadata);
// Get {X,Y}Resolution tags.
BaselineTIFFTagSet base = BaselineTIFFTagSet.getInstance();
TIFFTag tagXRes = base.getTag(BaselineTIFFTagSet.TAG_X_RESOLUTION);
TIFFTag tagYRes = base.getTag(BaselineTIFFTagSet.TAG_Y_RESOLUTION);
// Create {X,Y}Resolution fields.
TIFFField fieldXRes = new TIFFField(tagXRes, TIFFTag.TIFF_RATIONAL,
1, new long[][] {{dpiX, 1}});
TIFFField fieldYRes = new TIFFField(tagYRes, TIFFTag.TIFF_RATIONAL,
1, new long[][] {{dpiY, 1}});
// Append {X,Y}Resolution fields to directory.
dir.addTIFFField(fieldXRes);
dir.addTIFFField(fieldYRes);
// Convert to metadata object.
IIOMetadata metadata = dir.getAsMetadata();
// Add other metadata.
IIOMetadataNode root = new IIOMetadataNode("javax_imageio_1.0");
IIOMetadataNode horiz = new IIOMetadataNode("HorizontalPixelSize");
horiz.setAttribute("value", Double.toString(25.4f / dpiX));
IIOMetadataNode vert = new IIOMetadataNode("VerticalPixelSize");
vert.setAttribute("value", Double.toString(25.4f / dpiY));
IIOMetadataNode dim = new IIOMetadataNode("Dimension");
dim.appendChild(horiz);
dim.appendChild(vert);
root.appendChild(dim);
metadata.mergeTree("javax_imageio_1.0", root);
return metadata;
}
while writing the file again I'm getting the file double (sometimes triple) the size of actual and that too after applying the compression 'LZW'.
Any way that I can get the same file size as previous?
Thanks.

Affixing digital signature on a pdf

I am trying to affix a digital signature on a pdf document.
I am able to affix the signature on the pdf but the signature is not visible. I tried a lot looked at so many codes (How to make a signature visible on a document) making signature visible but somehow not able to do .Here is the code which i am using to affix the signature on the pdf.
String inputPDFlocation = INPUT_PDF_BASEPATH + inputPDFfilename;
String outputPDFlocation = OUTPUT_PDF_BASEPATH + inputPDFfilename;
PdfReader reader = new PdfReader(inputPDFlocation); // input PDF
PdfStamper stamper = PdfStamper.createSignature(reader, new FileOutputStream(outputPDFlocation), '\0', null, true);
// Finding the size of the page, and determining the location of signature:
Rectangle cropBox = reader.getCropBox(1); // Gets the 1st page
float width = 78;
float height = 34;
Rectangle rectangle;
// Top left
rectangle = new Rectangle(cropBox.getLeft(), cropBox.getTop(height), cropBox.getLeft(width), cropBox.getTop());
// Creating the appearance
PdfSignatureAppearance sap = stamper.getSignatureAppearance();
sap.setReason(SIGNATURE_REASON);
sap.setLocation(SIGNATURE_LOCATION);
sap.setVisibleSignature(rectangle, 1, sap.getNewSigName()); // new Rectangle(36, 748, 144, 780)
ExternalDigest externalDigest = new BouncyCastleDigest();
int estimatedSize = 8192;
PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
dic.setReason(sap.getReason());
dic.setLocation(sap.getLocation());
dic.setSignatureCreator(sap.getSignatureCreator());
dic.setContact(sap.getContact());
// Adding a buffer between the signature generation and the certificate start valid time.
Calendar cal = sap.getSignDate();
cal.add(Calendar.MINUTE, 1);
dic.setDate(new PdfDate(cal)); // time-stamp will over-rule this
sap.setCryptoDictionary(dic);
HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer>();
exc.put(PdfName.CONTENTS, new Integer(estimatedSize * 2 + 2));
sap.preClose(exc);
String hashAlgorithm = DigestAlgorithms.SHA256;
InputStream data = sap.getRangeStream();
byte hash[] = DigestAlgorithms.digest(data, externalDigest.getMessageDigest(hashAlgorithm));
//convert the byte to hex format method 1
StringBuffer sb = new StringBuffer();
for (int i = 0; i < hash.length; i++) {
sb.append(Integer.toString((hash[i] & 0xff) + 0x100, 16).substring(1));
}
// 5. Setting Document hash
esign.setInput(sb.toString());
StringWriter eSignXML = new StringWriter();
try {
JAXBContext.newInstance(Esign.class).createMarshaller().marshal(esign, eSignXML);
} catch (Exception ex) {
logger.error("There was an error converting <Esign> XML to String: {}", ex.getMessage());
}
// 7. Get the digital signer, and sign the XML
DigitalSigner ds = getDigitalSigner();
if (ds == null) {
return eSignResponse;
}
String signedEsignXML = ds.signXML(eSignXML.toString(), true);
// 8. Make a request
String responseXML = null;
Response response = HTTPClient.postRequestWithXmlPayloadOverTLS(eSignConfig.get(URL_ESIGN_SERVER), null, null, signedEsignXML, false);
if (response != null) {
if (Response.Status.Family.familyOf(response.getStatus()) == Response.Status.Family.SUCCESSFUL) {
responseXML = response.getEntity().toString();
}
}
// 9. Parse the response
EsignResp esignResp = XMLUtil.parseXML(responseXML, EsignResp.class);
if (esignResp != null) {
if (esignResp.getStatus() != null && esignResp.getStatus().equalsIgnoreCase("1")) {
eSignResponse.setStatus(1);
// If response is a SUCCESS, affix the signature ...
String pkcs7Response = esignResp.getPkcs7Response();
CMSSignedData cms = new CMSSignedData(Base64.decodeBase64(pkcs7Response.getBytes()));
byte[] paddedSig = new byte[estimatedSize];
System.arraycopy(cms.getEncoded(), 0, paddedSig, 0, cms.getEncoded().length);
PdfDictionary dic2 = new PdfDictionary();
dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
sap.close(dic2);
}
You use a 0x0 rectangle for the visualization:
// Finding the size of the page, and determining the location of signature:
Rectangle cropBox = reader.getCropBox(1); // Gets the 1st page
float width = 0;
float height = 0;
Rectangle rectangle;
// Top left
rectangle = new Rectangle(cropBox.getLeft(), cropBox.getTop(height), cropBox.getLeft(width), cropBox.getTop());
[...]
sap.setVisibleSignature(rectangle, 1, sap.getNewSigName()); // new Rectangle(36, 748, 144, 780)
Unless you choose positive values for width and height, you will never see a signature visualization.

PDFBox - merge 2 portrait pages onto a single side by side landscape page

I am trying to write a pdf conversion, that will take a pdf containing 1-up portrait pages, and create a new document, but merge every 2 pages into one 2-up landscape page
ie.
the following code will scale down the content 50%, but I cant figure out how to make the new page landscape, while injecting the other page as portrait, and injecting into the top left, and right of centre
public static void main(String[] args) throws IOException, DocumentException, COSVisitorException {
scalePages("c:/pdf/in.pdf", "c:/pdf/out" + new Date().getTime() + ".pdf", 0.50f);
}
public static void scalePages(String inFile, String outFile, float scale ) throws IOException, COSVisitorException {
PDDocument doc1 = null;
try {
doc1 = PDDocument.load( inFile );
List allPages = doc1.getDocumentCatalog().getAllPages();
for( int i=0; i<allPages.size(); i++ ) {
PDPage page1 = (PDPage)allPages.get(i );
PDRectangle mediaBox = page1.getMediaBox();
float oldX = mediaBox.getUpperRightX();
float newX = oldX * scale;
float oldY = mediaBox.getUpperRightY();
float newY = oldY * scale;
mediaBox.setUpperRightX(newX);
mediaBox.setUpperRightY(newY);
PDFStreamParser parser = new PDFStreamParser(page1.getContents());
parser.parse();
List tokens = parser.getTokens();
tokens.add(0,new COSFloat(scale));
tokens.add(1,new COSInteger(0));
tokens.add(2,new COSInteger(0));
tokens.add(3,new COSFloat(scale));
tokens.add(4,new COSInteger(0));
tokens.add(5,new COSInteger(0));
tokens.add(6,PDFOperator.getOperator("cm"));
PDStream newContents = new PDStream( doc1 );
ContentStreamWriter writer = new ContentStreamWriter( newContents.createOutputStream() );
writer.writeTokens( tokens );
newContents.addCompression();
page1.setContents(newContents);
//page1.setRotation(90);
mediaBox.setUpperRightX(oldX);
mediaBox.setUpperRightY(oldY);
}
doc1.save( outFile );
} finally {
if( doc1 != null ) {
doc1.close();
}
}
}
so the result is as follows
any pointers would be greatly appreciated
Here is an example that "stitches" two one page PDFs side-by-side and saves result in a new file using PDFBox. Enjoy!
function void generateSideBySidePDF() {
File pdf1File = new File(FILE1_PATH);
File pdf2File = new File(FILE2_PATH);
File outPdfFile = new File(OUTFILE_PATH);
PDDocument pdf1 = null;
PDDocument pdf2 = null;
PDDocument outPdf = null;
try {
pdf1 = PDDocument.load(pdf1File);
pdf2 = PDDocument.load(pdf2File);
outPdf = new PDDocument();
// Create output PDF frame
PDRectangle pdf1Frame = pdf1.getPage(0).getCropBox();
PDRectangle pdf2Frame = pdf2.getPage(0).getCropBox();
PDRectangle outPdfFrame = new PDRectangle(pdf1Frame.getWidth()+pdf2Frame.getWidth(), Math.max(pdf1Frame.getHeight(), pdf2Frame.getHeight()));
// Create output page with calculated frame and add it to the document
COSDictionary dict = new COSDictionary();
dict.setItem(COSName.TYPE, COSName.PAGE);
dict.setItem(COSName.MEDIA_BOX, outPdfFrame);
dict.setItem(COSName.CROP_BOX, outPdfFrame);
dict.setItem(COSName.ART_BOX, outPdfFrame);
PDPage outPdfPage = new PDPage(dict);
outPdf.addPage(outPdfPage);
// Source PDF pages has to be imported as form XObjects to be able to insert them at a specific point in the output page
LayerUtility layerUtility = new LayerUtility(outPdf);
PDFormXObject formPdf1 = layerUtility.importPageAsForm(pdf1, 0);
PDFormXObject formPdf2 = layerUtility.importPageAsForm(pdf2, 0);
// Add form objects to output page
AffineTransform afLeft = new AffineTransform();
layerUtility.appendFormAsLayer(outPdfPage, formPdf1, afLeft, "left");
AffineTransform afRight = AffineTransform.getTranslateInstance(pdf1Frame.getWidth(), 0.0);
layerUtility.appendFormAsLayer(outPdfPage, formPdf2, afRight, "right");
outPdf.save(outPdfFile);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (pdf1 != null) pdf1.close();
if (pdf2 != null) pdf2.close();
if (outPdf != null) outPdf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
I ended up doing this with itext
private String createTwoUp(String originalPdfFile) throws IOException, DocumentException {
String newFilename = FilenameUtils.getBaseName(originalPdfFile) + "_2up." + FilenameUtils.getExtension(originalPdfFile);
newFilename = FilenameUtils.concat(getPdfFileFolder(), newFilename);
PdfReader reader = new PdfReader(originalPdfFile);
Document doc = new Document(new RectangleReadOnly(842f, 595f), 0, 0, 0, 0);
PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(newFilename));
doc.open();
int totalPages = reader.getNumberOfPages();
for (int i = 1; i <= totalPages; i = i + 2) {
doc.newPage();
PdfContentByte cb = writer.getDirectContent();
PdfImportedPage page = writer.getImportedPage(reader, i); // page #1
float documentWidth = doc.getPageSize().getWidth() / 2;
float documentHeight = doc.getPageSize().getHeight();
if (i > 1) {
documentHeight = documentHeight - 65f;
}
float pageWidth = page.getWidth();
float pageHeight = page.getHeight();
float widthScale = documentWidth / pageWidth;
float heightScale = documentHeight / pageHeight;
float scale = Math.min(widthScale, heightScale);
//float offsetX = 50f;
float offsetX = (documentWidth - (pageWidth * scale)) / 2;
float offsetY = 0f;
cb.addTemplate(page, scale, 0, 0, scale, offsetX, offsetY);
if (i+1 <= totalPages) {
PdfImportedPage page2 = writer.getImportedPage(reader, i+1); // page #2
pageWidth = page.getWidth();
pageHeight = page.getHeight();
widthScale = documentWidth / pageWidth;
heightScale = documentHeight / pageHeight;
scale = Math.min(widthScale, heightScale);
offsetX = ((documentWidth - (pageWidth * scale)) / 2) + documentWidth;
cb.addTemplate(page2, scale, 0, 0, scale, offsetX, offsetY);
}
}
doc.close();
return newFilename;
}

How to set DPI information in an image?

I have an application that I want to export high-resolution (or rather, high pixel density?) images for printing - for example, I want images that print at 250 dots per inch (DPI), instead of the default, which I understand to be 72 DPI.
I'm using a BufferedImage with a Graphics2D object to draw the image, then ImageIO.write() to save the image.
Any idea how I can set the DPI?
Kurt's answer showed the way, still it took me quite some time to get it run, so here is the code that sets DPI when saving a PNG. There is a lot to do to get the proper writers and such...
private BufferedImage gridImage;
...
private void saveGridImage(File output) throws IOException {
output.delete();
final String formatName = "png";
for (Iterator<ImageWriter> iw = ImageIO.getImageWritersByFormatName(formatName); iw.hasNext();) {
ImageWriter writer = iw.next();
ImageWriteParam writeParam = writer.getDefaultWriteParam();
ImageTypeSpecifier typeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
IIOMetadata metadata = writer.getDefaultImageMetadata(typeSpecifier, writeParam);
if (metadata.isReadOnly() || !metadata.isStandardMetadataFormatSupported()) {
continue;
}
setDPI(metadata);
final ImageOutputStream stream = ImageIO.createImageOutputStream(output);
try {
writer.setOutput(stream);
writer.write(metadata, new IIOImage(gridImage, null, metadata), writeParam);
} finally {
stream.close();
}
break;
}
}
private void setDPI(IIOMetadata metadata) throws IIOInvalidTreeException {
// for PMG, it's dots per millimeter
double dotsPerMilli = 1.0 * DPI / 10 / INCH_2_CM;
IIOMetadataNode horiz = new IIOMetadataNode("HorizontalPixelSize");
horiz.setAttribute("value", Double.toString(dotsPerMilli));
IIOMetadataNode vert = new IIOMetadataNode("VerticalPixelSize");
vert.setAttribute("value", Double.toString(dotsPerMilli));
IIOMetadataNode dim = new IIOMetadataNode("Dimension");
dim.appendChild(horiz);
dim.appendChild(vert);
IIOMetadataNode root = new IIOMetadataNode("javax_imageio_1.0");
root.appendChild(dim);
metadata.mergeTree("javax_imageio_1.0", root);
}
Seting up TIFF DPI
If you want to set dpi for TIFF, try to do that by next steps:
private static IIOMetadata createMetadata(ImageWriter writer, ImageWriteParam writerParams, int resolution) throws
IIOInvalidTreeException
{
// Get default metadata from writer
ImageTypeSpecifier type = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY);
IIOMetadata meta = writer.getDefaultImageMetadata(type, writerParams);
// Convert default metadata to TIFF metadata
TIFFDirectory dir = TIFFDirectory.createFromMetadata(meta);
// Get {X,Y} resolution tags
BaselineTIFFTagSet base = BaselineTIFFTagSet.getInstance();
TIFFTag tagXRes = base.getTag(BaselineTIFFTagSet.TAG_X_RESOLUTION);
TIFFTag tagYRes = base.getTag(BaselineTIFFTagSet.TAG_Y_RESOLUTION);
// Create {X,Y} resolution fields
TIFFField fieldXRes = new TIFFField(tagXRes, TIFFTag.TIFF_RATIONAL, 1, new long[][] { { resolution, 1 } });
TIFFField fieldYRes = new TIFFField(tagYRes, TIFFTag.TIFF_RATIONAL, 1, new long[][] { { resolution, 1 } });
// Add {X,Y} resolution fields to TIFFDirectory
dir.addTIFFField(fieldXRes);
dir.addTIFFField(fieldYRes);
// Add unit field to TIFFDirectory (change to RESOLUTION_UNIT_CENTIMETER if necessary)
dir.addTIFFField(new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT), BaselineTIFFTagSet.RESOLUTION_UNIT_INCH));
// Return TIFF metadata so it can be picked up by the IIOImage
return dir.getAsMetadata();
}
Also, similar way you can setting up any TIFF tag.
Read more at the source
i am using this code for tiff file in my project and it works well..
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.media.jai.NullOpImage;
import javax.media.jai.OpImage;
import javax.media.jai.PlanarImage;
import com.sun.media.jai.codec.FileSeekableStream;
import com.sun.media.jai.codec.ImageCodec;
import com.sun.media.jai.codec.ImageDecoder;
import com.sun.media.jai.codec.ImageEncoder;
import com.sun.media.jai.codec.SeekableStream;
import com.sun.media.jai.codec.TIFFEncodeParam;
import com.sun.media.jai.codec.TIFFField;
class SetDDPI
{
static void tiff_Maker(List<BufferedImage> output, String result) throws IOException
{
TIFFEncodeParam params = new TIFFEncodeParam();
OutputStream out = new FileOutputStream(result);
List<BufferedImage> imageList = new ArrayList<BufferedImage>();
for (int i = 1; i < output.size(); i++)
{
imageList.add(output.get(i));
}
params.setWriteTiled(true);
params.setCompression(TIFFEncodeParam.COMPRESSION_GROUP4);
params.setExtraImages(imageList.iterator());
TIFFField[] extras = new TIFFField[2];
extras[0] = new TIFFField(282, TIFFField.TIFF_RATIONAL, 1, (Object) new long[][] { { (long) 300, (long) 1 },
{ (long) 0, (long) 0 } });
extras[1] = new TIFFField(283, TIFFField.TIFF_RATIONAL, 1, (Object) new long[][] { { (long) 300, (long) 1 },
{ (long) 0, (long) 0 } });
params.setExtraFields(extras);
ImageEncoder encoder = ImageCodec.createImageEncoder("tiff", out, params);
encoder.encode(output.get(0));
out.close();
}
static List<BufferedImage> tiff_Extractor(File tiff) throws IOException
{
List<BufferedImage> images = new ArrayList<BufferedImage>();
SeekableStream ss = new FileSeekableStream(tiff);
ImageDecoder decoder = ImageCodec.createImageDecoder("tiff", ss, null);
int numPages = decoder.getNumPages();
for (int j = 0; j < numPages; j++)
{
PlanarImage op = new NullOpImage(decoder.decodeAsRenderedImage(j), null, null, OpImage.OP_IO_BOUND);
images.add(op.getAsBufferedImage());
}
return images;
}
}
this is to set 300 DPI of Tiff image. you can change it according to your need.
extras[0] = new TIFFField(282, TIFFField.TIFF_RATIONAL, 1, (Object) new
long[][] { { (long) 300, (long) 1 },{ (long) 0, (long) 0 } });
extras[1] = new TIFFField(283, TIFFField.TIFF_RATIONAL, 1, (Object) new
long[][] { { (long) 300, (long) 1 },{ (long) 0, (long) 0 } });

Categories