2016-09-04 29 views
0

現在我正在學習Image。我想複製一張圖片。我嘗試:sun.awt.image.ByteInterleavedRaster.setPixels

private BufferedImage mImage, mNewImage; 
private int mWidth, mHeight; 
private int[] mPixelData; 

public void generate() { 
    try { 
     mImage = ImageIO.read(new File("D:\\Documents\\Pictures\\image.png")); 
     mWidth = mImage.getWidth(); 
     mHeight = mImage.getHeight(); 
     mPixelData = new int[mWidth * mHeight]; 
     // get pixel data from image 
     for (int i = 0; i < mHeight; i++) { 
      for (int j = 0; j < mWidth; j++) { 
       int rgb = mImage.getRGB(j, i); 
       int a = rgb >>> 24; 
       int r = (rgb >> 16) & 0xff; 
       int g = (rgb >> 8) & 0xff; 
       int b = rgb & 0xff; 
       int newRgb = (a << 24 | r << 16 | g << 8 | b); 
       mPixelData[i * mWidth + j] = newRgb; 
      } 

      mNewImage = new BufferedImage(mWidth, mHeight, mImage.getType()); 
      WritableRaster raster = (WritableRaster) mNewImage.getData(); 
      raster.setPixels(0, 0, mWidth, mHeight, mPixelData); 
      File file = new File("D:\\Documents\\Pictures\\image2.png"); 
      ImageIO.write(mNewImage, "png", file); 
     } 
     } catch (IOException e) { 
     e.printStackTrace(); 
     } 
} 

但我有一個例外:在sun.awt.image.ByteInterleavedRaster.setPixels(ByteInterleavedRaster.java 222748:在線程 「主要」 java.lang.ArrayIndexOutOfBoundsException

例外: 1108)

回答

1

在你的代碼的邏輯是理智的,但也有與上面的代碼的多個小問題,所以我會盡力通過一個點出來一個::-)

  1. 你的mPixelData是在壓縮ARGB佈局,這是一樣的使用BufferedImage.TYPE_INT_ARGB。所以你想使用這種類型,而不是原始圖像的類型。如果從堆棧軌跡中看到,則光柵類型爲ByteInterleavedRaster,並且這與您的int[]像素不兼容(使用原始類型可能導致的另一個問題是,它可能是TYPE_CUSTOM,無法創建它使用這個構造函數)。所以,第一個變化:

    mNewImage = new BufferedImage(mWidth, mHeight, BufferedImage.TYPE_INT_ARGB); 
    

    (注:你仍然會得到一個IndexOutOfBoundsException此更改後,我將回到這個版本)。

  2. BufferedImage.getData()會給你拷貝的像素數據,而不是參考當前數據。因此,在此副本上設置像素將不會影響稍後寫入磁盤的數據。而是,使用getRaster()方法,即不正是你想要什麼:

    WritableRaster raster = mNewImage.getRaster(); 
    
  3. Raster.setPixels(x, y, w, h, pixels)方法需要每個數組元素包含(A,R,G和B作爲單獨的樣品)一個樣本的陣列。這意味着你的數組的長度只有方法期望的四分之一,並且這最終是你看到的異常的原因。相反,當你陣是int -packed ARGB佈局(這是你現在使用的類型的本地佈局),你應該使用setDataElements方法:

    raster.setDataElements(0, 0, mWidth, mHeight, mPixelData); 
    
  4. 最後,我只是想指出的是,所有在你的循環中的位移將簡單地將所有像素分解爲單個組件(A,R,G和B),然後再將它們組裝在一起...因此,在這種情況下,newRGB == rgb。但是你也許計劃在後面添加色彩處理,在這種情況下它是有道理的。 :-)


PS:如果你想要做的是創造了原始圖像,這樣做的最快方法的精確副本大概是:

ColorModel cm = mImage.getColorModel(); 
WritableRaster raster = (WritableRaster) mImage.getData(); // Here we want a copy of the original image 
mNewImage = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);