48

ImageIO.read(File file) を使用してこの 1 つの JPEG ファイルを読み取る際に問題が発生しました。「サポートされていない画像の種類」というメッセージで例外がスローされます。

他の JPEG 画像を試してみましたが、問題なく動作するようです。

私が見つけた唯一の違いは、このファイルにサムネイルが含まれているように見えることです。それは ImageIO.read() で問題を引き起こすことが知られていますか?

面倒なイメージ

編集:

結果の画像を追加しました:

奇妙な色

4

6 に答える 6

53

古い投稿ですが、今後の参考のために:

この質問とここにあるリンクに触発されて、CMYKカラーモデルをサポートするImageIO用のJPEGImageReaderプラグインを作成しました(元のカラーモデルを使用するか、読み取り時に暗黙的にRGBに変換されます)。リーダーは、ここで言及されている他のソリューションとは対照的に、JPEG ストリームに埋め込まれた ICC プロファイルを使用して、適切な色変換も行います。

これはプレーンな Java であり、JAI は必要ありません。ソース コードとバイナリ ディストリビューションはgithub.com/haraldk/TwelveMonkeysで自由に入手でき、BSD スタイルのライセンスが適用されます。

インストールすると、次のように使用して CMYK JPEG を読み取ることができますImageIO.read(...)

File cmykJPEGFile = new File(/*path*/);
BufferedImage image = ImageIO.read(cmykJPEGFile);

つまり: ほとんどの場合、コードを変更する必要はありません。

于 2013-04-22T14:04:01.913 に答える
40

画像の「カラー モデル」は CMYK ですJPEGImageReader(ファイルを読み取る内部クラス) は、RGB カラー モデルのみを読み取ります。

CMYK 画像を読みたい場合は、変換する必要があります。このコードを試してください。

アップデート

CMYK イメージを RGB BufferedImage に読み込みます。

    File f = new File("/path/imagefile.jpg");

    //Find a suitable ImageReader
    Iterator readers = ImageIO.getImageReadersByFormatName("JPEG");
    ImageReader reader = null;
    while(readers.hasNext()) {
        reader = (ImageReader)readers.next();
        if(reader.canReadRaster()) {
            break;
        }
    }

    //Stream the image file (the original CMYK image)
    ImageInputStream input =   ImageIO.createImageInputStream(f); 
    reader.setInput(input); 

    //Read the image raster
    Raster raster = reader.readRaster(0, null); 

    //Create a new RGB image
    BufferedImage bi = new BufferedImage(raster.getWidth(), raster.getHeight(), 
    BufferedImage.TYPE_4BYTE_ABGR); 

    //Fill the new image with the old raster
    bi.getRaster().setRect(raster);

更新 - 2015 年 3 月 - シミュレーション画像の追加

元の画像は OP のドロップボックスから削除されました。そのため、それらで発生していた問題をシミュレートする新しい画像 (元の画像ではない) を追加しています。

最初の画像は、通常の RGB 画像がどのように見えるかです。

画像RGB

2 番目の画像は、同じ画像が CMYK カラー モデルでどのように見えるかです。

ホストによって RGB に変換されるため、Web 上で実際にどのように見えるかを確認することはできません。どのように見えるかを正確に確認するには、RGB 画像を取得し、RGB から CMYK へのコンバーターに通します。

3 番目の画像は、Java ImageIO を使用して読み取ってから書き込むと、CMYK 画像がどのように見えるかです。

イメージ CMYK は Java RGB を介して読み取られます

OPで発生していた問題は、画像2のようなものがあり、読み取ろうとすると例外がスローされることです。

于 2010-03-09T12:01:09.320 に答える
18

私はパーティーに少し遅れています。しかし、答えのどれも実際に問題を解決しないので、答えを投稿することはおそらくまだ価値があります。

このソリューションには、Sanselan (現在は Apache Commons Imaging と呼ばれています) が必要であり、適切な CMYK カラー プロファイル (.icc ファイル) が必要です。後者は Adob​​e または eci.org から入手できます。

基本的な問題は、Java がそのままの状態で RGB の JPEG ファイルしか読み取れないことです。CMYK ファイルがある場合は、通常の CMYK、Adobe CMYK (逆の値、つまり、インクなしの場合は 255、最大インクの場合は 0)、および Adob​​e CYYK (色が反転しているバリアントもあります) を区別する必要があります。

public class JpegReader {

    public static final int COLOR_TYPE_RGB = 1;
    public static final int COLOR_TYPE_CMYK = 2;
    public static final int COLOR_TYPE_YCCK = 3;

    private int colorType = COLOR_TYPE_RGB;
    private boolean hasAdobeMarker = false;

    public BufferedImage readImage(File file) throws IOException, ImageReadException {
        colorType = COLOR_TYPE_RGB;
        hasAdobeMarker = false;

        ImageInputStream stream = ImageIO.createImageInputStream(file);
        Iterator<ImageReader> iter = ImageIO.getImageReaders(stream);
        while (iter.hasNext()) {
            ImageReader reader = iter.next();
            reader.setInput(stream);

            BufferedImage image;
            ICC_Profile profile = null;
            try {
                image = reader.read(0);
            } catch (IIOException e) {
                colorType = COLOR_TYPE_CMYK;
                checkAdobeMarker(file);
                profile = Sanselan.getICCProfile(file);
                WritableRaster raster = (WritableRaster) reader.readRaster(0, null);
                if (colorType == COLOR_TYPE_YCCK)
                    convertYcckToCmyk(raster);
                if (hasAdobeMarker)
                    convertInvertedColors(raster);
                image = convertCmykToRgb(raster, profile);
            }

            return image;
        }

        return null;
    }

    public void checkAdobeMarker(File file) throws IOException, ImageReadException {
        JpegImageParser parser = new JpegImageParser();
        ByteSource byteSource = new ByteSourceFile(file);
        @SuppressWarnings("rawtypes")
        ArrayList segments = parser.readSegments(byteSource, new int[] { 0xffee }, true);
        if (segments != null && segments.size() >= 1) {
            UnknownSegment app14Segment = (UnknownSegment) segments.get(0);
            byte[] data = app14Segment.bytes;
            if (data.length >= 12 && data[0] == 'A' && data[1] == 'd' && data[2] == 'o' && data[3] == 'b' && data[4] == 'e')
            {
                hasAdobeMarker = true;
                int transform = app14Segment.bytes[11] & 0xff;
                if (transform == 2)
                    colorType = COLOR_TYPE_YCCK;
            }
        }
    }

    public static void convertYcckToCmyk(WritableRaster raster) {
        int height = raster.getHeight();
        int width = raster.getWidth();
        int stride = width * 4;
        int[] pixelRow = new int[stride];
        for (int h = 0; h < height; h++) {
            raster.getPixels(0, h, width, 1, pixelRow);

            for (int x = 0; x < stride; x += 4) {
                int y = pixelRow[x];
                int cb = pixelRow[x + 1];
                int cr = pixelRow[x + 2];

                int c = (int) (y + 1.402 * cr - 178.956);
                int m = (int) (y - 0.34414 * cb - 0.71414 * cr + 135.95984);
                y = (int) (y + 1.772 * cb - 226.316);

                if (c < 0) c = 0; else if (c > 255) c = 255;
                if (m < 0) m = 0; else if (m > 255) m = 255;
                if (y < 0) y = 0; else if (y > 255) y = 255;

                pixelRow[x] = 255 - c;
                pixelRow[x + 1] = 255 - m;
                pixelRow[x + 2] = 255 - y;
            }

            raster.setPixels(0, h, width, 1, pixelRow);
        }
    }

    public static void convertInvertedColors(WritableRaster raster) {
        int height = raster.getHeight();
        int width = raster.getWidth();
        int stride = width * 4;
        int[] pixelRow = new int[stride];
        for (int h = 0; h < height; h++) {
            raster.getPixels(0, h, width, 1, pixelRow);
            for (int x = 0; x < stride; x++)
                pixelRow[x] = 255 - pixelRow[x];
            raster.setPixels(0, h, width, 1, pixelRow);
        }
    }

    public static BufferedImage convertCmykToRgb(Raster cmykRaster, ICC_Profile cmykProfile) throws IOException {
        if (cmykProfile == null)
            cmykProfile = ICC_Profile.getInstance(JpegReader.class.getResourceAsStream("/ISOcoated_v2_300_eci.icc"));
        ICC_ColorSpace cmykCS = new ICC_ColorSpace(cmykProfile);
        BufferedImage rgbImage = new BufferedImage(cmykRaster.getWidth(), cmykRaster.getHeight(), BufferedImage.TYPE_INT_RGB);
        WritableRaster rgbRaster = rgbImage.getRaster();
        ColorSpace rgbCS = rgbImage.getColorModel().getColorSpace();
        ColorConvertOp cmykToRgb = new ColorConvertOp(cmykCS, rgbCS, null);
        cmykToRgb.filter(cmykRaster, rgbRaster);
        return rgbImage;
    }
}

コードはまず、RGB ファイルで機能する通常の方法を使用してファイルの読み取りを試みます。失敗した場合は、カラー モデルの詳細 (プロファイル、Adobe マーカー、Adobe バリアント) を読み取ります。次に、生のピクセル データ (ラスター) を読み取り、必要なすべての変換 (YCCK から CMYK、反転色、CMYK から RGB) を実行します。

私は自分の解決策に満足していません。色はおおむね良好ですが、暗い部分が少し明るすぎます。特に黒は完全な黒ではありません。誰かが私が改善できることを知っているなら、私はそれを聞いてうれしいです.

于 2012-08-26T18:31:33.417 に答える
7

ImageIO.read()->

File filePath = new File("C:\\Users\\chang\\Desktop\\05036877.jpg");
com.sun.image.codec.jpeg.JPEGImageDecoder jpegDecoder =  JPEGCodec.createJPEGDecoder (new FileInputStream(filePath));

BufferedImage image = jpegDecoder.decodeAsBufferedImage();
于 2012-08-02T10:16:48.760 に答える
6

ここでもhttps://stackoverflow.com/questions/22409...を見つけました。これは素晴らしい色変換を行います

そして、これを得るために両方を組み合わせました:

private BufferedImage convertCMYK2RGB(BufferedImage image) throws IOException{
    log.info("Converting a CYMK image to RGB");
    //Create a new RGB image
    BufferedImage rgbImage = new BufferedImage(image.getWidth(), image.getHeight(),
    BufferedImage.TYPE_3BYTE_BGR);
    // then do a funky color convert
    ColorConvertOp op = new ColorConvertOp(null);
    op.filter(image, rgbImage);
    return rgbImage;
}
于 2011-06-30T13:22:05.773 に答える