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