2016-09-04 2 views
0

Maintenant, je suis en train d'apprendre à propos de Image .Je veux copier une image. J'essaie: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(); 
     } 
} 

Mais je suis une exception:

Exception dans le thread "principal" java.lang.ArrayIndexOutOfBoundsException: 222748 à sun.awt.image.ByteInterleavedRaster.setPixels (ByteInterleavedRaster.java: 1108)

Répondre

1

la logique dans votre code est sain d'esprit, mais il y a plusieurs problèmes mineurs avec le code ci-dessus, donc je vais essayer de les signaler un par un: :-)

  1. Votre mPixelData est en format ARGB compressé, c'est la même que celle utilisée par BufferedImage.TYPE_INT_ARGB. Donc, vous voulez utiliser ce type, plutôt que le type de l'image originale. Si vous voyez à partir de votre trace de pile, le type de votre raster est ByteInterleavedRaster, et ce n'est pas compatible avec vos int[] pixels (un autre problème qui peut survenir en utilisant le type d'origine, c'est qu'il peut être TYPE_CUSTOM, qui ne peut pas être créé en utilisant ce constructeur). Alors, premier changement:

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

    (Remarque: vous obtiendrez toujours un IndexOutOfBoundsException après ce changement, je reviendrai plus tard).

  2. BufferedImage.getData() vous donnera une copie des données de pixel, plutôt qu'une référence aux données actuelles. Ainsi, définir les pixels sur cette copie n'aura aucun effet sur les données écrites sur le disque plus tard. Au lieu de cela, utilisez la méthode getRaster(), qui fait exactement ce que vous voulez:

    WritableRaster raster = mNewImage.getRaster(); 
    
  3. La méthode Raster.setPixels(x, y, w, h, pixels) attend un tableau contenant un échantillon par élément de tableau (A, R, G et B des échantillons séparés). Cela signifie que la longueur de votre tableau est seulement un quart de ce que la méthode attend, et c'est finalement la cause de l'exception que vous voyez. Au lieu de cela, comme vous tableau est en int -Emballé mise en page ARVB (ce qui est la disposition native du type que vous utilisez maintenant), vous devez utiliser la méthode setDataElements:

    raster.setDataElements(0, 0, mWidth, mHeight, mPixelData); 
    
  4. Enfin, je voudrais simplement souligner que tout le décalage de bits dans votre boucle déballera simplement tous les pixels dans les composants simples (A, R, G et B) et ensuite les emballer à nouveau ensemble ... Donc, newRGB == rgb dans ce cas. Mais vous envisagez peut-être d'ajouter la manipulation des couleurs ici plus tard, auquel cas c'est logique. :-)


PS: Si tout ce que vous voulez faire est de créer une copie exacte de l'image originale, le meilleur moyen de le faire est probablement:

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