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.

How to Add Java Applets to Your Site

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.