Image in Jar file

J

JScoobyCed

Hi,

I am bundling an application to a jar file, and I am meeting pb with
images.
My jar structure:
- meta-inf\manifest.mf
- foo\bar\**\*.class
- properties\*.properties
- images\*.gif

If I don't compress the jar file, the gif can be displayed correctly.
If I compress the jar, I can't get the gif images correct.
I triied to read the bytes of a gif from within the compressed and from
within a uncompressed jar file.
The two output are different. The compressed jar reading results in
extra bytes for the image.
For example, a 1601 bytes images results to a 1643 bytes if read from a
compressed jar.
I saw the bug on sun website:
http://bugs.sun.com/bugdatabase/view_bug.do;:YfiG?bug_id=4198073
It looks to be a known problem.

Does anybody know a turnaround that allows to compress the jar file?
I have several property files that are text, and result in a jar that is
bigger than it could be.

Thanks,
 
T

Thomas Weidenfeller

JScoobyCed said:
If I don't compress the jar file, the gif can be displayed correctly.
If I compress the jar, I can't get the gif images correct.
I triied to read the bytes of a gif from within the compressed and from
within a uncompressed jar file.
The two output are different. The compressed jar reading results in
extra bytes for the image.
For example, a 1601 bytes images results to a 1643 bytes if read from a
compressed jar.

a) Please show us complete code demonstrating the problem.

b) Please run the following experiment: Check if the first 1601 bytes in
the 1643 bytes from the compressed jar are the bytes you expect (match
the image data), because
I saw the bug on sun website:
http://bugs.sun.com/bugdatabase/view_bug.do;:YfiG?bug_id=4198073
It looks to be a known problem.

c) That bug report and the related ones shows the typical poor bug
handling from Sun. After having read it three times, and also the
mentioned related bug descriptions, I still don't get it completely. It
think they are

c.1) talking about some bugs in the VM implementation which they
have fixed, and

c.2) common user errors when using the read() method of the streams
class.

Because of c.2) I would love to see a) and b).

/Thomas
 
J

JScoobyCed

Thomas said:
a) Please show us complete code demonstrating the problem.

I don't have the code here. It's at home. So I just tried to re-write
from memory the method I wrote at home. And the funny things the code I
just wrote is working (it is not the way I did at home, in particular in
the 'while' loop:

<code>
byte[] tmp= new byte[102400];
int size = 0;
try {
InputStream is = getClass().getResourceAsStream("/image.gif");
while (is.available() > 0) {
is.read(tmp, size, 1);
size++;
}
is.close();
byte[] data = new byte[size];
System.arraycopy(tmp, 0, data, 0, size);
ImageIcon icon = new ImageIcon(data);
JOptionPane.showMessageDialog(null, icon, "Size: " + data.length,
OptionPane.INFORMATION_MESSAGE);
} catch (Exception exc) {
JOptionPane.showMessageDialog(null,exc.getMessage(),"Error.",OptionPane.ERROR_MESSAGE);
}
System.exit(0);
</code>

So I guess reading the compressed file byte by byte IS the solution. I
know at home I read the
InputStream each time something like
while((len = is.available())>0) {
is.read(tmp,index,len);
}

Thanks anyway :)
 
T

Thomas Weidenfeller

JScoobyCed said:
InputStream is = getClass().getResourceAsStream("/image.gif");
while (is.available() > 0) {

From the extremely strange Sun bug reports you mentioned it can be
interfered that available() is not a reliable method when used on zip
file data, because of some bug in some VMs. available() is also not a
good idea in other situations.

You might want to change the read loop using the return value from the
read(), which is the common way to do things in Java.
is.read(tmp, size, 1);

Reading one byte at a time is also rather inefficient, especially, if
you are already reading to a buffer.
byte[] data = new byte[size];
System.arraycopy(tmp, 0, data, 0, size);

Waste of time, you just copied the data to an array, and now you copy it
again, just to hand it over to an image icon, which will copy the data
to some image.
ImageIcon icon = new ImageIcon(data);

Another waste of time. An ImageIcon can take a URL as argument, so you
whole code could be written as:

URL url = getClass().getResource("/image.gif");
ImageIcon icon = url == null ? null : new ImageIcon(url);

JOptionPane.showMessageDialog(null, icon, "Size: " + data.length,
OptionPane.INFORMATION_MESSAGE);
} catch (Exception exc) {
JOptionPane.showMessageDialog(null,exc.getMessage(),"Error.",OptionPane.ERROR_MESSAGE);

}
System.exit(0);
</code>

So I guess reading the compressed file byte by byte IS the solution.

No, most likely you are using different VMs with different available()
implementations.

/Thomas
 
J

JScoobyCed

Thomas said:
No, most likely you are using different VMs with different available()
implementations.

/Thomas

Hi,

I guess I should rely on *some* method provided by Sun :)
I thought the ImageIcon(URL) wouldn't read the image in the jar, and
even didn't give a try.
From your comments, the "wasting time" sequence of code I used is
actually one of the *safest* way to read any InputStream (from file,
socket, bluetooth, serial, etc...) if I believe my findings on internet.
This method always works, but at the cost of slowliness.
But I agree my method is doing some extra byte copy and could be
improved :) That code was solely to make sure I can read the compressed
file.
Thanks for your good suggestions !
 

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

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,736
Latest member
zacharyharris

Latest Threads

Top