views:

470

answers:

3

I have a Java Applet that I'm making some edits to and am running into performance issues. More specifically, the applet generates an image which I need to export to the client's machine.

This is really at the proof-of-concept stage so bear with me. For right now, the image is exported to the clients machine at a pre-defined location (This will be replaced with a save-dialog or something in the future). However, the process takes nearly 15 seconds for a 32kb file.

I've done some 'shoot-by-the-hip' profiling where I have printed messages to the console at logical intervals throughout the method in question. I've found, to my surprise, that the bottleneck appears to be with the actual data stream writing process, not the jpeg encoding.

KEEP IN MIND THAT I ONLY HAVE A BASIC KNOWLEDGE OF JAVA AND ITS METHODS

So go slow :p - I'm mainly looking for suggestions to solve the problem rather the solution itself.

Here is the block of code where the magic happens:

ByteArrayOutputStream jpegOutput = new ByteArrayOutputStream();
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(jpegOutput);
encoder.encode(biFullView);
byte[] imageData = jpegOutput.toByteArray();

String myFile="C:" + File.separator + "tmpfile.jpg";
File f = new File(myFile);

try {
dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(myFile),512));
dos.writeBytes(byteToString(imageData));
dos.flush();
dos.close();
}
catch (SecurityException ee) {
    System.out.println("writeFile: caught security exception");
}
catch (IOException ioe) {
    System.out.println("writeFile: caught i/o exception");
}

Like I mentioned, using system.out.println() I've narrowed the performance bottleneck to the DataOutputStream block. Using a variety of machines with varying hardware stats seems to have little effect on the overall performance.

Any pointers/suggestions/direction would be much appreciated.

EDIT: As requested, byteToString():

public String byteToString(byte[] data){
  String text = new String();
  for ( int i = 0; i < data.length; i++ ){
    text += (char) ( data[i] & 0x00FF );
  }
  return text;
}
+1  A: 

You might want to take a look at ImageIO.

And I think the reason for the performance problem is the looping in byteToString. You never want to do a concatenation in a loop. You could use the String(byte[]) constructor instead, but you don't really need to be turning the bytes into a string anyway.

Michael Myers
A: 

If you don't need the image data byte array you can encode directly to the file:

String myFile="C:" + File.separator + "tmpfile.jpg";
File f = new File(myFile);
FileOutputStream fos = null;
try {
    fos = new FileOutputStream(f);
    JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(
                             new BufferedOutputStream(fos));
    encoder.encode(biFullView);
}
catch (SecurityException ee) {
    System.out.println("writeFile: caught security exception");
}
catch (IOException ioe) {
    System.out.println("writeFile: caught i/o exception");
}finally{
    if(fos != null) fos.close();
}

If you need the byte array to perform other operations it's better to write it directly to the FileOutputStream:

//...
fos = new FileOutputStream(myFile));
fos.write(imageData, 0, imageData.length);
//...
Serhii
Thanks. This gets me moving in the right direction. The performance improvement was incredible.
Mike B
A: 

You could also use the standard ImageIO API (classes in the com.sun.image.codec.jpeg package are not part of the core Java APIs).

String myFile="C:" + File.separator + "tmpfile.jpg";
File f = new File(myFile);
ImageIO.write(biFullView, "jpeg", f);
mongolito404