Java-Gaming.org    
Featured games (91)
games approved by the League of Dukes
Games in Showcase (576)
games submitted by our members
Games in WIP (497)
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  
  In-depth explanation of bufferedimage to bytebuffer?  (Read 5457 times)
0 Members and 1 Guest are viewing this topic.
Offline Glass

Senior Newbie





« Posted 2012-02-28 03:01:46 »

Since bytebuffers are what opengl uses, and I am needing this for opengl, I figured I'd post here. I've seen many pre-made texture loaders and things that convert from bufferedimage to bytebuffer that I could use, but I they're kind of daunting. What are the absolute basics for what you need changing a bufferedimage to bytebuffer?

For starters, what information does the bytebuffer need to get from bufferedimage and how is it gotten? I know this is a difficult question, sorry. To really understand the question, I feel like starting from the basics would be best.
Offline Stranger

Senior Member


Medals: 6



« Reply #1 - Posted 2012-02-28 07:02:44 »

Look at this post: http://www.java-gaming.org/topics/bufferedimage-to-lwjgl-texture/25516/msg/220280/view.html#msg220280

Anton
Offline gimbal

JGO Coder


Medals: 25



« Reply #2 - Posted 2012-02-28 16:22:44 »

For starters, what information does the bytebuffer need to get from bufferedimage and how is it gotten? I know this is a difficult question, sorry. To really understand the question, I feel like starting from the basics would be best.

You are not wrong, although you are focusing too much on the code. You should start by investigating the wonderful world of images, computer monitors and pixels and how a BufferedImage stores them. Pixel formats, bit depths, alpha channels, scanlines, all that jazz.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Glass

Senior Newbie





« Reply #3 - Posted 2012-02-29 02:47:45 »

Thanks for the responses guys,


That's one of the pre-made ones I was talking about. I suppose I can try to look deeper into it.

You are not wrong, although you are focusing too much on the code. You should start by investigating the wonderful world of images, computer monitors and pixels and how a BufferedImage stores them. Pixel formats, bit depths, alpha channels, scanlines, all that jazz.

Sounds like a good idea. Are there any references or java wiki pages that have something like that I could read, or is it not that straightforward?
Offline ra4king

JGO Kernel


Medals: 322
Projects: 2
Exp: 4 years


I'm the King!


« Reply #4 - Posted 2012-02-29 05:00:09 »

Images are extremely straightforward. Quick explanation:

Images are rectangular, made up of width * height number of pixels. Each pixel has 3 or 4 components, R(ed) G(reen) B(lue) are the essential ones and A(lpha) (transparency) if you need it. Most of the time, each component is 1 byte = 256 values (0 to 255), where 0 is none of it and 255 is all of it. When all of them are 0 = the pixel is black, when all of them are 255 = the pixel is white.

There may also be different bit depths, aka the number of bits used to store 1 pixel. The bit depth that I talked about above is 4 components * 8 bits each = 32-bit. There may also be 3 components (no alpha channel) * 8 bits each = 24-bit. Or 4 components * 4 bits each = 16-bit.

You probably already know that an 'int' is 32-bits, so.....they are mostly used to store pixel data Smiley
You can also use bytes, with every 4 bytes = 1 pixel.

Image file formats, such as PNG, JGP, BMP, etc.., can support different combinations of the components. For example, JPG is a lossy (meaning that the compression algorithm it uses loses data to save space) format that only supports RGB. PNG, however, is a lossless format that supports RGB and A so it is the format most preferred for game textures (however it produces larger files than JPG).

Offline Glass

Senior Newbie





« Reply #5 - Posted 2012-03-01 02:30:25 »

Thank you for typing that. So if images are made of length, width, and the color components, you just transfer that info from the bufferedimage to the bytebuffer and you're done?

I actually don't know the difference between a bufferedimage and a bytebuffer, other than OpenGL needs bytebuffers and can't use bufferedimage. Are there any complications to transfering the length, width, and RGBA?
Offline ra4king

JGO Kernel


Medals: 322
Projects: 2
Exp: 4 years


I'm the King!


« Reply #6 - Posted 2012-03-01 04:50:09 »

A BufferedImage is Java2D's way of storing that data. A ByteBuffer is LWJGL's way of storing that data to feed to OpenGL.

All ByteBuffer is, is just an array of bytes either in unmanaged (direct) memory or a normal byte[] array.

Offline Glass

Senior Newbie





« Reply #7 - Posted 2012-03-02 05:30:59 »

Thank you for your help, ra4king.

I didn't know that ByteBuffers were arrays. I looked back at the link that Stranger posted and compared it to a resource and I think I've got some of it. Looking at the loadTexture method, I now understand it up to the for-loop.

I don't understand how the for loop works.

1  
2  
3  
4  
5  
6  
7  
8  
    for(int y = 0; y < image.getHeight(); y++){
        for(int x = 0; x < image.getWidth(); x++){
            int pixel = pixels[y * image.getWidth() + x];
            buffer.put((byte) ((pixel >> 16) & 0xFF));     // Red component
           buffer.put((byte) ((pixel >> 8) & 0xFF));      // Green component
           buffer.put((byte) (pixel & 0xFF));               // Blue component
           buffer.put((byte) ((pixel >> 24) & 0xFF));    // Alpha component. Only for RGBA
           }

I've never heard of some of these things in this loop before. Anyone care to explain it like I'm five? Thank you everybody for your help so far.
Just to show that I'm actually trying to comprehend this and not sitting back and letting you all to do the work, I'll type what I understand in the loop below.

Say getWidth and getHeight both return 16. The first two lines make x and y go from 0 to 16 in every iteration. The third line is sort of confusing. I think pixel is equal to the certain spot for a pixel in the array that was created earlier? I don't know how "[y * image.getWidth() + x]" does that though. Then the next 4 lines are just putting data into that pixel? "((byte) ((pixel >> 16) & 0xFF))" is really a piece for me. The reference I was looking at had a ton of different parameter options for put(), and I can't figure out which one is being used here, so I don't know what's happening in there. I've seen 0xFF in a book I read a few weeks back but the 0xFF was the reason I put the book down, I have no idea what it is. I don't know if this is making zero sense at all, I have no idea what's going on in the bottom 5 lines, just a vague idea not based on the code itself but on context clues.
Offline ra4king

JGO Kernel


Medals: 322
Projects: 2
Exp: 4 years


I'm the King!


« Reply #8 - Posted 2012-03-02 06:32:05 »

The pixels array holds pixels in a 1D array, meaning every WIDTH number of indices is 1 scanline, or 1 row of pixels.
1  
pixels[y * image.getWidth() + x]

That gets the pixel at (x,y) by finding the Y'th row and then X'th pixel on that row.

0xFF - this is hex for 255, aka 1 byte: 11111111. I advise you learn the hexadecimal system Smiley

& - that is the AND command. This takes 2 values and outputs an AND'ed value. Basically, it tests each bit in the first value against each bit in the same position in the second value. Both bits have to be 1 to get a 1, otherwise you get 0. For example:
1  
2  
3  
int v1 = 18;       //00001010
int v2 = 20;       //00001100
int o = v1 & v2;   //00001000

There is also the OR command using | : int o = v1 | v2; This tests for at least 1 of the 2 bits to be a 1 to get a 1.
And lastly there is the XOR command using ^ : int o = v1 ^ v2; This tests for at MOST 1 of the 2 bits to be a 1 to get a 1. If both are 1 or 0 then you get 0.

V >> X - this is the right bit shift command. This shifts all the bits in value V to the right X number of times. For example:
1  
2  
byte v = 54;     //00110110 in binary
byte u = v >> 2; //00001101 = value of 13


Since an int is made up of 4 bytes and each color component is 1 byte, you want to separate out those 4 bytes into 4 separate variables.
The first line shifts the bits to the right 16 times to put the 2nd byte from the left in the rightmost byte position and makes sure only those rightmost 8 bits are left by doing "& 0xFF".
Second line gets the 3rd byte from the left.
Third line just gets the rightmost byte.
Fourth line gets the leftmost byte.

Offline Glass

Senior Newbie





« Reply #9 - Posted 2012-03-02 19:03:56 »

I apologize, it seems like each of your responses are making me ask even more questions. I'm learning a whole lot, though, so thank you again.

Quote from: ra4king
The pixels array holds pixels in a 1D array, meaning every WIDTH number of indices is 1 scanline, or 1 row of pixels.
1  
pixels[y * image.getWidth() + x]

That gets the pixel at (x,y) by finding the Y'th row and then X'th pixel on that row.

If getWidth and getHeight return 4 for the example,
on the first iteration it would be 0*4 + 0, so it would get the 0th int in the pixels array.
on the second iteration it would be 1*4 + 1, so it would get the 5th int in the pixels array.
on the third iteration it would be 2*4 + 2, so it would get the 10th int in the pixels array.
on the fourth iteration it would be 3*4 + 3, so it would get the 15th int in the pixels array.
Then y wouldn't be less than width anymore so it would stop.

Maybe it's because I don't understand 1D arrays, but the array was defined with getWidth * getHeight amount of numbers in it, which would be 16. But only the 0th, 5th, 10th, and 15th of them are being used? What about 1-4, 6-9, 11-14?

Quote from: ra4king
0xFF - this is hex for 255, aka 1 byte: 11111111. I advise you learn the hexadecimal system Smiley

I went and did just that. Also I found out that the 0x was just the prefix used for hex.

Quote from: ra4king
& - that is the AND command. This takes 2 values and outputs an AND'ed value. Basically, it tests each bit in the first value against each bit in the same position in the second value. Both bits have to be 1 to get a 1, otherwise you get 0. For example:
1  
2  
3  
int v1 = 18;       //0001010
int v2 = 20;       //0001100
int o = v1 & v2;   //0001000

There is also the OR command using | : int o = v1 | v2; This tests for at least 1 of the 2 bits to be a 1 to get a 1.
And lastly there is the XOR command using ^ : int o = v1 ^ v2; This tests for at MOST 1 of the 2 bits to be a 1 to get a 1. If both are 1 or 0 then you get 0.

Alright, I think I see what you mean. Using OR in the example you posted would get 0001110, and using XOR would get 0000110.

Quote from: ra4king
V >> X - this is the right bit shift command. This shifts all the bits in value V to the right X number of times. For example:
1  
2  
byte v = 54;     //00110110 in binary
byte u = v >> 2; //00001101 = value of 13


Since an int is made up of 4 bytes and each color component is 1 byte, you want to separate out those 4 bytes into 4 separate variables.
The first line shifts the bits to the right 16 times to put the 2nd byte from the left in the rightmost byte position and makes sure only those rightmost 8 bits are left by doing "& 0xFF".
Second line gets the 3rd byte from the left.
Third line just gets the rightmost byte.
Fourth line gets the leftmost byte.

Oh I get it. It's stored like AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB, so moving it to the right 16 times would make it AAAAAAAARRRRRRRR, right? And the reason that RRRRRRRR remains and not AAAAAAAARRRRRRRR, is because you 'AND' 'd 0xFF, which is 0000000011111111(which, when and'd with something, would make it only use the last 8. )?
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 605
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #10 - Posted 2012-03-02 19:07:07 »

Quote
If getWidth and getHeight return 4 for the example,
on the first iteration it would be 0*4 + 0, so it would get the 0th int in the pixels array.
on the second iteration it would be 1*4 + 1, so it would get the 5th int in the pixels array.
on the third iteration it would be 2*4 + 2, so it would get the 10th int in the pixels array.
on the fourth iteration it would be 3*4 + 3, so it would get the 15th int in the pixels array.
What do you mean by iteration? What you actually did here was stepping through your image diagonally.
Remember that the pixel at (x,y) is found at data[y*w+x], so if you lookup data[2*4+2] it will be visible at (2,2)

Quote
If getWidth and getHeight return 4 for the example,
...
Then y wouldn't be less than width anymore so it would stop.
'y' has nothing to do with 'width', you made it confusing for yourself by stating that both width and height were 4. Let's say w=4 and h=7, then y can be greater than w, it just must be less than h.


Everything else is correct Pointing

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline Glass

Senior Newbie





« Reply #11 - Posted 2012-03-02 19:31:24 »

The iteration as in every time it repeats the 'for' loop. With the for loops how they are, wouldn't it just run through it diagonally like you said?

1  
2  
3  
4  
5  
6  
    for(int y = 0; y < image.getHeight(); y++){
        for(int x = 0; x < image.getWidth(); x++){
            int pixel = pixels[y * image.getWidth() + x];
               ...
        }
    }


Ah, nevermind! It doesn't repeat each 'for' loop every time. Instead of what I posted earlier, if w is 4 and h is 7...

0 * 4 + 0 = 0,
0 * 4 + 1 = 1,
0 * 4 + 2 = 2,
0 * 4 + 3 = 3,
THEN the second for loop would end and the first one would iterate with y = 1 and the second one restarts,
1 * 4 + 0 = 4,
1 * 4 + 1 = 5,
1 * 4 + 2 = 6,
1 * 4 + 3 = 7,
Then the second loop ends again, and whatever. It keeps going.

Anyway, I thought that both 'for' loops repeated every single time, which wouldn't make any sense. Thanks for clearing that up, lol.

EDIT: I think I explained that kind of awkwardly. <___<;; heh, ah well.
Offline ra4king

JGO Kernel


Medals: 322
Projects: 2
Exp: 4 years


I'm the King!


« Reply #12 - Posted 2012-03-02 20:13:25 »

Glass your replies brought a smile to my face by how quickly you understood it Cheesy

Anyway, now you know how to convert BufferredImage to ByteBuffer Smiley

Offline Glass

Senior Newbie





« Reply #13 - Posted 2012-03-02 22:45:07 »

Gee, I couldn't have done it without your great help! Thanks.
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.

xsi3rr4x (11 views)
2014-04-15 18:08:23

BurntPizza (10 views)
2014-04-15 03:46:01

UprightPath (23 views)
2014-04-14 17:39:50

UprightPath (10 views)
2014-04-14 17:35:47

Porlus (27 views)
2014-04-14 15:48:38

tom_mai78101 (49 views)
2014-04-10 04:04:31

BurntPizza (107 views)
2014-04-08 23:06:04

tom_mai78101 (207 views)
2014-04-05 13:34:39

trollwarrior1 (176 views)
2014-04-04 12:06:45

CJLetsGame (182 views)
2014-04-01 02:16:10
List of Learning Resources
by Longarmx
2014-04-08 03:14:44

Good Examples
by matheus23
2014-04-05 13:51:37

Good Examples
by Grunnt
2014-04-03 15:48:46

Good Examples
by Grunnt
2014-04-03 15:48:37

Good Examples
by matheus23
2014-04-01 18:40:51

Good Examples
by matheus23
2014-04-01 18:40:34

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:22:30

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:05:20
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!