2008-09-24 18 views
24

Jestem obecnie toczenia tablicę wartości pikseli (pierwotnie utworzone z obiektem java.awt.image.PixelGrabber) do obiektu obrazu przy użyciu następującego kodu:Zamień tablicę pikseli w obiekt obrazu za pomocą Java ImageIO?

public Image getImageFromArray(int[] pixels, int width, int height) { 
    MemoryImageSource mis = new MemoryImageSource(width, height, pixels, 0, width); 
    Toolkit tk = Toolkit.getDefaultToolkit(); 
    return tk.createImage(mis); 
} 

Czy to możliwe, aby osiągnąć ten sam wynik przy użyciu klas z pakietów ImageIO, więc nie muszę korzystać z AWT Toolkit?

Toolkit.getDefaultToolkit() nie wydaje się być w 100% wiarygodne i czasami rzucić AWTError, natomiast klasy ImageIO powinny być zawsze dostępne, dlatego jestem zainteresowany zmianą moją metodę.

Odpowiedz

23

Możesz utworzyć obraz bez użycia ImageIO. Po prostu utwórz BufferedImage, używając typu obrazu pasującego do zawartości tablicy pikseli.

public static Image getImageFromArray(int[] pixels, int width, int height) { 
      BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 
      WritableRaster raster = (WritableRaster) image.getData(); 
      raster.setPixels(0,0,width,height,pixels); 
      return image; 
     } 

Podczas pracy z PixelGrabber, nie zapomnij, aby wyodrębnić informacje RGBA z tablicy pikseli przed wywołaniem getImageFromArray. Istnieje przykład tego w handlepixelmethod w javadoc PixelGrabber. Gdy to zrobisz, upewnij się, że typ obrazu w konstruktorze BufferedImage jest BufferedImage.TYPE_INT_ARGB.

+1

Dzięki bcash, ale gdy próbuję tego kodu, otrzymuję wyjątek java.lang.ArrayIndexOutOfBoundsException. Jakieś pomysły? –

+0

Myślę, że jest blisko, możemy potrzebować więcej szczegółów od Chrisa ze szczegółami? wygląda na to, że powinno działać ... Jakie są twoje ints? czy oni są RGB? ARGB? jakiś rodzaj spakowanego formatu? –

+0

Piksele pochodzą z PixelGrabber jako takie: int [] pixels = new int [szerokość * wysokość]; PixelGrabber pg = new PixelGrabber (img, 0, 0, szerokość, wysokość, piksele, 0, szerokość); pg.grabPixels(); –

1

Osiągnąłem dobry sukces, używając java.awt.Robot do przechwycenia zrzutu ekranu (lub fragmentu ekranu), ale aby współpracować z ImageIO, musisz zapisać go w buforze zamiast pamięci Źródło obrazu. Następnie możesz wywołać jedną statyczną metodę ImageIO i zapisać plik. Wypróbuj coś takiego:

// Capture whole screen 
Rectangle region = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()); 
BufferedImage capturedImage = new Robot().createScreenCapture(region); 

// Save as PNG 
File imageFile = new File("capturedImage.png"); 
ImageIO.write(capturedImage, "png", imageFile); 
7

Za pomocą tego rastra uzyskałem ArrayIndexOutOfBoundsException, nawet jeśli utworzyłem BufferedImage z TYPE_INT_ARGB. Jednak przy użyciu metody dla mnie pracował.

+0

Miałem podobny problem, mimo że rozmiar tablicy danych wejściowych i wyjściowych był zgodny. Skończyło się również na użyciu setRGB. To może być trywialnie wolniejsze, ale działa. Nie sądzę, aby Alpha vs. non-alpha zmienił rozmiar tablicy, ponieważ jest to po prostu 2 najbardziej znaczące bajty w indywidualnej int. – bobtheowl2

3

JavaDoc na BufferedImage.getData() mówi: "Raster, który jest skopiować danych obrazu."

Ten kod działa dla mnie, ale wątpię w to wydajność:

 // Получаем картинку из массива. 
     int[] pixels = new int[width*height]; 
      // Рисуем диагональ. 
      for (int j = 0; j < height; j++) { 
       for (int i = 0; i < width; i++) { 
        if (i == j) { 
         pixels[j*width + i] = Color.RED.getRGB(); 
        } 
        else { 
         pixels[j*width + i] = Color.BLUE.getRGB(); 
         //pixels[j*width + i] = 0x00000000; 
        } 
       } 
      } 

BufferedImage pixelImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);  
    pixelImage.setRGB(0, 0, width, height, pixels, 0, width); 
+1

.. lub użyj 'getRaster()' zamiast 'getData()'. – haraldK

0

Ponieważ jest to jeden z najwyższych głosowali pytanie oznakowanego z ImageIO na SO, myślę, że jest jeszcze miejsce dla lepszego rozwiązania, nawet jeśli pytanie jest stare. :-)

Spójrz na klasę BufferedImageFactory.java z mojego projektu open source imageio na GitHub.

Dzięki niemu można po prostu napisać:

BufferedImage image = new BufferedImageFactory(image).getBufferedImage(); 

Drugą dobrą rzeczą jest to, że takie podejście, w najgorszym wypadku, ma o tej samej wydajności (czas) jako PixelGrabber opartych o przykłady już w ten wątek. W większości typowych przypadków (zazwyczaj JPEG) jest to około dwa razy szybciej. W każdym razie zużywa mniej pamięci.

W ramach bonusu bocznego zachowany zostaje model kolorów i układ pikseli oryginalnego obrazu, zamiast przetłumaczonego na int ARGB z domyślnym modelem kolorów. Może to zaoszczędzić dodatkową pamięć.

(PS: Fabryka obsługuje również podsłuchiwanie, wyszukiwanie obszarów zainteresowania i słuchaczy postępu, jeśli ktoś jest zainteresowany.:-)

0

Miałem ten sam problem ze wszystkimi, którzy próbowali zastosować poprawną odpowiedź na to pytanie, moja tablica int faktycznie otrzymała OutOfboundException, gdzie naprawiłem to dodając jeszcze jeden indeks, ponieważ długość tablicy musi być równa * wysokość * 3 po tym nie mogłem uzyskać obraz tak naprawiłem to ustawienie rastra do obrazu

public static Image getImageFromArray(int[] pixels, int width, int height) { 
     BufferedImage image = new BufferedImage(width, height,  BufferedImage.TYPE_INT_ARGB); 
     WritableRaster raster = (WritableRaster) image.getData(); 
     raster.setPixels(0,0,width,height,pixels); 
     image.setData(raster); 
     return image; 
    } 

i widać obraz jeśli u pokazać je na etykiecie na JFrame tak

JFrame frame = new JFrame(); 
    frame.getContentPane().setLayout(new FlowLayout()); 
    frame.getContentPane().add(new JLabel(new ImageIcon(image))); 
    frame.pack(); 
    frame.setVisible(true); 

Ustawianie obrazu na imageIcon(). Ostatnia porada, którą możesz spróbować zmienić w Bufferedimage.TYPE_INT_ARGB na coś innego, co pasuje do obrazu, w którym tablica od tego typu jest bardzo ważna, miałem tablicę 0 i -1, więc użyłem tego typu BufferedImage.TYPE_3BYTE_BGR