Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (522)
Games in Android Showcase (127)
games submitted by our members
Games in WIP (590)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Converting a buffered image into an int[] array, then converting it back  (Read 3615 times)
0 Members and 1 Guest are viewing this topic.
Offline nhmllr

Senior Devvie


Medals: 1
Projects: 3


slow and steady...


« Posted 2012-12-09 02:18:30 »

Long story short, I want to get the int[] array of RGB values from a BufferedImage
The original BufferedImage is called startImage, for which the RGB values go into startPixels

Next I have another int array called endPixels, and an image called endImage. When the program is done, endPixels will be dithered from startPixels but for the time being they are identical.

Then I want endPixels to be converted to endImage, which is then written to a file.

Here is the code:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class DitherMain {

   static String imageString = "/IMG_3462.jpg";
   
   BufferedImage startImage, endImage;
   int[] startPixels,endPixels;
   int width, height;
   
   public static void main(String[] args){
      new DitherMain(loadImage(imageString));
   }
   
   //this object transforms the old image and writes the new image
   DitherMain(BufferedImage img){
      //filing the image into startpixels (this works)
      startImage = img;
      width = img.getWidth();
      height = img.getHeight();
      startPixels = new int[width*height];
      img.getRGB(0, 0, width, height, startPixels, 0, width);

      transformPixels();
     
      //putting endPixels in endImage (does not work)
      endImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
      WritableRaster raster = (WritableRaster) endImage.getData();
      raster.setPixels(0,0,width,height,endPixels);
     
      //writing the file for endImage into the harddrive (may or may not work)
      File file = new File("/RESULT.png");
      try {
         ImageIO.write(endImage, "jpg", file);
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
   
   void transformPixels(){
      //endPixels will one day be different from startPixels, but for now it is idenitcial
      endPixels = startPixels;
   }
   
   //this method just loads a specific buffered image
   public static BufferedImage loadImage(String fileName){  
      BufferedImage img;
     
      try{
         img = ImageIO.read(DitherMain.class.getResource(fileName));
      } catch (Exception e) {
         e.printStackTrace();
         throw new RuntimeException(e);
      }
      return img;
   }
}


And got this error message in the console:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1228800
   at java.awt.image.SinglePixelPackedSampleModel.setPixels(Unknown Source)
   at java.awt.image.WritableRaster.setPixels(Unknown Source)
   at sun.awt.image.SunWritableRaster.setPixels(Unknown Source)
   at DitherMain.<init>(DitherMain.java:34)
   at DitherMain.main(DitherMain.java:17)

Line 34 is
1  
      raster.setPixels(0,0,width,height,endPixels);


But I don't see what's wrong with this... does it have to do with storing an ARGB as an int, because I have no idea.
It says some array is going out of bounds. 1228800 is the height*width of the test image I'm using, but I don't see what should be out of bounds

I really don't understand what the problem with this code is, but seeing as I've never written something like this before I assume there are probably a lot.
In any case, can any of you guys shed some light on this?

Thanks
Offline moogie

JGO Knight


Medals: 13
Projects: 6
Exp: 10 years


Java games rock!


« Reply #1 - Posted 2012-12-09 05:16:04 »

Like most methods in java, indexes are zero based, so I would imagine you would want to use
      raster.setPixels(0,0,width-1,height-1,endPixels);

Offline davedes
« Reply #2 - Posted 2012-12-09 08:42:27 »

This is what I would do:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
if (image.getType() != BufferedImage.TYPE_INT_ABGR) {
    BufferedImage tmp = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
    tmp.getGraphics().drawImage(image, 0, 0, null);
    image = tmp;
}

int[] srcPixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();

BufferedImage out = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
int[] outPixels = ((DataBufferInt)out.getRaster().getDataBuffer()).getData();

//do something.. like copy pixels from A to B
System.arraycopy(srcPixels, 0, outPixels, 0, srcPixels.length);

//write to file...


Also note that you specify the output format as "png" but then use the JPG extension -- maybe a typo?

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline nsigma
« Reply #3 - Posted 2012-12-09 09:34:23 »

setPixels() doesn't do what you think it does. It expects the data to be unpacked, with ARGB in 4 separate ints, not 1. Therefore it's expecting your array to be 4 times the size it is, and throwing the exception.

You want to try setDataElements() instead.

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 836
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #4 - Posted 2012-12-09 11:55:15 »

You want to try setDataElements() instead.
He simply wants a reference to the actual pixels.


1  
int[] rgb = ((DataBufferInt)bufImg.getRaster().getDataBuffer()).getData();

No need to push the pixels back into the image. These are the pixels in the image.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline nsigma
« Reply #5 - Posted 2012-12-09 13:55:15 »

You want to try setDataElements() instead.
He simply wants a reference to the actual pixels.

You're assuming that's what the OP wants, though!  @davedes had already mentioned that method.  I was simply answering the OP's question / confusion about why he was getting an ArrayIndexOutOfBoundsException.

I usually use the direct data buffer method you mention, but to do so you have to understand the trade-offs between using get/setDataElements() and directly manipulating the data buffer.  Namely that get/setDataElements() will perform an extra copy of the data, while direct data buffer access will stop the image from being accelerated by the graphics card.  If all the OP wants to do (in the long term) is save the image to a file, then direct access is fine - if the code will eventually be used for repeated drawing to the screen it may not be.

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Offline davedes
« Reply #6 - Posted 2012-12-09 18:10:46 »

Quote
while direct data buffer access will stop the image from being accelerated by the graphics card.
Is there any way to "re-flag" it for acceleration after making some changes to the array?

Offline nsigma
« Reply #7 - Posted 2012-12-09 18:27:41 »

Quote
while direct data buffer access will stop the image from being accelerated by the graphics card.
Is there any way to "re-flag" it for acceleration after making some changes to the array?

There used to be.  No idea if it still works (maybe someone else knows for sure).  Use -Dsun.java2d.allowrastersteal=true or otherwise set that property as early as possible (before Java2d gets initialized by anything).  You'll then need to mark the image as dirty every time you modify the array - used to be recommended to draw a 1x1 transparent rectangle on it.

More in this old message - http://www.java-gaming.org/topics/software-rendering/12453/msg/100335/view.html#msg100335

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Offline StumpyStrust
« Reply #8 - Posted 2012-12-09 18:38:47 »

From what I know, every bufferedimage will try and be accelerated after it is drawn some number of times. So if you de-accelerate it, it should eventually be re accelerated as long as you don't change anything on it. Problem is most people want to change things every frame or so which kills performance.

Offline nhmllr

Senior Devvie


Medals: 1
Projects: 3


slow and steady...


« Reply #9 - Posted 2012-12-09 18:49:09 »

Yay! I got it to work!
It takes about 1 or 2 seconds for an image of 960 * 1280, but I don't care about performance. This project is just a hobby project I'm making to filter images.
I'm sure there's a much faster way than this, but here's the final code
It splits every color into RGB components (3 separate arrays) then it codes it into the image in 3 separate "bands"
At the moment, it just exports the same image that's imported, but now that I have the RGB arrays at my disposal, I can now edit the arrays to get some cool effects

Here's the code if anyone wants to do something similar in the future
It'll need a lot of cleaning up, but this is functional
http://pastebin.java-gaming.org/fe8b0023139
Thanks

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline nsigma
« Reply #10 - Posted 2012-12-10 11:28:23 »

From what I know, every bufferedimage will try and be accelerated after it is drawn some number of times. So if you de-accelerate it, it should eventually be re accelerated as long as you don't change anything on it. Problem is most people want to change things every frame or so which kills performance.
No, no, no, no and no!  Grin  If you grab the data array, the BufferedImage is permanently de-accelerated (unless you try the semi-official hack mentioned above).

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

trollwarrior1 (33 views)
2014-11-22 12:13:56

xFryIx (73 views)
2014-11-13 12:34:49

digdugdiggy (52 views)
2014-11-12 21:11:50

digdugdiggy (46 views)
2014-11-12 21:10:15

digdugdiggy (40 views)
2014-11-12 21:09:33

kovacsa (65 views)
2014-11-07 19:57:14

TehJavaDev (70 views)
2014-11-03 22:04:50

BurntPizza (68 views)
2014-11-03 18:54:52

moogie (83 views)
2014-11-03 06:22:04

CopyableCougar4 (82 views)
2014-11-01 23:36:41
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!