簡體   English   中英

使用java將透明的gif/png轉換為jpeg

[英]Converting transparent gif / png to jpeg using java

我想使用 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。

我還嘗試使用 gimp 將示例 gif 轉換為 png,並使用 png 作為 Java 代碼的輸入。 結果是一樣的。

這是JDK中的錯誤嗎? 如何在沒有 3rd 方庫的情況下正確轉換圖像?

更新:

答案表明 jpeg 轉換無法正確處理透明度(我仍然認為這是一個錯誤),並建議使用預定義顏色替換透明像素的解決方法。 兩種建議的方法都非常復雜,所以我實現了一個更簡單的方法(將作為答案發布)。 我接受此解決方法的第一個已發布答案(由 Markus)。 我不知道哪種實現更好。 我選擇了最簡單的一個,但我仍然找到了一個無法正常工作的 gif。

對於 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);

正如在問題的更新中已經提到的,我已經實現了一種用預定義顏色替換透明像素的更簡單的方法:

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);
}

問題(至少對於 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 用另一種顏色填充圖像來更改此設置。

晚了 3 個月,但我遇到了一個非常相似的問題(雖然甚至沒有加載 gif,但只是生成了一個透明圖像——比如,沒有背景,一個彩色的形狀——當保存到 jpeg 時,所有的顏色都搞砸了,不僅背景)

發現這段代碼在這個相當古老的Java2D的利息清單的線程,想我會分享,因為快速測試后,它比你的解決方案高性能:

        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);

不幸的是,我不能說我完全理解它的作用;)

如果你創建一個 BufferedImage.TYPE_INT_ARGB 類型的 BufferedImage 並保存到 JPEG 會導致奇怪的事情。 在我的情況下,顏色被扭曲成橙色。 在其他情況下,生成的圖像可能無效,其他讀者將拒絕加載它。

但是,如果您創建 BufferedImage.TYPE_INT_RGB 類型的圖像,則將其保存為 JPEG 可以正常工作。

因此,我認為這是 Java JPEG 圖像編寫器中的一個錯誤 - 它應該只編寫它可以不透明的內容(就像 .NET GDI+ 所做的那樣)。 或者在最壞的情況下拋出一個帶有有意義消息的異常,例如“無法編寫具有透明度的圖像”。

JPEG 不支持透明度。 因此,即使您正確獲得圓圈顏色,您仍然會有黑色或白色背景,具體取決於您的編碼器和/或渲染器。

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);

7/9/2020編輯:添加imageIO.write

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM