I convert my .tifs from uncompressed to PackBits compression... However I need to also change the PlanarConfiguration from Chunky to Separate, I do not know how to do this. It's not looking like there's anything on the web about it doing it in Java either. Only people saying to set PlanarConfiguration = 2; Here's my code for the .tif conversion so far...
public boolean packBitsConversionMove(File currentDirectory, File currentFile) throws IOException{
try{
InputStream fis = new BufferedInputStream(new FileInputStream(currentFile));
PNGImageReaderSpi spi = new PNGImageReaderSpi();
ImageReader reader = spi.createReaderInstance();
ImageInputStream iis = ImageIO.createImageInputStream(fis);
reader.setInput(iis, true);
BufferedImage bi = ImageIO.read(currentFile);
TIFFImageWriterSpi tiffspi = new TIFFImageWriterSpi();
ImageWriter writer = tiffspi.createWriterInstance();
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionType("PackBits");
File fOutputFile = new File(currentDirectory.getPath() + "\\" + currentFile.getName());
ImageOutputStream ios = ImageIO.createImageOutputStream(fOutputFile);
writer.setOutput(ios);
writer.write(null, new IIOImage(bi, null, null), param);
} catch (IOException e){
return false;
}
return true;
}
My param variable doesn't have any setPlanarCompression function but I do not know a work around. Thanks for any advice!
Related
I have a jpg image and I want to convert it to a tiff file, but when I create the output file from byteArrayOutputStream, the output file has 0 byte length.
public static void main(String[] args) throws Exception {
String root = "E:\\Temp\\imaging\\test\\";
File image = new File(root + "0riginalTif-convertedToJpg.JPG");
byte[] bytes = compressJpgToTiff(image);
File destination = new File(root + "OriginalJpg-compressedToTiff.tiff");
FileOutputStream fileOutputStream = new FileOutputStream(destination);
fileOutputStream.write(bytes);
}
public static byte[] compressJpgToTiff(File imageFile) throws Exception {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(255);
ImageOutputStream imageOutputStream = null;
try {
File input = new File(imageFile.getAbsolutePath());
Iterator<ImageWriter> imageWriterIterator = ImageIO.getImageWritersByFormatName("TIF");
ImageWriter writer = imageWriterIterator.next();
imageOutputStream = ImageIO.createImageOutputStream(byteArrayOutputStream);
writer.setOutput(imageOutputStream);
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionType("JPEG");
param.setCompressionQuality(0.1f);
BufferedImage bufferedImage = ImageIO.read(input);
writer.write(null, new IIOImage(bufferedImage, null, null), param);
writer.dispose();
return byteArrayOutputStream.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (imageOutputStream != null)
imageOutputStream.close();
byteArrayOutputStream.close();
}
}
I want to reduce the size of output tiff as much as possible. Is there a better approach? Is it even possible to reduce the size of a tiff image?
return byteArrayOutputStream.toByteArray(); but you didn't wirite data to byteArrayOutputStream. Look, you just added data to writer.
About compression of tiff file, you have already done it with - param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
Your byteArrayOutputStream object is getting closed in finally block before you converting byteArrayOutputStream to byteArray using byteArrayOutputStream.toByteArray() thats why you getting content length to be 0. So modify your code once as below :
public static byte[] compressJpgToTiff(File imageFile) throws Exception {
//Add rest of your method code here
writer.dispose();
byte[] bytesToReturn = byteArrayOutputStream.toByteArray();
return bytesToReturn;
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (imageOutputStream != null)
imageOutputStream.close();
byteArrayOutputStream.close();
}
}
I am using a piece of code posted on stackover flow to write custom metadata to PNG image and read it. The write function seems to work fine but when i try to read data that i had written it throws NullPointerException. Can someone tell me what is wrong?
Here is code for writing metadata
try{
image=ImageIO.read(new FileInputStream("input.png"));
writeCustomData(image, "software", "FRDDC");
ImageIO.write(image, "png", new File("output.png"));
}
catch(Exception e){
e.printStackTrace();
}
Method to write metadata
public static byte[] writeCustomData(BufferedImage buffImg, String key, String value) throws Exception {
ImageWriter writer = ImageIO.getImageWritersByFormatName("png").next();
ImageWriteParam writeParam = writer.getDefaultWriteParam();
ImageTypeSpecifier typeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
//adding metadata
javax.imageio.metadata.IIOMetadata metadata = writer.getDefaultImageMetadata(typeSpecifier, writeParam);
IIOMetadataNode textEntry = new IIOMetadataNode("tEXtEntry");
textEntry.setAttribute("keyword", key);
textEntry.setAttribute("value", value);
IIOMetadataNode text = new IIOMetadataNode("tEXt");
text.appendChild(textEntry);
IIOMetadataNode root = new IIOMetadataNode("javax_imageio_png_1.0");
root.appendChild(text);
metadata.mergeTree("javax_imageio_png_1.0", root);
//writing the data
ByteArrayOutputStream baos = new ByteArrayOutputStream();
javax.imageio.stream.ImageOutputStream stream = ImageIO.createImageOutputStream(baos);
writer.setOutput(stream);
writer.write(metadata, new IIOImage(buffImg, null, metadata), writeParam);
try {
ImageIO.write(buffImg, "png", new File("new.png"));
} catch (Exception e) {
e.printStackTrace();
}
stream.close();
return baos.toByteArray();
}
Reading metadata
try{
image=ImageIO.read(new FileInputStream("output.png"));
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ImageIO.write(image, "png", baos );
byte[] b=baos.toByteArray();
String out=readCustomData(b, "software");
}
catch(Exception e){
e.printStackTrace();
}
Method to read metadata
public static String readCustomData(byte[] imageData, String key) throws IOException{
ImageReader imageReader = ImageIO.getImageReadersByFormatName("png").next();
imageReader.setInput(ImageIO.createImageInputStream(new ByteArrayInputStream(imageData)), true);
// read metadata of first image
javax.imageio.metadata.IIOMetadata metadata = imageReader.getImageMetadata(0);
//this cast helps getting the contents
//Node n=metadata.getAsTree("javax_imageio_png_1.0");
//NodeList childNodes=n.getChildNodes();
PNGMetadata pngmeta = (PNGMetadata) metadata;
if(pngmeta.getStandardTextNode()==null){
System.out.println("not found");
}
NodeList childNodes = pngmeta.getStandardTextNode().getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
String keyword = node.getAttributes().getNamedItem("keyword").getNodeValue();
String value = node.getAttributes().getNamedItem("value").getNodeValue();
if(key.equals(keyword)){
return value;
}
}
return null;
}
Error Message
not found
java.lang.NullPointerException
at PNGMeta.readCustomData(PNGMeta.java:104)
at PNGMeta.main(PNGMeta.java:40)
BUILD SUCCESSFUL (total time: 2 seconds)
Here's the most efficient way of modifying and then reading the metadata that I know of. In contrast to the code posted by the OP, this version does not fully replace the metadata in the image, but merges the new content with any existing content.
As it uses the "standard" metadata format, it should also work for any format supported by ImageIO, that allows arbitrary text comments (I only tested for PNG, though). The actual data written, should match that of the native PNG metadata format in this case.
It reads all image pixel data and metadata using a single method, to avoid excess stream open/close and seeking and memory usage. It writes all image pixel data and metadata at once for the same reason. For lossless, single image formats like PNG, this roundtrip should not lose any quality or metadata.
When reading metadata back, only the metadata is read, pixel data is ignored.
public class IIOMetadataUpdater {
public static void main(final String[] args) throws IOException {
File in = new File(args[0]);
File out = new File(in.getParent(), createOutputName(in));
System.out.println("Output path: " + out.getAbsolutePath());
try (ImageInputStream input = ImageIO.createImageInputStream(in);
ImageOutputStream output = ImageIO.createImageOutputStream(out)) {
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
ImageReader reader = readers.next(); // TODO: Validate that there are readers
reader.setInput(input);
IIOImage image = reader.readAll(0, null);
addTextEntry(image.getMetadata(), "foo", "bar");
ImageWriter writer = ImageIO.getImageWriter(reader); // TODO: Validate that there are writers
writer.setOutput(output);
writer.write(image);
}
try (ImageInputStream input = ImageIO.createImageInputStream(out)) {
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
ImageReader reader = readers.next(); // TODO: Validate that there are readers
reader.setInput(input);
String value = getTextEntry(reader.getImageMetadata(0), "foo");
System.out.println("value: " + value);
}
}
private static String createOutputName(final File file) {
String name = file.getName();
int dotIndex = name.lastIndexOf('.');
String baseName = name.substring(0, dotIndex);
String extension = name.substring(dotIndex);
return baseName + "_copy" + extension;
}
private static void addTextEntry(final IIOMetadata metadata, final String key, final String value) throws IIOInvalidTreeException {
IIOMetadataNode textEntry = new IIOMetadataNode("TextEntry");
textEntry.setAttribute("keyword", key);
textEntry.setAttribute("value", value);
IIOMetadataNode text = new IIOMetadataNode("Text");
text.appendChild(textEntry);
IIOMetadataNode root = new IIOMetadataNode(IIOMetadataFormatImpl.standardMetadataFormatName);
root.appendChild(text);
metadata.mergeTree(IIOMetadataFormatImpl.standardMetadataFormatName, root);
}
private static String getTextEntry(final IIOMetadata metadata, final String key) {
IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
NodeList entries = root.getElementsByTagName("TextEntry");
for (int i = 0; i < entries.getLength(); i++) {
IIOMetadataNode node = (IIOMetadataNode) entries.item(i);
if (node.getAttribute("keyword").equals(key)) {
return node.getAttribute("value");
}
}
return null;
}
}
Expected output of the above code is:
Output path: /path/to/yourfile_copy.png
value: bar
Your output contains "not found", which is created by
if(pngmeta.getStandardTextNode()==null){
System.out.println("not found");
}
Therefore
NodeList childNodes = pngmeta.getStandardTextNode().getChildNodes();
must fail with a NullPointerException. pngmeta.getStandardTextNode() results in null, so you actully call
null.getChildNodes();
HI I am working on the following snippet which is supposed to convert my png file to tiff.
String fileName = "4848970_1";
// String fileName = "color";
String inFileType = ".PNG";
String outFileType = ".TIFF";
File fInputFile = new File("C:\\Users\\abc\\Downloads\\image2.png");
InputStream fis = new BufferedInputStream(new FileInputStream(fInputFile));
ImageReaderSpi spi = new PNMImageReaderSpi();
ImageReader reader = spi.createReaderInstance();
ImageInputStream iis = ImageIO.createImageInputStream(fis);
reader.setInput(iis, true);
BufferedImage bi = reader.read(0);
int[] xi = bi.getSampleModel().getSampleSize();
for (int i : xi) {
System.out.println("bitsize " + i);
}
ImageWriterSpi tiffspi = new TIFFImageWriterSpi();
TIFFImageWriter writer = (TIFFImageWriter) tiffspi.createWriterInstance();
// TIFFImageWriteParam param = (TIFFImageWriteParam) writer.getDefaultWriteParam();
TIFFImageWriteParam param = new TIFFImageWriteParam(Locale.US);
String[] strings = param.getCompressionTypes();
for (String string : strings) {
System.out.println(string);
}
//param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
//param.setCompressionType("LZW");
File fOutputFile = new File("C:\\Users\\abc\\Downloads\\" + fileName + outFileType);
OutputStream fos = new BufferedOutputStream(new FileOutputStream(fOutputFile));
ImageOutputStream ios = ImageIO.createImageOutputStream(fos);
writer.setOutput(ios);
writer.write(null, new IIOImage(bi, null, null), param);
ios.flush();
writer.dispose();
ios.close();
But this gives me following error
Exception in thread "main" java.lang.RuntimeException: What in the stream isn't a PNM image.
at com.sun.media.imageioimpl.plugins.pnm.PNMImageReader.readHeader(PNMImageReader.java:187)
at com.sun.media.imageioimpl.plugins.pnm.PNMImageReader.read(PNMImageReader.java:301)
at javax.imageio.ImageReader.read(Unknown Source)
at com.imageconv.TiffImage.main(TiffImage.java:40)
Is it that its unable to read the PNG file or it recognises it as a non png file.Am I wrong anywhere?
You are trying to read a PNG image as if it was a PNM image. These two file formats have nothing in common; hence the error.
Ok, here is our issue:
We are trying to convert a series of black and white .tiff files into jpeg2000 .jpf files, using imageio. We are always getting viewable .jpf files, but they usually do not have the specified number of layers or decomposition levels for zooming.
Here is our code:
//Get the tiff reader
Iterator<ImageReader> readerIterator = ImageIO.getImageReadersByFormatName("tiff");
ImageReader tiffreader = readerIterator.next();
//make an ImageInputStream from our tiff file and have the tiff reader read it
ImageInputStream iis = ImageIO.createImageInputStream(itemFile);
tiffreader.setInput(iis);
//just pass empty params to the tiff reader
ImageReadParam tparam;
tparam = new TIFFImageReadParam();
IIOImage img = tiffreader.readAll(0, tparam);
//set up target file
File f = new File(itemTargetDirectory.getAbsolutePath() + "/" + destFileName);
//we have tried FILTER_97 as well as different ProgressionTypes and compression settings
J2KImageWriteParam param;
param = new J2KImageWriteParam();
param.setProgressionType("layer");
param.setFilter(J2KImageWriteParam.FILTER_53);
//Our problem is that this param is not always respected in the resulting .jpf
param.setNumDecompositionLevels(5);
//get the JPEG 2000 writer
Iterator<ImageWriter> writerIterator = ImageIO.getImageWritersByFormatName("JPEG 2000");
J2KImageWriter jp2kwriter = null;
jp2kwriter = (J2KImageWriter) writerIterator.next();
//write the jpf file
ImageOutputStream ios = ImageIO.createImageOutputStream(f);
jp2kwriter.setOutput(ios);
jp2kwriter.write(null, img, param);
It has been an odd experience, as the same code has behaved differently on subsequent runs.
Any insights will be appreciated!
Do all the TIFF files have the same settings (color model)? J2KImageWriter.java shows the decomposition levels getting set (forced) to zero when indexed-color or multi-pixel packed source images are used as input.
Drew was on the right track, and here is the code that ended up sorting things out for us:
public void compressor(String inputFile, String outputFile) throws IOException {
J2KImageWriteParam iwp = new J2KImageWriteParam();
FileInputStream fis = new FileInputStream(new File(inputFile));
BufferedImage image = ImageIO.read(fis);
fis.close();
if (image == null)
{
System.out.println("If no registered ImageReader claims to be able to read the resulting stream");
}
Iterator writers = ImageIO.getImageWritersByFormatName("JPEG2000");
String name = null;
ImageWriter writer = null;
while (name != "com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageWriter") {
writer = (ImageWriter) writers.next();
name = writer.getClass().getName();
System.out.println(name);
}
File f = new File(outputFile);
long s = System.currentTimeMillis();
ImageOutputStream ios = ImageIO.createImageOutputStream(f);
writer.setOutput(ios);
J2KImageWriteParam param = (J2KImageWriteParam) writer.getDefaultWriteParam();
IIOImage ioimage = new IIOImage(image, null, null);
param.setSOP(true);
param.setWriteCodeStreamOnly(true);
param.setProgressionType("layer");
param.setLossless(false);
param.setCompressionMode(J2KImageWriteParam.MODE_EXPLICIT);
param.setCompressionType("JPEG2000");
param.setCompressionQuality(0.1f);
param.setEncodingRate(1.01);
param.setFilter(J2KImageWriteParam.FILTER_97);
writer.write(null, ioimage, param);
System.out.println(System.currentTimeMillis() - s);
writer.dispose();
ios.flush();
ios.close();
image.flush();
}
I have a java.awt.Image that I need to add CCITT T.6 compression and convert to a TIFF byte array. I have seen some examples of using TIFFImageWriteParam and other classes from the javax.imageio package but I can’t find a complete example going all the way from Image to byte array.
Here is what I have so far beginning with a java.awt.Image obtained from scanning. This works just fine to generate a byte array of a TIFF, but I need to find a way, using TIFFImageWriteParam or some other means, to compress the TIFF prior to processing it as a byte array:
thisImage = ... a java.awt.Image from a scanner
if(thisImage!=null){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedImage bimg = new BufferedImage(thisImage.getWidth(null),thisImage.getHeight(null), BufferedImage.TYPE_BYTE_BINARY);
bimg.createGraphics().drawImage(thisImage, 0, 0, null);
try {
ImageIO.write(bimg, "tiff", baos);
} catch (Exception e) {
e.printStackTrace();
}
thisByteArray = baos.toByteArray();
...
Any help would be appreciated.
I found a solution thanks to: this thread.
Here is what I ended up doing that solved my issue:
thisImage = thisImage = ... a java.awt.Image from a scanner
if(thisImage!=null){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
boolean foundWriter = false;
BufferedImage bimg = new BufferedImage(thisImage.getWidth(null),thisImage.getHeight(null), BufferedImage.TYPE_BYTE_BINARY);
bimg.createGraphics().drawImage(thisImage, 0, 0, null);
for(Iterator<ImageWriter> writerIter = ImageIO.getImageWritersByFormatName("tif"); writerIter.hasNext() && !foundWriter;) {
foundWriter = true;
ImageWriter writer = (ImageWriter)writerIter.next();
writer.setOutput(ios);
TIFFImageWriteParam writeParam = (TIFFImageWriteParam)writer.getDefaultWriteParam();
writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
writeParam.setCompressionType("CCITT T.6");
writer.prepareWriteSequence(null);
ImageTypeSpecifier spec = ImageTypeSpecifier.createFromRenderedImage(bimg);
javax.imageio.metadata.IIOMetadata metadata = writer.getDefaultImageMetadata(spec, writeParam);
IIOImage iioImage = new IIOImage(bimg, null, metadata);
writer.writeToSequence(iioImage, writeParam);
bimg.flush();
writer.endWriteSequence();
ios.flush();
writer.dispose();
ios.close();
thisByteArray = baos.toByteArray();
baos.close();
}
}