Write a .TIFF with JAI - java

I'm a beginner in Java and a geomatics student.
I'am using IntelliJ.
I would like to create a TIFF from a BufferedImage.
This is my code :
byte[] buffer = new byte[width * height];
ColorSpace cs = ColorSpace.getInstance( ColorSpace.CS_GRAY );
int[] nBits = { 8 };
ColorModel cm = new ComponentColorModel( cs, nBits, false, true,Transparency.OPAQUE, DataBuffer.TYPE_BYTE );
SampleModel sm = cm.createCompatibleSampleModel( width, height );
DataBufferByte db = new DataBufferByte( buffer, width * height );
WritableRaster raster = Raster.createWritableRaster( sm, db, null);
BufferedImage result = new BufferedImage( cm, raster, false , null );
File outputfile = new File( "saved.png" );
ImageIO.write( result, "png", outputfile );
A raster .png is create and it works well. But I want to create a .TIFF and ImageIO.write don't create TIFF (only png,bmp and jpeg). So I download the JAI (Java Advanced Imaging) here : http://download.java.net/media/jai/builds/release/1_1_3/
I upload it on my project and on Maven, but I don't know how to make a tiff simply... I try some snippets that I found on the internet but it don't work..
TIFFEncodeParam params = new TIFFEncodeParam();
FileOutputStream os = new FileOutputStream("PingsTiff.tiff");
javax.media.jai.JAI.create("encode", result, os, "TIFF", params);
The "TIFFEncodeParam" and "media" is not recognized...and I'm a real noob at programming..
Thanks

First of all, JAI comes with a set of ImageIO plugins, that will allow you to use ImageIO.write to write in TIFF format. But it requires the jai_imageio.jar to be on class path. I guess this is the JAR you are missing.
Also, the code you posted should work, if you have the imports and dependencies set up correctly. It's a little tricky because some parts of JAI requires native libraries that needs to be installed using the installer, and in the correct JRE, etc. Because of this, it's not a perfect fit with Maven (although certainly doable).
However, as you see from the download link in your question, JAI is a pretty much dead project (the latest update is from 2006).
Because of this lack of updates, bug fixes and support, along with the native parts and the license issues, I set up an open source project, aimed to provide at least as good file format support as JAI, with no native requirements and released under BSD license.
You can read about it, and the TIFF plugin in particular at the project home page. A little further down the page is down is download links, Maven dependency information etc.
When you have declared dependency on the TIFF plugin, you should be able to write your TIFF using plain ImageIO like this:
File outputfile = new File("saved.tif");
if (!ImageIO.write(result, "TIFF", outputfile)) {
// Beware, write is a boolean method, that returns success!
System.err.println("Could not write " + outputfile.getAbsolutePath() + " in TIFF format.");
}

Related

It is possible to use the TessAPI1.TessPDFRendererCreate API of tess4J without needing to create physical files?

I am using the Tesseract Java API (tess4J) to convert Tiff images to PDFs.
This works nicely, but I am forced to write both the source Tiff image and the output PDF to local filestore as actual physical files in order to use the TessAPI1.TessPDFRendererCreate API.
Please note the following in the code snippet below: -
The input Tiff is originally a java.awt.image.BufferedImage, but I have to write it to a physical file (sourceTiffFile is a File object).
I must specify a file path for the output (pdfFullFilepath is a String representing an absolute path for the new PDF file).
try {
ImageIO.write(bufferedImage, "tiff", sourceTiffFile);
} catch (Exception ioe) {
//handling code...
}
TessResultRenderer renderer = TessAPI1.TessPDFRendererCreate(pdfFullFilepath, dataPath, 0);
TessAPI1.TessResultRendererInsert(renderer, TessAPI1.TessPDFRendererCreate(pdfFullFilepath, dataPath, 0));
int result = TessAPI1.TessBaseAPIProcessPages(handle, sourceTiffFile.getAbsolutePath(), null, 0, renderer);
I would really like to avoid creating physical files, but am not sure if it is possible with this API. Ideally, I would like to pass the Tiff as a java.awt.image.BufferedImage or a byte array and receive the output PDF as a byte array.
Any suggestions would be most welcome as always. Thank you :)
You can pass in ProcessPage API method a Pix, which can be converted from a BufferedImage, but the output will still be a physical file. Tesseract API dictates that.
https://tesseract-ocr.github.io/tessapi/4.0.0/a01625.html
http://tess4j.sourceforge.net/docs/docs-4.4/net/sourceforge/tess4j/TessAPI1.html
For ex:
int result = TessAPI1.TessBaseAPIProcessPage(handle, LeptUtils.convertImageToPix(bufferedImage), page_index, "input file name", null, 0, renderer);

Decoding of old style JPEG-in-TIFF data is not supported

I need to display the 3rd page of scanned tiff files. i used the code
TIFFReader reader = new TIFFReader(new File(pathOfFile));
RenderedImage image = reader.getPage(2);
its sometimes work. and show error : Decoding of old style JPEG-in-TIFF data is not supported.
I used aspriseTIFF.jar
then how i solve this problem.
please reply.
thanks in advance
The problem you have run into is that "old style" JPEG compression in the TIFF format (compression == 6), is not supported in the library you use.
This is quite common I guess, as "old-style" JPEG compression is deprecated in TIFF, because it was never fully specified. And because of this under-specification, various vendors implemented it in different, incompatible ways. Support was dropped in favor for TIFF compression 7, JPEG.
Unfortunately, old TIFF files using this compression still exists, so you need to find another library. The good news is that you can use ImageIO and a proper plug-in.
Using a TIFF ImageReader plug-in, like the one from my TwelveMonkeys ImageIO open source project, you should be able to do this:
// Create input stream
try (ImageInputStream input = ImageIO.createImageInputStream(file)) {
// Get the reader
ImageReader reader = ImageIO.getImageReaders(input).next();
try {
reader.setInput(input);
// Read page 2 of the TIFF file
BufferedImage image = reader.read(2, null);
}
finally {
reader.dispose();
}
}
(sorry about the try/finally boiler-plate, but it is important to avoid resource/memory leaks).

How do we convert WMF/EMF (MS metafiles) into standard images like JPG or PNG using any Java API?

I have been stuck in converting WMF/EMF images into standard image format such as JPG or PNG using Java.
What are the best options available?
The Batik library is a toolkit to handle SVG in Java. There are converters included like WMFTranscoder to convert from WMF to SVG and JPEGTranscoder and PNGTranscoder to convert SVG to JPEG/PNG. See Transcoder API Docs for more details.
Another alternative is ImageMagick. It's not Java but has Java bindings: im4java and JMagick.
wmf is a vector file format. For best results, convert them to .svg or .pdf format.
I did it in two stages
1) wmf2fig --auto XXXX.wmf
2) fig2pdf --nogv XXXX.fig
I created a python script for bulk conversion
import subprocess as sbp
a = sbp.Popen("ls *.wmf",shell=True, stderr=sbp.PIPE, stdout=sbp.PIPE)
filelist = a.communicate()[0].splitlines()
for ele in filelist:
cmdarg = 'wmf2fig --auto '+ ele.rsplit('.',1)[0]+'.wmf'
a = sbp.Popen(cmdarg, shell=True, stderr=sbp.PIPE, stdout=sbp.PIPE)
out = a.communicate()
for ele in filelist:
cmdarg = 'fig2pdf --nogv '+ ele.rsplit('.',1)[0]+'.fig'
a = sbp.Popen(cmdarg, shell=True, stderr=sbp.PIPE, stdout=sbp.PIPE)
out = a.communicate()
cmdarg = 'rm *.fig'
a = sbp.Popen(cmdarg, shell=True, stderr=sbp.PIPE, stdout=sbp.PIPE)
out = a.communicate()
If you are deploying your application in a Windows environment, then SWT can handle the conversion for you.
Image image = new Image(Display.getCurrent(), "test.wmf");
ImageLoader loader = new ImageLoader();
loader.data = new ImageData[] { image.getImageData() };
try(FileOutputStream stream = new FileOutputStream("test.png"))
{
loader.save(stream, SWT.IMAGE_PNG);
}
image.dispose();
The purpose of SWT is to provide a Java wrapper around native functionality, and in this case it is calling the windows GDI directly to get it to render the WMF.
I've created some wrappers around the Batik package (as mentioned by vanje's answer) some time ago, that provides ImageIO support for SVG and WMF/EMF.
With these plugins you should be able to write:
ImageIO.write(ImageIO.read(wmfFile), pngFile, "png");
Source code on GitHub.
While the ImageIO plugins are convenient, im4java and JMagick might still have better format support.
Here is one way.
Get (or make) a Java component that can render the files in question.
Create a BufferedImage the same size as the component needs to display the image.
Get the Graphics object from the BufferedImage.
Call renderComponent.paintComponent(Graphics)
Save the image using one of the ImageIO.write() variants.
See my answer to Swing: Obtain Image of JFrame for steps 2-5. Step 1. is something I'd ask Google about.

Creating JPEGs: converting access restricted code (JPEGImageEncoder) to "safe" code

I was given the following code, and Eclipse marked it (at the JPEGImageEncoder line) as an error (Access restriction). I changed Eclipse options to make that code compile, but I read that the error means that that class (JPEGImageEncoder) may not be implemented by some JRE implementation (not a Sun/Oracle one).
So, what should be the code that wouldn't have access restrictions, i.e. completely safe code to do the same thing (create a JPG image)?
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(filename));
JPEGImageEncoder encoder=JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(buffImage);
param.setQuality(0.8f, false);
encoder.encode(buffImage, param);
Maybe I've misunderstood, but if all you're looking to do is save a BufferedImage object as a jpeg, you can do this (from Java 1.4 onwards):
ImageIO.write(bufferedImage,"jpg",file);
Here's a link with more information: http://download.oracle.com/javase/tutorial/2d/images/saveimage.html
As you can see, it says that JPEG, PNG, GIF, BMP and WBMP will always be supported.
If you want to set the compression/quality, it's a little more work but not too much. Assuming you have a bufferedImage and an outFile:
IIOImage outputImage = new IIOImage(bufferedImage, null, null);
ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next();
writer.setOutput(new FileImageOutputStream(outFile));
ImageWriteParam writeParam = writer.getDefaultWriteParam();
writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
writeParam.setCompressionQuality(.75f); // float between 0 and 1, 1 for max quality.
writer.write( null, outputImage, writeParam);
(fixed from previous answer)

Is there a 100% Java alternative to ImageIO for reading JPEG files?

We are using Java2D to resize photos uploaded to our website, but we run into an issue (a seemingly old one, cf.: http://forums.sun.com/thread.jspa?threadID=5425569) - a few particular JPEGs raise a CMMException when we try to ImageIO.read() an InputStream containing their binary data:
java.awt.color.CMMException: Invalid image format
at sun.awt.color.CMM.checkStatus(CMM.java:131)
at sun.awt.color.ICC_Transform.<init>(ICC_Transform.java:89)
at java.awt.image.ColorConvertOp.filter(ColorConvertOp.java:516)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.acceptPixels(JPEGImageReader.java:1114)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readImage(Native Method)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:1082)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:897)
at javax.imageio.ImageIO.read(ImageIO.java:1422)
at javax.imageio.ImageIO.read(ImageIO.java:1326)
...
(snipped the remainder of the stack trace, which is our ImageIO.read() call, servlet code and such)
We narrowed it down to photos taken on specific cameras, and I selected a photo that triggers this error: http://img214.imageshack.us/img214/5121/estacaosp.jpg.
We noticed that this only happens with Sun's JVM (on Linux and Mac, just tested it on 1.6.0_20) - a test machine with OpenJDK reads the same photos without a hitch, possibly due to a different implementation of the JPEG reader.
Unfortunately, we are unable to switch JVMs in production, nor to use native-dependent solutions such as ImageMagick ( http://www.imagemagick.org/ ).
Considering that, my question is: Does a replacement for ImageIOs JPEG reader which can handle photos such as the linked one exist? If not, is there another 100% pure Java photo resizing solution which we can use?
Thank you!
One possibly useful library for you could be the Java Advanced Imaging Library (JAI)
Using this library can be quite a bit more complicated than using ImageIO but in a quick test I just ran, it did open and display the problem image file you linked.
public static void main(String[] args) {
RenderedImage image = JAI.create("fileload", "estacaosp.jpg");
float scale=(float) 0.5;
ParameterBlock pb = new ParameterBlock();
pb.addSource(image);
pb.add(scale);
pb.add(scale);
pb.add(1.0F);
pb.add(1.0F);
pb.add(new InterpolationNearest() );// ;InterpolationBilinear());
image = JAI.create("scale", pb);
// Create an instance of DisplayJAI.
DisplayJAI srcdj = new DisplayJAI(image);
JScrollPane srcScrollPaneImage = new JScrollPane(srcdj);
// Use a label to display the image
JFrame frame = new JFrame();
frame.getContentPane().add(srcScrollPaneImage, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
After running this code the image seems to load fine. It is then resized by 50% using the ParamaterBlock
And finally if you wish to save the file you can just call :
String filename2 = new String ("tofile.jpg");
String format = new String ("JPEG");
RenderedOp op = JAI.create ("filestore", image, filename2, format);
I hope this helps you out. Best of luck.
Old post, but for future reference:
Inspired by this question and links found here, I've written a JPEGImageReader plugin for ImageIO that supports JPEG images with these kind of "bad" ICC color profiles (the "issue" is the rendering intent in the ICC profile is incompatible with Java's ColorConvertOp). It's plain Java and does not require JAI.
The source code and linked binary builds are freely available from the TwelveMonkeys project on GitHub.
I faced the same issue. I was reluctant to use JAI as it is outdated but it looks like it's the shortest solution.
This code converts an InputStream to a BufferedImage, using sun's ImageIO (fast) or in the few cases where this problem occur, using JAI:
public static BufferedImage read(InputStream is) throws IOException {
try {
// We try it with ImageIO
return ImageIO.read(ImageIO.createImageInputStream(is));
} catch (CMMException ex) {
// If we failed...
// We reset the inputStream (start from the beginning)
is.reset();
// And use JAI
return JAI.create("stream", SeekableStream.wrapInputStream(is, true)).getAsBufferedImage();
}
}

Categories