Convert PNG to bitonal TIFF - java

-Edit-
FYI.. I am converting b&w documents scanned in as greyscale or color.
1)The first solution worked, it just reversed black & white (black background, white text). It also took nearly 10 minutes.
2)The JAI solution in the 2nd answer didn't work for me. I tried it before posting here.
Has anyone worked with other libraries free or pay that handle image manipulation well?
-Original-
I am trying to convert an PNG to a bitonal TIFF using Java ImageIO. Has anyone had any luck doing this? I have got it to convert from PNG to TIFF. I am not sure if I need to convert the BufferedImage (PNG) that I read in or convert on the TIFF as I write it. I have searched and searched but nothing seems to work? Does anyone have an suggestions where to look?
Here is the code that converts...
public static void test() throws IOException {
String fileName = "4848970_1";
// String fileName = "color";
String inFileType = ".PNG";
String outFileType = ".TIFF";
File fInputFile = new File("I:/HPF/UU/" + fileName + inFileType);
InputStream fis = new BufferedInputStream(new FileInputStream(fInputFile));
ImageReaderSpi spi = new PNGImageReaderSpi();
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("I:\\HPF\\UU\\" + 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();
}
I have tried changing the compression to type "CCITT T.6" as that appears to be what I want, but I get an error " Bits per sample must be 1 for T6 compression! " Any suggestion would be appreciated.

Most likely, you want something like this to convert to 1 bit before you save to TIFF with CCITT compression.
To expound a little bit - be aware that converting from other bit depths to 1 bit is non-trivial. You are doing a data reduction operation and there are dozens of domain specific solutions which vary greatly in output quality (blind threshold, adaptive threshold, dithering, local threshold, global threshold and so on). None of them are particularly good at all image types (adaptive threshold is pretty good for documents, but lousy for photographs, for example).

As plinth said, you have to do the conversion, Java won't do it magically for you...
If the PNG image is already black & white (as it seems, looking at your comment), using a threshold is probably the best solution.
Somebody seems to have the same problem: HELP: how to compress the tiff. A solution is given on the thread (untested!).

Related

javafx read javafx.scene.image.Image to ImageIO.write(), from CMYK to RGB

What I want to do is read an image from FileChooser and write it to file. I had to store the image in a javafx.scene.image.Image so that I can display it and clip it inside a circle. I have a little problem with trying to write the image that I got from javafx.scene.image.Image to file. The conversion process is not fluid, converts from CMYK to RGB (therefore turning my picture to some pink thing.
Please, I have checked a lot of other sources, and no one has been able to give me a notable solution
FileChooser fileChooser = new FileChooser();
File selectedFile = fileChooser.showOpenDialog(parent);
// get Image from selectedFile
Image userImg = = new Image( selectedFile.toURI().toURL().toString() );
if ( userImg != null ) {
String format = "jpg";
String filename = "d:\\pictureName."+ format;
File file = new File(filename);
// convert Image to BufferedImage
BufferedImage bufferedImage = SwingFXUtils.fromFXImage( userImg, null);
try {
// this is where i want to convert the color mode
// from cmyk to rgb, before i write it to file
ImageIO.write( bufferedImage, format, file );
} catch (IOException e) {
System.out.println("Exception :: "+ e.getMessage() );
}
}
Why do you think that there is some CMYK to RGB conversion happening? I suspect the reason for your "pink thing" is something different. The easiest way to find out is to change your output format from jpeg to png and see whether it makes a difference.
I think you are again one of the many people who are hit by this bug https://bugs.openjdk.java.net/browse/JDK-8119048 which is not considered important enough to be fixed. If you read the comments in there you will find a work-arround. Basically the idea is to copy the image after the conversion into a new image without alpha channel.
I'd really like to know how many more people have to waste their time until this bug finally gets enough attention to be fixed.

How do I save a BufferedImage to a pgm file?

I looked through the internet but I could not find an answer. I have a pgm file which I use as a BufferedImage to do a convolution (I use JAI for that) but I am having trouble in saving it back to a pgm file.
So far I used following code to save:
JAI.create("filestore", newImage, outputFileName);
With that I get a pgm file but when I open the image IfranView tells me that it is a TIF file with incorrect extension. What do I need to change?
I appreciate any help! Please provide code examples if possible. Thanks everyone.
Kind regards,
Staniel
BufferedImage bufferedImage = ImageIO.read(new File("input file directory...image.png"));
ImageIO.write(bufferedImage, "pgm", new File("output file directory.....image.pgm"));
This should take a buffered image (jpeg, png...etc) and convert it properly to a pgm.
EDIT: The JAI Plugin which allows for .pgm files to be used with ImageIO can be found at http://www.oracle.com/technetwork/java/index.html
Here's an example I found. Not tested.
// Create the OutputStream.
OutputStream out = new FileOutputStream(fileToWriteTo);
// Create the ParameterBlock.
PNMEncodeParam param = new PNMEncodeParam();
param.setRaw(true.equals("raw"));
//Create the PNM image encoder.
ImageEncoder encoder = ImageCodec.createImageEncoder("PNM", out, param);
See Writing PNM Files.
I found the answer. I already added the external JAI imageio to my library.
ImageIO.write(bufferedImage, "pnm", new File("output file directory.....image.pgm"));
Instead of "pgm" it should say "pnm". The new file will automatically have the pgm extension.
Maybe late, but I just wrote one. A simple PGM writer taking a 2d-double array with values in range [0.0,1.0].
public static void WritePGM(string fileName, double[,] bitmap)
{
var width = bitmap.GetLength(0);
var height = bitmap.GetLength(1);
var header = "P5\n" + width + " " + height + "\n255\n";
var writer = new BinaryWriter(new FileStream(fileName, FileMode.Create));
writer.Write(System.Text.Encoding.ASCII.GetBytes(header));
for (var j = 0; j < height; j++)
{
for (var i = width-1; i >= 0; i--)
{
var c = (byte)(System.Math.Max(System.Math.Min(1.0, bitmap[i, j]), 0.0) * 255.0);
writer.Write(c);
}
}
writer.Close();
}

Compression of PNG using JAI (Java Advanced Imaging)

I am using javax.imageio API and JAI for compressing different types of images. It works fine for JPEG using JPEGImageWriter and GIF using GIFImageWriter. But it is not supporting for PNG compression using PNGImageWriter which throws an exception like compression type is not set or "No valid compression", etc. So I used this below ImageWriter for PNG. It works but image quality is too bad.
Can anyone suggest how to use PNGImageWriter for PNG compression and which JAR contains it?
File input = new File("test.png");
InputStream is = new FileInputStream(input);
BufferedImage image = ImageIO.read(is);
File compressedImageFile = new File(input.getName());
OutputStream os =new FileOutputStream(compressedImageFile);
Iterator<ImageWriter>writers =
ImageIO.getImageWritersByFormatName("jpg"); // here "png" does not work
ImageWriter writer = (ImageWriter) writers.next();
ImageOutputStream ios = ImageIO.createImageOutputStream(os);
writer.setOutput(ios);
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(0.5f);
writer.write(null, new IIOImage(image, null, null), param);
It seems the default com.sun.imageio.plugins.png.PNGImageWriter that is bundled with the JRE does not support setting compression. This is kind of surprising, as the format obviously supports compression. However, the PNGImageWriter always writes compressed.
You can see from the source code that it uses:
Deflater def = new Deflater(Deflater.BEST_COMPRESSION);
Which will give you good, but slow compression. It might be good enough for you, but for some cases it might be better to use faster compression and larger files.
To fix your code, so that it would work with any format name, change the lines:
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(0.5f);
to:
ImageWriteParam param = writer.getDefaultWriteParam();
if (param.canWriteCompressed()) {
// NOTE: Any method named [set|get]Compression.* throws UnsupportedOperationException if false
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(0.5f);
}
It will still write compressed PNGs.
If you need more control over the PNG compression, like setting compression or filter used, you need to find an ImageWriter that supports it. As you mention JAI, I think the CLibPNGImageWriter that is part of jai-imageio.jar or jai-imageio-tools.jar supports setting compression. You just need to look through the ImageWriters iterator, to see if you have it installed:
Iterator<ImageWriter>writers = ImageIO.getImageWritersByFormatName("png");
ImageWriter writer = null;
while (writers.hasNext()) {
ImageWriter candidate = writers.next();
if (candidate.getClass().getSimpleName().equals("CLibPNGImageWriter")) {
writer = candidate; // This is the one we want
break;
}
else if (writer == null) {
writer = candidate; // Any writer is better than no writer ;-)
}
}
With the correct ImageWriter, your code should work as expected.
Please check that this code may work for you.
ImageWriteParam writeParam = writer.getDefaultWriteParam();
writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
writeParam.setCompressionType("PackBits");
writeParam.setCompressionQuality(0.5f);
Thanks.

Java Converting ByteArray into Image

I'm reading a file that has an array of bytes. I downloaded the Apache Commons IO library to use the FileUtils' method readFileToByteArray
File file = new File("/home/username/array.txt");
FileUtils fu = new FileUtils();
byte[] array = FileUtils.readFileToByteArray(file);
I want to convert the array of bytes to an Image.
ByteArrayInputStream bis = new ByteArrayInputStream(array);
Iterator<?> readers = ImageIO.getImageReadersByFormatName("gif");
ImageReader reader = (ImageReader) readers.next();
Object source = bis;
ImageInputStream iis = ImageIO.createImageInputStream(source);
reader.setInput(iis, true);
ImageReadParam param = reader.getDefaultReadParam();
Image image = reader.read(0, param); // this line is the problem
When the code goes to the referred line, it throws an Exception saying
javax.imageio.IIOException: Unexpected block type 128!
I don't know what this exception means, therefore, I don't know how to fix it.
Any further information that could be helpful just need to be requested.
Thanks
I've tried your code on this file and it works fine.
What's the format of your array.txt? readFileToByteArray() expects a binary format, and your image reader will further expect it to be a GIF file.
Once you have byte[] you can use ImageIO to write it to BufferedImage.
BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(array));
ImageIO.write(bImageFromConvert, "gif", new File("c:/test.gif"));
That code means the reader couldn't decipher the metadata on the image file. Make sure the right file is getting read and it's well formed. Or it may be expecting a different file type.
without byte[] i feel this will be good for multipart file transfer,for this we need apache common jar files
final FileOutputStream output = new FileOutputStream("D:\\Dir\\"+ request.getParameter("imageName") + ".jpg");
IOUtils.copy(request.getPart("file").getInputStream(), output);
output.close();

How to combine two or many tiff image files in to one multipage tiff image in JAVA

I have 5 single page tiff images.
I want to combine all these 5 tiff images in to one multipage tiff image.
I am using Java Advanced Imaging API.
I have read the JAI API documentation and tutorials given by SUN.
I am new to JAI. I know the basic core java.
I dont understand those documentation and turorial by SUN.
So friends Please tell me how to combine 5 tiff image file in to one multipage tiff image.
Please give me some guidence on above topic.
I have been searching internet for above topic but not getting any single clue.
I hope you have the computer memory to do this. TIFF image files are large.
You're correct in that you need to use the Java Advanced Imaging (JAI) API to do this.
First, you have to convert the TIFF images to a java.awt.image.BufferedImage. Here's some code that will probably work. I haven't tested this code.
BufferedImage image[] = new BufferedImage[numImages];
for (int i = 0; i < numImages; i++) {
SeekableStream ss = new FileSeekableStream(input_dir + file[i]);
ImageDecoder decoder = ImageCodec.createImageDecoder("tiff", ss, null);
PlanarImage op = new NullOpImage(decoder.decodeAsRenderedImage(0), null, null, OpImage.OP_IO_BOUND);
image[i] = op.getAsBufferedImage();
}
Then, you convert the BufferedImage array back into a multiple TIFF image. I haven't tested this code either.
TIFFEncodeParam params = new TIFFEncodeParam();
OutputStream out = new FileOutputStream(output_dir + image_name + ".tif");
ImageEncoder encoder = ImageCodec.createImageEncoder("tiff", out, params);
Vector vector = new Vector();
for (int i = 0; i < numImages; i++) {
vector.add(image[i]);
}
params.setExtraImages(vector.listIterator(1)); // this may need a check to avoid IndexOutOfBoundsException when vector is empty
encoder.encode(image[0]);
out.close();

Categories