monitoring loading progress in Applet

Many people have suggested that images should be contained in a single jar file to improve loading efficiency. But
I also want to give the user a general idea how many image files have been downloaded. Is there any way I can accomplish
both?

Regards,

Pan

Download the ZIP (containing the images) from within your applet. That way you can count the bytes and show a progress bar, If your server sends the ContentLength (which it probably does) you can use it to calculate the percentage using URLConnection.getContentLength()

Downside is that that ZIP will never end up on your browser’s cache.

images are useally very staticy and your code changes in comparison a lot, I wouldn’t package them together. The additional request you save pales in comparison with the additional download.

Java 6 will cache it. I get 304 “Not Modified” responses in my apache logs all the time.

Fancy stuff. Good to know!

Thanks for the reply guys. However I don’t have my own server, I use a free file server called freewbes.com to host my applet.
It is rather inconvenience to use cause I can only upload one file at a time (at least it is true last time I tried). This is another reason
why I want to pack all the image files into a single jar/zip.

I think riven 's approach sounds like a good idea. Could you show me some of the code of how to do this?
You can assume that all my class files are packaged in a sigle jar, and all the image files are packaged
in another jar.

Many thanks

Pan

And if you’re stuck with jre < 1.6 compatibility, you could always just zip your images and rename the zip to .class. f you download it over an urlconnection with the property useCache(true) it will cache your zip…

Below is an excerpt I copy pasted from my IO lib (some helper methods might be missing, but you get the point), the download method would return a byte[] of the zipped data in your case, which you can then feed to the decompress method:


	public synchronized static byte[] downloadData(String resource, Class loader, ResourceInfo info, ProgressListener plistener, boolean cache)
	{
		try 
		{
			InputStream is = openStream(resource, loader, info, cache);
			DataInputStream dis = new DataInputStream(is);
			
			if (dis==null) {
				Log.log(this, "Resource not found: " + resource);
				return null;
			}

			int length=dis.available();
			//read min blocks of 8kb to force frequent updates for plistener (=~1update/sec on a 56k modem)
			if (length <= 0) length = 8192;
			//read max blocks of 100kb to prevent downloading all data in one sweep
			if (length >= 10240) length = 10240;

			byte[] chunk=new byte[length];
			ByteArrayOutputStream bos = new ByteArrayOutputStream();

			//set the progresslistener if available
			//if (plistener != null) plistener.next(plistener.DOWNLOAD);

			//read in bytes from the stream & update the progresslistener if available
			int bytesRead = 0;
			while((bytesRead = dis.read(chunk,0,length)) != -1) {
				//System.out.println("bytes read from bis: "+bytesRead);
				bos.write(chunk,0,bytesRead);
				//if(plistener!=null) plistener.update(bytesRead);
			}

			bos.flush();
			closeStream(dis);
			closeStream(is);
			return bos.toByteArray();
		}
		catch(Exception e) {
			Log.log(this, e);
			return null;
		}
	}

	public synchronized static void decompress(byte[] data, ProgressListener plistener)
	{
		//check how many zipentries the data contains
		int size=getNrEntries(data),index=0;

		sizes = new String[size*2];

		//check if there are any entries to process and tell the progress listener
		if(size>0) {
			Log.log(this, "Decompressing: "+size+" zipentries found");
			//if(plistener!=null) plistener.init(size);
		}
		else 
		{
			Log.log(this, "Decompressing: no zip entries in data");
			return;
		}

		try
		{
			ZipEntry ze;
			ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(data));

			while ((ze=zis.getNextEntry())!=null) 
			{
				if (ze.isDirectory()) {
					continue;
				}
				
				size=(int)ze.getSize();
				
				sizes[index++]=ze.getName();
				sizes[index++]=""+size;
				
				Log.log(this, "Decompressing: zip entry: "+ze.getName()+","+"size="+size);
             
				//if this is a valid entry, decompress it
				if (size>-1) 
				{
					//set the progresslistener for this entry
					//if(plistener!=null) plistener.next(plistener.DECOMP);

					byte[] decompData = new byte[(int)size];
					int bytesRead=0;
					int chunk=0;
					while ((size - bytesRead) > 0) 
					{
						chunk=zis.read(decompData,bytesRead,(int)size - bytesRead);
						if (chunk==-1) {
							break;
						}
						bytesRead+=chunk;
						
						//if(plistener!=null) plistener.update(chunk);
					}
            
					//cache the entry in the game cache
					GameContext.addObject(ze.getName(),decompData);
					Log.log(this, "Decompressing: zip entry: "+ze.getName()+"  bytes read="+bytesRead+",size="+size+",compressed size="+ze.getCompressedSize());
				}
				else
				{
					Log.log(this, "Decompressing: zip entry: "+ze.getName()+" has unknown size");
					continue;
				}
			}
		}
		catch (NullPointerException e) {
			Log.log(this, e);
		} 
		catch (FileNotFoundException e)	{
			Log.log(this, e);
		} 
		catch (IOException e) {
			Log.log(this, e);
		}
	}


[quote] the download method would return a byte[] of the zipped data in your case, which you can then feed to the decompress method
[/quote]
Thanks for posting the code, however I have a question:
Suppose now I have the raw data of a jpg image in the format of byte[], how do I create an Image object from it?

You could use the ByteArrayInputStream to convert the byte array into a stream and the use ImageIO to create an image from the stream.

Ah, thats the easy part :wink:

Image = Toolkit.getDefaultToolkit().createImage( imagebyte[] );

Or

BufferedImage image = ImageIO.read ( new ByteArrayInputStream ( imagebyte[] ) );

[quote]Image = Toolkit.getDefaultToolkit().createImage( imagebyte[] );
[/quote]
May be a silly question:
How could the it tell whether the byte data contains a jpeg image or image in other format ?

ImageIO won’t care about format if it’s not reading the image from a file. It uses its own format types which you can access via myImage.getType(). If you want to have a specific type of image (like one with transparency and color values from 0 to 255, or a custom type, or a compressed type, etc.) then you can just create a new image of that type and then copy the ImageIO one over.

Either way just assume ImageIO is magic and that elves give you a useable image, regardless of whether it was PNG, JPG, or whatever.

Thanks for the help. Didn’t know that java image library is that powerful. :slight_smile: