2008-11-05 29 views
8

Tôi đang cố viết một tệp png từ java.awt.image.BufferedImage. Tất cả mọi thứ hoạt động tốt nhưng png kết quả là một tập tin 32-bit.Trong java, làm thế nào để bạn viết một java.awt.image.BufferedImage vào một tệp png 8-bit?

Có cách nào để tạo tệp png là 8 bit không? Hình ảnh có màu xám, nhưng tôi cần độ trong suốt vì đây là hình ảnh lớp phủ. Tôi đang sử dụng java 6, và tôi muốn trả về một OutputStream để tôi có thể có thỏa thuận lớp gọi điện thoại với việc viết tệp ra đĩa/db.

Dưới đây là phần có liên quan của mã:

public static ByteArrayOutputStream createImage(InputStream originalStream) 
      throws IOException { 

     ByteArrayOutputStream oStream = null; 

     java.awt.Image newImg = javax.imageio.ImageIO.read(originalStream); 
     int imgWidth = newImg.getWidth(null); 
     int imgHeight = newImg.getHeight(null); 
     java.awt.image.BufferedImage bim = new java.awt.image.BufferedImage(imgWidth, 
       imgHeight, java.awt.image.BufferedImage.TYPE_INT_ARGB); 

     Color bckgrndColor = new Color(0x80, 0x80, 0x80); 

     Graphics2D gf = (Graphics2D)bim.getGraphics(); 

     // set transparency for fill image 
     gf.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f)); 
     gf.setColor(bckgrndColor); 
     gf.fillRect(0, 0, imgWidth, imgHeight); 

     oStream = new ByteArrayOutputStream(); 
     javax.imageio.ImageIO.write(bim, "png", oStream); 
     oStream.close(); 

     return oStream; 
    } 
+0

Có thể tìm thêm thông tin tại http://stackoverflow.com/questions/665406/make-a-color-transparent-in-bufferedimage-to-be-saved-as-png – VonC

Trả lời

1

Đó là một câu hỏi thú vị ... Đó là muộn, tôi sẽ thử nghiệm vào ngày mai. Trước tiên tôi sẽ thử và sử dụng một BufferedImage.TYPE_BYTE_INDEXED (có lẽ sau khi vẽ) để xem nếu Java đủ thông minh để tạo ra một PNG 8bit.
Hoặc có thể một số thư viện hình ảnh có thể cho phép điều đó.

[EDIT] Một số năm sau ... Thực ra, tôi đã tạo mã tại thời điểm đó, nhưng quên cập nhật chủ đề này ... Tôi đã sử dụng the code pointed at by Kat, với một chút tinh tế về xử lý độ trong suốt và tiết kiệm trong PNG định dạng thay vì định dạng Gif. Nó hoạt động trong việc tạo một tệp PNG 8 bit với độ trong suốt không có gì cả.

Bạn có thể tìm thấy tệp thử nghiệm đang hoạt động tại http://bazaar.launchpad.net/~philho/+junk/Java/view/head:/Tests/src/org/philhosoft/tests/image/AddTransparency.java sử dụng lớp học ImageUtil của tôi.

Vì mã không phải là lớn, vì lợi ích của hậu thế, tôi đăng nó ở đây, mà không có JavaDoc để lưu một số dòng.

public class ImageUtil 
{ 
    public static int ALPHA_BIT_MASK = 0xFF000000; 

    public static BufferedImage imageToBufferedImage(Image image, int width, int height) 
    { 
    return imageToBufferedImage(image, width, height, BufferedImage.TYPE_INT_ARGB); 
    } 

    public static BufferedImage imageToBufferedImage(Image image, int width, int height, int type) 
    { 
    BufferedImage dest = new BufferedImage(width, height, type); 
    Graphics2D g2 = dest.createGraphics(); 
    g2.drawImage(image, 0, 0, null); 
    g2.dispose(); 
    return dest; 
    } 

    public static BufferedImage convertRGBAToIndexed(BufferedImage srcImage) 
    { 
    // Create a non-transparent palletized image 
    Image flattenedImage = transformTransparencyToMagenta(srcImage); 
    BufferedImage flatImage = imageToBufferedImage(flattenedImage, 
     srcImage.getWidth(), srcImage.getHeight(), BufferedImage.TYPE_BYTE_INDEXED); 
    BufferedImage destImage = makeColorTransparent(flatImage, 0, 0); 
    return destImage; 
    } 

    private static Image transformTransparencyToMagenta(BufferedImage image) 
    { 
    ImageFilter filter = new RGBImageFilter() 
    { 
     @Override 
     public final int filterRGB(int x, int y, int rgb) 
     { 
     int pixelValue = 0; 
     int opacity = (rgb & ALPHA_BIT_MASK) >>> 24; 
     if (opacity < 128) 
     { 
      // Quite transparent: replace color with transparent magenta 
      // (traditional color for binary transparency) 
      pixelValue = 0x00FF00FF; 
     } 
     else 
     { 
      // Quite opaque: get pure color 
      pixelValue = (rgb & 0xFFFFFF) | ALPHA_BIT_MASK; 
     } 
     return pixelValue; 
     } 
    }; 

    ImageProducer ip = new FilteredImageSource(image.getSource(), filter); 
     return Toolkit.getDefaultToolkit().createImage(ip); 
    } 

    public static BufferedImage makeColorTransparent(BufferedImage image, int x, int y) 
    { 
    ColorModel cm = image.getColorModel(); 
    if (!(cm instanceof IndexColorModel)) 
     return image; // No transparency added as we don't have an indexed image 

    IndexColorModel originalICM = (IndexColorModel) cm; 
    WritableRaster raster = image.getRaster(); 
    int colorIndex = raster.getSample(x, y, 0); // colorIndex is an offset in the palette of the ICM' 
    // Number of indexed colors 
    int size = originalICM.getMapSize(); 
    byte[] reds = new byte[size]; 
    byte[] greens = new byte[size]; 
    byte[] blues = new byte[size]; 
    originalICM.getReds(reds); 
    originalICM.getGreens(greens); 
    originalICM.getBlues(blues); 
    IndexColorModel newICM = new IndexColorModel(8, size, reds, greens, blues, colorIndex); 
    return new BufferedImage(newICM, raster, image.isAlphaPremultiplied(), null); 
    } 
} 
+0

4 năm sau, vẫn đang chờ đợi câu trả lời này chứ không phải là một câu hỏi khác. – mjaggard

+1

Tôi không thấy một câu hỏi về câu trả lời của tôi, mặc dù thành thật mà nói tôi không nhìn thấy một câu trả lời (hey, tôi là mới trên SO vào thời điểm đó ...). Dù sao, mặc dù giọng điệu, cảm ơn cho người đứng đầu lên. – PhiLho

+0

Xin lỗi vì âm thanh, nó không phải là âm thanh hung dữ. SO yêu cầu bạn chỉ định lý do tại sao bạn bỏ phiếu vì vậy tôi chỉ trả lời câu hỏi đó. – mjaggard

4

Xây dựng trong trình ghi ảnh png sẽ ghi 32bit tệp png trên tất cả nền tảng tôi đã sử dụng, bất kể ảnh nguồn là gì. Bạn cũng nên biết rằng nhiều người đã phàn nàn rằng kết quả nén thấp hơn nhiều so với những gì có thể với định dạng png. Có sẵn một số độc lập png libraries cho phép bạn chỉ định định dạng chính xác, nhưng tôi không thực sự có bất kỳ trải nghiệm nào với bất kỳ định dạng nào trong số đó.

0

Cảm ơn bạn đã trả lời, tôi sẽ thử một số TYPE_BYTE_INDEXED với một IndexColorModel và vẫn có thể nhưng nếu ImageIO viết ra 32 bit bất kể có vẻ như tôi có thể lãng phí thời gian của tôi ở đó.

Hình ảnh tôi đang cố gắng viết có thể rất lớn (lên đến 8000x4000) nhưng chỉ là một mặt nạ đơn giản cho hình ảnh bên dưới, vì vậy sẽ chỉ có màu xám trong suốt ~ 30% và cắt bỏ trong suốt 100%. Tôi sẽ sử dụng một GIF nhưng IE6 dường như có vấn đề với việc hiển thị một trong những lớn.

Chỉ được tạo một lần và trong màn hình thiết lập nội bộ, do đó hiệu suất không phải là vấn đề, nhưng nó phải được thực hiện trong mã java chứ không phải bởi tiện ích ngoại tuyến.

Các thư viện mà bạn chỉ định có thể được sử dụng để chuyển đổi thư trong khi viết ... Tôi sẽ kiểm tra xem.

Nếu có ai có cách tốt hơn, vui lòng cho tôi biết !!

Cảm ơn!

1

Tôi tìm thấy câu trả lời như thế nào để chuyển đổi RGBA để lập chỉ mục ở đây: http://www.eichberger.de/2007/07/transparent-gifs-in-java.html

Tuy nhiên, kết quả là file png 8-bit chỉ có 100% hoặc 0% tính minh bạch.Bạn có thể tinh chỉnh các mảng IndexColorModel, nhưng chúng tôi đã quyết định tạo tệp đã tạo (một mặt nạ lớp phủ) thành một jpg lớp lót và sử dụng nền tảng tĩnh như lớp phủ trong suốt là gì.

+1

Thay vì giải quyết các câu trả lời cho bài đăng của bạn, bạn thực sự có thể thêm thông tin vào câu hỏi ban đầu của mình bằng cách nhấp vào chỉnh sửa. Người dùng có thể xem những gì đã được thay đổi và nó không chỉ tiếp tục thêm vào cột câu trả lời. –

Các vấn đề liên quan