23

Java を使用して gif 画像を jpeg に変換したいと考えています。ほとんどの画像でうまく機能しますが、単純な透明な gif 画像があります。

入力 gif 画像 http://img292.imageshack.us/img292/2103/indexedtestal7.gif

[画像が欠落している場合: 周囲に透明なピクセルがある青い円です]

次のコードを使用してこの画像を変換すると:

File file = new File("indexed_test.gif");
BufferedImage image = ImageIO.read(file);
File f = new File("indexed_test.jpg");
ImageIO.write(image, "jpg", f);

このコードは例外をスローせずに機能しますが、無効な jpeg 画像が生成されます。

jpeg画像を出力

[画像がない場合: IE では jpeg を表示できません。Firefox では無効な色の画像が表示されます。]

Java 1.5 を使用しています。

また、サンプル gif を gimp で png に変換し、その png を Java コードの入力として使用してみました。結果は同じです。

JDKのバグですか?できればサードパーティのライブラリを使用せずに画像を正しく変換するにはどうすればよいですか?

アップデート:

回答は、jpeg 変換が透明度を正しく処理できないことを示し (これはまだバグだと思います)、透明なピクセルを定義済みの色に置き換えるための回避策を提案します。提案された方法はどちらも非常に複雑であるため、より単純な方法を実装しました (回答として投稿します)。この回避策で最初に公開された回答を受け入れます(Markusによる)。どの実装が優れているかはわかりません。私は最も単純なものを選びますが、機能していないgifを見つけました。

4

7 に答える 7

43

Java 6 (および 5 もあると思います) の場合:

BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
g = bufferedImage.createGraphics();
//Color.WHITE estes the background to white. You can use any other color
g.drawImage(image, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), Color.WHITE, null);
于 2009-10-09T18:39:16.827 に答える
11

質問の更新で既に述べたように、透明なピクセルを定義済みの色に置き換える簡単な方法を実装しました。

public static BufferedImage fillTransparentPixels( BufferedImage image, 
                                                   Color fillColor ) {
    int w = image.getWidth();
    int h = image.getHeight();
    BufferedImage image2 = new BufferedImage(w, h, 
        BufferedImage.TYPE_INT_RGB);
    Graphics2D g = image2.createGraphics();
    g.setColor(fillColor);
    g.fillRect(0,0,w,h);
    g.drawRenderedImage(image, null);
    g.dispose();
    return image2;
}

そして、この方法で jpeg 変換の前にこのメソッドを呼び出します。

if( inputImage.getColorModel().getTransparency() != Transparency.OPAQUE) {
    inputImage = fillTransparentPixels(inputImage, Color.WHITE);
}
于 2009-01-22T09:08:11.587 に答える
4

問題 (少なくとも png から jpg への変換) は、jpg が透明度をサポートしていないため、配色が同じではないことです。

私たちが成功したのは、次のようなものです (これはさまざまなコードから引き出されたものです。書式設定が粗雑であることをご容赦ください)。

File file = new File("indexed_test.gif");
BufferedImage image = ImageIO.read(file);
int width = image.getWidth();
int height = image.getHeight();
BufferedImage jpgImage;

//you can probably do this without the headless check if you just use the first block
if (GraphicsEnvironment.isHeadless()) {
  if (image.getType() == BufferedImage.TYPE_CUSTOM) {
      //coerce it to  TYPE_INT_ARGB and cross fingers -- PNGs give a    TYPE_CUSTOM and that doesn't work with
      //trying to create a new BufferedImage
     jpgImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
  } else {
     jpgImage = new BufferedImage(width, height, image.getType());
  }
} else {
     jgpImage =   GraphicsEnvironment.getLocalGraphicsEnvironment().
        getDefaultScreenDevice().getDefaultConfiguration().
        createCompatibleImage(width, height, image.getTransparency()); 
}

//copy the original to the new image
Graphics2D g2 = null;
try {
 g2 = jpg.createGraphics();

 g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, 
                    RenderingHints.VALUE_INTERPOLATION_BICUBIC);
 g2.drawImage(image, 0, 0, width, height, null);
}
finally {
   if (g2 != null) {
       g2.dispose();
   }
}

File f = new File("indexed_test.jpg");

ImageIO.write(jpgImage, "jpg", f);

これは、png から jpg および gif から jpg で機能します。そして、透明なビットがあった場所に白い背景ができます。これを変更するには、drawImage 呼び出しの前に g2 で画像を別の色で塗りつぶします。

于 2009-01-21T16:58:17.190 に答える
4

3か月遅れましたが、私は非常によく似た問題を抱えています(gifをロードするのではなく、単に透明な画像を生成するだけです-たとえば、背景なし、色付きの形状-jpegに保存すると、すべての色が台無しになります背景)

java2d-interest list のこのかなり古いスレッドでこのコードを見つけました。簡単なテストの後、ソリューションよりもはるかにパフォーマンスが高いため、共有したいと思いました。

        final WritableRaster raster = img.getRaster();
        final WritableRaster newRaster = raster.createWritableChild(0, 0, img.getWidth(), img.getHeight(), 0, 0, new int[]{0, 1, 2});

        // create a ColorModel that represents the one of the ARGB except the alpha channel
        final DirectColorModel cm = (DirectColorModel) img.getColorModel();
        final DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(), cm.getRedMask(), cm.getGreenMask(), cm.getBlueMask());

        // now create the new buffer that we'll use to write the image
        return new BufferedImage(newCM, newRaster, false, null);

残念ながら、それが何をするのか正確に理解しているとは言えません;)

于 2009-05-13T16:37:45.540 に答える
3

タイプ BufferedImage.TYPE_INT_ARGB の BufferedImage を作成して JPEG に保存すると、奇妙な結果になります。私の場合、色はオレンジに食い込んでいます。それ以外の場合、生成された画像が無効である可能性があり、他のリーダーはその読み込みを拒否します。

しかし、タイプ BufferedImage.TYPE_INT_RGB の画像を作成すると、それを JPEG に保存しても問題なく動作します。

したがって、これはJava JPEGイメージライターのバグだと思います.透過性なしでできることだけを書き込む必要があります(.NET GDI+のように)。または、最悪の場合、「透過性を持つ画像を書き込めません」などの意味のあるメッセージとともに例外がスローされます。

于 2011-01-05T10:14:17.980 に答える
2

JPEG は透明度をサポートしていません。そのため、円の色を正しく取得した場合でも、エンコーダーやレンダラーに応じて、黒または白の背景が残ります。

于 2009-01-21T11:01:09.363 に答える
1
BufferedImage originalImage = ImageIO.read(getContent());
BufferedImage newImage = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_3BYTE_BGR);

    for (int x = 0; x < originalImage.getWidth(); x++) {
        for (int y = 0; y < originalImage.getHeight(); y++) {
            newImage.setRGB(x, y, originalImage.getRGB(x, y));
        }
    }
 ImageIO.write(newImage, "jpg", f);

2020/7/9編集:追加imageIO.write

于 2016-03-07T18:41:44.020 に答える