Bitmask & Graphics Question

R

Rod Nibbe

I wrote a simple program several years ago that reads a Targa graphics
file (.tga) and displays it. It works fine, but today I had occasion to
resurrect this code and for the life of me I can't figure out what I did
in setting the rgb values. The entire program is below.

The part of the code I'm struggling with is here, where I set the rgb
value for each pixel used to populate a BufferedImage:

bi = new BufferedImage(image_width, image_height,
BufferedImage.TYPE_INT_RGB);

byte [] image = new byte[npixels*3];
int rgb = 0 ;

for(int i=npixels,r=2,g=1,b=0; i>0; r+=3,g+=3,b+=3,i--)
{ // WHY NOT SIMPLY THIS...?
rgb = image[r] << 16 ; // rgb = image[r] << 16 ;
rgb |= (image[g]&0xff) << 8 ; // rgb |= image[g] << 8 ;
rgb |= (image&0xff) ; // rgb |= image ;
bi.setRGB(x,y,rgb) ;
// increment x/y
...
}

If I mask the green(g) and blue(b) pixels with 0xff (8 bits of ones)
before the left bit shift, the picture displays perfectly. If I don't
mask first, the picture is produced but the colors are hokey. Here's
where I'm confused. Performing a logical AND (&) with 0xff on a given
value just returns the value. So why...

...isn't this ----> rgb = image[r] << 16 ;
rgb |= (image[g]&0xff) << 8 ;
rgb |= (image&0xff) ;

the same as this? ----> rgb = image[r] << 16 ;
rgb |= image[g] << 8 ;
rgb |= image ;

Thanks in advance,
-RKN


<code>
package Targa;

import java.io.*;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
import javax.swing.JFrame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Dimension;
import java.awt.BorderLayout;

public class TargaReader extends JPanel {

BufferedImage offs = null ;
Graphics2D g2 = null;

public TargaReader(){
super(false);
}

public void paintComponent(Graphics g) {

super.paintComponent(g) ;

g2 = (Graphics2D)g;

if(offs == null) {
return ;
}
g2.drawImage(offs,0,0,this) ;
g2.dispose() ;
}

public AppFrame getFrame() {

AppFrame app = new AppFrame("Display Targa File") ;
app.getContentPane().setLayout(new BorderLayout());
app.center();

app.setContentPane(this) ;
return app ;

}

public static void main(String [] args) {

DataInputStream tr = null;
String filename = null;
BufferedImage bi = null;

int lsb,msb,image_width=0,image_height=0;
short xorigin,yorigin,width,height ;
byte pixeldepth,imagedesc;

if(args.length > 0)
{
filename = new String(args[0]);
}
else {
System.out.println("Usage: java TargaReader targafile");
System.exit(-1);
}

try {

tr = new DataInputStream(new FileInputStream(filename));

tr.read() ; // ID Length <1 byte>
tr.read() ; // Colormap type <1 byte>
tr.read() ; // Image type <1 byte>

tr.skipBytes(5); // Colormap indicies, not used here. <5 bytes>
tr.skipBytes(4); // X and Y origin, ignore. <4 bytes>

lsb = tr.read() ;
msb = tr.read() ;
image_width = ((msb << 8) | lsb) ;
System.out.println("Image Width: "+ image_width ) ;

lsb = tr.read() ;
msb = tr.read() ;
image_height = ((msb << 8) | lsb) ;
System.out.println("Image Height: "+ image_height);

// Assuming 24-bit pixel depth with no alpha channel.
System.out.println("Pixel Depth: "+tr.read()) ; // Pixel
depth <1 byte>
System.out.println("Image Descriptor: "+tr.read()) ; // Image
descriptor <1 byte>

int npixels = image_width*image_height ;
int rgb = 0;
int x = 0;
int y = image_height-1;

bi = new BufferedImage(image_width, image_height,
BufferedImage.TYPE_INT_RGB);

byte [] image = new byte[npixels*3];

try
{
tr.readFully(image) ; //fetch image data, rgb <24-bit>
}
catch (EOFException eofe) { System.out.println( "EOF:" +
eofe.toString() ); }

for(int i=npixels,r=2,g=1,b=0; i>0; r+=3,g+=3,b+=3,i--)
{ // WHY NOT THIS?...
rgb = image[r] << 16 ; // rgb = image[r] << 16 ;
rgb |= (image[g]&0xff) << 8 ; // rgb |= image[g] << 8 ;
rgb |= (image&0xff) ; // rgb |= image ;
bi.setRGB(x,y,rgb) ;
x++ ;
if(x == image_width) //New scanline
{
x = 0;
y--;
}
}

}
catch (FileNotFoundException fnf)
{
System.out.println("File "+filename+" Not Found") ;
System.exit(-1);
}
catch (IOException ioe)
{
System.out.println("General IO Exception\n" + ioe.toString());
//System.exit(-2);
}

TargaReader targa = new TargaReader() ;
targa.offs = bi ;
AppFrame jf = targa.getFrame() ;
jf.setSize(image_width,image_height);
jf.center();
jf.setVisible(true);
}
}

</code>
 
B

Babu Kalakrishnan

Rod said:
I wrote a simple program several years ago that reads a Targa graphics
file (.tga) and displays it. It works fine, but today I had occasion to
resurrect this code and for the life of me I can't figure out what I did
in setting the rgb values. The entire program is below.

The part of the code I'm struggling with is here, where I set the rgb
value for each pixel used to populate a BufferedImage:

bi = new BufferedImage(image_width, image_height,
BufferedImage.TYPE_INT_RGB);

byte [] image = new byte[npixels*3];
int rgb = 0 ;

for(int i=npixels,r=2,g=1,b=0; i>0; r+=3,g+=3,b+=3,i--)
{ // WHY NOT SIMPLY THIS...?
rgb = image[r] << 16 ; // rgb = image[r] << 16 ;
rgb |= (image[g]&0xff) << 8 ; // rgb |= image[g] << 8 ;
rgb |= (image&0xff) ; // rgb |= image ;
bi.setRGB(x,y,rgb) ;
// increment x/y
...
}

If I mask the green(g) and blue(b) pixels with 0xff (8 bits of ones)
before the left bit shift, the picture displays perfectly. If I don't
mask first, the picture is produced but the colors are hokey. Here's
where I'm confused. Performing a logical AND (&) with 0xff on a given
value just returns the value. So why...

...isn't this ----> rgb = image[r] << 16 ;
rgb |= (image[g]&0xff) << 8 ;
rgb |= (image&0xff) ;

the same as this? ----> rgb = image[r] << 16 ;
rgb |= image[g] << 8 ;
rgb |= image ;


Actually I would like to see even the first value (image[r]) also to be
and'ed with 0xFF before the shift. (May be the code works because the
setRGB operation discards the top 8 bits).

Since image is an array of bytes, the values held by it are assumed to
be in the range -128 to +127. So if you don't perform the "&" operation,
Java will sign extend the byte while performing the promotion to
integer, and the MSB 24 bits will end up being "1" in case bit 7 of the
byte value was 1.

When you and with 0xFF, the sequence of operation is : "promote both
values to int and perform the & operation to produce an integer result".
So even if the top 24 bits become 1 during the promotion, the and
operation will null them to zero.

BK
 
R

Rod Nibbe

Ah, but of course. I had completely overlooked this implication of
promotion to integer.

Thanx,
-RKN

Babu said:
Rod said:
I wrote a simple program several years ago that reads a Targa graphics
file (.tga) and displays it. It works fine, but today I had occasion
to resurrect this code and for the life of me I can't figure out what
I did
in setting the rgb values. The entire program is below.

The part of the code I'm struggling with is here, where I set the rgb
value for each pixel used to populate a BufferedImage:

bi = new BufferedImage(image_width, image_height,
BufferedImage.TYPE_INT_RGB);

byte [] image = new byte[npixels*3];
int rgb = 0 ;

for(int i=npixels,r=2,g=1,b=0; i>0; r+=3,g+=3,b+=3,i--)
{ // WHY NOT SIMPLY THIS...?
rgb = image[r] << 16 ; // rgb = image[r] << 16 ;
rgb |= (image[g]&0xff) << 8 ; // rgb |= image[g] << 8 ;
rgb |= (image&0xff) ; // rgb |= image ;
bi.setRGB(x,y,rgb) ;
// increment x/y
...
}

If I mask the green(g) and blue(b) pixels with 0xff (8 bits of ones)
before the left bit shift, the picture displays perfectly. If I don't
mask first, the picture is produced but the colors are hokey. Here's
where I'm confused. Performing a logical AND (&) with 0xff on a given
value just returns the value. So why...

...isn't this ----> rgb = image[r] << 16 ;
rgb |= (image[g]&0xff) << 8 ;
rgb |= (image&0xff) ;

the same as this? ----> rgb = image[r] << 16 ;
rgb |= image[g] << 8 ;
rgb |= image ;


Actually I would like to see even the first value (image[r]) also to be
and'ed with 0xFF before the shift. (May be the code works because the
setRGB operation discards the top 8 bits).

Since image is an array of bytes, the values held by it are assumed to
be in the range -128 to +127. So if you don't perform the "&" operation,
Java will sign extend the byte while performing the promotion to
integer, and the MSB 24 bits will end up being "1" in case bit 7 of the
byte value was 1.

When you and with 0xFF, the sequence of operation is : "promote both
values to int and perform the & operation to produce an integer result".
So even if the top 24 bits become 1 during the promotion, the and
operation will null them to zero.

BK
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,820
Latest member
GilbertoA5

Latest Threads

Top