Polymap
/********************************************************************************
* ImageMap.java: Java Polymap Applet source code *
* *
* Copyright (C) 1996 Cheong S Ang *
* *
* Java Polymap Applet, both binary and source (hereafter, Software) is *
* copyrighted by Cheong S Ang (hereafter, Author), and ownership remains *
* with the the Author. *
* *
* The Author grants you (hereafter, Licensee) a license to use the Software *
* for academic, research and non-commercial purposes only, without a *
* fee. Licensee may distribute the binary and source code (if released) *
* to third parties provided that the copyright notice and this statement *
* appears on all copies and that no charge is associated with such *
* copies. *
* *
* Licensee may make derivative works. However, if Licensee distributes *
* any derivative work based on or derived from the Software, then *
* Licensee will (1) notify the Author regarding its distributing of the *
* derivative work, and (2) clearly notify users that such derivative *
* work is derived from the Software. *
* *
* Any Licensee wishing to make commercial use of the Software should *
* contact the Author, to negotiate an appropriate license for such *
* commercial use. Commercial use included (1) integration of all or *
* part of the source code into a product for sale or license by or on *
* behalf of Licensee to third parties, or (2) distribution of the binary *
* code or source code to third parties that need it to utilize a *
* commercial product sold or licensed by or on behalf of Licensee. *
* *
* THE AUTHOR MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE *
* FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED *
* WARRANTY. THE AUTHOR SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE *
* USERS OF THIS SOFTWARE. *
* *
* By using or copying this Software, Licensee agrees to abide by the *
* copyright law and all other applicable laws of the U.S. including, but *
* not limited to, export control laws, and the terms of this license. *
* The Author shall have the right to terminate this license immediately by *
* written notice upon Licensee's breach of, or non-compliance with, any *
* of its terms. Licensee may be held legally responsible for any *
* copyright infringement that is caused or encouraged by Licensee's *
* failure to abide by the terms of this license. *
* *
********************************************************************************/
/*
* @version 1.0 15 March 1996
* @author Cheong S Ang
*/
import java.applet.Applet;
import java.lang.Thread;
import java.lang.Integer;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.Color;
import java.awt.Image;
import java.awt.image.*;
import java.awt.Rectangle;
import java.net.URL;
import java.net.URLConnection;
import java.net.MalformedURLException;
import java.io.InputStream;
import java.io.ByteArrayOutputStream;
class Point {
int x, y;
}
class Poly {
Polygon pol; // cache it
Point[] pt;
int npts;
}
class PolyObj {
Poly[] p;
String url;
int nps;
}
class Polymap {
PolyObj[] pobj;
int npobjs;
}
public class ImageMap extends Applet {
static final int NONE = -1;
Polygon current_polygon;
int current_obj=NONE;
int current_poly=NONE;
Polymap pm;
Color highlight_color;
Image baseImage;
public void init() {
baseImage = getImage(getDocumentBase(), getParameter("img"));
byte[] im;
URL url;
InputStream us;
ByteArrayOutputStream bos;
int nread = 0;
int st;
try {
String base = getDocumentBase().toString();
int s=0, e;
while((e=base.indexOf('/', s))!=-1) {
s = e+1;
}
//System.out.println("base: " + base);
char[] nurl = base.toCharArray();
base = new String(nurl, 0, s);
String surl = base + getParameter("img");
//System.out.println("base: " + base + " img: " + getParameter("img"));
System.out.println("full img url: " + surl);
showStatus("Polymap Applet. Copyright © 1996 Cheong S Ang.");
url = new URL(surl);
us = url.openStream();
byte[] buf = new byte[1024];
int nbytes = 0;
bos = new ByteArrayOutputStream();
nread = us.read(buf, 0, 1024);
bos.write(buf, 0, nread);
while (nread > 0) {
nread = us.read(buf, 0, 1024);
if (nread<=0) break;
bos.write(buf, 0, nread);
nbytes += nread;
//System.out.println(nbytes + " bytes read");
}
String str = bos.toString();
st = str.indexOf("PMAP1.0");
//if (st > 0) System.out.println("Location of PMAP: " + st);
}
catch (Exception e) {
e.printStackTrace();
return;
}
if (st > 0) { // found PMAP1.0
im = bos.toByteArray();
String sim = new String(im, 0, st, 20);
DoPolymap(im, st); // create pm
// create all the polygons ahead of time
int max_j, max_k;
for (int i=pm.npobjs-1; i>=0; i--) {
max_j = pm.pobj[i].nps;
for (int j=0; j<max_j; j++) {
max_k = pm.pobj[i].p[j].npts;
int[] xpts=new int[max_k];
int[] ypts=new int[max_k];
for (int k=0; k<max_k; k++) {
xpts[k] = pm.pobj[i].p[j].pt[k].x;
ypts[k] = pm.pobj[i].p[j].pt[k].y;
}
pm.pobj[i].p[j].pol = new Polygon(xpts, ypts, max_k);
}
}
String scolor = getParameter("color");
Integer icolor;
try {
icolor = Integer.valueOf(scolor, 16);
highlight_color = new Color(icolor.intValue());
} catch (NumberFormatException e) {
highlight_color = Color.blue;
}
}
}
int nim; // im pointer
boolean ReadOK(byte[] src, byte[] buffer, int b, int len) {
for (int i=0; i<len; i++)
buffer[b+i] = src[nim+i];
nim += len;
return true;
}
boolean ZeroDataBlock = false;
int GetDataBlock(byte[] im, byte[] buf, int b) {
byte[] count = new byte[1];
count[0]=0;
if (! ReadOK(im, count, 0, 1)) {
System.out.println( "error in getting DataBlock size");
return -1;
}
ZeroDataBlock = ((count[0]&0xff) == 0);
if (((count[0]&0xff) != 0) && (! ReadOK(im, buf, b, (count[0]&0xff)))) {
System.out.println( "error in reading DataBlock\r\n");
return -1;
}
return (count[0]&0xff);
}
/*
** Used in nextCode
*/
int curbit, lastbit;
int last_byte;
boolean return_clear, get_done;
int[] maskTbl = {
0x0000, 0x0001, 0x0003, 0x0007,
0x000f, 0x001f, 0x003f, 0x007f,
0x00ff, 0x01ff, 0x03ff, 0x07ff,
0x0fff, 0x1fff, 0x3fff, 0x7fff,
};
byte[] buf = new byte[280];
/*
** Used in nextLWZ
*/
static final int MAX_LWZ_BITS = 12;
int[] stack;
int sp; // stack pointer
int code_size, set_code_size;
int max_code, max_code_size;
int clear_code, end_code;
int nextCode(byte[] im, int code_size) {
int i, j, ret, end;
if (return_clear) {
return_clear = false;
return clear_code;
}
end = curbit + code_size;
if (end >= lastbit) {
int count;
if (get_done) {
if (curbit >= lastbit)
System.out.println("ran off the end of my bits \r\n" );
return -1;
}
buf[0] = buf[last_byte-2];
buf[1] = buf[last_byte-1];
if ((count = GetDataBlock(im, buf, 2)) == 0)
get_done = true;
last_byte = 2 + count;
curbit = (curbit - lastbit) + 16;
lastbit = (2+count)*8 ;
end = curbit + code_size;
}
j = end / 8;
i = curbit / 8;
if (i == j)
ret = (buf[i]&0xff);
else if (i + 1 == j)
ret = (buf[i]&0xff) | (((buf[i+1]&0xff)) << 8);
else
ret = (buf[i]&0xff) | (((buf[i+1]&0xff)) << 8) | (((buf[i+2]&0xff)) << 16);
ret = (ret >> (curbit % 8)) & maskTbl[code_size];
curbit += code_size;
return ret;
}
int readLWZ(byte[] im) {
if (sp > 0)
return stack[--sp];
else
return nextLWZ(im);
}
int[][] table = new int[2][(1<< MAX_LWZ_BITS)];
int firstcode=0;
int oldcode=0;
int nextLWZ(byte[] im) {
int code, incode;
int i;
while ((code = nextCode(im, code_size)) >= 0) {
if (code == clear_code) {
/* corrupt GIFs can make this happen */
if (clear_code >= (1<<MAX_LWZ_BITS)) {
System.out.println("Gif Error: probable corrupt gif.");
return -2;
}
for (i = 0; i < clear_code; ++i) {
table[0][i] = 0;
table[1][i] = i;
}
for (; i < (1<<MAX_LWZ_BITS); ++i)
table[0][i] = table[1][i] = 0;
code_size = set_code_size+1;
max_code_size = 2*clear_code;
max_code = clear_code+2;
sp = 0;
do {
firstcode = oldcode = nextCode(im, code_size);
} while (firstcode == clear_code);
return firstcode;
}
if (code == end_code) {
int count;
byte[] buf = new byte[260];
if (ZeroDataBlock) {
System.out.println("Gif Error? ZeroDataBlock");
return -2;
}
while ((count = GetDataBlock(im, buf, 0)) > 0);
if (count != 0)
System.out.println("missing EOD in data stream (common occurence)");
System.out.println("GIF: code==end_code");
return -2;
}
incode = code;
if (code >= max_code) {
stack[sp++] = firstcode;
code = oldcode;
}
while (code >= clear_code) {
stack[sp++] = table[1][code];
if (code == table[0][code]) {
System.out.println("circular table entry BIG ERROR");
return(code);
}
code = table[0][code];
}
stack[sp++] = firstcode = table[1][code];
if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
table[0][code] = oldcode;
table[1][code] = firstcode;
++max_code;
if ((max_code >= max_code_size) && (max_code_size < (1<<MAX_LWZ_BITS))) {
max_code_size *= 2;
++code_size;
}
}
oldcode = incode;
if (sp > 0)
return stack[--sp];
}
return code;
}
boolean inited = false;
void initLWZ(int input_code_size) {
set_code_size = input_code_size;
code_size = set_code_size + 1;
clear_code = 1 << set_code_size ;
end_code = clear_code + 1;
max_code_size = 2 * clear_code;
max_code = clear_code + 2;
curbit = lastbit = 0;
last_byte = 2;
get_done = false;
return_clear = true;
stack = new int[(1<<MAX_LWZ_BITS)*2];
sp = 0;
}
void ReadPolymapData ( byte[] im, byte[] mdata, int nbytes, int bit_size )
{
int i, v, m=0;
initLWZ(bit_size);
for (i = 0; i < nbytes; i++) {
if ((v = readLWZ(im)) < 0) {
System.out.println("Skipping extra LWZ data");
break;
}
mdata[m++] = (byte)v;
}
}
boolean DoPolymap(byte[] im, int st) { // read polymap from byte array
int nbytes, bit_size;
int n = st+7;
byte[] b = new byte[4];
b[0] = im[n++];
b[1] = im[n++];
b[2] = im[n++];
b[3] = im[n++];
nbytes = (b[0]&0xff) | (b[1]&0xff)<<8 | (b[2]&0xff)<<16 | (b[3]&0xff)<<24;
bit_size = im[n++]&0xff;
byte[] mdata = new byte[nbytes];
nim = n; // the global im pointer; current reading position
ReadPolymapData( im, mdata, nbytes, bit_size );
b[0] = mdata[0];
b[1] = mdata[1];
int NumObjs = (b[0]&0xff) | (b[1]&0xff)<<8;
if (NumObjs <= 0) return false;
pm = new Polymap();
pm.pobj = new PolyObj[NumObjs];
pm.npobjs = NumObjs;
byte[] buf = new byte[100];
int len, nb;
nb = 2; // mdata[0] and mdata[1] used, see above
for (int i=0; i<NumObjs; i++) {
len = 0;
while ((char)mdata[nb] != '\0') {
buf[len++] = mdata[nb++];
}
nb++;
pm.pobj[i] = new PolyObj();
pm.pobj[i].url = new String(buf, 0, 0, len);
}
if (true) {
int uc_left = nbytes;
int nuc, i, value;
i = n = NONE;
nuc = nb; // nb bytes of mdata read as url's, see above
while (nuc < uc_left) {
b[0] = mdata[nuc]; b[1] = mdata[nuc+1];
value = (b[0]&0xff) | (b[1]&0xff)<<8;
if (value == 65535) {
nuc+=2;
b[0] = mdata[nuc++]; b[1] = mdata[nuc++];
i = b[0] | b[1]<<8;
b[0] = mdata[nuc++]; b[1] = mdata[nuc++];
n = (b[0]&0xff) | (b[1]&0xff)<<8;
if (n>0) {
Poly[] tmp = new Poly[pm.pobj[i].nps];
for (int j=0; j<pm.pobj[i].nps; j++)
tmp[j] = pm.pobj[i].p[j];
pm.pobj[i].p = new Poly[pm.pobj[i].nps+1];
for (int j=0; j<pm.pobj[i].nps; j++)
pm.pobj[i].p[j] = tmp[j];
pm.pobj[i].nps++;
}
else {
pm.pobj[i].nps = 1;
pm.pobj[i].p = new Poly[1];
}
pm.pobj[i].p[n] = new Poly();
pm.pobj[i].p[n].npts = 0;
}
else if (i >= 0 && n >= 0) {
if (nuc < uc_left) {
b[0] = mdata[nuc]; b[1] = mdata[nuc+1];
value = (b[0]&0xff) | (b[1]&0xff)<<8;
while (nuc < uc_left && value != 65535) {
nuc+=2;
if (pm.pobj[i].p[n].npts > 0) {
Point[] tmp = new Point[pm.pobj[i].p[n].npts];
for (int j=0; j<pm.pobj[i].p[n].npts; j++){
tmp[j] = pm.pobj[i].p[n].pt[j];
}
pm.pobj[i].p[n].pt = new Point[pm.pobj[i].p[n].npts+1];
for (int j=0; j<pm.pobj[i].p[n].npts; j++) {
pm.pobj[i].p[n].pt[j] = tmp[j];
}
pm.pobj[i].p[n].npts++;
}
else {
pm.pobj[i].p[n].npts = 1;
pm.pobj[i].p[n].pt = new Point[1];
}
pm.pobj[i].p[n].pt[pm.pobj[i].p[n].npts-1] = new Point();
pm.pobj[i].p[n].pt[pm.pobj[i].p[n].npts-1].x = value;
b[0] = mdata[nuc++]; b[1] = mdata[nuc++];
value = (b[0]&0xff) | (b[1]&0xff)<<8;
pm.pobj[i].p[n].pt[pm.pobj[i].p[n].npts-1].y = value;
if (nuc+1 >= uc_left) break; // about to access two more bytes
b[0] = mdata[nuc]; b[1] = mdata[nuc+1];
value = (b[0]&0xff) | (b[1]&0xff)<<8;
}
}
}
else {
System.out.println("Corrupted Polymap data");
return false;
}
}
}
return true;
}
public void paint(Graphics g) {
if (baseImage == null) {
return;
}
g.drawImage(baseImage, 0, 0, this);
}
public void update(Graphics g) {
if (current_poly!=NONE) {
Rectangle rect = current_polygon.getBoundingBox();
g.clipRect(rect.x, rect.y, rect.width+1, rect.height+1);
}
else {
int w = baseImage.getWidth(this);
int h = baseImage.getHeight(this);
g.clipRect(0, 0, w+1, h+1);
}
paint(g);
}
boolean just_entered = true;
public boolean mouseEnter(java.awt.Event evt, int x, int y) {
showStatus("Polymap Applet. Copyright © 1996 Cheong S Ang.");
just_entered = true;
return true;
}
/**
* Make sure that no ImageAreas are highlighted.
*/
public boolean mouseExit(java.awt.Event evt, int x, int y) {
if (current_obj!=NONE && current_poly!=NONE) {
repaint();
showStatus("Polymap Applet. Copyright © 1996 Cheong S Ang.");
}
return true;
}
public boolean mouseMove(java.awt.Event evt, int x, int y) {
try { // just to test for null pm
if (pm.npobjs <= 0) return true;
}
catch (Exception e) { // no polymap
showStatus("No Polymap data");
return true;
}
Graphics g = getGraphics();
g.setColor(highlight_color);
int max_j;
for (int i=pm.npobjs-1; i>=0; i--) {
max_j = pm.pobj[i].nps;
for (int j=0; j<max_j; j++) {
Polygon pol = pm.pobj[i].p[j].pol; // created earlier
if (pol.inside(x,y)) {
if (i==current_obj && j==current_poly) return true;
if ((i!=current_obj || j!=current_poly) &&
(current_obj!=NONE && current_poly!=NONE)) {
update(g);
}
current_obj = i;
current_poly = j;
current_polygon = pol;
Graphics g2 = getGraphics(); //get a new one. g has been clipRect in update(g)
g2.setColor(highlight_color);
g2.drawPolygon(pol);
showStatus(pm.pobj[current_obj].url);
return true;
}
}
}
if (current_obj!=NONE && current_poly!=NONE) {
repaint();
just_entered = false;
}
current_obj = NONE;
current_poly = NONE;
if (just_entered)
showStatus("Polymap Applet. Copyright © 1996 Cheong S Ang.");
else
showStatus("Ready");
return true;
}
public boolean mouseDown(java.awt.Event evt, int x, int y) {
mouseMove(evt, x, y); // let mouse move handle it
return true;
}
public boolean mouseUp(java.awt.Event evt, int x, int y) {
if (current_obj!=NONE && current_poly!=NONE) {
URL url;
try {
url = new URL(pm.pobj[current_obj].url);
}
catch (Exception e) {
e.printStackTrace();
return true;
}
super.getAppletContext().showDocument(url);
}
return true;
}
}
Back to the Polymap applet page.
New on the Java Boutique:
New Review:
Time Management Made Easy with the Quartz Enterprise Job Scheduler
Why not just use the Java timer API? This open source scheduling
API boasts simplicity, ease-of-integration, a well-rounded feature
set, and it's free!
New Applet:
Reverse Complement
Reverse Complement is a simple applet that converts DNA or RNA
sequences into three useful formats.
Elsewhere on internet.com:
WebDeveloper Java
Lots of Java information on webdeveloper.com
WDVL Java
Thorough Java resource at the Web Developer's Virtual Library.
ScriptSearch Java
Hundreds of free Java code files to download.
jGuru: Your View of the Java Universe
Customizable portal with online training, FAQs, regular news updates, and tutorials.
|