web-dev-qa-db-ja.com

ImageIO.read(File file)を使用してJPEG画像を読み取れません

ImageIO.read(File file)を使用してこの1つのJPEGファイルの読み取りに問題があります-「サポートされていないイメージタイプ」というメッセージを含む例外をスローします。

他のJPEG画像を試しましたが、うまく機能しているようです。

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

Troublesome image

編集:

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

Strange colors

41
Malakim

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

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

[〜#〜] update [〜#〜]

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画像の外観です。

Image RGB

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

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

番目の画像は、Java ImageIO。

Image CMYK read through Java RGB

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

38
medopal

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

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

Javaであり、JAIを必要としません。ソースコードとバイナリ配布は github.com/haraldk/TwelveMonkeys で自由に利用でき、BSD-でカバーされています。スタイルライセンス。

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

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

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

46
haraldK

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

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

基本的な問題は、Java-箱から出して-RGBのJPEGファイルしか読み取れないことです。CMYKファイルがある場合は、通常のCMYK、Adobe CMYK(反転値付き) 、つまり、インクなしの場合は255、最大インクの場合は0)およびAdobe 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)を実行します。

私のソリューションには満足していません。色はほとんど良好ですが、暗い部分は少し明るすぎます。特に黒は完全に黒ではありません。私が改善できることを誰かが知っていれば、それを聞いてうれしいです。

18
Codo

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();
6
Peter

私も見つけました 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;
}
5
enkor

これで直します。この依存関係を追加するだけです。 ImageIOでCMYK画像を読み取ることができます。 TwelveMonkeys

ImageIO.read(new URL("http://img3.tianyancha.com/api/9b80a61183787909e719c77fd0f78103.png"))
0
yaoning