Image file writes with double the size of actual - java

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.

Related

Save BufferedImages as TIFF

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);
}
}

bad output(monocolor) with Java Advanced Imaging api

I m having a sample image(sorry for the type of image) which i m feeding into JAI code to get a compressed image.
Now the output image i m getting is in mono-color. I don't know why is the output is abnormal but other images are getting processed just fine.
The sample original and processed images are -
Original Image -
Processed Image -
The JAI code to process the image -
private static final String JAI_STREAM_ACTION = "stream";
private static final String JAI_SUBSAMPLE_AVERAGE_ACTION = "SubsampleAverage";
private static final String JAI_ENCODE_FORMAT_JPEG = "JPEG";
private static final String JAI_ENCODE_ACTION = "encode";
private static final String JPEG_CONTENT_TYPE = "image/jpeg";
private int mMaxWidth = 800;
//private int mMaxWidthThumbnail = 150;
private byte[] resizeImageAsJPG(byte[] pImageData, int pMaxWidth) throws IOException {
InputStream imageInputStream = new ByteArrayInputStream(pImageData);
SeekableStream seekableImageStream = SeekableStream.wrapInputStream(imageInputStream, true);
RenderedOp originalImage = JAI.create(JAI_STREAM_ACTION, seekableImageStream);
((OpImage) originalImage.getRendering()).setTileCache(null);
int origImageWidth = originalImage.getWidth();
double scale = 1.0;
/*
if (pMaxWidth > 0 && origImageWidth > pMaxWidth) {
scale = (double) pMaxWidth / originalImage.getWidth();
} */
ParameterBlock paramBlock = new ParameterBlock();
paramBlock.addSource(originalImage); // The source image
paramBlock.add(scale); // The xScale
paramBlock.add(scale); // The yScale
paramBlock.add(0.0); // The x translation
paramBlock.add(0.0); // The y translation
RenderingHints qualityHints = new RenderingHints(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
RenderedOp resizedImage = JAI.create(JAI_SUBSAMPLE_AVERAGE_ACTION, paramBlock, qualityHints);
BufferedImage scaledImage = null ;
ByteArrayOutputStream encoderOutputStream = new ByteArrayOutputStream();
JAI.create(JAI_ENCODE_ACTION, resizedImage, encoderOutputStream, JAI_ENCODE_FORMAT_JPEG, null);
//byte[] resizedImageByteArray = encoderOutputStream.toByteArray();
System.out.println("This is from exiting JAI");
return encoderOutputStream.toByteArray();
}
With imgScalr I m also getting the same output.
In openJDK with JAI I get the error -
javax.media.jai.util.ImagingException: All factories fail for the operation "encode"
With imgScalr in openJDK-
javax.imageio.IIOException: Invalid argument to native writeImage
Any other library i can use in java to get the desired result.
Regards
The solution is to convert the image to 3Byte_BGR -
private synchronized BufferedImage getScaledImage1(BufferedImage imageBytes)
{
BufferedImage scaledImage = null;
int type = 0;
try
{
type = imageBytes.getType();
if(type == 0 || type ==6) {
int w = imageBytes.getWidth();
int h = imageBytes.getHeight();
BufferedImage newImage =
new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR);
Graphics2D g = newImage.createGraphics();
g.drawImage(imageBytes, 0, 0, null);
g.dispose();
imageBytes = newImage;
}
scaledImage = Scalr.resize(imageBytes, Scalr.Method.ULTRA_QUALITY,2000,
Scalr.OP_ANTIALIAS);
} catch(Exception e) {
}
return scaledImage;
}

Java - set DPI to print image

I have a bunch of .jpg images and I want to print them (on paper with ink), at a fixed size (in cm).
Let's say image1.png is 400x600 pixels and I want to print it at 300 dpi.
I've tried using PrinterJob and Printable implementation, but it seems I can't specify DPI.
Here is the code snippets:
PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintable(new PrintableDeck(cardDB));
PrintRequestAttributeSet attr = new HashPrintRequestAttributeSet();
attr.add(new PrinterResolution(300, 300, PrinterResolution.DPI));
attr.add(new MediaPrintableArea(8,21,210-16,296-42,MediaPrintableArea.MM));
attr.add(MediaSizeName.ISO_A4);
attr.add(new Copies(1));
attr.add(OrientationRequested.PORTRAIT);
attr.add(PrintQuality.HIGH);
//attr.add(Fidelity.FIDELITY_TRUE);
job.print(attr);
and
public class PrintableDeck implements Printable {
BufferedImage image;
public PrintableDeck(DB cardDB){
// This load an image into 'image'
BufferedImage image = cardDB.getCard(5462).getBufferedImage();
}
public int print(Graphics graphics, PageFormat pf, int page)
throws PrinterException{
if(page>0){
return NO_SUCH_PAGE;
}
Graphics2D g2 = (Graphics2D) graphics;
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
double pageHeight = pf.getImageableHeight();
double pageWidth = pf.getImageableWidth();
// This print ONLY ~596x842, as if page is 72 DPI
System.out.println("Imageable WH: "+pageWidth+" x "+pageHeight);
// This print correctly 400x600
System.out.println("Image: "+images.get(0).getWidth(null)+" x "+images.get(0).getHeight(null));
g2.drawImage(image, 0, 0, null);
g2.dispose();
return PAGE_EXISTS;
}
}
As you can see above, I have PageFormat.getImageableHeight() ~ 842 and PageFormat.getImageableWidth() ~ 595. If page would be 300 DPI, I expected these values to be much higher, about 3000 x 2500.
What I am missing?
Thank you so much.
Java sets the image's DPI to the default java 72dpi if there is no previously a defined DPI in the image's meta data, so it was better than scalling your image to its dimensions in the java 72dpi default resolution, it is better to add your 300dpi resolution to your image meta data, thus, it would be adjusted in the better resolution in the right printable area dimensions, and that is besides setting printer resolution, media size, and media printable area attributes, You may set the dpi to your saved image with such method in http://www.javased.com/?post=321736 :
private void saveGridImage(File output,BufferedImage gridImage) 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 {
double INCH_2_CM = 2.54;
// 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);
}
Then add printing attributes such :
attr.add(new PrinterResolution(300, 300, PrinterResolution.DPI));
attr.add(new MediaPrintableArea(8,21,210-16,296-42,MediaPrintableArea.MM));
attr.add(MediaSizeName.ISO_A4);
To have better quality of image's view and resolution.
here's my code, note I am using Scalr.
private String autoResizeImage(String image, int width, int dpi, String prefix) throws IllegalArgumentException, ImagingOpException, IOException {
File file = new File(image);
BufferedImage img = ImageIO.read(file);
BufferedImage result = Scalr.resize(img, Scalr.Method.SPEED, Scalr.Mode.FIT_TO_WIDTH, width, Scalr.OP_ANTIALIAS);
File outputfile = new File(prefix);
PNGEncodeParam penc = PNGEncodeParam.getDefaultEncodeParam(result);
double meter2inchRatio = 1d / 0.0254d;
int dim = (int) (dpi * meter2inchRatio) + 1;
penc.setPhysicalDimension(dim, dim, 1);
// resize orginal image
JAI.create("filestore", result, outputfile.getAbsolutePath(), "PNG", penc);
return outputfile.getAbsolutePath();
}

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