package net.xoetrope.optional.laf.synth;
import java.awt.Color;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Hashtable;
import net.xoetrope.optional.filter.FilePreprocessor;
import net.xoetrope.xui.XProject;
import net.xoetrope.xui.XProjectManager;
import net.xoetrope.xui.style.XStyle;
import net.xoetrope.xui.style.XStyleManager;
/**
* Process a svg file to replace colors etc... with the styles
* <p>Copyright (c) Xoetrope Ltd., 2001-2005<br>
* License: see license.txt
* $Revision: 1.7 $
*/
public class SvgPreprocessor implements FilePreprocessor
{
private static Hashtable methodNames = new Hashtable();
private XProject currentProject;
/** Creates a new instance of SvgPreprocessor */
protected SvgPreprocessor()
{
currentProject = XProjectManager.getCurrentProject();
/**
* @todo Use constants for the IDs
*/
methodNames.put( "getColorForegroundRgb", new Integer( 0 ) );
methodNames.put( "getColorForegroundHex", new Integer( 1 ) );
methodNames.put( "getColorBackgroundRgb", new Integer( 2 ) );
methodNames.put( "getColorBackgroundHex", new Integer( 3 ) );
methodNames.put( "getHsbColorForegroundRgb", new Integer( 4 ) );
methodNames.put( "getHsbColorForegroundHex", new Integer( 5 ) );
methodNames.put( "getHsbColorBackgroundHex", new Integer( 6 ) );
methodNames.put( "getHsbColorBackgroundHex", new Integer( 7 ) );
}
/**
* Read the file from the input stream, do any substitutions required and
* return the processed file as a string.
* @param is the input stream
* @throws java.io.IOException problems processing the input stream
* @return the processed file contents
*/
public String process( BufferedInputStream is ) throws IOException
{
byte[] b = new byte[ 1000 ];
if ( is != null ) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int i = is.read( b );
while ( i != -1 ) {
baos.write( b, 0, i );
b = new byte[ 1000 ];
i = is.read( b );
}
return findAndReplace( methodNames, baos.toString() );
}
return null;
}
/**
* Search and replace a function references embedded in the synth file
* @param methodNames the table of methods to find and replace
* @param originalText the original config file text
* @return the processed text
*/
protected String findAndReplace( Hashtable methodNames, String originalText )
{
/**
* @todo Use something like a StringTokenizer to split the string and allow for recursion
*/
String resultString = "";
int startPos = 0;
int espressionStart = 0;
int argsStart = 0;
int argsEnd = 0;
while ( ( espressionStart = originalText.indexOf( "${", startPos ) ) > 0 ) {
argsStart = originalText.indexOf( "(", espressionStart );
String key = originalText.substring( espressionStart + 2, argsStart );
argsEnd = originalText.indexOf( ")}", argsStart );
if ( argsEnd > 0 ) {
resultString += originalText.substring( startPos, espressionStart );
startPos = argsEnd + 2;
String result = "";
String args = originalText.substring( argsStart + 1, argsEnd );
args = findAndReplace( methodNames, args );
switch ( ( ( Integer ) methodNames.get( key ) ).intValue() ) {
case 0:
result = getColorStyleAttribute( args, XStyle.COLOR_FORE, true, false );
break;
case 1:
result = getColorStyleAttribute( args, XStyle.COLOR_FORE, false, false );
break;
case 2:
result = getColorStyleAttribute( args, XStyle.COLOR_BACK, true, false );
break;
case 3:
result = getColorStyleAttribute( args, XStyle.COLOR_BACK, false, false );
break;
case 4:
result = getColorStyleAttribute( args, XStyle.COLOR_FORE, true, true );
break;
case 5:
result = getColorStyleAttribute( args, XStyle.COLOR_FORE, false, true );
break;
case 6:
result = getColorStyleAttribute( args, XStyle.COLOR_BACK, true, true );
break;
case 7:
result = getColorStyleAttribute( args, XStyle.COLOR_BACK, false, true );
break;
}
resultString += result;
}
}
if ( argsEnd == 0 )
return originalText;
if ( argsEnd < originalText.length() )
resultString += originalText.substring( argsEnd + 2 );
return resultString;
}
/**
* Replace the tagged field. Replace ${tag(args)} with #F0E000
* or whatever the hex color value is. Alternatively ${getColorForegroundHex(name,percentRed,percentGreen,PercentBlue)}
* where the percent fields indicate the variation of each color channel. A value of 100 results in no change
* a value less than 100 (%) results in a linear scaling of the color value to 00. A value between 100
* and 200 scales the value to FF or 255 for an RGB color.<br>The getColorForegroundHex tag may be replaced
* by getColorForegroundRgb for RGB output in the form rgb(r,g,b). Finally ${getHsbColorForegroundHex(name,hRed,stGreen,bBlue)}
* works in a similar fashion with the HSB values being scaled in the same manner. Variations for forground/background
* and Hex/RGB output are also supported.
* @param isHSB is a HSB color space used instead of RGB
* @param args the text to locate e.g. ${getColorForegroundHex(name)}
* @param attrib the attribute to lookup in the style
* @param isRgb true to output an RGB color, or false for Hex
* @return the attribute as a string
*/
protected String getColorStyleAttribute( String args, int attrib, boolean isRgb, boolean isHSB )
{
XStyleManager sm = currentProject.getStyleManager();
int rScale = 100;
int gScale = 100;
int bScale = 100;
int pos;
if ( ( pos = args.indexOf( ',' ) ) > 0 ) {
int pos2 = args.indexOf( ',', pos + 1 );
int pos3 = args.indexOf( ',', pos2 + 1 );
rScale = Integer.parseInt( args.substring( pos + 1, pos2 ) );
gScale = Integer.parseInt( args.substring( pos2 + 1, pos3 ) );
bScale = Integer.parseInt( args.substring( pos3 + 1 ) );
args = args.substring( 0, pos );
}
Color attribValue = sm.getStyle( args.trim() ).getStyleAsColor( attrib );
int r = attribValue.getRed();
int g = attribValue.getGreen();
int b = attribValue.getBlue();
if ( !isHSB ) {
if ( rScale < 100 )
r = ( rScale * r ) / 100;
else if ( rScale > 100 )
r = r + ( ( 255 - r ) * ( Math.max( rScale, 200 ) - 100 ) ) / 100;
if ( gScale < 100 )
g = ( gScale * g ) / 100;
else if ( gScale > 100 )
g = g + ( ( 255 - g ) * ( Math.max( gScale, 200 ) - 100 ) ) / 100;
if ( bScale < 100 )
b = ( bScale * b ) / 100;
else if ( bScale > 100 )
b = b + ( ( 255 - b ) * ( Math.max( bScale, 200 ) - 100 ) ) / 100;
}
else {
float[] hsbVals = Color.RGBtoHSB( r, g, b, null );
if ( rScale < 100.0f )
hsbVals[ 0 ] = ( ( float ) rScale * hsbVals[ 0 ] ) / 100.0f;
else if ( rScale > 100.0f )
hsbVals[ 0 ] = hsbVals[ 0 ] + ( ( 255.0f - hsbVals[ 0 ] ) * ( Math.max( ( float ) rScale, 200.0f ) - 100.0f ) ) / 100.0f;
if ( gScale < 100.0f )
hsbVals[ 1 ] = ( ( float ) gScale * hsbVals[ 1 ] ) / 100.0f;
else if ( gScale > 100.0f )
hsbVals[ 1 ] = hsbVals[ 1 ] + ( ( 255.0f - hsbVals[ 1 ] ) * ( Math.max( ( float ) gScale, 200.0f ) - 100.0f ) ) / 100.0f;
if ( bScale < 100.0f )
hsbVals[ 2 ] = ( ( float ) bScale * hsbVals[ 2 ] ) / 100.0f;
else if ( bScale > 100.0f )
hsbVals[ 2 ] = hsbVals[ 2 ] + ( ( 255.0f - hsbVals[ 2 ] ) * ( Math.max( ( float ) bScale, 200.0f ) - 100.0f ) ) / 100.0f;
Color c = Color.getHSBColor( hsbVals[ 0 ], hsbVals[ 1 ], hsbVals[ 2 ] );
r = c.getRed();
g = c.getGreen();
b = c.getBlue();
}
String val = "";
if ( isRgb ) {
val = "rgb(" + r + "," + g + "," + b + ")";
}
else {
if ( r < 11 )
val = "0";
val += Integer.toHexString( r );
if ( g < 11 )
val += "0";
val += Integer.toHexString( g );
if ( b < 11 )
val += "0";
val += Integer.toHexString( b );
}
return val;
}
}