There seems to be some debate about whether JPEGs with alpha channels are valid or not. The answer I 开发者_JS百科had always understood to be correct is that in the JPEG FAQ, which is essentially "No". (This is reiterated in another question on Stack Overflow.)
However, Java's JPEGImageWriter in Sun's ImageIO library will happily write and read grayscale and RGB images with an alpha channel, even though there are virtually no applications on Linux I've tried so far that will load such JPEGs correctly. This has been reported in the past as a bug, but Sun's response is that these are valid files:
This is not an Image I/O bug, but rather a deficiency in the other applications the submitter mentions. The IIO JPEGImageWriter is able to write images with a color model that contains an alpha channel (referred to in the IJG native source code as the "NIFTY" color spaces, such as RGBA, YCbCrA, etc.), but many applications are not aware of these color spaces. So even though these images written by the IIO JPEG writer are compliant with the JPEG specification (which is blind to the various color space possiblities), some applications may not recognize color spaces that contain an alpha channel and may throw an error or render a corrupted image, as the submitter describes.
Developers wishing to maintain compatibility with these other alpha-unaware applications should write images that do not contain an alpha channel (such as TYPE_INT_RGB). Developers who want the capability of writing/reading an image containing an alpha channel in the JPEG format can do so using the Image I/O API, but need to be aware that many native applications out there are not quite compliant with the YCbCrA and RGBA formats.
For more information, see the Image I/O JPEG Metadata Format Specification and Usage Notes: http://java.sun.com/j2se/1.4.1/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html
Closing as "not a bug". xxxxx@xxxxx 2003-03-24
I'm working with a Java application that creates files like these, and want to write some C code that will load these as fast as possible. (Essentially the problem is that the Java ImageIO library is remarkably slow at decompressing these files, and we would like to replace the loader with native code via JNI that improves this - it's a performance bottleneck at the moment.)
There are some example files here - apologies to anyone who's coulrophobic:
- http://mythic-beasts.com/~mark/example-jpegs/
And here you can see the results of trying to view the grayscale+alpha and RGB+alpha images with various bit of Linux software that I believe use libjpeg
:
grayscale image with alpha channel view with various programs http://mythic-beasts.com/~mark/all-alpha-bridges.png
(source: mark at mythic-beasts.com)So it looks as if the color space is just being misinterpreted in each case. The only allowed values in jpeglib.h
are:
/* Known color spaces. */
typedef enum {
JCS_UNKNOWN, /* error/unspecified */
JCS_GRAYSCALE, /* monochrome */
JCS_RGB, /* red/green/blue */
JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */
JCS_CMYK, /* C/M/Y/K */
JCS_YCCK /* Y/Cb/Cr/K */
} J_COLOR_SPACE;
... which doesn't look promising.
If I load these images with a slightly modified version of example.c
from libjpeg
, the values of cinfo.jpeg_color_space
and cinfo.out_color_space
for each image after reading the header are as follows:
gray-normal.jpg: jpeg_color_space is JCS_GRAYSCALE, out_color_space is JCS_GRAYSCALE
gray-alpha.jpg: jpeg_color_space is JCS_CMYK, out_color_space is JCS_CMYK
rgb-normal.jpg: jpeg_color_space is JCS_YCbCr, out_color_space is JCS_RGB
rgb-alpha.jpg: jpeg_color_space is JCS_CMYK, out_color_space is JCS_CMYK
So, my questions are:
- Can libjpeg be used to correctly read these files?
- If not, is there an alternative C library I can use which will cope with them?
Obviously there are at least two other solutions to the more general problem:
- Change the software to output normal JPEGs + a PNG file representing the alpha channel
- Somehow improve the performance of Sun's ImageIO
... but the first would involve a lot of code changes, and it's not clear how to go about the latter. In any case, I think that the question of how to use libjpeg
to load such files is likely to be one of more general interest.
Any suggestions would be much appreciated.
Even if you store your images as 4 channel jpeg images, there's no standardized way I know of how to specify the color format in the jpeg file.
The JFIF standard assumes YCbCr.
Have you already tried libjpeg-turbo? It is supposed to be able to decode RGBA and there is already a Java wrapper for it.
I have tried running libjpeg-turbo on color images that have an alpha channel and which have been saved with java's ImageIO as jpeg.
This is how I compiled libjpeg-turbo for linux 64-bit:
$ autoreconf -fiv
$ mkdir build
$ cd build
$ sh ../configure --with-java CPPFLAGS="-I$JAVA_HOME/include -I$JAVA_HOME/include/linux"
$ make
$ cd ..
$ mkdir my-install
$ cd build
$ make install prefix=$PWD/../my-install libdir=$PWD/../my-install/lib64
This is how I run Fiji with the correct library path and classpath, to include libjpeg-turbo:
$ cd Programming/fiji
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/../java/libjpeg-turbo/libjpeg-turbo/my-install/lib64
$ ./fiji -cp $PWD/../java/libjpeg-turbo/libjpeg-turbo/my-install/classes/turbojpeg.jar
This is a small jython script to read such jpeg+alpha files:
###### path = "/home/albert/Desktop/t2/trakem2.1263462814399.1347985440.1111111/trakem2.mipmaps/0/17.07may04b_GridID02043_Insertion001_00013gr_00005sq_00014ex.tif.jpg" from org.libjpegturbo.turbojpeg import TJDecompressor, TJ from java.io import File, FileInputStream from java.awt.image import BufferedImage from jarray import zeros f = File(path) fis = FileInputStream(f) b = zeros(fis.available(), 'b') print len(b) fis.read(b) fis.close() d = TJDecompressor(b) print d.getWidth(), d.getHeight() bi = d.decompress(d.getWidth(), d.getHeight(), BufferedImage.TYPE_INT_ARGB, 0) ImagePlus("that", ColorProcessor(bi)).show() ####
The problem: no matter what flag I use (the '0' above in the call to decompress) from the TJ class (see http://libjpeg-turbo.svn.sourceforge.net/viewvc/libjpeg-turbo/trunk/java/doc/org/libjpegturbo/turbojpeg/TJ.html), I cannot get the jpeg to load.
Here's the error message:
Started turbojpeg.py at Thu Jun 02 12:36:58 EDT 2011 Traceback (most recent call last): File "", line 15, in at org.libjpegturbo.turbojpeg.TJDecompressor.decompressHeader(Native Method) at org.libjpegturbo.turbojpeg.TJDecompressor.setJPEGImage(TJDecompressor.java:89) at org.libjpegturbo.turbojpeg.TJDecompressor.(TJDecompressor.java:58) at sun.reflect.GeneratedConstructorAccessor10.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at org.python.core.PyReflectedConstructor.constructProxy(PyReflectedConstructor.java:210) java.lang.Exception: java.lang.Exception: tjDecompressHeader2(): Could not determine subsampling type for JPEG image
So it appears that either libjpeg-turbo cannot read jpeg with alpha as saved by ImageIO, or there is a very non-obvious setting in the call to "decompress" that I am unable to grasp.
精彩评论