DicomDroid.jar used to open a .dcm formated image in my Android application. I got the follwing exception when try to open it.
java.io.IOException: DICOM JPEG compression not yet supported
Adding my code below
try {
// Read the imagefile into a byte array (data[])
File imagefile = new File(path);
byte[] data = new byte[(int) imagefile.length()];
FileInputStream fis = new FileInputStream(imagefile);
fis.read(data);
fis.close();
// Create a DicomReader with the given data array (data[])
DicomReader DR = new DicomReader(data);
} catch (Exception ex) {
Log.e("ERROR", ex.toString());
}
What can be done to avoid this error?
Thanks in advance.
The cause is pretty obvious. That DICOM library doesn't support that particular kind of DICOM file.
There's not much you can do about it ... unless you are prepared to enhance the library yourself.
But I think you have probably made a mistake in setting up your instrument to generate DICOM files with JPEG compression. JPEG is lossy, and best practice is to capture and store images with the best resolution feasible. If you need to downgrade resolution to reduce bandwidth, it would be better to
save a high resolution DICOM,
convert the DICOM to a low resolution JPG, and
send the JPEG.
Another option is to get the Dicom file in an uncompressed format (ej: Explicit VR Little Endian). This is the simplest dicom file format and every dicom library has support for such format.
So, when you get your Dicom file from your PACS, force this transfer syntax. This way, your dicom library will be able to deal with the image file.
Related
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);
I got a strange issue with a GIF image in Java. The image is provided by an XML API as Base64 encoded string. To decode the Base64, I use the commons-codec library in version 1.13.
When I just decode the Base64 string and write the bytes out to a file, the image shows properly in browsers and MS Paint (nothing else to test here).
final String base64Gif = "[Base64 as provided by API]";
final byte[] sigImg = Base64.decodeBase64(base64Gif);
File sigGif = new File("C:/Temp/pod_1Z12345E5991872040.org.gif");
try (FileOutputStream fos = new FileOutputStream()) {
fos.write(sigImg);
fos.flush();
}
The resulting file opened in MS Paint:
But when I now start consuming this file using Java (for example creating a PDF document from HTML using the openhtmltopdf library), it is corrupted and does not show properly.
final String htmlLetterStr = "[HTML as provided by API]";
final Document doc = Jsoup.parse(htmlLetterStr);
try (FileOutputStream fos = new FileOutputStream(new File("C:/Temp/letter_1Z12345E5991872040.pdf"))) {
PdfRendererBuilder builder = new PdfRendererBuilder();
builder.useFastMode();
builder.withW3cDocument(new W3CDom().fromJsoup(doc), "file:///C:/Temp/");
builder.toStream(fos);
builder.useDefaultPageSize(210, 297, BaseRendererBuilder.PageSizeUnits.MM);
builder.run();
fos.flush();
}
When I now open the resulting PDF, the image created above looks like this. It seems that only the first pixel lines are printed, some layer is missing, or something like that.
The same happens, if I read the image again with ImageIO and try to convert it into PNG. The resulting PNG looks exactly the same as the image printed in the PDF document.
How can I get the image to display properly in the PDF document?
Edit:
Link to original GIF Base64 as provided by API: https://pastebin.com/sYJv6j0h
As #haraldK pointed out in the comments, the GIF file provided via the XML API does not conform to the GIF standard and thus cannot be parsed by Java's ImageIO API.
Since there does not seem to exist a pure Java tool to repair the file, the workaround I came up with now is to use ImageMagick via Java's Process API. Calling the convert command with the -coalesce option will parse the broken GIF and create a new one that does conform to the GIF standard.
// Decode broken GIF image and write to disk
final String base64Gif = "[Base64 as provided by API]";
final byte[] sigImg = Base64.decodeBase64(base64Gif);
Path gifPath = Paths.get("C:/Temp/pod_1Z12345E5991872040.tmp.gif");
if (!Files.exists(gifPath)) {
Files.createFile(gifPath);
}
Files.write(gifPath, sigImg, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
// Use the Java Process API to call ImageMagick (on Linux you would use the 'convert' binary)
ProcessBuilder procBuild = new ProcessBuilder();
procBuild.command("C:\\Program Files\\ImageMagick-7.0.9-Q16\\magick.exe", "C:\\Temp\\pod_1Z12345E5991872040.tmp.gif", "-coalesce", "C:\\Temp\\pod_1Z12345E5991872040.gif");
Process proc = procBuild.start();
// Wait for ImageMagick to complete its work
proc.waitFor();
The newly created file can be read by Java's ImageIO API and be used as expected.
I need to open an .hdr file and work on it, but imageIO doesn't supports that format.
The problem is that I need to keep the information loss as little as possible: 32bpc is perfect, 16 is fine and less the 16 won't work.
There are 3 possible solutions I came up to:
Find a plugin that allow me to open .HDR file. I've been searching for it a lot but without luck;
Find a way to convert the .HDR file to a format I can find a plugin for. Tiff maybe? Tried this too but still no luck;
Reduce the dynamic range from 32bpc to 16bpc and then convert it to png. This is tricky because once I have a png file I win, but it's not that easy to cut the range without killing the image..
What would you recommend me to do? Do you know a way to make one of those 3 options works? Or do you have a better idea?
You can now read .HDR using ImageIO. :-)
This is a first version, so it might be a little rough around the edges, but should work for standard (default settings) Radiance RGBE .HDR files.
The returned image will be a custom BufferedImage with a DataBufferFloat backing (ie., samples will be in 3 samples, 32-bit float interleaved RGB format).
By default, a simple global tone-mapping is applied, and all RGB values will be normalized to range [0...1] (this allows anyone to just use ImageIO.read(hdrFile) and the image will look somewhat reasonable, in a very reasonable time).
It is also possible to pass an HDRImageReadParam to the ImageReader instance with a NullToneMapper. This is even faster, but the float values will be unnormalized, and might exceed the max value. This allows you to do custom, more sophisticated tone-mapping on the image data, before converting to something more displayable.
Something like:
// Create input stream
ImageInputStream input = ImageIO.createImageInputStream(hdrFile);
try {
// Get the reader
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
if (!readers.hasNext()) {
throw new IllegalArgumentException("No reader for: " + hdrFile);
}
ImageReader reader = readers.next();
try {
reader.setInput(input);
// Disable default tone mapping
HDRImageReadParam param = (HDRImageReadParam) reader.getDefaultReadParam();
param.setToneMapper(new NullToneMapper());
// Read the image, using settings from param
BufferedImage image = reader.read(0, param);
}
finally {
// Dispose reader in finally block to avoid memory leaks
reader.dispose();
}
}
finally {
// Close stream in finally block to avoid resource leaks
input.close();
}
// Get float data
float[] rgb = ((DataBufferFloat) image.getRaster().getDataBuffer()).getData();
// TODO: Custom tone mapping on float RGB data
// Convert the image to something easily displayable
BufferedImage converted = new ColorConvertOp(null).filter(image, new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB));
// Optionally write as JPEG or other format
ImageIO.write(converted, "JPEG", new File(...));
I would like to write IPTC data, such as title, description or keywords to an jpg file, but it does not work. If i run the sample code a second jpg file is writen, but no sample data. I am using the commons imaging library from Apache:
http://commons.apache.org/proper/commons-imaging/
Here is the sample code:
TiffImageMetadata metadata = ((JpegImageMetadata)Imaging.getMetadata(new File(JPG_PATH +
"\\IMGP5996_empty.jpg"))).getExif();
ExifRewriter rewriter = new ExifRewriter();
TiffOutputSet outputSet = metadata.getOutputSet();
TiffOutputDirectory exif = outputSet.getOrCreateExifDirectory();
exif.add(MicrosoftTagConstants.EXIF_TAG_XPAUTHOR, "TEST_AUTHOR");
exif.add(MicrosoftTagConstants.EXIF_TAG_XPCOMMENT, "TEST_COMMENT");
exif.add(MicrosoftTagConstants.EXIF_TAG_XPSUBJECT, "TEST_SUBJECT");
exif.add(MicrosoftTagConstants.EXIF_TAG_XPTITLE, "TEST_TITLE");
exif.add(MicrosoftTagConstants.EXIF_TAG_XPKEYWORDS, "TEST_KEYWORD");
FileOutputStream fos=new FileOutputStream(new File(JPG_PATH + "\\IMGP5996_empty-2.jpg"));
rewriter.updateExifMetadataLossy(jpgFile, fos, outputSet);
Can anyone help me?
I think at this moment, it is not possible to write (with commons imaging) IPTC metadata to a jpg file:
http://commons.apache.org/proper/commons-imaging/todo.html
It would be straightforward, but not trivial, to do this on your own. You would need to rewrite the EXIF APPn Market, but this could be down without modifying the rest of the compressed data stream. You would need to read the EXIF standard to understand how the metadata tags are encoded.
Thank you all for your reply
I have fond a solution with iim4j:
http://iim4j.sourceforge.net/
Good library but poor documenation
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).