CIUGraphicsContext class construction, resize, drawing, and GIF output
    /** *************************************************************
     *
     * Construct a CIUgraphicsContext of the necessary size.
     *
     * @param w The width of the image
     * @param h The height of the image
     * @param bgColor The background color of the image as a LUT index
     * @param cc The color LUT
     *
     */
    public CIUGraphicsContext( int w, int h, byte bgColor, CIUNetscapeColorCube cc )
    {
        if ( null == cc )
          System.err.println("CIUGraphicsContext> Constructing with null color cube");

        this.m_data = new CIUByteArray( w, h );
	this.m_bgColor = bgColor;
	this.m_data.fill( this.m_bgColor );
    	
        this.m_vChildren = new Vector();
    	this.m_lut = cc;

	return;
    }



    /** *************************************************************
     * 
     * Resize the graphics context.
     *
     * @param newW The new width
     * @param newH The new height
     *
     * @returns int indicating if any children were clipped
     * upon being redrawn on the new context
     * (NoClip, VClip, HClip, HVClip)
     *
     */
    public int resize( int newW, int newH )
    {
        CIUPrimitive child = null;
	int vertClip = NoClip;
	int horzClip = NoClip;
	
        // Resize the byte array
	m_data = null;
	m_data = new CIUByteArray( newW, newH );     
        this.m_data.fill( this.m_bgColor );


        // Redraw the children
        try
        {

          for (Enumeration e = m_vChildren.elements() ; e.hasMoreElements() ;)
          {
	        child = (CIUPrimitive)(e.nextElement());
                int clip = this.drawChild( child, true );

                if ( HClip==clip ) horzClip=HClip;
		if ( VClip==clip ) vertClip=VClip;
                if ( HVClip==clip ) 
                  { horzClip=HClip; vertClip=VClip; }
          }

       }
       catch( Exception e )
       {
           System.err.println("CIUGraphicsContext::resize> Exception: " + e );
       }


       return (horzClip+vertClip);
    }


    /** *************************************************************
     *
     * Draw a child on the graphics context.
     *
     * @param The child to draw
     * @param resize A boolean indicating if we're resizing or not
     *
     * @returns int indicating if any children were clipped
     * upon being redrawn on the new context
     * (NoClip, VClip, HClip, HVClip)
     *
     */
    public int drawChild( CIUPrimitive child, boolean resize )
    {
       int cW, cH;                   // Child width, height
       int cX, cY;                   // Child x-translation, y-translation
       int tW, tH;                   // this width, height
       int sX, eX;                   // start x-position, y-position
       int sY, eY;                   // end x-position, y-position
       int bOffset;                  // The pixel offset into the byte array
       int horzClip = NoClip;        // Horizontal child clip
       int vertClip = NoClip;        // Vertical child clip
       byte childColor = 0;          // The child's color
       boolean bIsTextured = false;  // Is the child solid or textured?


       if ( null == child ) 
       {       
          System.err.println("CIUGraphicsContext::drawChild> null child. nothing to do.");
	  return NoClip;
       }


       // Keep a reference to the child around for future
       // resizing
       if ( false == resize )
         this.m_vChildren.addElement( child );


       tW = this.m_data.m_w;
       tH = this.m_data.m_h;


       // Try to draw the child into the gc byte array
       try
       {
            //
	    // Find child's color.
	    bIsTextured = child.textured();
            if ( false == bIsTextured )
	        childColor = child.color(0,0);

	    //
            // Get the childs dimensions
            cW = child.width();
            cH = child.height();
            cX = child.transX();
            cY = child.transY();

            //
            // Clip the child if necessary...
            sX = 0;    eX = cW;
            sY = 0;    eY = cH;

            if ( cX < 0 )     { sX = (-cX);  horzClip=NoClip; }
            if ( cY < 0 )     { sY = (-cY);  vertClip=NoClip; }
            if ( (cX+cW)>tW ) { eX=tW-cX;    horzClip=HClip;  }
            if ( (cY+cH)>tH ) { eY=tH-cY;    vertClip=VClip;  }


            //
            // the starting point in gc byte array (translation of child)
            if ( cX<0 && cY<0 ) bOffset = 0;
            else if ( cX<0 && cY>0 ) bOffset = (tW*cY);
            else if ( cX>0 && cY<0 ) bOffset = cX;
            else                     bOffset = (tW*cY) + cX;


            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // Add the child color to the context....solid color.
            if ( !bIsTextured )
            {
                 for ( int j=0; j<(eY-sY); j++, bOffset+=tW )
                    for ( int i=0; i<(eX-sX); i++ )
                      if ( child.pixelOn( i+sX, j+sY ) )
                        this.m_data.m_bytes[ bOffset + i ] = childColor;
            }

            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // Add the child color to the context....textured color.
            else
            {
                 for ( int j=0; j<(eY-sY); j++, bOffset+=tW )
                    for ( int i=0; i<(eX-sX); i++ )
                      if ( child.pixelOn( i+sX, j+sY ) )
                      {
                        childColor = child.color( i+sX, j+sY );
                        this.m_data.m_bytes[ bOffset + i ] = childColor;
                      }
            }

       }
       catch( ArrayIndexOutOfBoundsException ae )
       {
           System.err.println("CIUGraphicsContext::draw> Array index out of bounds: " + ae );
           System.err.println("CIUGraphicsContext::draw> Skipping this child..." );
       }
       catch ( Exception ex )
       {
           System.err.println("CIUGraphicsContext::draw> Exception: " + ex );
           System.err.println("CIUGraphicsContext::draw> Skipping this child..." );
       }


        return (vertClip+horzClip);
    }




    /** *************************************************************
     *
     * Write out the file in GIF format.  All IUColors will need
     * to be mapped to LUT indexes here.  They don't map until
     * render time so you can change the LUT at any point.
     *
     * @param os The output stream to write to
     * @param baos The byte array output stream to use for LZW compression
     *
     */
    public boolean writeGIF87a( OutputStream os, ByteArrayOutputStream baos )
    {
        //
        // Calculate the required size of the byte stream.
        //
        // "GIF87a + sd + LUT + id + LZW(m_bytes) + id"
        //

    	short _SW = (short)this.m_data.m_w;  // 2 bytes
        short _SH = (short)this.m_data.m_h;  // 2 bytes

        byte bw0 = (byte)( _SW & 0xFF );    byte bw1 = (byte)( (_SW>>8) & 0xFF );
        byte bh0 = (byte)( _SH & 0xFF );    byte bh1 = (byte)( (_SH>>8) & 0xFF );

        byte header[] =  { (byte)'G', (byte)'I', (byte)'F', (byte)'8', (byte)'7', (byte)'a' };
        byte image1[] =  { (byte)44, 0, 0, 0, 0, bw0, bw1, bh0, bh1, 0 };
        byte image2[] =  { (byte)59, 0, 0, 0, 0, 0, 0, 0, 0, 0 };


        if ( null == os ) 
          System.err.println("CIUGraphicsContext::writeGIF87a> null OutputStream");
        if ( null == baos ) 
          System.err.println("CIUGraphicsContext::writeGIF87a> null ByteArrayOutputStream");



        try {

	    // Clear buffer total accumulated bytes
	    baos.reset();

            // Write GIF header
            baos.write( header );

            // Write screen parameters.
	    CIUScreenDescriptor gsd = new CIUScreenDescriptor( 
		(short)m_data.m_w, (short)m_data.m_h, m_lut.numColors(), m_bgColor 
	    );

            baos.write( gsd.info() );

            // Write the LUT
            baos.write( m_lut.colors(), 0, m_lut.colorLen() );

            // Write the leading image descriptor
            baos.write( image1 );

            // For LZW index,  need bits/pixel
            baos.write( m_lut.bitsPerIndex() );

            // Compress the image.
            LZWCompressor.LZWCompress( baos, m_lut.bitsPerIndex(), m_data.m_bytes );

            // Null terminator for LZW
            baos.write(0);

    	    // Write out trailing image descriptor
            baos.write( image2 );

            baos.flush();
            byte[] data = baos.toByteArray();

	    DataOutputStream dos = new DataOutputStream( os );
            dos.write(data);
	    dos.close();
	    dos = null;

	    baos.reset();
        }
        catch ( IOException ioe )
        {
            System.err.println("CIUGraphicsContext::writeGIF> IOException: " + ioe );
            return false;
        }

        return true;
    }