• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 700
  • Last Modified:

Reading in raw pixel data and creating an image

I don't know if I need to know anymore specifics on this, but I cannot seem to get this to work. I have a custom file format that has header information, other file information, image width/height and raw pixel data. To make it simple, I have extracted the pixel data (using a hex editor) and put it in a separate file. What I am trying to do is just read in that data and create an image.

Here is the code I am using to read in the pixel data:

Note: fileLength is just the length of the file containing the data...

-----------------------------------
[code]
int i, count = 0;

int [] pixels = new int[ fileLength ];

try {

while ( count != fileLength ) {

i = bufferedInputStream.read();

// if this byte is valid, let's add it to the array
if ( i != -1 ) {

pixels[ count ] = i;

count++;
prog.setValue( count );

}

} // end while

bufferedInputStream.close();

} catch ( IOException e ) {
System.out.println( e );
}
[/code]
-----------------------------------

Then I create the image:

[code]
Image image = createImage( new MemoryImageSource( 150, 200, lf.getPixels(), 0, 150 ) );
[/code]

I already know that the image is 150px by 200px, so this is just hardcoded.

When I try and display this image, it is just all black (which is the background color I paint...so basically the image just isn't being rendered). Any suggestions?

Thanks,
Chris
0
ctjoumas
Asked:
ctjoumas
1 Solution
 
allelopathCommented:
Have you created a a color model for the image?
0
 
ctjoumasAuthor Commented:
No I haven't.  I haven't had any experience with doing that - suggestions?
0
 
allelopathCommented:
So you've got this pixel data that is an array of ints, with the ints representing a color.
The problem may be the you need something to tell the renderer what colors are represented by those int values, e.g 0 => black

You may be able you use the following class (filling in some blanks, indicated by ???)
It is a class for a 16-color image.


/*
 * @MyImage.java
 *
 */
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.io.*;
import java.util.*;

/**
 * Instantiate this class and then use the draw() method to draw the
 * generated on the graphics context.
 */
public class MyImage
{
// Holds the generated image
Image image;

// Create an Image from an Array of Color-Indexed Pixel Values
ColorModel colorModel = generateColorModel();

// true if image is scaled, false otherwise
boolean scaled = true;

Rectangle2D.Float rect;


/**
 *  Constructor
 */
public MyImage(int width,
                             int height)
{
    rect = new Rectangle2D.Float();
    createNewImage( width,
                                  height,
                                  rect);
} // end constructor

   
/**
 *  create pixel data based on dta by calling generateImage()
 *  create a data buffer from pixel image
 *  create a sample model from from data buffer
 *  create a raster object from sample model
 *  create a buffered image from raster object and color model
 *
 * @param width width of image
 * @param height height of image
 * @param loc location of image
 */
public void createNewImage(int width,
                                          int height,
                                           Rectangle2D.Float loc)
{
    // Generate the pixel data
    // Creating an Image from an Array of Color-Indexed Pixel Values
     byte[] pixels = ??? get pixel data here ???

    // Create a data buffer using the byte buffer of pixel data.
    // The pixel data is not copied; the data buffer uses the byte buffer array.
    DataBuffer dbuf = new DataBufferByte(pixels, width*height, 0);
   
     int numBanks = dbuf.getNumBanks(); // 1

    // Prepare a sample model that specifies a storage 4-bits of
    // pixel datavd in an 8-bit data element
    int bitMasks[] = new int[]{(byte)0xf};
    SampleModel sampleModel = new SinglePixelPackedSampleModel(DataBuffer.TYPE_BYTE, width, height, bitMasks);
   
    // Create a raster using the sample model and data buffer
    WritableRaster raster = Raster.createWritableRaster(sampleModel, dbuf, null);

    // Combine the color model and raster into a buffered image
    image = new BufferedImage(colorModel, raster, false, null);

}  // end constructor

   
/**
 * generate a color model
 *
 */
private static ColorModel generateColorModel()
{
  // Generate 16-color model
  byte[] r = new byte[16];
  byte[] g = new byte[16];
  byte[] b = new byte[16];

  r[0] = 0; g[0] = 0; b[0] = 0;                                               // 0x000000   0 black
  r[1] = 0; g[1] = 0; b[1] = (byte)192;                                   // 0x0000c0   1 dark blue
  r[2] = 0; g[2] = 0; b[2] = (byte)255;                                   // 0x0000ff   2 blue
  r[3] = 0; g[3] = (byte)192; b[3] = 0;                                   // 0x00c000   3 dark green
  r[4] = 0; g[4] = (byte)255; b[4] = 0;                                   // 0x00ff00   4 green
  r[5] = 0; g[5] = (byte)192; b[5] = (byte)192;                       // 0x00c0c0   5 teal
  r[6] = 0; g[6] = (byte)255; b[6] = (byte)255;                       // 0x00ffff   6 cyan
  r[7] = (byte)192; g[7] = 0; b[7] = 0;                                   // 0xc00000   7 dark red
  r[8] = (byte)255; g[8] = 0; b[8] = 0;                                   // 0xff0000   8 red
  r[9] = (byte)192; g[9] = (byte)240; b[9] = (byte)192;           // 0xc0f0c0   9 light green
  r[10] = (byte)255; g[10] = 0; b[10] = (byte)255;                 // 0xff00ff   10 magenta
  r[11] = (byte)192; g[11] = (byte)192; b[11] =  (byte)192;    // 0xc0c0c0   11 light grey
  r[12] = (byte)255; g[12] = (byte)255; b[12] = 0;                 // 0xffff00   12 yellow
  r[13] = (byte)128; g[13] = (byte)128; b[13] = (byte)128;     // 0x808080   13 med grey
  r[14] = (byte)80; g[14] = (byte)80; b[14] = (byte)80;          // 0x505050   14 dark grey
  r[15] = (byte)255; g[15] = (byte)255; b[15] = (byte)255;     // 0xffffff   15 white  

  return new IndexColorModel(4, 16, r, g, b);
}

 
/**
 * check if image is scaled
 *
 * @param g graphics context
 * @param x x-coordinate
 * @param y y-coordinate
 */
public void draw(Graphics g, int x, int y)
{
    g.drawImage(image, x, y, null);
}
   
} // end class
   
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
ctjoumasAuthor Commented:
I tried what you had and I still get the same result...

I think this might change things - but I just found out from someone that all of these images will be grayscale.  Sorry I didn't have that information earlier (if it changes anything)!

Chris
0
 
allelopathCommented:
greyscale could be implemented by changing the rgb code to different shades of grey, rather than color.

  r[0] = 0; g[0] = 0; b[0] = 0;                                               // 0x000000   0 black
  r[1] = ?; g[1] = ?; b[1] = ?;                                                // really dark grey
  ...
  r[14] = ?; g[14] = ?; b[14] = ?;                                          // really light grey
  r[15] = (byte)255; g[15] = (byte)255; b[15] = (byte)255;     // 0xffffff   15 white  

There may be a better way though, in which case it would be a good time for a more experienced java person to jump in (objects, CEHJ, jimmack, el al)
0
 
objectsCommented:
> There may be a better way though

No thats about right :)
0
 
allelopathCommented:
i am not worthy  :)
0
 
allelopathCommented:
Oh, also, to take a baby step, you could create a 150x200 grey scale gif file and try to display that in the same area where you now get black.
0
 
ctjoumasAuthor Commented:
I actually couldn't get that to work, but I have tried different ways to get my desired result.  Also, sorry for the lack of points - just posting this if anyone is curious or if anyone has any solution - here's a pretty good rundown of what I'm doing and what my progress is so far (I'm actually getting an image, it just looks liike crap!):

I'm reading in raw pixel data of a 16-bit signed grayscale image. I was trying to use the int array of what the readPixels returned (where readPixels returns an Object), but I don't know if what I was trying will make any difference. So, I guess I'm gonna kinda change this topic in case anyone has any ideas:

I am trying different ways to open the raw data -
1) Using a FileInputStream to read the file and creating the image like:

            try {

                FileInputStream in = new FileInputStream( fileName );

                int i;
                int x = 0;
                int y = 0;

                while ( (i = in.read()) != -1 ) {

                    image.setRGB( x, y, 0xFF000000 + (i<<16) + (i<<8) + i );

                    x++;
                    if ( x >= WIDTH ) {
                        x = 0;
                        y++;
                        if ( y >= HEIGHT )
                            break;
                    } // end if

                } // end while
                in.close();
            } catch ( Exception ex ) { ex.printStackTrace(); }


The problem there is that the BufferedImage that I am setting RGB values for is a Grayscale image (BufferedImage.TYPE_BYTE_GRAY), which is unsigned - whereas I need signed and am not sure how to do that.

2) Trying the same way as above, but using ImageReader like this:


            try {

                FileInputStream in = new FileInputStream( fileName );

                ImageReader ir = new ImageReader( fi );
                Object pixels = ir.readPixels( in );

                in.close();

                int x = 0;
                int y = 0;

                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream( bos );
                oos.writeObject( pixels );
                oos.flush();
                oos.close();
                bos.close();
                byte [] data = bos.toByteArray();

                int [] pix = new int[ data.length ];

                for ( int i=0; i<data.length; i++ ) {
                    pix[ i ] = data[ i ];
                    System.out.println( data[ i ] );
                }

                for ( int i=0; i<pix.length; i++ ) {

                    image.setRGB( x, y, 0xFF000000 + (pix[ i ]<<16) + (pix[ i ]<<8) + pix[ i ] );

                    x++;
                    if ( x >= WIDTH ) {
                        x = 0;
                        y++;
                        if ( y >= HEIGHT )
                            break;
                    } // end if
                } // end for
            } catch ( Exception e ) { System.out.println( e ); }


I get a null pointer exception when using setRGB at the first pixel, so not sure whats going on there.

3) the third way I am trying is using a FileOpener to get an ImagePlus image back - again, I think this is an unsigned image, so I get the same exact result as method 1:


            FileInfo fi = new FileInfo();
            fi.width = WIDTH;
            fi.height = HEIGHT;
            fi.offset = 0;
            fi.fileName = fileName;
            fi.intelByteOrder = true;
            FileOpener fo = new FileOpener( fi );
            ImagePlus ip = fo.open( false );
            image = ip.getImage();

0
 
ctjoumasAuthor Commented:
I got the third way to work by doing the following:

            FileInfo fi = new FileInfo();
            fi.width = WIDTH;
            fi.height = HEIGHT;
            fi.offset = 0;
            fi.fileName = fileName;

            fi.intelByteOrder = false;
            fi.fileType = FileInfo.GRAY16_SIGNED;

            FileOpener fo = new FileOpener( fi );
            ImagePlus ip = fo.open( false );

            image = ip.getImage();


The image doesn't seem to be as high quality as the software that loaded it (CINE I think it is), but that software may have had something internally to sharpen it.  This method doesn't give me as much flexibility as I'd like since it is all done by itself - is there a way to duplicate this logic with one of the othe rmethods I was using before?

Thanks,
Chris
0
 
allelopathCommented:
hmmm...converting 16 bit signed to unsigned can be done by something like this (i think):
if the signed number < 0 then
  signed number = 2^16 + signed number
else // signed number is >= 0
  do nothing

you should definitely check the math on that though, i'm just remembering this from long ago.


0
 
ctjoumasAuthor Commented:
I don't want to convert from signed to unsigned - the raw data is signed.  In the other 2 methods that I am using, I need to create a BufferedImage object - and the types that I can choose (the TYPE_BYTE_GRAY) is unsigned.  So my problem in the other methods is storing signed into unsigned!  So I was thinking that there might be another way to create the BufferedImage so that it is not unsigned - or if there is someway to convert the image to signed.

Hope this is clear enough!
0
 
NetminderCommented:
User resolved; points (45) refunded and question closed.

Netminder
EE Admin
0

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now