/** ************************************************************* * * 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; }