×

Discussion Board

Results 1 to 3 of 3
  1. #1
    Regular Contributor
    Join Date
    Mar 2003
    Location
    UK
    Posts
    229

    Loading Image data from 'raw' bytes

    Hi everyone,

    In reply to a question about optimizing MIDlets for size, I commented that you can get space savings in jar files by converting your png files to a 'raw' format. It seems that the zip compression often works better on this raw format than on png's so you end up with a smaller package.

    Here is a small program I use to convert .png files into files that contain nothing but a small header and the raw pixel data in Nokia UI TYPE_1_BYTE_GRAY format. This data can then be loaded directly by a midlet and Image objects created from it using the Nokia UI drawPixels call.

    The formatting seems to be thrown away by the forum posting, but it should be easy enough to load into an editor and auto format. I'll add a second post to this thread with code to load this data into a midlet.

    Cheers,
    Steve

    // Java application for converting png files into raw 1 bit per pixel
    // TYPE_1_BYTE_GRAY format data
    //
    // Uses the Java PNG library from http://www.sixlegs.com/software/png/
    // so you need download this and include png.jar in the classpath
    // when compiling and executing.
    import java.io.*;
    import java.awt.image.*;
    import java.util.Vector;
    import java.util.Hashtable;

    public class Image {

    java.awt.Image image;

    ByteArrayOutputStream bos = new ByteArrayOutputStream();

    byte current_pixel[] = new byte[1];

    int current_pixel_offset;

    DataOutputStream out = null;

    Image (InputStream is) {
    this.image = java.awt.Toolkit.getDefaultToolkit ().createImage
    (new com.sixlegs.image.png.PngImage (is));
    }

    public static Image createImage (File file) throws IOException {

    InputStream is = new FileInputStream(file);
    if (is == null) throw new IOException
    ("Resosurce '"+file+"' not found!"

    return new Image (is);
    }

    public int width() {
    return image.getWidth(null);
    }

    public int height() {
    return image.getHeight(null);
    }

    public void setOutputStream(OutputStream o) {
    out = new DataOutputStream(o);
    }


    public void handlesinglepixel(int x, int y, int pixel) throws IOException {
    if(pixel == 0xFFFFFFFF) { // White pixel

    // Unset the current pixel bit
    current_pixel[0] &= ~(1 << (7-current_pixel_offset));

    } else { // Black pixel

    // Set the current pixel bit
    current_pixel[0] |= (1 << (7-current_pixel_offset));

    }

    if(++current_pixel_offset % 8 == 0) {
    current_pixel_offset = 0;
    write8Pixels();
    }

    }

    public void write8Pixels() {
    // Write the byte out to the output stream
    bos.write( current_pixel, 0, 1);
    current_pixel[0] = 0;
    }

    public void handlepixels(int x, int y, int w, int h) throws IOException {
    int[] pixels = new int[w * h];
    PixelGrabber pg = new PixelGrabber(image, x, y, w, h, pixels, 0, w);
    try {
    pg.grabPixels();
    } catch (InterruptedException e) {
    System.err.println("interrupted waiting for pixels!"
    return;
    }
    if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
    System.err.println("image fetch aborted or errored"
    return;
    }

    System.out.println("Grabbed pixels, processing..."

    current_pixel_offset = 0;
    current_pixel[0] = 0;
    for(int i = 0; i < h; i++) {
    for(int j = 0; j < w; j++) {
    handlesinglepixel(j, i, pixels[(i * w) + j]);
    }
    }

    if(current_pixel_offset % 8 != 0)
    write8Pixels();

    System.out.println(""
    }

    public int writeData() throws IOException {

    if(out != null) {

    System.out.println("Writing Data"

    // Write the bytes in the array to the output stream
    bos.writeTo(out);
    }

    return bos.size();
    }

    public int writeHeader() throws IOException {

    if(out != null) {

    System.out.println("Writing Header"

    //
    // Write the header for the file, 16 bytes
    //
    // Offset Type
    // 0 Byte '1' 4 Byte identifier '01BI' at the start of the file
    // 1 Byte '2'
    // 2 Byte 'B'
    // 3 Byte 'I'
    // 4,5 Short 0X0001 Version number
    // 6,7,8,9 Int 0XWWWWWWWW Width of image
    // 10,11,12,13 Int 0xHHHHHHHH Height of image
    // 14,15 Byte 2 bytes of 0xFF reserved for future use :-)
    //

    // The image data follows the header. Each sequence of 8 pixels written as a byte
    // in the Nokia UI TYPE_BYTE_1_GRAY format
    out.writeByte ( '0' );
    out.writeByte ( '1' );
    out.writeByte ( 'B' );
    out.writeByte ( 'I' );
    out.writeShort( 0x0001 );
    out.writeInt ( width() );
    out.writeInt ( height() );
    out.writeByte ( 0xFF );
    out.writeByte ( 0xFF );

    }

    return 16;
    }

    public static void main(String args[]) throws IOException {

    if(args.length != 1) {
    System.out.println("Usage : java Image <pngfilename>|<dirname>"
    System.exit(1);
    }

    File t = new File(args[0]);

    if(t.isDirectory()) {

    // Get a list of all the files in the directory
    File f = new File(args[0]);
    File [] files = f.listFiles();

    for(int i = 0; i < files.length; i++) {
    String name = files[i].getName();
    if(name.indexOf(".png&quot != -1) {
    oneFile(files[i]);
    }
    }

    } else {
    oneFile(t);
    }

    System.exit(0);
    }

    public static void oneFile(File f) throws IOException {

    Image i = Image.createImage(f);

    String name = f.getCanonicalPath();

    System.out.println("Loaded "+name+" width="+i.width()+" height="+i.height());

    // Get an output file name
    String outfilename = name.substring(0,name.indexOf(".&quot) + ".01b";

    FileOutputStream fos = new FileOutputStream(outfilename);

    i.setOutputStream(fos);

    i.handlepixels(0,0,i.width(),i.height());

    int bytes = 0;
    bytes += i.writeHeader();
    bytes += i.writeData();

    System.out.println("Written "+bytes+" to "+outfilename);

    fos.close();
    }

    }

    // End of class Image

  2. #2
    Regular Contributor
    Join Date
    Mar 2003
    Location
    UK
    Posts
    229

    RE: Loading Image data from 'raw' bytes

    Here's a bit of code for loading a file with this raw data in and creating an Image object from it. Apologies for the formatting again!

    Your mileage my vary with space savings, but I've used a similiar method quite sucessfully using the TYPE_4444_ARGB 16 bpp pixel format used on the 7650. Using a similiar raw format with a variable palette, I've managed to reduce colour pngs to almost a quarter of their size.

    You need to be careful with runtime memory usage with these routines though. At one point, you've got the resource file, a byte array and the Image all in memory at once, so be aware of heap limits.

    I hope this is of some use to someone, and please ask any questions you may have.

    Steve

    public Image loadRaw(String resource) {
    InputStream in = new Object().getClass ().getResourceAsStream(resource);
    DataInputStream din = new DataInputStream(in);
    din.skip(6); // skip the eyecatcher and version number
    int width = din.readInt();
    int height = din.readInt();
    din.skip(2); // skip the 2 reserved bytes

    // allocate the byte array
    byte [] data = new byte [(width * height) >> 3];

    // read it in from the stream
    din.read(data);

    // close the stream
    din.close();

    // Create a new Image object
    Image image = new Image(width,height);

    // Get a DirectGraphics object from the image
    DirectGraphics dg = DirectUtils.getDirectGraphics(image.getGraphics());

    // Draw the pixels from the resource onto the image
    dg.drawPixels(data,
    null, // No mask this time
    0, // 0 offset
    width, // scanlength
    0,0, // x,y
    width,
    height,
    0, // no manipulation
    DirectGraphics.TYPE_1_BYTE_GRAY);

    // Give the garbage collector a chance
    data = null;
    in = null;
    din = null;

    // Return the image
    return image;
    }

  3. #3
    Registered User
    Join Date
    Mar 2003
    Location
    London
    Posts
    37

    RE: Loading Image data from 'raw' bytes

    Hello Long, I'm freelance programmer and I'm with troubles developping a gui for the 7650, I agree your help.
    Well I'm creating images with Image.createImage("/name.png&quot, and I have about 20 , sometimes appears two, sometimes three and the problem is that when the midlet is running about 5 minutes, stops and I must to reiniziate the device.
    My heap memory is ok, do you know something about ???

    Regards

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
×