removed unused classes
This commit is contained in:
parent
8731eaffc7
commit
c8a85d5a04
45 changed files with 0 additions and 8999 deletions
|
@ -1,613 +0,0 @@
|
|||
// Fmt - some simple single-arg sprintf-like routines
|
||||
//
|
||||
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme;
|
||||
|
||||
/// Some simple single-arg sprintf-like routines.
|
||||
// <P>
|
||||
// It is apparently impossible to declare a Java method that accepts
|
||||
// variable numbers of any type of argument. You can declare it to take
|
||||
// Objects, but numeric variables and constants are not in fact Objects.
|
||||
// <P>
|
||||
// However, using the built-in string concatenation, it's almost as
|
||||
// convenient to make a series of single-argument formatting routines.
|
||||
// <P>
|
||||
// Fmt can format the following types:
|
||||
// <BLOCKQUOTE><CODE>
|
||||
// byte short int long float double char String Object
|
||||
// </CODE></BLOCKQUOTE>
|
||||
// For each type there is a set of overloaded methods, each returning
|
||||
// a formatted String. There's the plain formatting version:
|
||||
// <BLOCKQUOTE><PRE>
|
||||
// Fmt.fmt( x )
|
||||
// </PRE></BLOCKQUOTE>
|
||||
// There's a version specifying a minimum field width:
|
||||
// <BLOCKQUOTE><PRE>
|
||||
// Fmt.fmt( x, minWidth )
|
||||
// </PRE></BLOCKQUOTE>
|
||||
// And there's a version that takes flags:
|
||||
// <BLOCKQUOTE><PRE>
|
||||
// Fmt.fmt( x, minWidth, flags )
|
||||
// </PRE></BLOCKQUOTE>
|
||||
// Currently available flags are:
|
||||
// <BLOCKQUOTE><PRE>
|
||||
// Fmt.ZF - zero-fill
|
||||
// Fmt.LJ - left justify
|
||||
// Fmt.HX - hexadecimal
|
||||
// Fmt.OC - octal
|
||||
// </PRE></BLOCKQUOTE>
|
||||
// The HX and OC flags imply unsigned output.
|
||||
// <P>
|
||||
// For doubles and floats, there's a significant-figures parameter before
|
||||
// the flags:
|
||||
// <BLOCKQUOTE><PRE>
|
||||
// Fmt.fmt( d )
|
||||
// Fmt.fmt( d, minWidth )
|
||||
// Fmt.fmt( d, minWidth, sigFigs )
|
||||
// Fmt.fmt( d, minWidth, sigFigs, flags )
|
||||
// </PRE></BLOCKQUOTE>
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/Fmt.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
// <HR>
|
||||
// Similar classes:
|
||||
// <UL>
|
||||
// <LI> Andrew Scherpbier's <A HREF="http://www.sdsu.edu/doc/java-SDSU/sdsu.FormatString.html">FormatString</A>
|
||||
// Tries to allow variable numbers of arguments by
|
||||
// supplying overloaded routines with different combinations of parameters,
|
||||
// but doesn't actually supply that many. The floating point conversion
|
||||
// is described as "very incomplete".
|
||||
// <LI> Core Java's <A HREF="http://www.apl.jhu.edu/~hall/java/CoreJava-Format.html">Format</A>.
|
||||
// The design seems a little weird. They want you to create an instance,
|
||||
// passing the format string to the constructor, and then call an instance
|
||||
// method with your data to do the actual formatting. The extra steps are
|
||||
// pointless; better to just use static methods.
|
||||
// </UL>
|
||||
|
||||
public class Fmt
|
||||
{
|
||||
|
||||
// Flags.
|
||||
/// Zero-fill.
|
||||
public static final int ZF = 1;
|
||||
/// Left justify.
|
||||
public static final int LJ = 2;
|
||||
/// Hexadecimal.
|
||||
public static final int HX = 4;
|
||||
/// Octal.
|
||||
public static final int OC = 8;
|
||||
// Was a number - internal use.
|
||||
private static final int WN = 16;
|
||||
|
||||
// byte
|
||||
public static String fmt( byte b )
|
||||
{
|
||||
return fmt( b, 0, 0 );
|
||||
}
|
||||
public static String fmt( byte b, int minWidth )
|
||||
{
|
||||
return fmt( b, minWidth, 0 );
|
||||
}
|
||||
public static String fmt( byte b, int minWidth, int flags )
|
||||
{
|
||||
boolean hexadecimal = ( ( flags & HX ) != 0 );
|
||||
boolean octal = ( ( flags & OC ) != 0 );
|
||||
if ( hexadecimal )
|
||||
return fmt( Integer.toString( b & 0xff, 16 ), minWidth, flags|WN );
|
||||
else if ( octal )
|
||||
return fmt( Integer.toString( b & 0xff, 8 ), minWidth, flags|WN );
|
||||
else
|
||||
return fmt( Integer.toString( b & 0xff ), minWidth, flags|WN );
|
||||
}
|
||||
|
||||
// short
|
||||
public static String fmt( short s )
|
||||
{
|
||||
return fmt( s, 0, 0 );
|
||||
}
|
||||
public static String fmt( short s, int minWidth )
|
||||
{
|
||||
return fmt( s, minWidth, 0 );
|
||||
}
|
||||
public static String fmt( short s, int minWidth, int flags )
|
||||
{
|
||||
boolean hexadecimal = ( ( flags & HX ) != 0 );
|
||||
boolean octal = ( ( flags & OC ) != 0 );
|
||||
if ( hexadecimal )
|
||||
return fmt(
|
||||
Integer.toString( s & 0xffff, 16 ), minWidth, flags|WN );
|
||||
else if ( octal )
|
||||
return fmt(
|
||||
Integer.toString( s & 0xffff, 8 ), minWidth, flags|WN );
|
||||
else
|
||||
return fmt( Integer.toString( s ), minWidth, flags|WN );
|
||||
}
|
||||
|
||||
// int
|
||||
public static String fmt( int i )
|
||||
{
|
||||
return fmt( i, 0, 0 );
|
||||
}
|
||||
public static String fmt( int i, int minWidth )
|
||||
{
|
||||
return fmt( i, minWidth, 0 );
|
||||
}
|
||||
public static String fmt( int i, int minWidth, int flags )
|
||||
{
|
||||
boolean hexadecimal = ( ( flags & HX ) != 0 );
|
||||
boolean octal = ( ( flags & OC ) != 0 );
|
||||
if ( hexadecimal )
|
||||
return fmt(
|
||||
Long.toString( i & 0xffffffffL, 16 ), minWidth, flags|WN );
|
||||
else if ( octal )
|
||||
return fmt(
|
||||
Long.toString( i & 0xffffffffL, 8 ), minWidth, flags|WN );
|
||||
else
|
||||
return fmt( Integer.toString( i ), minWidth, flags|WN );
|
||||
}
|
||||
|
||||
// long
|
||||
public static String fmt( long l )
|
||||
{
|
||||
return fmt( l, 0, 0 );
|
||||
}
|
||||
public static String fmt( long l, int minWidth )
|
||||
{
|
||||
return fmt( l, minWidth, 0 );
|
||||
}
|
||||
public static String fmt( long l, int minWidth, int flags )
|
||||
{
|
||||
boolean hexadecimal = ( ( flags & HX ) != 0 );
|
||||
boolean octal = ( ( flags & OC ) != 0 );
|
||||
if ( hexadecimal )
|
||||
{
|
||||
if ( ( l & 0xf000000000000000L ) != 0 )
|
||||
return fmt(
|
||||
Long.toString( l >>> 60, 16 ) +
|
||||
fmt( l & 0x0fffffffffffffffL, 15, HX|ZF ),
|
||||
minWidth, flags|WN );
|
||||
else
|
||||
return fmt( Long.toString( l, 16 ), minWidth, flags|WN );
|
||||
}
|
||||
else if ( octal )
|
||||
{
|
||||
if ( ( l & 0x8000000000000000L ) != 0 )
|
||||
return fmt(
|
||||
Long.toString( l >>> 63, 8 ) +
|
||||
fmt( l & 0x7fffffffffffffffL, 21, OC|ZF ),
|
||||
minWidth, flags|WN );
|
||||
else
|
||||
return fmt( Long.toString( l, 8 ), minWidth, flags|WN );
|
||||
}
|
||||
else
|
||||
return fmt( Long.toString( l ), minWidth, flags|WN );
|
||||
}
|
||||
|
||||
// float
|
||||
public static String fmt( float f )
|
||||
{
|
||||
return fmt( f, 0, 0, 0 );
|
||||
}
|
||||
public static String fmt( float f, int minWidth )
|
||||
{
|
||||
return fmt( f, minWidth, 0, 0 );
|
||||
}
|
||||
public static String fmt( float f, int minWidth, int sigFigs )
|
||||
{
|
||||
return fmt( f, minWidth, sigFigs, 0 );
|
||||
}
|
||||
public static String fmt( float f, int minWidth, int sigFigs, int flags )
|
||||
{
|
||||
if ( sigFigs != 0 )
|
||||
return fmt(
|
||||
sigFigFix( Float.toString( f ), sigFigs ), minWidth,
|
||||
flags|WN );
|
||||
else
|
||||
return fmt( Float.toString( f ), minWidth, flags|WN );
|
||||
}
|
||||
|
||||
// double
|
||||
public static String fmt( double d )
|
||||
{
|
||||
return fmt( d, 0, 0, 0 );
|
||||
}
|
||||
public static String fmt( double d, int minWidth )
|
||||
{
|
||||
return fmt( d, minWidth, 0, 0 );
|
||||
}
|
||||
public static String fmt( double d, int minWidth, int sigFigs )
|
||||
{
|
||||
return fmt( d, minWidth, sigFigs, 0 );
|
||||
}
|
||||
public static String fmt( double d, int minWidth, int sigFigs, int flags )
|
||||
{
|
||||
if ( sigFigs != 0 )
|
||||
return fmt(
|
||||
sigFigFix( doubleToString( d ), sigFigs ), minWidth,
|
||||
flags|WN );
|
||||
else
|
||||
return fmt( doubleToString( d ), minWidth, flags|WN );
|
||||
}
|
||||
|
||||
// char
|
||||
public static String fmt( char c )
|
||||
{
|
||||
return fmt( c, 0, 0 );
|
||||
}
|
||||
public static String fmt( char c, int minWidth )
|
||||
{
|
||||
return fmt( c, minWidth, 0 );
|
||||
}
|
||||
public static String fmt( char c, int minWidth, int flags )
|
||||
{
|
||||
// return fmt( Character.toString( c ), minWidth, flags );
|
||||
// Character currently lacks a static toString method. Workaround
|
||||
// is to make a temporary instance and use the instance toString.
|
||||
return fmt( new Character( c ).toString(), minWidth, flags );
|
||||
}
|
||||
|
||||
// Object
|
||||
public static String fmt( Object o )
|
||||
{
|
||||
return fmt( o, 0, 0 );
|
||||
}
|
||||
public static String fmt( Object o, int minWidth )
|
||||
{
|
||||
return fmt( o, minWidth, 0 );
|
||||
}
|
||||
public static String fmt( Object o, int minWidth, int flags )
|
||||
{
|
||||
return fmt( o.toString(), minWidth, flags );
|
||||
}
|
||||
|
||||
// String
|
||||
public static String fmt( String s )
|
||||
{
|
||||
return fmt( s, 0, 0 );
|
||||
}
|
||||
public static String fmt( String s, int minWidth )
|
||||
{
|
||||
return fmt( s, minWidth, 0 );
|
||||
}
|
||||
public static String fmt( String s, int minWidth, int flags )
|
||||
{
|
||||
int len = s.length();
|
||||
boolean zeroFill = ( ( flags & ZF ) != 0 );
|
||||
boolean leftJustify = ( ( flags & LJ ) != 0 );
|
||||
boolean hexadecimal = ( ( flags & HX ) != 0 );
|
||||
boolean octal = ( ( flags & OC ) != 0 );
|
||||
boolean wasNumber = ( ( flags & WN ) != 0 );
|
||||
if ( ( hexadecimal || octal || zeroFill ) && ! wasNumber )
|
||||
throw new InternalError( "Acme.Fmt: number flag on a non-number" );
|
||||
if ( zeroFill && leftJustify )
|
||||
throw new InternalError( "Acme.Fmt: zero-fill left-justify is silly" );
|
||||
if ( hexadecimal && octal )
|
||||
throw new InternalError( "Acme.Fmt: can't do both hex and octal" );
|
||||
if ( len >= minWidth )
|
||||
return s;
|
||||
int fillWidth = minWidth - len;
|
||||
StringBuffer fill = new StringBuffer( fillWidth );
|
||||
for ( int i = 0; i < fillWidth; ++i )
|
||||
if ( zeroFill )
|
||||
fill.append( '0' );
|
||||
else
|
||||
fill.append( ' ' );
|
||||
if ( leftJustify )
|
||||
return s + fill;
|
||||
else if ( zeroFill && s.startsWith( "-" ) )
|
||||
return "-" + fill + s.substring( 1 );
|
||||
else
|
||||
return fill + s;
|
||||
}
|
||||
|
||||
|
||||
// Internal routines.
|
||||
|
||||
private static String sigFigFix( String s, int sigFigs )
|
||||
{
|
||||
// First dissect the floating-point number string into sign,
|
||||
// integer part, fraction part, and exponent.
|
||||
String sign;
|
||||
String unsigned;
|
||||
if ( s.startsWith( "-" ) || s.startsWith( "+" ) )
|
||||
{
|
||||
sign = s.substring( 0, 1 );
|
||||
unsigned = s.substring( 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
sign = "";
|
||||
unsigned = s;
|
||||
}
|
||||
String mantissa;
|
||||
String exponent;
|
||||
int eInd = unsigned.indexOf( 'e' );
|
||||
if ( eInd == -1 ) // it may be 'e' or 'E'
|
||||
eInd = unsigned.indexOf( 'E' );
|
||||
if ( eInd == -1 )
|
||||
{
|
||||
mantissa = unsigned;
|
||||
exponent = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
mantissa = unsigned.substring( 0, eInd );
|
||||
exponent = unsigned.substring( eInd );
|
||||
}
|
||||
StringBuffer number, fraction;
|
||||
int dotInd = mantissa.indexOf( '.' );
|
||||
if ( dotInd == -1 )
|
||||
{
|
||||
number = new StringBuffer( mantissa );
|
||||
fraction = new StringBuffer( "" );
|
||||
}
|
||||
else
|
||||
{
|
||||
number = new StringBuffer( mantissa.substring( 0, dotInd ) );
|
||||
fraction = new StringBuffer( mantissa.substring( dotInd + 1 ) );
|
||||
}
|
||||
|
||||
int numFigs = number.length();
|
||||
int fracFigs = fraction.length();
|
||||
if ( ( numFigs == 0 || number.equals( "0" ) ) && fracFigs > 0 )
|
||||
{
|
||||
// Don't count leading zeros in the fraction.
|
||||
numFigs = 0;
|
||||
for ( int i = 0; i < fraction.length(); ++i )
|
||||
{
|
||||
if ( fraction.charAt( i ) != '0' )
|
||||
break;
|
||||
--fracFigs;
|
||||
}
|
||||
}
|
||||
int mantFigs = numFigs + fracFigs;
|
||||
if ( sigFigs > mantFigs )
|
||||
{
|
||||
// We want more figures; just append zeros to the fraction.
|
||||
for ( int i = mantFigs; i < sigFigs; ++i )
|
||||
fraction.append( '0' );
|
||||
}
|
||||
else if ( sigFigs < mantFigs && sigFigs >= numFigs )
|
||||
{
|
||||
// Want fewer figures in the fraction; chop.
|
||||
fraction.setLength(
|
||||
fraction.length() - ( fracFigs - ( sigFigs - numFigs ) ) );
|
||||
// Round?
|
||||
}
|
||||
else if ( sigFigs < numFigs )
|
||||
{
|
||||
// Want fewer figures in the number; turn them to zeros.
|
||||
fraction.setLength( 0 ); // should already be zero, but make sure
|
||||
for ( int i = sigFigs; i < numFigs; ++i )
|
||||
number.setCharAt( i, '0' );
|
||||
// Round?
|
||||
}
|
||||
// Else sigFigs == mantFigs, which is fine.
|
||||
|
||||
if ( fraction.length() == 0 )
|
||||
return sign + number + exponent;
|
||||
else
|
||||
return sign + number + "." + fraction + exponent;
|
||||
}
|
||||
|
||||
|
||||
/// Improved version of Double.toString(), returns more decimal places.
|
||||
// <P>
|
||||
// The JDK 1.0.2 version of Double.toString() returns only six decimal
|
||||
// places on some systems. In JDK 1.1 full precision is returned on
|
||||
// all platforms.
|
||||
// @deprecated
|
||||
// @see java.lang.Double#toString
|
||||
public static String doubleToString( double d )
|
||||
{
|
||||
// Handle special numbers first, to avoid complications.
|
||||
if ( Double.isNaN( d ) )
|
||||
return "NaN";
|
||||
if ( d == Double.NEGATIVE_INFINITY )
|
||||
return "-Inf";
|
||||
if ( d == Double.POSITIVE_INFINITY )
|
||||
return "Inf";
|
||||
|
||||
// Grab the sign, and then make the number positive for simplicity.
|
||||
boolean negative = false;
|
||||
if ( d < 0.0D )
|
||||
{
|
||||
negative = true;
|
||||
d = -d;
|
||||
}
|
||||
|
||||
// Get the native version of the unsigned value, as a template.
|
||||
String unsStr = Double.toString( d );
|
||||
|
||||
// Dissect out the exponent.
|
||||
String mantStr, expStr;
|
||||
int exp;
|
||||
int eInd = unsStr.indexOf( 'e' );
|
||||
if ( eInd == -1 ) // it may be 'e' or 'E'
|
||||
eInd = unsStr.indexOf( 'E' );
|
||||
if ( eInd == -1 )
|
||||
{
|
||||
mantStr = unsStr;
|
||||
expStr = "";
|
||||
exp = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mantStr = unsStr.substring( 0, eInd );
|
||||
expStr = unsStr.substring( eInd + 1 );
|
||||
if ( expStr.startsWith( "+" ) )
|
||||
exp = Integer.parseInt( expStr.substring( 1 ) );
|
||||
else
|
||||
exp = Integer.parseInt( expStr );
|
||||
}
|
||||
|
||||
// Dissect out the number part.
|
||||
String numStr;
|
||||
int dotInd = mantStr.indexOf( '.' );
|
||||
if ( dotInd == -1 )
|
||||
numStr = mantStr;
|
||||
else
|
||||
numStr = mantStr.substring( 0, dotInd );
|
||||
long num;
|
||||
if ( numStr.length() == 0 )
|
||||
num = 0;
|
||||
else
|
||||
num = Integer.parseInt( numStr );
|
||||
|
||||
// Build the new mantissa.
|
||||
StringBuffer newMantBuf = new StringBuffer( numStr + "." );
|
||||
double p = Math.pow( 10, exp );
|
||||
double frac = d - num * p;
|
||||
String digits = "0123456789";
|
||||
int nDigits = 16 - numStr.length(); // about 16 digits in a double
|
||||
for ( int i = 0; i < nDigits; ++i )
|
||||
{
|
||||
p /= 10.0D;
|
||||
int dig = (int) ( frac / p );
|
||||
if ( dig < 0 ) dig = 0;
|
||||
if ( dig > 9 ) dig = 9;
|
||||
newMantBuf.append( digits.charAt( dig ) );
|
||||
frac -= dig * p;
|
||||
}
|
||||
|
||||
if ( (int) ( frac / p + 0.5D ) == 1 )
|
||||
{
|
||||
// Round up.
|
||||
boolean roundMore = true;
|
||||
for ( int i = newMantBuf.length() - 1; i >= 0; --i )
|
||||
{
|
||||
int dig = digits.indexOf( newMantBuf.charAt( i ) );
|
||||
if ( dig == -1 )
|
||||
continue;
|
||||
++dig;
|
||||
if ( dig == 10 )
|
||||
{
|
||||
newMantBuf.setCharAt( i, '0' );
|
||||
continue;
|
||||
}
|
||||
newMantBuf.setCharAt( i, digits.charAt( dig ) );
|
||||
roundMore = false;
|
||||
break;
|
||||
}
|
||||
if ( roundMore )
|
||||
{
|
||||
// If this happens, we need to prepend a 1. But I haven't
|
||||
// found a test case yet, so I'm leaving it out for now.
|
||||
// But if you get this message, please let me know!
|
||||
newMantBuf.append( "ROUNDMORE" );
|
||||
}
|
||||
}
|
||||
|
||||
// Chop any trailing zeros.
|
||||
int len = newMantBuf.length();
|
||||
while ( newMantBuf.charAt( len - 1 ) == '0' )
|
||||
newMantBuf.setLength( --len );
|
||||
// And chop a trailing dot, if any.
|
||||
if ( newMantBuf.charAt( len - 1 ) == '.' )
|
||||
newMantBuf.setLength( --len );
|
||||
|
||||
// Done.
|
||||
return ( negative ? "-" : "" ) +
|
||||
newMantBuf +
|
||||
( expStr.length() != 0 ? ( "e" + expStr ) : "" );
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
/// Test program.
|
||||
public static void main( String[] args )
|
||||
{
|
||||
System.out.println( "Starting tests." );
|
||||
show( Fmt.fmt( "Hello there." ) );
|
||||
show( Fmt.fmt( 123 ) );
|
||||
show( Fmt.fmt( 123, 10 ) );
|
||||
show( Fmt.fmt( 123, 10, Fmt.ZF ) );
|
||||
show( Fmt.fmt( 123, 10, Fmt.LJ ) );
|
||||
show( Fmt.fmt( -123 ) );
|
||||
show( Fmt.fmt( -123, 10 ) );
|
||||
show( Fmt.fmt( -123, 10, Fmt.ZF ) );
|
||||
show( Fmt.fmt( -123, 10, Fmt.LJ ) );
|
||||
show( Fmt.fmt( (byte) 0xbe, 22, Fmt.OC ) );
|
||||
show( Fmt.fmt( (short) 0xbabe, 22, Fmt.OC ) );
|
||||
show( Fmt.fmt( 0xcafebabe, 22, Fmt.OC ) );
|
||||
show( Fmt.fmt( 0xdeadbeefcafebabeL, 22, Fmt.OC ) );
|
||||
show( Fmt.fmt( 0x8000000000000000L, 22, Fmt.OC ) );
|
||||
show( Fmt.fmt( (byte) 0xbe, 16, Fmt.HX ) );
|
||||
show( Fmt.fmt( (short) 0xbabe, 16, Fmt.HX ) );
|
||||
show( Fmt.fmt( 0xcafebabe, 16, Fmt.HX ) );
|
||||
show( Fmt.fmt( 0xdeadbeefcafebabeL, 16, Fmt.HX ) );
|
||||
show( Fmt.fmt( 0x8000000000000000L, 16, Fmt.HX ) );
|
||||
show( Fmt.fmt( 'c' ) );
|
||||
show( Fmt.fmt( new java.util.Date() ) );
|
||||
show( Fmt.fmt( 123.456F ) );
|
||||
show( Fmt.fmt( 123456000000000000.0F ) );
|
||||
show( Fmt.fmt( 123.456F, 0, 8 ) );
|
||||
show( Fmt.fmt( 123.456F, 0, 7 ) );
|
||||
show( Fmt.fmt( 123.456F, 0, 6 ) );
|
||||
show( Fmt.fmt( 123.456F, 0, 5 ) );
|
||||
show( Fmt.fmt( 123.456F, 0, 4 ) );
|
||||
show( Fmt.fmt( 123.456F, 0, 3 ) );
|
||||
show( Fmt.fmt( 123.456F, 0, 2 ) );
|
||||
show( Fmt.fmt( 123.456F, 0, 1 ) );
|
||||
show( Fmt.fmt( 123456000000000000.0F, 0, 4 ) );
|
||||
show( Fmt.fmt( -123.456F, 0, 4 ) );
|
||||
show( Fmt.fmt( -123456000000000000.0F, 0, 4 ) );
|
||||
show( Fmt.fmt( 123.0F ) );
|
||||
show( Fmt.fmt( 123.0D ) );
|
||||
show( Fmt.fmt( 1.234567890123456789F ) );
|
||||
show( Fmt.fmt( 1.234567890123456789D ) );
|
||||
show( Fmt.fmt( 1234567890123456789F ) );
|
||||
show( Fmt.fmt( 1234567890123456789D ) );
|
||||
show( Fmt.fmt( 0.000000000000000000001234567890123456789F ) );
|
||||
show( Fmt.fmt( 0.000000000000000000001234567890123456789D ) );
|
||||
show( Fmt.fmt( 12300.0F ) );
|
||||
show( Fmt.fmt( 12300.0D ) );
|
||||
show( Fmt.fmt( 123000.0F ) );
|
||||
show( Fmt.fmt( 123000.0D ) );
|
||||
show( Fmt.fmt( 1230000.0F ) );
|
||||
show( Fmt.fmt( 1230000.0D ) );
|
||||
show( Fmt.fmt( 12300000.0F ) );
|
||||
show( Fmt.fmt( 12300000.0D ) );
|
||||
show( Fmt.fmt( Float.NaN ) );
|
||||
show( Fmt.fmt( Float.POSITIVE_INFINITY ) );
|
||||
show( Fmt.fmt( Float.NEGATIVE_INFINITY ) );
|
||||
show( Fmt.fmt( Double.NaN ) );
|
||||
show( Fmt.fmt( Double.POSITIVE_INFINITY ) );
|
||||
show( Fmt.fmt( Double.NEGATIVE_INFINITY ) );
|
||||
show( Fmt.fmt( 1.0F / 8.0F ) );
|
||||
show( Fmt.fmt( 1.0D / 8.0D ) );
|
||||
System.out.println( "Done with tests." );
|
||||
}
|
||||
|
||||
private static void show( String str )
|
||||
{
|
||||
System.out.println( "#" + str + "#" );
|
||||
}
|
||||
******************************************************************************/
|
||||
|
||||
}
|
|
@ -1,314 +0,0 @@
|
|||
// ImageDecoder - abstract class for reading in an image
|
||||
//
|
||||
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Decoders;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.awt.image.*;
|
||||
|
||||
/// Abstract class for reading in an image.
|
||||
// <P>
|
||||
// A framework for classes that read in and decode an image in
|
||||
// a particular file format.
|
||||
// <P>
|
||||
// This provides a very simplified rendition of the ImageProducer interface.
|
||||
// It requires the decoder to read the image a row at a time. It requires
|
||||
// use of the RGBdefault color model.
|
||||
// If you want more flexibility you can always implement ImageProducer
|
||||
// directly.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Decoders/ImageDecoder.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
// <P>
|
||||
// @see PpmDecoder
|
||||
// @see Acme.JPM.Encoders.ImageEncoder
|
||||
|
||||
public abstract class ImageDecoder implements ImageProducer
|
||||
{
|
||||
|
||||
private InputStream in;
|
||||
private int width, height;
|
||||
private boolean[] rowsRead;
|
||||
private int[][] rgbPixels;
|
||||
private boolean startedRead = false;
|
||||
private boolean gotSize = false;
|
||||
private boolean err = false;
|
||||
private boolean producing = false;
|
||||
private Vector consumers = new Vector();
|
||||
private static final ColorModel model = ColorModel.getRGBdefault();
|
||||
|
||||
|
||||
/// Constructor.
|
||||
// @param in The stream to read the bytes from.
|
||||
public ImageDecoder( InputStream in )
|
||||
{
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
|
||||
// Methods that subclasses implement.
|
||||
|
||||
/// Subclasses implement this to read in enough of the image stream
|
||||
// to figure out the width and height.
|
||||
abstract void readHeader( InputStream in ) throws IOException;
|
||||
|
||||
/// Subclasses implement this to return the width, or -1 if not known.
|
||||
abstract int getWidth();
|
||||
|
||||
/// Subclasses implement this to return the height, or -1 if not known.
|
||||
abstract int getHeight();
|
||||
|
||||
/// Subclasses implement this to read pixel data into the rgbRow
|
||||
// array, an int[width]. One int per pixel, no offsets or padding,
|
||||
// RGBdefault (AARRGGBB) color model.
|
||||
abstract void readRow( InputStream in, int row, int[] rgbRow ) throws IOException;
|
||||
|
||||
|
||||
// Our own methods.
|
||||
|
||||
void readImage()
|
||||
{
|
||||
try
|
||||
{
|
||||
readHeader( in );
|
||||
width = getWidth();
|
||||
height = getHeight();
|
||||
if ( width == -1 || height == -1 )
|
||||
err = true;
|
||||
else
|
||||
{
|
||||
rowsRead = new boolean[height];
|
||||
for ( int row = 0; row < height; ++row )
|
||||
rowsRead[row] = false;
|
||||
gotSize = true;
|
||||
notifyThem();
|
||||
rgbPixels = new int[height][width];
|
||||
for ( int row = 0; row < height; ++row )
|
||||
{
|
||||
readRow( in, row, rgbPixels[row] );
|
||||
rowsRead[row] = true;
|
||||
notifyThem();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
err = true;
|
||||
width = -1;
|
||||
height = -1;
|
||||
rowsRead = null;
|
||||
rgbPixels = null;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void notifyThem()
|
||||
{
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
void sendImage()
|
||||
{
|
||||
// Grab the list of consumers, in case it changes while we're sending.
|
||||
ImageConsumer[] c = new ImageConsumer[consumers.size()];
|
||||
int i;
|
||||
for ( i = 0; i < c.length; ++i )
|
||||
c[i] = (ImageConsumer) consumers.elementAt( i );
|
||||
// Try to be as parallel as possible.
|
||||
waitForSize();
|
||||
for ( i = 0; i < c.length; ++i )
|
||||
sendHead( c[i] );
|
||||
for ( int row = 0; row < height; ++row )
|
||||
for ( i = 0; i < c.length; ++i )
|
||||
sendPixelRow( c[i], row );
|
||||
for ( i = 0; i < c.length; ++i )
|
||||
sendTail( c[i] );
|
||||
producing = false;
|
||||
}
|
||||
|
||||
private synchronized void waitForSize()
|
||||
{
|
||||
while ( ( ! err ) && ( ! gotSize ))
|
||||
{
|
||||
try
|
||||
{
|
||||
wait();
|
||||
}
|
||||
catch ( InterruptedException ignore ) {}
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void waitForRow( int row )
|
||||
{
|
||||
while ( ( ! err ) && ( ! rowsRead[row] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
wait();
|
||||
}
|
||||
catch ( InterruptedException ignore ) {}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendHead( ImageConsumer ic )
|
||||
{
|
||||
if ( err )
|
||||
return;
|
||||
ic.setDimensions( width, height );
|
||||
ic.setColorModel( model );
|
||||
ic.setHints(
|
||||
ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES |
|
||||
ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME );
|
||||
}
|
||||
|
||||
private void sendPixelRow( ImageConsumer ic, int row )
|
||||
{
|
||||
if ( err )
|
||||
return;
|
||||
waitForRow( row );
|
||||
if ( err )
|
||||
return;
|
||||
ic.setPixels( 0, row, width, 1, model, rgbPixels[row], 0, width );
|
||||
}
|
||||
|
||||
private void sendTail( ImageConsumer ic )
|
||||
{
|
||||
if ( err )
|
||||
ic.imageComplete( ImageConsumer.IMAGEERROR );
|
||||
else
|
||||
ic.imageComplete( ImageConsumer.STATICIMAGEDONE );
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Methods from ImageProducer.
|
||||
|
||||
/// This method is used to register an ImageConsumer with the
|
||||
// ImageProducer for access to the image data during a later
|
||||
// reconstruction of the Image. The ImageProducer may, at its
|
||||
// discretion, start delivering the image data to the consumer
|
||||
// using the ImageConsumer interface immediately, or when the
|
||||
// next available image reconstruction is triggered by a call
|
||||
// to the startProduction method.
|
||||
// @see #startProduction
|
||||
public void addConsumer( ImageConsumer ic )
|
||||
{
|
||||
if ( ic != null && ! isConsumer( ic ) )
|
||||
consumers.addElement( ic );
|
||||
}
|
||||
|
||||
/// This method determines if a given ImageConsumer object
|
||||
// is currently registered with this ImageProducer as one
|
||||
// of its consumers.
|
||||
public boolean isConsumer( ImageConsumer ic )
|
||||
{
|
||||
return consumers.contains( ic );
|
||||
}
|
||||
|
||||
/// This method removes the given ImageConsumer object
|
||||
// from the list of consumers currently registered to
|
||||
// receive image data. It is not considered an error
|
||||
// to remove a consumer that is not currently registered.
|
||||
// The ImageProducer should stop sending data to this
|
||||
// consumer as soon as is feasible.
|
||||
public void removeConsumer( ImageConsumer ic )
|
||||
{
|
||||
consumers.removeElement( ic );
|
||||
}
|
||||
|
||||
/// This method both registers the given ImageConsumer object
|
||||
// as a consumer and starts an immediate reconstruction of
|
||||
// the image data which will then be delivered to this
|
||||
// consumer and any other consumer which may have already
|
||||
// been registered with the producer. This method differs
|
||||
// from the addConsumer method in that a reproduction of
|
||||
// the image data should be triggered as soon as possible.
|
||||
// @see #addConsumer
|
||||
public void startProduction( ImageConsumer ic )
|
||||
{
|
||||
addConsumer( ic );
|
||||
if ( ! startedRead )
|
||||
{
|
||||
startedRead = true;
|
||||
new ImageDecoderRead( this );
|
||||
}
|
||||
if ( ! producing )
|
||||
{
|
||||
producing = true;
|
||||
sendImage();
|
||||
}
|
||||
}
|
||||
|
||||
/// This method is used by an ImageConsumer to request that
|
||||
// the ImageProducer attempt to resend the image data one
|
||||
// more time in TOPDOWNLEFTRIGHT order so that higher
|
||||
// quality conversion algorithms which depend on receiving
|
||||
// pixels in order can be used to produce a better output
|
||||
// version of the image. The ImageProducer is free to
|
||||
// ignore this call if it cannot resend the data in that
|
||||
// order. If the data can be resent, then the ImageProducer
|
||||
// should respond by executing the following minimum set of
|
||||
// ImageConsumer method calls:
|
||||
// <PRE>
|
||||
// ic.setHints( TOPDOWNLEFTRIGHT | [otherhints] );
|
||||
// ic.setPixels( [...] ); // as many times as needed
|
||||
// ic.imageComplete( [status] );
|
||||
// </PRE>
|
||||
// @see ImageConsumer#setHints
|
||||
public void requestTopDownLeftRightResend( ImageConsumer ic )
|
||||
{
|
||||
addConsumer( ic );
|
||||
waitForSize();
|
||||
sendHead( ic );
|
||||
for ( int row = 0; row < height; ++row )
|
||||
sendPixelRow( ic, row );
|
||||
sendTail( ic );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class ImageDecoderRead extends Thread
|
||||
{
|
||||
|
||||
private ImageDecoder parent;
|
||||
|
||||
public ImageDecoderRead( ImageDecoder parent )
|
||||
{
|
||||
this.parent = parent;
|
||||
start();
|
||||
}
|
||||
|
||||
// Methods from Runnable.
|
||||
|
||||
public void run()
|
||||
{
|
||||
parent.readImage();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,267 +0,0 @@
|
|||
// PpmDecoder - read in a PPM image
|
||||
//
|
||||
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Decoders;
|
||||
|
||||
import java.io.*;
|
||||
import java.awt.image.*;
|
||||
|
||||
/// Read in a PPM image.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Decoders/PpmDecoder.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
// <P>
|
||||
// @see Acme.JPM.Encoders.PpmEncoder
|
||||
|
||||
public class PpmDecoder extends ImageDecoder
|
||||
{
|
||||
|
||||
/// Constructor.
|
||||
// @param in The stream to read the bytes from.
|
||||
public PpmDecoder( InputStream in )
|
||||
{
|
||||
super( in );
|
||||
}
|
||||
|
||||
|
||||
private int type;
|
||||
private static final int PBM_ASCII = 1;
|
||||
private static final int PGM_ASCII = 2;
|
||||
private static final int PPM_ASCII = 3;
|
||||
private static final int PBM_RAW = 4;
|
||||
private static final int PGM_RAW = 5;
|
||||
private static final int PPM_RAW = 6;
|
||||
|
||||
private int width = -1, height = -1;
|
||||
private int maxval;
|
||||
|
||||
/// Subclasses implement this to read in enough of the image stream
|
||||
// to figure out the width and height.
|
||||
void readHeader( InputStream in ) throws IOException
|
||||
{
|
||||
char c1, c2;
|
||||
|
||||
c1 = (char) readByte( in );
|
||||
c2 = (char) readByte( in );
|
||||
|
||||
if ( c1 != 'P' )
|
||||
throw new IOException( "not a PBM/PGM/PPM file" );
|
||||
switch ( c2 )
|
||||
{
|
||||
case '1':
|
||||
type = PBM_ASCII;
|
||||
break;
|
||||
case '2':
|
||||
type = PGM_ASCII;
|
||||
break;
|
||||
case '3':
|
||||
type = PPM_ASCII;
|
||||
break;
|
||||
case '4':
|
||||
type = PBM_RAW;
|
||||
break;
|
||||
case '5':
|
||||
type = PGM_RAW;
|
||||
break;
|
||||
case '6':
|
||||
type = PPM_RAW;
|
||||
break;
|
||||
default:
|
||||
throw new IOException( "not a standard PBM/PGM/PPM file" );
|
||||
}
|
||||
width = readInt( in );
|
||||
height = readInt( in );
|
||||
if ( type != PBM_ASCII && type != PBM_RAW )
|
||||
maxval = readInt( in );
|
||||
}
|
||||
|
||||
/// Subclasses implement this to return the width, or -1 if not known.
|
||||
int getWidth()
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
/// Subclasses implement this to return the height, or -1 if not known.
|
||||
int getHeight()
|
||||
{
|
||||
return height;
|
||||
}
|
||||
|
||||
/// Subclasses implement this to read pixel data into the rgbRow
|
||||
// array, an int[width]. One int per pixel, no offsets or padding,
|
||||
// RGBdefault (AARRGGBB) color model
|
||||
void readRow( InputStream in, int row, int[] rgbRow ) throws IOException
|
||||
{
|
||||
int col, r, g, b;
|
||||
int rgb = 0;
|
||||
char c;
|
||||
|
||||
for ( col = 0; col < width; ++col )
|
||||
{
|
||||
switch ( type )
|
||||
{
|
||||
case PBM_ASCII:
|
||||
c = readChar( in );
|
||||
if ( c == '1' )
|
||||
rgb = 0xff000000;
|
||||
else if ( c == '0' )
|
||||
rgb = 0xffffffff;
|
||||
else
|
||||
throw new IOException( "illegal PBM bit" );
|
||||
break;
|
||||
case PGM_ASCII:
|
||||
g = readInt( in );
|
||||
rgb = makeRgb( g, g, g );
|
||||
break;
|
||||
case PPM_ASCII:
|
||||
r = readInt( in );
|
||||
g = readInt( in );
|
||||
b = readInt( in );
|
||||
rgb = makeRgb( r, g, b );
|
||||
break;
|
||||
case PBM_RAW:
|
||||
if ( readBit( in ) )
|
||||
rgb = 0xff000000;
|
||||
else
|
||||
rgb = 0xffffffff;
|
||||
break;
|
||||
case PGM_RAW:
|
||||
g = readByte( in );
|
||||
if ( maxval != 255 )
|
||||
g = fixDepth( g );
|
||||
rgb = makeRgb( g, g, g );
|
||||
break;
|
||||
case PPM_RAW:
|
||||
r = readByte( in );
|
||||
g = readByte( in );
|
||||
b = readByte( in );
|
||||
if ( maxval != 255 )
|
||||
{
|
||||
r = fixDepth( r );
|
||||
g = fixDepth( g );
|
||||
b = fixDepth( b );
|
||||
}
|
||||
rgb = makeRgb( r, g, b );
|
||||
break;
|
||||
}
|
||||
rgbRow[col] = rgb;
|
||||
}
|
||||
}
|
||||
|
||||
/// Utility routine to read a byte. Instead of returning -1 on
|
||||
// EOF, it throws an exception.
|
||||
private static int readByte( InputStream in ) throws IOException
|
||||
{
|
||||
int b = in.read();
|
||||
if ( b == -1 )
|
||||
throw new EOFException();
|
||||
return b;
|
||||
}
|
||||
|
||||
private int bitshift = -1;
|
||||
private int bits;
|
||||
|
||||
/// Utility routine to read a bit, packed eight to a byte, big-endian.
|
||||
private boolean readBit( InputStream in ) throws IOException
|
||||
{
|
||||
if ( bitshift == -1 )
|
||||
{
|
||||
bits = readByte( in );
|
||||
bitshift = 7;
|
||||
}
|
||||
boolean bit = ( ( ( bits >> bitshift ) & 1 ) != 0 );
|
||||
--bitshift;
|
||||
return bit;
|
||||
}
|
||||
|
||||
/// Utility routine to read a character, ignoring comments.
|
||||
private static char readChar( InputStream in ) throws IOException
|
||||
{
|
||||
char c;
|
||||
|
||||
c = (char) readByte( in );
|
||||
if ( c == '#' )
|
||||
{
|
||||
do
|
||||
{
|
||||
c = (char) readByte( in );
|
||||
}
|
||||
while ( c != '\n' && c != '\r' );
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/// Utility routine to read the first non-whitespace character.
|
||||
private static char readNonwhiteChar( InputStream in ) throws IOException
|
||||
{
|
||||
char c;
|
||||
|
||||
do
|
||||
{
|
||||
c = readChar( in );
|
||||
}
|
||||
while ( c == ' ' || c == '\t' || c == '\n' || c == '\r' );
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/// Utility routine to read an ASCII integer, ignoring comments.
|
||||
private static int readInt( InputStream in ) throws IOException
|
||||
{
|
||||
char c;
|
||||
int i;
|
||||
|
||||
c = readNonwhiteChar( in );
|
||||
if ( c < '0' || c > '9' )
|
||||
throw new IOException( "junk in file where integer should be" );
|
||||
|
||||
i = 0;
|
||||
do
|
||||
{
|
||||
i = i * 10 + c - '0';
|
||||
c = readChar( in );
|
||||
}
|
||||
while ( c >= '0' && c <= '9' );
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/// Utility routine to rescale a pixel value from a non-eight-bit maxval.
|
||||
private int fixDepth( int p )
|
||||
{
|
||||
return ( p * 255 + maxval / 2 ) / maxval;
|
||||
}
|
||||
|
||||
/// Utility routine make an RGBdefault pixel from three color values.
|
||||
private static int makeRgb( int r, int g, int b )
|
||||
{
|
||||
return 0xff000000 | ( r << 16 ) | ( g << 8 ) | b;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,448 +0,0 @@
|
|||
// JpegEncoder - write out an image as a JPEG
|
||||
//
|
||||
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Encoders;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.*;
|
||||
|
||||
/// Write out an image as a JPEG.
|
||||
// DOESN'T WORK YET.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Encoders/JpegEncoder.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
// <P>
|
||||
// @see ToJpeg
|
||||
|
||||
public class JpegEncoder extends ImageEncoder
|
||||
{
|
||||
|
||||
/// Constructor.
|
||||
// @param img The image to encode.
|
||||
// @param out The stream to write the JPEG to.
|
||||
public JpegEncoder( Image img, OutputStream out ) throws IOException
|
||||
{
|
||||
super( img, out );
|
||||
}
|
||||
|
||||
/// Constructor.
|
||||
// @param prod The ImageProducer to encode.
|
||||
// @param out The stream to write the JPEG to.
|
||||
public JpegEncoder( ImageProducer prod, OutputStream out ) throws IOException
|
||||
{
|
||||
super( prod, out );
|
||||
}
|
||||
|
||||
int qfactor = 100;
|
||||
|
||||
/// Set the Q-factor.
|
||||
public void setQfactor( int qfactor )
|
||||
{
|
||||
this.qfactor = qfactor;
|
||||
}
|
||||
|
||||
int width, height;
|
||||
int[][] rgbPixels;
|
||||
|
||||
void encodeStart( int width, int height ) throws IOException
|
||||
{
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
rgbPixels = new int[height][width];
|
||||
}
|
||||
|
||||
void encodePixels(
|
||||
int x, int y, int w, int h, int[] rgbPixels, int off, int scansize )
|
||||
throws IOException
|
||||
{
|
||||
// Save the pixels.
|
||||
for ( int row = 0; row < h; ++row )
|
||||
System.arraycopy(
|
||||
rgbPixels, row * scansize + off,
|
||||
this.rgbPixels[y + row], x, w );
|
||||
|
||||
}
|
||||
|
||||
void encodeDone() throws IOException
|
||||
{
|
||||
writeJfifHuffHeader();
|
||||
// !!!
|
||||
}
|
||||
|
||||
|
||||
// Some of the following code is derived from the Berkeley Continuous
|
||||
// Media Toolkit (http://bmrc.berkeley.edu/projects/cmt/), which is
|
||||
// Copyright (c) 1996 The Regents of the University of California.
|
||||
// All rights reserved.
|
||||
//
|
||||
// IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
|
||||
// DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING
|
||||
// OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE
|
||||
// UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
// DAMAGE.
|
||||
//
|
||||
// THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
// ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION
|
||||
// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
|
||||
|
||||
// This array represents the default JFIF header for quality = 100 and
|
||||
// size = 640x480, with Huffman tables. The values are adjusted when a
|
||||
// file is generated.
|
||||
private static byte[] jfifHuff100Header = {
|
||||
// SOI
|
||||
(byte) 0xFF, (byte) 0xD8,
|
||||
|
||||
// JFIF header
|
||||
(byte) 0xFF, (byte) 0xE0, // Marker
|
||||
(byte) 0x00, (byte) 0x10, // Length = 16 bytes
|
||||
(byte) 0x4A, (byte) 0x46, (byte) 0x49, (byte) 0x46, // "JFIF"
|
||||
(byte) 0x00, (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00,
|
||||
|
||||
// Start of frame (section B.2.2)
|
||||
(byte) 0xFF, (byte) 0xC0, // Baseline DCT
|
||||
(byte) 0x00, (byte) 0x11, // Length = 17 bytes
|
||||
(byte) 0x08, // Sample precision
|
||||
(byte) 0x01, (byte) 0xE0, // Height
|
||||
(byte) 0x02, (byte) 0x80, // Width
|
||||
(byte) 0x03, // Number of components = 3
|
||||
// Scan 1: 2:1 horiz, (byte) 1:1 vertical, (byte) use QT 0
|
||||
(byte) 0x01, (byte) 0x21, (byte) 0x00,
|
||||
// Scan 2: 1:1 horiz, (byte) 1:1 vertical, (byte) use QT 1
|
||||
(byte) 0x02, (byte) 0x11, (byte) 0x01,
|
||||
// Scan 3: 1:1 horiz, (byte) 1:1 vertical, (byte) use QT 1
|
||||
(byte) 0x03, (byte) 0x11, (byte) 0x01,
|
||||
|
||||
// Define Quant table (section B.2.4.1)
|
||||
(byte) 0xFF, (byte) 0xDB, // Marker
|
||||
(byte) 0x00, (byte) 0x84, // Length (both tables)
|
||||
(byte) 0x00, // 8 bit values, (byte) table 0
|
||||
(byte) 0x10, (byte) 0x0B, (byte) 0x0C, (byte) 0x0E, (byte) 0x0C,
|
||||
(byte) 0x0A, (byte) 0x10, (byte) 0x0E, (byte) 0x0D, (byte) 0x0E,
|
||||
(byte) 0x12, (byte) 0x11, (byte) 0x10, (byte) 0x13, (byte) 0x18,
|
||||
(byte) 0x28, (byte) 0x1A, (byte) 0x18, (byte) 0x16, (byte) 0x16,
|
||||
(byte) 0x18, (byte) 0x31, (byte) 0x23, (byte) 0x25, (byte) 0x1D,
|
||||
(byte) 0x28, (byte) 0x3A, (byte) 0x33, (byte) 0x3D, (byte) 0x3C,
|
||||
(byte) 0x39, (byte) 0x33, (byte) 0x38, (byte) 0x37, (byte) 0x40,
|
||||
(byte) 0x48, (byte) 0x5C, (byte) 0x4E, (byte) 0x40, (byte) 0x44,
|
||||
(byte) 0x57, (byte) 0x45, (byte) 0x37, (byte) 0x38, (byte) 0x50,
|
||||
(byte) 0x6D, (byte) 0x51, (byte) 0x57, (byte) 0x5F, (byte) 0x62,
|
||||
(byte) 0x67, (byte) 0x68, (byte) 0x67, (byte) 0x3E, (byte) 0x4D,
|
||||
(byte) 0x71, (byte) 0x79, (byte) 0x70, (byte) 0x64, (byte) 0x78,
|
||||
(byte) 0x5C, (byte) 0x65, (byte) 0x67, (byte) 0x63,
|
||||
|
||||
(byte) 0x01, // 8 bit values, (byte) table 1
|
||||
(byte) 0x11, (byte) 0x12, (byte) 0x12, (byte) 0x18, (byte) 0x15,
|
||||
(byte) 0x18, (byte) 0x2F, (byte) 0x1A, (byte) 0x1A, (byte) 0x2F,
|
||||
(byte) 0x63, (byte) 0x42, (byte) 0x38, (byte) 0x42, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
|
||||
// Define huffman table (section B.2.4.1)
|
||||
(byte) 0xFF, (byte) 0xC4, // Marker
|
||||
(byte) 0x00, (byte) 0x1F, // Length (31 bytes)
|
||||
(byte) 0x00, // DC, (byte) table 0
|
||||
(byte) 0x00, (byte) 0x01, (byte) 0x05, (byte) 0x01, (byte) 0x01,
|
||||
(byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x00,
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03,
|
||||
(byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08,
|
||||
(byte) 0x09, (byte) 0x0A, (byte) 0x0B,
|
||||
|
||||
// Define huffman table (section B.2.4.1)
|
||||
(byte) 0xFF, (byte) 0xC4, // Marker
|
||||
(byte) 0x00, (byte) 0xB5, // Length (181 bytes)
|
||||
(byte) 0x10, // AC, (byte) table 0
|
||||
(byte) 0x00, (byte) 0x02, (byte) 0x01, (byte) 0x03, (byte) 0x03,
|
||||
(byte) 0x02, (byte) 0x04, (byte) 0x03, (byte) 0x05, (byte) 0x05,
|
||||
(byte) 0x04, (byte) 0x04, (byte) 0x00, (byte) 0x00, (byte) 0x01,
|
||||
(byte) 0x7D, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x00,
|
||||
(byte) 0x04, (byte) 0x11, (byte) 0x05, (byte) 0x12, (byte) 0x21,
|
||||
(byte) 0x31, (byte) 0x41, (byte) 0x06, (byte) 0x13, (byte) 0x51,
|
||||
(byte) 0x61, (byte) 0x07, (byte) 0x22, (byte) 0x71, (byte) 0x14,
|
||||
(byte) 0x32, (byte) 0x81, (byte) 0x91, (byte) 0xA1, (byte) 0x08,
|
||||
(byte) 0x23, (byte) 0x42, (byte) 0xB1, (byte) 0xC1, (byte) 0x15,
|
||||
(byte) 0x52, (byte) 0xD1, (byte) 0xF0, (byte) 0x24, (byte) 0x33,
|
||||
(byte) 0x62, (byte) 0x72, (byte) 0x82, (byte) 0x09, (byte) 0x0A,
|
||||
(byte) 0x16, (byte) 0x17, (byte) 0x18, (byte) 0x19, (byte) 0x1A,
|
||||
(byte) 0x25, (byte) 0x26, (byte) 0x27, (byte) 0x28, (byte) 0x29,
|
||||
(byte) 0x2A, (byte) 0x34, (byte) 0x35, (byte) 0x36, (byte) 0x37,
|
||||
(byte) 0x38, (byte) 0x39, (byte) 0x3A, (byte) 0x43, (byte) 0x44,
|
||||
(byte) 0x45, (byte) 0x46, (byte) 0x47, (byte) 0x48, (byte) 0x49,
|
||||
(byte) 0x4A, (byte) 0x53, (byte) 0x54, (byte) 0x55, (byte) 0x56,
|
||||
(byte) 0x57, (byte) 0x58, (byte) 0x59, (byte) 0x5A, (byte) 0x63,
|
||||
(byte) 0x64, (byte) 0x65, (byte) 0x66, (byte) 0x67, (byte) 0x68,
|
||||
(byte) 0x69, (byte) 0x6A, (byte) 0x73, (byte) 0x74, (byte) 0x75,
|
||||
(byte) 0x76, (byte) 0x77, (byte) 0x78, (byte) 0x79, (byte) 0x7A,
|
||||
(byte) 0x83, (byte) 0x84, (byte) 0x85, (byte) 0x86, (byte) 0x87,
|
||||
(byte) 0x88, (byte) 0x89, (byte) 0x8A, (byte) 0x92, (byte) 0x93,
|
||||
(byte) 0x94, (byte) 0x95, (byte) 0x96, (byte) 0x97, (byte) 0x98,
|
||||
(byte) 0x99, (byte) 0x9A, (byte) 0xA2, (byte) 0xA3, (byte) 0xA4,
|
||||
(byte) 0xA5, (byte) 0xA6, (byte) 0xA7, (byte) 0xA8, (byte) 0xA9,
|
||||
(byte) 0xAA, (byte) 0xB2, (byte) 0xB3, (byte) 0xB4, (byte) 0xB5,
|
||||
(byte) 0xB6, (byte) 0xB7, (byte) 0xB8, (byte) 0xB9, (byte) 0xBA,
|
||||
(byte) 0xC2, (byte) 0xC3, (byte) 0xC4, (byte) 0xC5, (byte) 0xC6,
|
||||
(byte) 0xC7, (byte) 0xC8, (byte) 0xC9, (byte) 0xCA, (byte) 0xD2,
|
||||
(byte) 0xD3, (byte) 0xD4, (byte) 0xD5, (byte) 0xD6, (byte) 0xD7,
|
||||
(byte) 0xD8, (byte) 0xD9, (byte) 0xDA, (byte) 0xE1, (byte) 0xE2,
|
||||
(byte) 0xE3, (byte) 0xE4, (byte) 0xE5, (byte) 0xE6, (byte) 0xE7,
|
||||
(byte) 0xE8, (byte) 0xE9, (byte) 0xEA, (byte) 0xF1, (byte) 0xF2,
|
||||
(byte) 0xF3, (byte) 0xF4, (byte) 0xF5, (byte) 0xF6, (byte) 0xF7,
|
||||
(byte) 0xF8, (byte) 0xF9, (byte) 0xFA,
|
||||
|
||||
// Define huffman table (section B.2.4.1)
|
||||
(byte) 0xFF, (byte) 0xC4, // Marker
|
||||
(byte) 0x00, (byte) 0x1F, // Length (31 bytes)
|
||||
(byte) 0x01, // DC, (byte) table 1
|
||||
(byte) 0x00, (byte) 0x03, (byte) 0x01, (byte) 0x01, (byte) 0x01,
|
||||
(byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01,
|
||||
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03,
|
||||
(byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08,
|
||||
(byte) 0x09, (byte) 0x0A, (byte) 0x0B,
|
||||
|
||||
// Define huffman table (section B.2.4.1)
|
||||
(byte) 0xFF, (byte) 0xC4, // Marker
|
||||
(byte) 0x00, (byte) 0xB5, // Length (181 bytes)
|
||||
(byte) 0x11, // AC, (byte) table 1
|
||||
(byte) 0x00, (byte) 0x02, (byte) 0x01, (byte) 0x02, (byte) 0x04,
|
||||
(byte) 0x04, (byte) 0x03, (byte) 0x04, (byte) 0x07, (byte) 0x05,
|
||||
(byte) 0x04, (byte) 0x04, (byte) 0x00, (byte) 0x01, (byte) 0x02,
|
||||
(byte) 0x77, (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03,
|
||||
(byte) 0x11, (byte) 0x04, (byte) 0x05, (byte) 0x21, (byte) 0x31,
|
||||
(byte) 0x06, (byte) 0x12, (byte) 0x41, (byte) 0x51, (byte) 0x07,
|
||||
(byte) 0x61, (byte) 0x71, (byte) 0x13, (byte) 0x22, (byte) 0x32,
|
||||
(byte) 0x81, (byte) 0x08, (byte) 0x14, (byte) 0x42, (byte) 0x91,
|
||||
(byte) 0xA1, (byte) 0xB1, (byte) 0xC1, (byte) 0x09, (byte) 0x23,
|
||||
(byte) 0x33, (byte) 0x52, (byte) 0xF0, (byte) 0x15, (byte) 0x62,
|
||||
(byte) 0x72, (byte) 0xD1, (byte) 0x0A, (byte) 0x16, (byte) 0x24,
|
||||
(byte) 0x34, (byte) 0xE1, (byte) 0x25, (byte) 0xF1, (byte) 0x17,
|
||||
(byte) 0x18, (byte) 0x19, (byte) 0x1A, (byte) 0x26, (byte) 0x27,
|
||||
(byte) 0x28, (byte) 0x29, (byte) 0x2A, (byte) 0x35, (byte) 0x36,
|
||||
(byte) 0x37, (byte) 0x38, (byte) 0x39, (byte) 0x3A, (byte) 0x43,
|
||||
(byte) 0x44, (byte) 0x45, (byte) 0x46, (byte) 0x47, (byte) 0x48,
|
||||
(byte) 0x49, (byte) 0x4A, (byte) 0x53, (byte) 0x54, (byte) 0x55,
|
||||
(byte) 0x56, (byte) 0x57, (byte) 0x58, (byte) 0x59, (byte) 0x5A,
|
||||
(byte) 0x63, (byte) 0x64, (byte) 0x65, (byte) 0x66, (byte) 0x67,
|
||||
(byte) 0x68, (byte) 0x69, (byte) 0x6A, (byte) 0x73, (byte) 0x74,
|
||||
(byte) 0x75, (byte) 0x76, (byte) 0x77, (byte) 0x78, (byte) 0x79,
|
||||
(byte) 0x7A, (byte) 0x82, (byte) 0x83, (byte) 0x84, (byte) 0x85,
|
||||
(byte) 0x86, (byte) 0x87, (byte) 0x88, (byte) 0x89, (byte) 0x8A,
|
||||
(byte) 0x92, (byte) 0x93, (byte) 0x94, (byte) 0x95, (byte) 0x96,
|
||||
(byte) 0x97, (byte) 0x98, (byte) 0x99, (byte) 0x9A, (byte) 0xA2,
|
||||
(byte) 0xA3, (byte) 0xA4, (byte) 0xA5, (byte) 0xA6, (byte) 0xA7,
|
||||
(byte) 0xA8, (byte) 0xA9, (byte) 0xAA, (byte) 0xB2, (byte) 0xB3,
|
||||
(byte) 0xB4, (byte) 0xB5, (byte) 0xB6, (byte) 0xB7, (byte) 0xB8,
|
||||
(byte) 0xB9, (byte) 0xBA, (byte) 0xC2, (byte) 0xC3, (byte) 0xC4,
|
||||
(byte) 0xC5, (byte) 0xC6, (byte) 0xC7, (byte) 0xC8, (byte) 0xC9,
|
||||
(byte) 0xCA, (byte) 0xD2, (byte) 0xD3, (byte) 0xD4, (byte) 0xD5,
|
||||
(byte) 0xD6, (byte) 0xD7, (byte) 0xD8, (byte) 0xD9, (byte) 0xDA,
|
||||
(byte) 0xE2, (byte) 0xE3, (byte) 0xE4, (byte) 0xE5, (byte) 0xE6,
|
||||
(byte) 0xE7, (byte) 0xE8, (byte) 0xE9, (byte) 0xEA, (byte) 0xF2,
|
||||
(byte) 0xF3, (byte) 0xF4, (byte) 0xF5, (byte) 0xF6, (byte) 0xF7,
|
||||
(byte) 0xF8, (byte) 0xF9, (byte) 0xFA,
|
||||
|
||||
// Start of Scan (section B.2.3)
|
||||
(byte) 0xFF, (byte) 0xDA, // Marker
|
||||
(byte) 0x00, (byte) 0x0C, // Length of header
|
||||
(byte) 0x03, // Number of image components
|
||||
// Scan 1: use DC/AC huff tables 0/0
|
||||
(byte) 0x01, (byte) 0x00,
|
||||
// Scan 2: use DC/AC huff tables 1/1
|
||||
(byte) 0x02, (byte) 0x11,
|
||||
// Scan 3: use DC/AC huff tables 1/1
|
||||
(byte) 0x03, (byte) 0x11,
|
||||
(byte) 0x00, (byte) 0x3F, (byte) 0x00 // Not used
|
||||
};
|
||||
|
||||
// This array represents the default JFIF header for quality = 100 and
|
||||
// size = 640x480, without Huffman tables. The values are adjusted when a
|
||||
// file is generated.
|
||||
private static byte[] jfifNoHuff100Header = {
|
||||
// SOI
|
||||
(byte) 0xFF, (byte) 0xD8,
|
||||
|
||||
// JFIF header
|
||||
(byte) 0xFF, (byte) 0xE0, // Marker
|
||||
(byte) 0x00, (byte) 0x10, // Length = 16 bytes
|
||||
(byte) 0x4A, (byte) 0x46, (byte) 0x49, (byte) 0x46, // "JFIF"
|
||||
(byte) 0x00, (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00,
|
||||
|
||||
// Start of frame (section B.2.2)
|
||||
(byte) 0xFF, (byte) 0xC0, // Baseline DCT
|
||||
(byte) 0x00, (byte) 0x11, // Length = 17 bytes
|
||||
(byte) 0x08, // Sample precision
|
||||
(byte) 0x01, (byte) 0xE0, // Height
|
||||
(byte) 0x02, (byte) 0x80, // Width
|
||||
(byte) 0x03, // Number of components = 3
|
||||
// Scan 1: 2:1 horiz, (byte) 1:1 vertical, (byte) use QT 0
|
||||
(byte) 0x01, (byte) 0x21, (byte) 0x00,
|
||||
// Scan 2: 1:1 horiz, (byte) 1:1 vertical, (byte) use QT 1
|
||||
(byte) 0x02, (byte) 0x11, (byte) 0x01,
|
||||
// Scan 3: 1:1 horiz, (byte) 1:1 vertical, (byte) use QT 1
|
||||
(byte) 0x03, (byte) 0x11, (byte) 0x01,
|
||||
|
||||
// Define Quant table (section B.2.4.1)
|
||||
(byte) 0xFF, (byte) 0xDB, // Marker
|
||||
(byte) 0x00, (byte) 0x84, // Length (both tables)
|
||||
(byte) 0x00, // 8 bit values, (byte) table 0
|
||||
(byte) 0x10, (byte) 0x0B, (byte) 0x0C, (byte) 0x0E, (byte) 0x0C,
|
||||
(byte) 0x0A, (byte) 0x10, (byte) 0x0E, (byte) 0x0D, (byte) 0x0E,
|
||||
(byte) 0x12, (byte) 0x11, (byte) 0x10, (byte) 0x13, (byte) 0x18,
|
||||
(byte) 0x28, (byte) 0x1A, (byte) 0x18, (byte) 0x16, (byte) 0x16,
|
||||
(byte) 0x18, (byte) 0x31, (byte) 0x23, (byte) 0x25, (byte) 0x1D,
|
||||
(byte) 0x28, (byte) 0x3A, (byte) 0x33, (byte) 0x3D, (byte) 0x3C,
|
||||
(byte) 0x39, (byte) 0x33, (byte) 0x38, (byte) 0x37, (byte) 0x40,
|
||||
(byte) 0x48, (byte) 0x5C, (byte) 0x4E, (byte) 0x40, (byte) 0x44,
|
||||
(byte) 0x57, (byte) 0x45, (byte) 0x37, (byte) 0x38, (byte) 0x50,
|
||||
(byte) 0x6D, (byte) 0x51, (byte) 0x57, (byte) 0x5F, (byte) 0x62,
|
||||
(byte) 0x67, (byte) 0x68, (byte) 0x67, (byte) 0x3E, (byte) 0x4D,
|
||||
(byte) 0x71, (byte) 0x79, (byte) 0x70, (byte) 0x64, (byte) 0x78,
|
||||
(byte) 0x5C, (byte) 0x65, (byte) 0x67, (byte) 0x63,
|
||||
|
||||
(byte) 0x01, // 8 bit values, (byte) table 1
|
||||
(byte) 0x11, (byte) 0x12, (byte) 0x12, (byte) 0x18, (byte) 0x15,
|
||||
(byte) 0x18, (byte) 0x2F, (byte) 0x1A, (byte) 0x1A, (byte) 0x2F,
|
||||
(byte) 0x63, (byte) 0x42, (byte) 0x38, (byte) 0x42, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
(byte) 0x63, (byte) 0x63, (byte) 0x63, (byte) 0x63,
|
||||
|
||||
// Start of Scan (section B.2.3)
|
||||
(byte) 0xFF, (byte) 0xDA, // Marker
|
||||
(byte) 0x00, (byte) 0x0C, // Length of header
|
||||
(byte) 0x03, // Number of image components
|
||||
// Scan 1: use DC/AC huff tables 0/0
|
||||
(byte) 0x01, (byte) 0x00,
|
||||
// Scan 2: use DC/AC huff tables 1/1
|
||||
(byte) 0x02, (byte) 0x11,
|
||||
// Scan 3: use DC/AC huff tables 1/1
|
||||
(byte) 0x03, (byte) 0x11,
|
||||
(byte) 0x00, (byte) 0x3F, (byte) 0x00 // Not used
|
||||
};
|
||||
|
||||
private void writeJfifHuffHeader() throws IOException
|
||||
{
|
||||
byte[] newHeader = new byte[jfifHuff100Header.length];
|
||||
|
||||
System.arraycopy(
|
||||
jfifHuff100Header, 0, newHeader, 0, jfifHuff100Header.length );
|
||||
|
||||
// Set image width in JFIF header.
|
||||
newHeader[27] = (byte) ( ( width >>> 8 ) & 0xff );
|
||||
newHeader[28] = (byte) ( width & 0xff );
|
||||
|
||||
// Set image height in JFIF header.
|
||||
newHeader[25] = (byte) ( ( height >>> 8 ) & 0xff );
|
||||
newHeader[26] = (byte) ( height & 0xff );
|
||||
|
||||
// Adjust the quality factor.
|
||||
//
|
||||
// The default quality factor is 100, therefore if
|
||||
// our quality factor does not equal 100 we must
|
||||
// scale the quantization matrices in the JFIF header.
|
||||
// Note that values are clipped to a max of 255.
|
||||
if ( qfactor != 100 )
|
||||
{
|
||||
for ( int i = 44; i < 108; ++i )
|
||||
{
|
||||
int t = ( newHeader[i] * qfactor ) / 100;
|
||||
newHeader[i] = (byte) Math.max( t, 0xff );
|
||||
}
|
||||
for ( int i = 109; i < 173; ++i )
|
||||
{
|
||||
int t = ( newHeader[i] * qfactor ) / 100;
|
||||
newHeader[i] = (byte) Math.max( t, 0xff );
|
||||
}
|
||||
}
|
||||
|
||||
// Write out buffer.
|
||||
out.write( newHeader );
|
||||
}
|
||||
|
||||
private void writeJfifNoHuffHeader() throws IOException
|
||||
{
|
||||
byte[] newHeader = new byte[jfifNoHuff100Header.length];
|
||||
|
||||
System.arraycopy(
|
||||
jfifNoHuff100Header, 0, newHeader, 0, jfifNoHuff100Header.length );
|
||||
|
||||
// Set image width in JFIF header.
|
||||
newHeader[27] = (byte) ( ( width >>> 8 ) & 0xff );
|
||||
newHeader[28] = (byte) ( width & 0xff );
|
||||
|
||||
// Set image height in JFIF header.
|
||||
newHeader[25] = (byte) ( ( height >>> 8 ) & 0xff );
|
||||
newHeader[26] = (byte) ( height & 0xff );
|
||||
|
||||
// Adjust the quality factor.
|
||||
//
|
||||
// The default quality factor is 100, therefore if
|
||||
// our quality factor does not equal 100 we must
|
||||
// scale the quantization matrices in the JFIF header.
|
||||
// Note that values are clipped to a max of 255.
|
||||
if ( qfactor != 100 )
|
||||
{
|
||||
for ( int i = 44; i < 108; ++i )
|
||||
{
|
||||
int t = ( newHeader[i] * qfactor ) / 100;
|
||||
newHeader[i] = (byte) Math.max( t, 0xff );
|
||||
}
|
||||
for ( int i = 109; i < 173; ++i )
|
||||
{
|
||||
int t = ( newHeader[i] * qfactor ) / 100;
|
||||
newHeader[i] = (byte) Math.max( t, 0xff );
|
||||
}
|
||||
}
|
||||
|
||||
// Write out buffer.
|
||||
out.write( newHeader );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
// PpmEncoder - write out an image as a PPM
|
||||
//
|
||||
// Copyright (C)1996,1998 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Encoders;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.*;
|
||||
|
||||
/// Write out an image as a PPM.
|
||||
// <P>
|
||||
// Writes an image onto a specified OutputStream in the PPM file format.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Encoders/PpmEncoder.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
// <P>
|
||||
// @see ToPpm
|
||||
|
||||
public class PpmEncoder extends ImageEncoder
|
||||
{
|
||||
|
||||
/// Constructor.
|
||||
// @param img The image to encode.
|
||||
// @param out The stream to write the PPM to.
|
||||
public PpmEncoder( Image img, OutputStream out ) throws IOException
|
||||
{
|
||||
super( img, out );
|
||||
}
|
||||
|
||||
/// Constructor.
|
||||
// @param prod The ImageProducer to encode.
|
||||
// @param out The stream to write the PPM to.
|
||||
public PpmEncoder( ImageProducer prod, OutputStream out ) throws IOException
|
||||
{
|
||||
super( prod, out );
|
||||
}
|
||||
|
||||
|
||||
void encodeStart( int width, int height ) throws IOException
|
||||
{
|
||||
writeString( out, "P6\n" );
|
||||
writeString( out, width + " " + height + "\n" );
|
||||
writeString( out, "255\n" );
|
||||
}
|
||||
|
||||
static void writeString( OutputStream out, String str ) throws IOException
|
||||
{
|
||||
byte[] buf = str.getBytes();
|
||||
out.write( buf );
|
||||
}
|
||||
|
||||
void encodePixels(
|
||||
int x, int y, int w, int h, int[] rgbPixels, int off, int scansize )
|
||||
throws IOException
|
||||
{
|
||||
byte[] ppmPixels = new byte[w * 3];
|
||||
for ( int row = 0; row < h; ++row )
|
||||
{
|
||||
int rowOff = off + row * scansize;
|
||||
for ( int col = 0; col < w; ++col )
|
||||
{
|
||||
int i = rowOff + col;
|
||||
int j = col * 3;
|
||||
ppmPixels[j ] = (byte) ( ( rgbPixels[i] & 0xff0000 ) >> 16 );
|
||||
ppmPixels[j + 1] = (byte) ( ( rgbPixels[i] & 0x00ff00 ) >> 8 );
|
||||
ppmPixels[j + 2] = (byte) ( rgbPixels[i] & 0x0000ff );
|
||||
}
|
||||
out.write( ppmPixels );
|
||||
}
|
||||
}
|
||||
|
||||
void encodeDone() throws IOException
|
||||
{
|
||||
// Nothing.
|
||||
}
|
||||
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
// CompositeFilter - compose two filters into one
|
||||
//
|
||||
// Copyright (C) 1997 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Filters;
|
||||
|
||||
import java.awt.image.*;
|
||||
import java.util.*;
|
||||
|
||||
/// Compose two filters into one.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Filters/CompositeFilter.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
|
||||
public class CompositeFilter extends ImageFilterPlus
|
||||
{
|
||||
|
||||
private ImageFilterPlus filterOne, filterTwo;
|
||||
private ImageFilter instanceOne, instanceTwo;
|
||||
|
||||
/// Constructor. Builds a filter chain with a FilteredImageSource as
|
||||
// the glue.
|
||||
public CompositeFilter( ImageProducer producer, ImageFilterPlus filterOne, ImageFilterPlus filterTwo )
|
||||
{
|
||||
super( producer );
|
||||
this.filterOne = filterOne;
|
||||
this.filterTwo = filterTwo;
|
||||
|
||||
filterOne.setSource( producer );
|
||||
ImageProducer producerOne =
|
||||
new FilteredImageSource( producer, filterOne );
|
||||
filterTwo.setSource( producerOne );
|
||||
}
|
||||
|
||||
public ImageFilter getFilterInstance( ImageConsumer consumer )
|
||||
{
|
||||
CompositeFilter instance = (CompositeFilter) clone();
|
||||
instance.instanceTwo = filterTwo.getFilterInstance( consumer );
|
||||
instance.instanceOne = filterOne.getFilterInstance( instanceTwo );
|
||||
return (ImageFilter) instance;
|
||||
}
|
||||
|
||||
|
||||
// The rest of the methods just delegate to instanceOne.
|
||||
|
||||
public void setColorModel( ColorModel model )
|
||||
{
|
||||
instanceOne.setColorModel( model );
|
||||
}
|
||||
|
||||
public void setDimensions( int width, int height )
|
||||
{
|
||||
instanceOne.setDimensions( width, height );
|
||||
}
|
||||
|
||||
public void setHints( int hintflags )
|
||||
{
|
||||
instanceOne.setHints( hintflags );
|
||||
}
|
||||
|
||||
public void setProperties( Hashtable props )
|
||||
{
|
||||
instanceOne.setProperties( props );
|
||||
}
|
||||
|
||||
public void setPixels( int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize )
|
||||
{
|
||||
instanceOne.setPixels( x, y, w, h, model, pixels, off, scansize );
|
||||
}
|
||||
|
||||
public void setPixels( int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize )
|
||||
{
|
||||
instanceOne.setPixels( x, y, w, h, model, pixels, off, scansize );
|
||||
}
|
||||
|
||||
public void imageComplete( int status )
|
||||
{
|
||||
//super.imageComplete( status );
|
||||
instanceOne.imageComplete( status );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,169 +0,0 @@
|
|||
// EdgeDetect - edge-detection filter
|
||||
//
|
||||
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Filters;
|
||||
|
||||
import java.io.*;
|
||||
import java.awt.image.*;
|
||||
import Acme.JPM.Decoders.*;
|
||||
import Acme.JPM.Encoders.*;
|
||||
|
||||
/// Edge-detection filter.
|
||||
// <IMG ALIGN=RIGHT WIDTH=202 HEIGHT=200 SRC="Earth-EdgeDetect.jpg">
|
||||
// <IMG ALIGN=RIGHT WIDTH=202 HEIGHT=200 SRC="Earth.jpg">
|
||||
// <P>
|
||||
// Outlines the edges of an image.
|
||||
// The edge detection technique used is to take the Pythagorean sum of
|
||||
// two Sobel gradient operators at 90 degrees to each other, separately
|
||||
// for each color component.
|
||||
// For more details see "Digital Image Processing" by Gonzalez and Wintz,
|
||||
// chapter 7.
|
||||
// <P>
|
||||
// This filter is slow.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Filters/EdgeDetect.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
|
||||
public class EdgeDetect extends RGBAllFilter
|
||||
{
|
||||
|
||||
// Constructor.
|
||||
public EdgeDetect( ImageProducer producer )
|
||||
{
|
||||
super( producer );
|
||||
}
|
||||
|
||||
|
||||
private static final double SCALE = 1.8D;
|
||||
|
||||
public void filterRGBAll( int width, int height, int[][] rgbPixels )
|
||||
{
|
||||
int[][] newPixels = new int[height][width];
|
||||
long sum1, sum2;
|
||||
double sum;
|
||||
int r, g, b;
|
||||
|
||||
// First and last rows are black.
|
||||
for ( int col = 0; col < width; ++col )
|
||||
{
|
||||
newPixels[0][col] = 0xff000000;
|
||||
newPixels[height - 1][col] = 0xff000000;
|
||||
}
|
||||
for ( int row = 1; row < height - 1; ++row )
|
||||
{
|
||||
// First and last columns are black too.
|
||||
newPixels[row][0] = 0xff000000;
|
||||
newPixels[row][width - 1] = 0xff000000;
|
||||
// The real pixels.
|
||||
for ( int col = 1; col < width - 1; ++col )
|
||||
{
|
||||
sum1 =
|
||||
rgbModel.getRed( rgbPixels[row - 1][col + 1] ) -
|
||||
rgbModel.getRed( rgbPixels[row - 1][col - 1] ) +
|
||||
2 * (
|
||||
rgbModel.getRed( rgbPixels[row][col + 1] ) -
|
||||
rgbModel.getRed( rgbPixels[row][col - 1] ) ) +
|
||||
rgbModel.getRed( rgbPixels[row + 1][col + 1] ) -
|
||||
rgbModel.getRed( rgbPixels[row + 1][col - 1] );
|
||||
sum2 = (
|
||||
rgbModel.getRed( rgbPixels[row + 1][col - 1] ) +
|
||||
2 * rgbModel.getRed( rgbPixels[row + 1][col] ) +
|
||||
rgbModel.getRed( rgbPixels[row + 1][col + 1] )
|
||||
) - (
|
||||
rgbModel.getRed( rgbPixels[row - 1][col - 1] ) +
|
||||
2 * rgbModel.getRed( rgbPixels[row - 1][col] ) +
|
||||
rgbModel.getRed( rgbPixels[row - 1][col + 1] )
|
||||
);
|
||||
sum = Math.sqrt( (double) ( sum1*sum1 + sum2*sum2 ) ) / SCALE;
|
||||
r = Math.min( (int) sum, 255 );
|
||||
|
||||
sum1 =
|
||||
rgbModel.getGreen( rgbPixels[row - 1][col + 1] ) -
|
||||
rgbModel.getGreen( rgbPixels[row - 1][col - 1] ) +
|
||||
2 * (
|
||||
rgbModel.getGreen( rgbPixels[row][col + 1] ) -
|
||||
rgbModel.getGreen( rgbPixels[row][col - 1] ) ) +
|
||||
rgbModel.getGreen( rgbPixels[row + 1][col + 1] ) -
|
||||
rgbModel.getGreen( rgbPixels[row + 1][col - 1] );
|
||||
sum2 = (
|
||||
rgbModel.getGreen( rgbPixels[row + 1][col - 1] ) +
|
||||
2 * rgbModel.getGreen( rgbPixels[row + 1][col] ) +
|
||||
rgbModel.getGreen( rgbPixels[row + 1][col + 1] )
|
||||
) - (
|
||||
rgbModel.getGreen( rgbPixels[row - 1][col - 1] ) +
|
||||
2 * rgbModel.getGreen( rgbPixels[row - 1][col] ) +
|
||||
rgbModel.getGreen( rgbPixels[row - 1][col + 1] )
|
||||
);
|
||||
sum = Math.sqrt( (double) ( sum1*sum1 + sum2*sum2 ) ) / SCALE;
|
||||
g = Math.min( (int) sum, 255 );
|
||||
|
||||
sum1 =
|
||||
rgbModel.getBlue( rgbPixels[row - 1][col + 1] ) -
|
||||
rgbModel.getBlue( rgbPixels[row - 1][col - 1] ) +
|
||||
2 * (
|
||||
rgbModel.getBlue( rgbPixels[row][col + 1] ) -
|
||||
rgbModel.getBlue( rgbPixels[row][col - 1] ) ) +
|
||||
rgbModel.getBlue( rgbPixels[row + 1][col + 1] ) -
|
||||
rgbModel.getBlue( rgbPixels[row + 1][col - 1] );
|
||||
sum2 = (
|
||||
rgbModel.getBlue( rgbPixels[row + 1][col - 1] ) +
|
||||
2 * rgbModel.getBlue( rgbPixels[row + 1][col] ) +
|
||||
rgbModel.getBlue( rgbPixels[row + 1][col + 1] )
|
||||
) - (
|
||||
rgbModel.getBlue( rgbPixels[row - 1][col - 1] ) +
|
||||
2 * rgbModel.getBlue( rgbPixels[row - 1][col] ) +
|
||||
rgbModel.getBlue( rgbPixels[row - 1][col + 1] )
|
||||
);
|
||||
sum = Math.sqrt( (double) ( sum1*sum1 + sum2*sum2 ) ) / SCALE;
|
||||
b = Math.min( (int) sum, 255 );
|
||||
|
||||
newPixels[row][col] =
|
||||
0xff000000 | ( r << 16 ) | ( g << 8 ) | b;
|
||||
}
|
||||
}
|
||||
setPixels( width, height, newPixels );
|
||||
}
|
||||
|
||||
|
||||
// Main routine for command-line interface.
|
||||
public static void main( String[] args )
|
||||
{
|
||||
if ( args.length != 0 )
|
||||
usage();
|
||||
ImageFilterPlus filter = new EdgeDetect( null );
|
||||
System.exit(
|
||||
ImageFilterPlus.filterStream( System.in, System.out, filter ) );
|
||||
}
|
||||
|
||||
private static void usage()
|
||||
{
|
||||
System.err.println( "usage: EdgeDetect" );
|
||||
System.exit( 1 );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,140 +0,0 @@
|
|||
// Enlarge - an ImageFilter that enlarges by pixel replication
|
||||
//
|
||||
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Filters;
|
||||
|
||||
import java.awt.image.*;
|
||||
|
||||
/// An ImageFilter that enlarges by pixel replication.
|
||||
// <P>
|
||||
// Enlarges an image an integral factor by replicating pixels.
|
||||
// The output uses the same color model as the input.
|
||||
// This filter is very fast.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Filters/Enlarge.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
// <P>
|
||||
// @see Shrink
|
||||
// @see ScaleCopy
|
||||
|
||||
public class Enlarge extends ImageFilterPlus
|
||||
{
|
||||
|
||||
private int multiplier;
|
||||
private int newWidth, newHeight;
|
||||
|
||||
/// Constructor.
|
||||
public Enlarge( ImageProducer producer, int multiplier )
|
||||
{
|
||||
super( producer );
|
||||
this.multiplier = multiplier;
|
||||
}
|
||||
|
||||
|
||||
public void setDimensions( int width, int height )
|
||||
{
|
||||
newWidth = width * multiplier;
|
||||
newHeight = height * multiplier;
|
||||
consumer.setDimensions( newWidth, newHeight );
|
||||
}
|
||||
|
||||
public void setPixels( int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize )
|
||||
{
|
||||
int newX = Math.min( x * multiplier, newWidth - 1 );
|
||||
int newY = Math.min( y * multiplier, newHeight - 1 );
|
||||
int newW = w * multiplier;
|
||||
if ( newX + newW > newWidth )
|
||||
newW = newWidth - newX;
|
||||
int newH = h * multiplier;
|
||||
if ( newY + newH > newHeight )
|
||||
newH = newHeight - newY;
|
||||
byte[] newPixels = new byte[newW * newH];
|
||||
for ( int row = 0; row < h; ++row )
|
||||
{
|
||||
for ( int col = 0; col < w; ++col )
|
||||
{
|
||||
byte pixel = pixels[row * scansize + off + col];
|
||||
for ( int i = 0; i < multiplier; ++i )
|
||||
for ( int j = 0; j < multiplier; ++j )
|
||||
{
|
||||
int newRow = row * multiplier + i;
|
||||
int newCol = col * multiplier + j;
|
||||
newPixels[newRow * newW + newCol] = pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
consumer.setPixels( newX, newY, newW, newH, model, newPixels, 0, newW );
|
||||
}
|
||||
|
||||
public void setPixels( int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize )
|
||||
{
|
||||
int newX = Math.min( x * multiplier, newWidth - 1 );
|
||||
int newY = Math.min( y * multiplier, newHeight - 1 );
|
||||
int newW = w * multiplier;
|
||||
if ( newX + newW > newWidth )
|
||||
newW = newWidth - newX;
|
||||
int newH = h * multiplier;
|
||||
if ( newY + newH > newHeight )
|
||||
newH = newHeight - newY;
|
||||
int[] newPixels = new int[newW * newH];
|
||||
for ( int row = 0; row < h; ++row )
|
||||
{
|
||||
for ( int col = 0; col < w; ++col )
|
||||
{
|
||||
int pixel = pixels[row * scansize + off + col];
|
||||
for ( int i = 0; i < multiplier; ++i )
|
||||
for ( int j = 0; j < multiplier; ++j )
|
||||
{
|
||||
int newRow = row * multiplier + i;
|
||||
int newCol = col * multiplier + j;
|
||||
newPixels[newRow * newW + newCol] = pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
consumer.setPixels( newX, newY, newW, newH, model, newPixels, 0, newW );
|
||||
}
|
||||
|
||||
|
||||
// Main routine for command-line interface.
|
||||
public static void main( String[] args )
|
||||
{
|
||||
if ( args.length != 1 )
|
||||
usage();
|
||||
ImageFilterPlus filter =
|
||||
new Enlarge( null, Integer.parseInt( args[0] ) );
|
||||
System.exit(
|
||||
ImageFilterPlus.filterStream( System.in, System.out, filter ) );
|
||||
}
|
||||
|
||||
private static void usage()
|
||||
{
|
||||
System.err.println( "usage: Enlarge <multiplier>" );
|
||||
System.exit( 1 );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,295 +0,0 @@
|
|||
// Flip - an ImageFilter that flips or rotates the image
|
||||
//
|
||||
// Copyright (C) 1997 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Filters;
|
||||
|
||||
import java.awt.image.*;
|
||||
|
||||
/// An ImageFilter that flips or rotates the image.
|
||||
// <P>
|
||||
// Flips the image left-right, top-bottom, rotates clockwise or
|
||||
// counter-clockwise, or otherwise munges the image as specified.
|
||||
// This filter is fast.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Filters/Flip.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
|
||||
public class Flip extends ImageFilterPlus
|
||||
{
|
||||
|
||||
/// The null transformation.
|
||||
public static final int FLIP_NULL = 0;
|
||||
|
||||
/// Flip left to right.
|
||||
public static final int FLIP_LR = 1;
|
||||
|
||||
/// Flip top to bottom.
|
||||
public static final int FLIP_TB = 2;
|
||||
|
||||
/// Transpose X and Y - reflection along a diagonal.
|
||||
public static final int FLIP_XY = 3;
|
||||
|
||||
/// Rotate clockwise 90 degrees.
|
||||
public static final int FLIP_CW = 4;
|
||||
|
||||
/// Rotate counter-clockwise 90 degrees.
|
||||
public static final int FLIP_CCW = 5;
|
||||
|
||||
/// Rotate 180 degrees.
|
||||
public static final int FLIP_R180 = 6;
|
||||
|
||||
private int flipType;
|
||||
private int width, height;
|
||||
private int newWidth, newHeight;
|
||||
|
||||
/// Constructor.
|
||||
public Flip( ImageProducer producer, int flipType )
|
||||
{
|
||||
super( producer, true );
|
||||
this.flipType = flipType;
|
||||
}
|
||||
|
||||
|
||||
public void setDimensions( int width, int height )
|
||||
{
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
switch ( flipType )
|
||||
{
|
||||
case FLIP_NULL:
|
||||
case FLIP_LR:
|
||||
case FLIP_TB:
|
||||
case FLIP_R180:
|
||||
newWidth = width;
|
||||
newHeight = height;
|
||||
break;
|
||||
case FLIP_XY:
|
||||
case FLIP_CW:
|
||||
case FLIP_CCW:
|
||||
newWidth = height;
|
||||
newHeight = width;
|
||||
break;
|
||||
}
|
||||
consumer.setDimensions( newWidth, newHeight );
|
||||
}
|
||||
|
||||
public void setPixels( int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize )
|
||||
{
|
||||
int newX = x;
|
||||
int newY = y;
|
||||
int newW = w;
|
||||
int newH = h;
|
||||
switch ( flipType )
|
||||
{
|
||||
case FLIP_NULL:
|
||||
break;
|
||||
case FLIP_LR:
|
||||
newX = width - ( x + w );
|
||||
break;
|
||||
case FLIP_TB:
|
||||
newY = height - ( y + h );
|
||||
break;
|
||||
case FLIP_XY:
|
||||
newW = h;
|
||||
newH = w;
|
||||
newX = y;
|
||||
newY = x;
|
||||
break;
|
||||
case FLIP_CW:
|
||||
newW = h;
|
||||
newH = w;
|
||||
newX = height - ( y + h );
|
||||
newY = x;
|
||||
break;
|
||||
case FLIP_CCW:
|
||||
newW = h;
|
||||
newH = w;
|
||||
newX = y;
|
||||
newY = width - ( x + w );
|
||||
break;
|
||||
case FLIP_R180:
|
||||
newX = width - ( x + w );
|
||||
newY = height - ( y + h );
|
||||
break;
|
||||
}
|
||||
byte[] newPixels = new byte[newW * newH];
|
||||
for ( int row = 0; row < h; ++row )
|
||||
{
|
||||
for ( int col = 0; col < w; ++col )
|
||||
{
|
||||
int index = row * scansize + off + col;
|
||||
int newRow = row;
|
||||
int newCol = col;
|
||||
switch ( flipType )
|
||||
{
|
||||
case FLIP_NULL:
|
||||
break;
|
||||
case FLIP_LR:
|
||||
newCol = w - col - 1;
|
||||
break;
|
||||
case FLIP_TB:
|
||||
newRow = h - row - 1;
|
||||
break;
|
||||
case FLIP_XY:
|
||||
newRow = col;
|
||||
newCol = row;
|
||||
break;
|
||||
case FLIP_CW:
|
||||
newRow = col;
|
||||
newCol = h - row - 1;;
|
||||
break;
|
||||
case FLIP_CCW:
|
||||
newRow = w - col - 1;
|
||||
newCol = row;
|
||||
break;
|
||||
case FLIP_R180:
|
||||
newRow = h - row - 1;
|
||||
newCol = w - col - 1;
|
||||
break;
|
||||
}
|
||||
int newIndex = newRow * newW + newCol;
|
||||
newPixels[newIndex] = pixels[index];
|
||||
}
|
||||
}
|
||||
consumer.setPixels( newX, newY, newW, newH, model, newPixels, 0, newW );
|
||||
}
|
||||
|
||||
public void setPixels( int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize )
|
||||
{
|
||||
int newX = x;
|
||||
int newY = y;
|
||||
int newW = w;
|
||||
int newH = h;
|
||||
switch ( flipType )
|
||||
{
|
||||
case FLIP_NULL:
|
||||
break;
|
||||
case FLIP_LR:
|
||||
newX = width - ( x + w );
|
||||
break;
|
||||
case FLIP_TB:
|
||||
newY = height - ( y + h );
|
||||
break;
|
||||
case FLIP_XY:
|
||||
newW = h;
|
||||
newH = w;
|
||||
newX = y;
|
||||
newY = x;
|
||||
break;
|
||||
case FLIP_CW:
|
||||
newW = h;
|
||||
newH = w;
|
||||
newX = height - ( y + h );
|
||||
newY = x;
|
||||
break;
|
||||
case FLIP_CCW:
|
||||
newW = h;
|
||||
newH = w;
|
||||
newX = y;
|
||||
newY = width - ( x + w );
|
||||
break;
|
||||
case FLIP_R180:
|
||||
newX = width - ( x + w );
|
||||
newY = height - ( y + h );
|
||||
break;
|
||||
}
|
||||
int[] newPixels = new int[newW * newH];
|
||||
for ( int row = 0; row < h; ++row )
|
||||
{
|
||||
for ( int col = 0; col < w; ++col )
|
||||
{
|
||||
int index = row * scansize + off + col;
|
||||
int newRow = row;
|
||||
int newCol = col;
|
||||
switch ( flipType )
|
||||
{
|
||||
case FLIP_NULL:
|
||||
break;
|
||||
case FLIP_LR:
|
||||
newCol = w - col - 1;
|
||||
break;
|
||||
case FLIP_TB:
|
||||
newRow = h - row - 1;
|
||||
break;
|
||||
case FLIP_XY:
|
||||
newRow = col;
|
||||
newCol = row;
|
||||
break;
|
||||
case FLIP_CW:
|
||||
newRow = col;
|
||||
newCol = h - row - 1;;
|
||||
break;
|
||||
case FLIP_CCW:
|
||||
newRow = w - col - 1;
|
||||
newCol = row;
|
||||
break;
|
||||
case FLIP_R180:
|
||||
newRow = h - row - 1;
|
||||
newCol = w - col - 1;
|
||||
break;
|
||||
}
|
||||
int newIndex = newRow * newW + newCol;
|
||||
newPixels[newIndex] = pixels[index];
|
||||
}
|
||||
}
|
||||
consumer.setPixels( newX, newY, newW, newH, model, newPixels, 0, newW );
|
||||
}
|
||||
|
||||
|
||||
// Main routine for command-line interface.
|
||||
public static void main( String[] args )
|
||||
{
|
||||
if ( args.length != 1 )
|
||||
usage();
|
||||
int flipType = FLIP_NULL;
|
||||
if ( args[0].equalsIgnoreCase( "-lr" ) )
|
||||
flipType = FLIP_LR;
|
||||
else if ( args[0].equalsIgnoreCase( "-tb" ) )
|
||||
flipType = FLIP_TB;
|
||||
else if ( args[0].equalsIgnoreCase( "-xy" ) )
|
||||
flipType = FLIP_XY;
|
||||
else if ( args[0].equalsIgnoreCase( "-cw" ) )
|
||||
flipType = FLIP_CW;
|
||||
else if ( args[0].equalsIgnoreCase( "-ccw" ) )
|
||||
flipType = FLIP_CCW;
|
||||
else if ( args[0].equalsIgnoreCase( "-r180" ) )
|
||||
flipType = FLIP_R180;
|
||||
else
|
||||
usage();
|
||||
ImageFilterPlus filter = new Flip( null, flipType );
|
||||
System.exit(
|
||||
ImageFilterPlus.filterStream( System.in, System.out, filter ) );
|
||||
}
|
||||
|
||||
private static void usage()
|
||||
{
|
||||
System.err.println( "usage: Flip -lr|-tb|-xy|-cw|-ccw|-r180" );
|
||||
System.exit( 1 );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,148 +0,0 @@
|
|||
// Gamma - gamma-correction filter
|
||||
//
|
||||
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Filters;
|
||||
|
||||
import java.awt.image.*;
|
||||
|
||||
/// Gamma-correction filter.
|
||||
// <P>
|
||||
// Gamma correction fixes a form of color distortion common to many monitors.
|
||||
// Values less than 1.0 darken the image, and greater than 1.0 lighten it.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Filters/Gamma.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
|
||||
public class Gamma extends RGBBlockFilter
|
||||
{
|
||||
|
||||
private double rValue, gValue, bValue;
|
||||
|
||||
/// Constructor, single exponent.
|
||||
public Gamma( ImageProducer producer, double value )
|
||||
{
|
||||
this( producer, value, value, value );
|
||||
}
|
||||
|
||||
/// Constructor, different exponents for R G and B.
|
||||
public Gamma( ImageProducer producer, double rValue, double gValue, double bValue )
|
||||
{
|
||||
super( producer );
|
||||
this.rValue = rValue;
|
||||
this.gValue = gValue;
|
||||
this.bValue = bValue;
|
||||
}
|
||||
|
||||
|
||||
private int[] rTable, gTable, bTable;
|
||||
|
||||
public int[][] filterRGBBlock( int x, int y, int width, int height, int[][] rgbPixels )
|
||||
{
|
||||
initialize();
|
||||
for ( int row = 0; row < height; ++row )
|
||||
for ( int col = 0; col < width; ++col )
|
||||
{
|
||||
int rgb = rgbPixels[row][col];
|
||||
int a = ( rgb >> 24 ) & 0xff;
|
||||
int r = ( rgb >> 16 ) & 0xff;
|
||||
int g = ( rgb >> 8 ) & 0xff;
|
||||
int b = rgb & 0xff;
|
||||
r = rTable[r];
|
||||
g = gTable[g];
|
||||
b = bTable[b];
|
||||
rgbPixels[row][col] =
|
||||
( a << 24 ) | ( r << 16 ) | ( g << 8 ) | b;
|
||||
}
|
||||
return rgbPixels;
|
||||
}
|
||||
|
||||
|
||||
private boolean initialized = false;
|
||||
|
||||
private void initialize()
|
||||
{
|
||||
if ( initialized )
|
||||
return;
|
||||
initialized = true;
|
||||
|
||||
rTable = buildTable( rValue );
|
||||
|
||||
if ( gValue == rValue )
|
||||
gTable = rTable;
|
||||
else
|
||||
gTable = buildTable( gValue );
|
||||
|
||||
if ( bValue == rValue )
|
||||
bTable = rTable;
|
||||
else if ( bValue == gValue )
|
||||
bTable = gTable;
|
||||
else
|
||||
bTable = buildTable( bValue );
|
||||
}
|
||||
|
||||
private int[] buildTable( double gamma )
|
||||
{
|
||||
int[] table = new int[256];
|
||||
double oneOverGamma = 1.0D / gamma;
|
||||
for ( int i = 0; i < 256; ++i )
|
||||
{
|
||||
int v = (int) (
|
||||
( 255.0D * Math.pow( i / 255.0D, oneOverGamma ) ) + 0.5D );
|
||||
if ( v > 255 )
|
||||
v = 255;
|
||||
table[i] = v;
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
// Main routine for command-line interface.
|
||||
public static void main( String[] args )
|
||||
{
|
||||
ImageFilterPlus filter = null;
|
||||
if ( args.length == 1 )
|
||||
filter = new Gamma( null, Double.valueOf( args[0] ).doubleValue() );
|
||||
else if ( args.length == 3 )
|
||||
filter = new Gamma( null,
|
||||
Double.valueOf( args[0] ).doubleValue(),
|
||||
Double.valueOf( args[1] ).doubleValue(),
|
||||
Double.valueOf( args[2] ).doubleValue() );
|
||||
else
|
||||
usage();
|
||||
System.exit(
|
||||
ImageFilterPlus.filterStream( System.in, System.out, filter ) );
|
||||
}
|
||||
|
||||
private static void usage()
|
||||
{
|
||||
System.err.println( "usage: Gamma <value>" );
|
||||
System.err.println( "or: Gamma <rValue> <gValue> <bValue>" );
|
||||
System.exit( 1 );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,160 +0,0 @@
|
|||
// ImageFilterPlus - an ImageFilter with some extra features and bug fixes
|
||||
//
|
||||
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Filters;
|
||||
|
||||
import java.awt.image.*;
|
||||
import java.io.*;
|
||||
import Acme.JPM.Decoders.*;
|
||||
import Acme.JPM.Encoders.*;
|
||||
|
||||
/// An ImageFilter with some extra features and bug fixes.
|
||||
// <P>
|
||||
// You can use an image filter to turn one Image into another via
|
||||
// a FilteredImageSource, e.g.:
|
||||
// <BLOCKQUOTE><CODE><PRE>
|
||||
// Image newImage = comp.createImage( new FilteredImageSource(
|
||||
// oldImage.getSource(), new SomeFilter( oldImage.getSource() ) ) );
|
||||
// </PRE></CODE></BLOCKQUOTE>
|
||||
// Or use the convenient utility JPMUtils.filterImage():
|
||||
// <BLOCKQUOTE><CODE><PRE>
|
||||
// Image newImage = JPMUtils.filterImage(
|
||||
// comp, SomeFilter( oldImage.getSource() ) );
|
||||
// </PRE></CODE></BLOCKQUOTE>
|
||||
// <P>
|
||||
// You can also use image filters from the command line, reading PPM
|
||||
// from stdin and writing PPM to stdout, if you add code like the following
|
||||
// to each filter:
|
||||
// <BLOCKQUOTE><CODE><PRE>
|
||||
// System.exit(
|
||||
// ImageFilterPlus.filterStream(
|
||||
// System.in, System.out,
|
||||
// new SomeFilter( null ) ) );
|
||||
// </PRE></CODE></BLOCKQUOTE>
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Filters/ImageFilterPlus.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
|
||||
public class ImageFilterPlus extends ImageFilter
|
||||
{
|
||||
|
||||
private ImageProducer producer;
|
||||
private boolean pixelOrderChanges;
|
||||
|
||||
/// Constructor.
|
||||
// @param producer The ImageProducer is required, so that we can
|
||||
// remove ourself from its consumers list when we're done.
|
||||
// However, if you don't have the producer available when you want
|
||||
// to create the filter, you can pass in null and set it later
|
||||
// via setSource().
|
||||
public ImageFilterPlus( ImageProducer producer )
|
||||
{
|
||||
this( producer, false );
|
||||
}
|
||||
|
||||
/// Constructor, with pixel order change.
|
||||
// @param producer The ImageProducer is required, so that we can
|
||||
// remove ourself from its consumers list when we're done.
|
||||
// However, if you don't have the producer available when you want
|
||||
// to create the filter, you can pass in null and set it later
|
||||
// via setSource().
|
||||
// @param pixelOrderChanges If the filter may output pixels in a different
|
||||
// order from the one they were delivered in, this flag must be set.
|
||||
public ImageFilterPlus( ImageProducer producer, boolean pixelOrderChanges )
|
||||
{
|
||||
setSource( producer );
|
||||
this.pixelOrderChanges = pixelOrderChanges;
|
||||
}
|
||||
|
||||
|
||||
/// The default color model - useful for comparisons.
|
||||
public static final ColorModel rgbModel = ColorModel.getRGBdefault();
|
||||
|
||||
|
||||
/// Return the ImageProducer for this filter.
|
||||
public ImageProducer getSource()
|
||||
{
|
||||
return producer;
|
||||
}
|
||||
|
||||
/// Set the ImageProducer for this filter, if it wasn't set by the
|
||||
// constructor.
|
||||
public void setSource( ImageProducer producer )
|
||||
{
|
||||
this.producer = producer;
|
||||
}
|
||||
|
||||
|
||||
/// Set the hint flags. If the pixel order may change, we have to
|
||||
// turn off the TOPDOWNLEFTRIGHT flag; otherwise the flags are passed
|
||||
// through unmodified.
|
||||
public void setHints( int hintflags )
|
||||
{
|
||||
if ( pixelOrderChanges )
|
||||
hintflags &= ~TOPDOWNLEFTRIGHT;
|
||||
consumer.setHints( hintflags );
|
||||
}
|
||||
|
||||
|
||||
/// This routine fixes a bug in java.awt.image.ImageFilter. All
|
||||
// ImageConsumers are required remove themselves from the producer's
|
||||
// list when they're done reading. If they don't do this then some
|
||||
// producers will generate an error. The standard ImageFilter class
|
||||
// fails to do this, but this one does it.
|
||||
public void imageComplete( int status )
|
||||
{
|
||||
if ( status != ImageConsumer.SINGLEFRAMEDONE )
|
||||
producer.removeConsumer( this );
|
||||
super.imageComplete( status );
|
||||
}
|
||||
|
||||
|
||||
/// Filter a PPM InputStream to a PPM OutputStream.
|
||||
// <P>
|
||||
// Create the filter with a null producer, and this routine will
|
||||
// fill it in for you.
|
||||
// @return a status code suitable for use with System.exit().
|
||||
public static int filterStream( InputStream in, OutputStream out, ImageFilterPlus filter )
|
||||
{
|
||||
ImageDecoder producer = new PpmDecoder( in );
|
||||
filter.setSource( producer );
|
||||
try
|
||||
{
|
||||
ImageEncoder consumer = new PpmEncoder(
|
||||
new FilteredImageSource( producer, filter ), out );
|
||||
consumer.encode();
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
System.err.println( e.toString() );
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
// Invert - color-inversion filter
|
||||
//
|
||||
// Copyright (C) 1997 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Filters;
|
||||
|
||||
import java.awt.image.*;
|
||||
|
||||
/// Color-inversion filter.
|
||||
// <P>
|
||||
// Switches black for white, and all the other colors too.
|
||||
// This filter is very fast.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Filters/Invert.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
|
||||
public class Invert extends RGBBlockFilter
|
||||
{
|
||||
|
||||
/// Constructor.
|
||||
public Invert( ImageProducer producer )
|
||||
{
|
||||
super( producer );
|
||||
}
|
||||
|
||||
|
||||
public int[][] filterRGBBlock( int x, int y, int width, int height, int[][] rgbPixels )
|
||||
{
|
||||
for ( int row = 0; row < height; ++row )
|
||||
for ( int col = 0; col < width; ++col )
|
||||
{
|
||||
int rgb = rgbPixels[row][col];
|
||||
int alpha = rgb & 0xff000000;
|
||||
int rest = ( ~ rgb ) & 0x00ffffff;
|
||||
rgbPixels[row][col] = alpha | rest;
|
||||
}
|
||||
return rgbPixels;
|
||||
}
|
||||
|
||||
|
||||
// Main routine for command-line interface.
|
||||
public static void main( String[] args )
|
||||
{
|
||||
ImageFilterPlus filter = null;
|
||||
if ( args.length == 0 )
|
||||
filter = new Invert( null );
|
||||
else
|
||||
usage();
|
||||
System.exit(
|
||||
ImageFilterPlus.filterStream( System.in, System.out, filter ) );
|
||||
}
|
||||
|
||||
private static void usage()
|
||||
{
|
||||
System.err.println( "usage: Invert" );
|
||||
System.exit( 1 );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
// Margin - an ImageFilter that adds a margin to an image
|
||||
//
|
||||
// Copyright (C) 1997 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Filters;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
|
||||
/// An ImageFilter that adds a margin to an image.
|
||||
// <P>
|
||||
// Adds a margin of a specified color and width around an image.
|
||||
// The output uses the same color model as the input.
|
||||
// This filter is very fast.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Filters/Margin.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
|
||||
public class Margin extends ImageFilterPlus
|
||||
{
|
||||
|
||||
private Color color;
|
||||
private int size;
|
||||
private int width, height;
|
||||
private int newWidth;
|
||||
|
||||
/// Constructor.
|
||||
public Margin( ImageProducer producer, Color color, int size )
|
||||
{
|
||||
super( producer, true );
|
||||
this.color = color;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
|
||||
public void setDimensions( int width, int height )
|
||||
{
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
newWidth = width + size * 2;
|
||||
consumer.setDimensions( newWidth, height + size * 2 );
|
||||
}
|
||||
|
||||
private boolean started = false;
|
||||
|
||||
private void start()
|
||||
{
|
||||
started = true;
|
||||
int rgb = color.getRGB();
|
||||
|
||||
int[] fullRow = new int[newWidth];
|
||||
for ( int col = 0; col < newWidth; ++col )
|
||||
fullRow[col] = rgb;
|
||||
for ( int row = 0; row < size; ++row )
|
||||
{
|
||||
consumer.setPixels(
|
||||
0, row, newWidth, 1, rgbModel, fullRow, 0, newWidth );
|
||||
consumer.setPixels(
|
||||
0, size + height + row, newWidth, 1, rgbModel, fullRow, 0,
|
||||
newWidth );
|
||||
}
|
||||
|
||||
int[] sideRow = new int[size];
|
||||
for ( int col = 0; col < size; ++col )
|
||||
sideRow[col] = rgb;
|
||||
for ( int row = 0; row < height; ++row )
|
||||
{
|
||||
consumer.setPixels(
|
||||
0, size + row, size, 1, rgbModel, sideRow, 0, size );
|
||||
consumer.setPixels(
|
||||
size + width, size + row, size, 1, rgbModel, sideRow, 0, size );
|
||||
}
|
||||
}
|
||||
|
||||
public void setPixels( int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize )
|
||||
{
|
||||
if ( ! started )
|
||||
start();
|
||||
consumer.setPixels(
|
||||
x + size, y + size, w, h, model, pixels, off, scansize );
|
||||
}
|
||||
|
||||
public void setPixels( int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize )
|
||||
{
|
||||
if ( ! started )
|
||||
start();
|
||||
consumer.setPixels(
|
||||
x + size, y + size, w, h, model, pixels, off, scansize );
|
||||
}
|
||||
|
||||
|
||||
// Main routine for command-line interface.
|
||||
public static void main( String[] args )
|
||||
{
|
||||
if ( args.length != 1 )
|
||||
usage();
|
||||
ImageFilterPlus filter =
|
||||
new Margin( null, Color.black, Integer.parseInt( args[0] ) );
|
||||
System.exit(
|
||||
ImageFilterPlus.filterStream( System.in, System.out, filter ) );
|
||||
}
|
||||
|
||||
private static void usage()
|
||||
{
|
||||
System.err.println( "usage: Margin <size>" );
|
||||
System.exit( 1 );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,141 +0,0 @@
|
|||
// Oil - oil-transfer filter
|
||||
//
|
||||
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Filters;
|
||||
|
||||
import java.awt.image.*;
|
||||
|
||||
/// Oil-transfer filter.
|
||||
// <IMG ALIGN=RIGHT WIDTH=202 HEIGHT=200 SRC="Earth-Oil.jpg">
|
||||
// <IMG ALIGN=RIGHT WIDTH=202 HEIGHT=200 SRC="Earth.jpg">
|
||||
// <P>
|
||||
// The oil transfer is described in "Beyond Photography" by Holzmann,
|
||||
// chapter 4, photo 7.
|
||||
// It's a sort of localized smearing.
|
||||
// The parameter controls the size of the smeared area, with a default of 3.
|
||||
// <P>
|
||||
// This filter is very slow.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Filters/Oil.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
|
||||
public class Oil extends RGBAllFilter
|
||||
{
|
||||
|
||||
private int n;
|
||||
|
||||
/// Constructor.
|
||||
public Oil( ImageProducer producer, int n )
|
||||
{
|
||||
super( producer );
|
||||
this.n = n;
|
||||
}
|
||||
|
||||
/// Constructor, default value.
|
||||
public Oil( ImageProducer producer )
|
||||
{
|
||||
this( producer, 3 );
|
||||
}
|
||||
|
||||
|
||||
public void filterRGBAll( int width, int height, int[][] rgbPixels )
|
||||
{
|
||||
int[][] newPixels = new int[height][width];
|
||||
int[] rHist = new int[256];
|
||||
int[] gHist = new int[256];
|
||||
int[] bHist = new int[256];
|
||||
|
||||
for ( int row = 0; row < height; ++row )
|
||||
{
|
||||
for ( int col = 0; col < width; ++col )
|
||||
{
|
||||
for ( int i = 0; i < 256; ++i )
|
||||
rHist[i] = gHist[i] = bHist[i] =0;
|
||||
for ( int drow = row - n; drow <= row + n; ++drow )
|
||||
if ( drow >= 0 && drow < height )
|
||||
for ( int dcol = col - n; dcol <= col + n; ++dcol )
|
||||
if ( dcol >= 0 && dcol < width )
|
||||
{
|
||||
int rgb = rgbPixels[drow][dcol];
|
||||
rHist[( rgb >> 16 ) & 0xff]++;
|
||||
gHist[( rgb >> 8 ) & 0xff]++;
|
||||
bHist[rgb & 0xff]++;
|
||||
}
|
||||
int r = 0, g = 0, b = 0;
|
||||
for ( int i = 1; i < 256; ++i )
|
||||
{
|
||||
if ( rHist[i] > rHist[r] )
|
||||
r = i;
|
||||
if ( gHist[i] > gHist[g] )
|
||||
g = i;
|
||||
if ( bHist[i] > bHist[b] )
|
||||
b = i;
|
||||
}
|
||||
newPixels[row][col] =
|
||||
0xff000000 | ( r << 16 ) | ( g << 8 ) | b;
|
||||
}
|
||||
}
|
||||
setPixels( width, height, newPixels );
|
||||
}
|
||||
|
||||
|
||||
// Main routine for command-line interface.
|
||||
public static void main( String[] args )
|
||||
{
|
||||
int n = -1;
|
||||
int argc = args.length;
|
||||
int argn;
|
||||
for ( argn = 0; argn < argc && args[argn].charAt( 0 ) == '-'; ++argn )
|
||||
{
|
||||
if ( args[argn].equals( "-n" ) && argn + 1 < argc )
|
||||
{
|
||||
++argn;
|
||||
n = Integer.parseInt( args[argn] );
|
||||
}
|
||||
else
|
||||
usage();
|
||||
}
|
||||
if ( argn != argc )
|
||||
usage();
|
||||
|
||||
ImageFilterPlus filter;
|
||||
if ( n == -1 )
|
||||
filter = new Oil( null );
|
||||
else
|
||||
filter = new Oil( null, n );
|
||||
System.exit(
|
||||
ImageFilterPlus.filterStream( System.in, System.out, filter ) );
|
||||
}
|
||||
|
||||
private static void usage()
|
||||
{
|
||||
System.err.println( "usage: Oil [-n N]" );
|
||||
System.exit( 1 );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,170 +0,0 @@
|
|||
// RGBAllFilter - an ImageFilter that grabs the whole image
|
||||
//
|
||||
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Filters;
|
||||
|
||||
import java.awt.image.*;
|
||||
|
||||
/// An ImageFilter that grabs the whole image.
|
||||
// <P>
|
||||
// Many image filters need to work on the whole image at once.
|
||||
// This class collects up the image and hands it to a single
|
||||
// routine for processing.
|
||||
// <P>
|
||||
// Also, because Java's image classes allow each setPixels() call to
|
||||
// use a different color model, we have to convert all pixels into
|
||||
// the default RGB model.
|
||||
// <P>
|
||||
// Here's a sample RGBAllFilter that smooths an image by averaging
|
||||
// nine adjacent pixels.
|
||||
// <BLOCKQUOTE><CODE><PRE>
|
||||
// class SmoothFilter extends RGBAllFilter
|
||||
// {
|
||||
// public void filterRGBAll( int width, int height, int[][] rgbPixels )
|
||||
// {
|
||||
// int[][] newPixels = new int[height][width];
|
||||
// for ( int row = 0; row < height; ++row )
|
||||
// for ( int col = 0; col < width; ++col )
|
||||
// {
|
||||
// int a = 0, r = 0, g = 0, b = 0, c = 0;
|
||||
// for ( int subrow = row - 1; subrow <= row + 1; ++subrow )
|
||||
// if ( subrow >= 0 && subrow < height )
|
||||
// for ( int subcol = col - 1; subcol <= col + 1; ++subcol )
|
||||
// if ( subcol >= 0 && subcol < width )
|
||||
// {
|
||||
// int pixel = rgbPixels[subrow][subcol];
|
||||
// a += rgbModel.getAlpha( pixel );
|
||||
// r += rgbModel.getRed( pixel );
|
||||
// g += rgbModel.getGreen( pixel );
|
||||
// b += rgbModel.getBlue( pixel );
|
||||
// ++c;
|
||||
// }
|
||||
// a /= c;
|
||||
// r /= c;
|
||||
// g /= c;
|
||||
// b /= c;
|
||||
// newPixels[row][col] =
|
||||
// ( a << 24 ) | ( r << 16 ) | ( g << 8 ) | b;
|
||||
// }
|
||||
// setPixels( width, height, newPixels );
|
||||
// }
|
||||
// }
|
||||
// </PRE></CODE></BLOCKQUOTE>
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Filters/RGBAllFilter.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
|
||||
public abstract class RGBAllFilter extends ImageFilterPlus
|
||||
{
|
||||
|
||||
private int width = -1, height = -1;
|
||||
private int[][] rgbPixels = null;
|
||||
|
||||
public RGBAllFilter( ImageProducer producer )
|
||||
{
|
||||
super( producer );
|
||||
}
|
||||
|
||||
|
||||
/// This is the routine that subclasses must implement.
|
||||
// It gets the entire image as an int[height][width] in the default
|
||||
// RGB color model. It should call setPixels() with a filtered array,
|
||||
// same color model.
|
||||
public abstract void filterRGBAll( int width, int height, int[][] rgbPixels );
|
||||
|
||||
|
||||
/// The version of setPixels() that gets called by the subclass.
|
||||
public void setPixels( int newWidth, int newHeight, int[][] newPixels )
|
||||
{
|
||||
// Send it on to the consumer.
|
||||
consumer.setDimensions( newWidth, newHeight );
|
||||
for ( int row = 0; row < newHeight; ++row )
|
||||
consumer.setPixels(
|
||||
0, row, newWidth, 1, rgbModel, newPixels[row], 0, newWidth );
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void setColorModel( ColorModel model )
|
||||
{
|
||||
consumer.setColorModel( rgbModel );
|
||||
}
|
||||
|
||||
public void setDimensions( int width, int height )
|
||||
{
|
||||
if ( width == this.width && height == this.height )
|
||||
return;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
rgbPixels = new int[height][width];
|
||||
}
|
||||
|
||||
public void setPixels( int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize )
|
||||
{
|
||||
for ( int row = 0; row < h; ++row )
|
||||
{
|
||||
int rowOffsetIn = row * scansize + off;
|
||||
for ( int col = 0; col < w; ++col )
|
||||
rgbPixels[y + row][x + col] =
|
||||
model.getRGB( pixels[rowOffsetIn + col] & 0xff );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setPixels( int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize )
|
||||
{
|
||||
for ( int row = 0; row < h; ++row )
|
||||
{
|
||||
int rowOffsetIn = row * scansize + off;
|
||||
if ( model == rgbModel )
|
||||
System.arraycopy(
|
||||
pixels, rowOffsetIn, rgbPixels[y + row], x, w );
|
||||
else
|
||||
for ( int col = 0; col < w; ++col )
|
||||
rgbPixels[y + row][x + col] =
|
||||
model.getRGB( pixels[rowOffsetIn + col] );
|
||||
}
|
||||
}
|
||||
|
||||
public void imageComplete( int status )
|
||||
{
|
||||
if ( status == ImageConsumer.IMAGEERROR ||
|
||||
status == ImageConsumer.IMAGEABORTED )
|
||||
{
|
||||
super.imageComplete( status );
|
||||
return;
|
||||
}
|
||||
|
||||
// Do the actual work.
|
||||
filterRGBAll( width, height, rgbPixels );
|
||||
|
||||
// And we're done.
|
||||
super.imageComplete( status );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,135 +0,0 @@
|
|||
// RGBBlockFilter - more efficient RGB ImageFilter
|
||||
//
|
||||
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Filters;
|
||||
|
||||
import java.awt.image.*;
|
||||
|
||||
/// More efficient RGB ImageFilter.
|
||||
// <P>
|
||||
// Similar in concept to java.awt.image.RGBImageFilter, but designed
|
||||
// to run more efficiently when filtering large images.
|
||||
// <P>
|
||||
// As with RGBImageFilter, you only have to implement a single routine
|
||||
// to use the filter. However, RGBImageFilter's routine filters a single
|
||||
// pixel at a time. This means a lot of routine-calling overhead.
|
||||
// RGBBlockFilter filters a block at a time.
|
||||
// <P>
|
||||
// Here's a sample RGBBlockFilter that makes an image translucent
|
||||
// by setting all the alpha values to 0x80:
|
||||
// <BLOCKQUOTE><CODE><PRE>
|
||||
// class TranslucentFilter extends RGBBlockFilter
|
||||
// {
|
||||
// public int[] filterRGBBlock(
|
||||
// int x, int y, int width, int height, int[][] rgbPixels )
|
||||
// {
|
||||
// for ( int row = 0; row < height; ++row )
|
||||
// for ( int col = 0; col < width; ++col )
|
||||
// rgbPixels[row][col] =
|
||||
// ( rgbPixels[row][col] & 0x00ffffff ) | 0x80000000;
|
||||
// return rgbPixels;
|
||||
// }
|
||||
// }
|
||||
// </PRE></CODE></BLOCKQUOTE>
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Filters/RGBBlockFilter.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
|
||||
public abstract class RGBBlockFilter extends ImageFilterPlus
|
||||
{
|
||||
|
||||
public RGBBlockFilter( ImageProducer producer )
|
||||
{
|
||||
super( producer );
|
||||
}
|
||||
|
||||
|
||||
/// This is the routine that subclasses must implement.
|
||||
// It gets a block of the image as an int[height][width] in the default
|
||||
// RGB color model. It should return a filtered array, same size
|
||||
// and same model.
|
||||
public abstract int[][] filterRGBBlock(
|
||||
int x, int y, int width, int height, int[][] rgbPixels );
|
||||
|
||||
|
||||
public void setColorModel( ColorModel model )
|
||||
{
|
||||
consumer.setColorModel( rgbModel );
|
||||
}
|
||||
|
||||
/// Byte version of setPixels reformats the pixels to RGB and the
|
||||
// array to 2 dimensions.
|
||||
public void setPixels(
|
||||
int x, int y, int width, int height, ColorModel model,
|
||||
byte[] pixels, int offset, int scansize )
|
||||
{
|
||||
int[][] rgbPixels = new int[height][width];
|
||||
for ( int row = 0; row < height; ++row )
|
||||
{
|
||||
int rowOffsetIn = offset + row * scansize;
|
||||
for ( int col = 0; col < width; ++col )
|
||||
rgbPixels[row][col] =
|
||||
model.getRGB( pixels[rowOffsetIn + col] & 0xff );
|
||||
}
|
||||
setPixels( x, y, width, height, rgbPixels );
|
||||
}
|
||||
|
||||
/// Int version of setPixels reformats the array to 2 dimensions.
|
||||
public void setPixels(
|
||||
int x, int y, int width, int height, ColorModel model,
|
||||
int[] pixels, int offset, int scansize )
|
||||
{
|
||||
int[][] rgbPixels = new int[height][width];
|
||||
for ( int row = 0; row < height; ++row )
|
||||
{
|
||||
int rowOffsetIn = offset + row * scansize;
|
||||
int rowOffsetOut = row * width;
|
||||
// Convert color models if necessary.
|
||||
if ( model == rgbModel )
|
||||
System.arraycopy(
|
||||
pixels, rowOffsetIn, rgbPixels[row], 0, width );
|
||||
else
|
||||
for ( int col = 0; col < width; ++col )
|
||||
rgbPixels[row][col] =
|
||||
model.getRGB( pixels[rowOffsetIn + col] );
|
||||
}
|
||||
setPixels( x, y, width, height, rgbPixels );
|
||||
}
|
||||
|
||||
/// Call the filter routine, and send the results to the consumer.
|
||||
private void setPixels( int x, int y, int width, int height, int[][] rgbPixels )
|
||||
{
|
||||
int[][] newPixels = filterRGBBlock( x, y, width, height, rgbPixels );
|
||||
|
||||
// And send it on to the consumer.
|
||||
for ( int row = 0; row < height; ++row )
|
||||
consumer.setPixels(
|
||||
x, y + row, width, 1, rgbModel, newPixels[row], 0, width );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
// Rotate - rotate an image by some angle
|
||||
//
|
||||
// Copyright (C) 1997 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Filters;
|
||||
|
||||
import java.awt.image.*;
|
||||
|
||||
/// Rotate an image by some angle.
|
||||
// <P>
|
||||
// Rotates an image by the specified angle.
|
||||
// The angle is in degrees measured counter-clockwise.
|
||||
// It can be negative, but it should be between -90 and 90
|
||||
// or the resulting image will be unreasonably large.
|
||||
// Staying between -45 and 45 is best.
|
||||
// <P>
|
||||
// The rotation algorithm is Alan Paeth's three-shear method, described
|
||||
// in "A Fast Algorithm for General Raster Rotation", Graphics Interface
|
||||
// '86, pp. 77-81.
|
||||
// <P>
|
||||
// This filter is slow.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Filters/Rotate.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
|
||||
public class Rotate extends CompositeFilter
|
||||
{
|
||||
|
||||
private double angle;
|
||||
|
||||
/// Constructor.
|
||||
public Rotate( ImageProducer producer, double angle )
|
||||
{
|
||||
super( producer, new Shear( null, angle ), new Flip( null, Flip.FLIP_XY ) );
|
||||
this.angle = angle * Math.PI / 180.0;
|
||||
double xshearfac = Math.tan( angle / 2.0 );
|
||||
double yshearfac = Math.sin( angle );
|
||||
}
|
||||
|
||||
|
||||
// Main routine for command-line interface.
|
||||
public static void main( String[] args )
|
||||
{
|
||||
if ( args.length != 1 )
|
||||
usage();
|
||||
ImageFilterPlus filter = new Rotate( null, Integer.parseInt( args[0] ) );
|
||||
System.exit(
|
||||
ImageFilterPlus.filterStream( System.in, System.out, filter ) );
|
||||
}
|
||||
|
||||
private static void usage()
|
||||
{
|
||||
System.err.println( "usage: Rotate <angle>" );
|
||||
System.exit( 1 );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,159 +0,0 @@
|
|||
// ScaleCopy - an ImageFilter that scales by pixel copying
|
||||
//
|
||||
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Filters;
|
||||
|
||||
import java.awt.image.*;
|
||||
|
||||
/// An ImageFilter that scales by pixel copying.
|
||||
// <P>
|
||||
// Scales an image by copying pixels.
|
||||
// If the image is being enlarged, pixels get replicated;
|
||||
// if the image is being shrunk, pixels get dropped.
|
||||
// The output uses the same color model as the input.
|
||||
// For enlarging, this filter is slightly slower than Enlarge due
|
||||
// to the floating-point arithmetic;
|
||||
// for shrinking, it's much faster than Shrink, but
|
||||
// the results aren't as nice.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Filters/ScaleCopy.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
// <P>
|
||||
// @see Enlarge
|
||||
// @see Shrink
|
||||
|
||||
public class ScaleCopy extends ImageFilterPlus
|
||||
{
|
||||
|
||||
private double xScale, yScale;
|
||||
private int newWidth, newHeight;
|
||||
|
||||
/// Constructor, same X and Y scale factor.
|
||||
public ScaleCopy( ImageProducer producer, double scale )
|
||||
{
|
||||
this( producer, scale, scale );
|
||||
}
|
||||
|
||||
/// Constructor, different X and Y scale factors.
|
||||
public ScaleCopy( ImageProducer producer, double xScale, double yScale )
|
||||
{
|
||||
super( producer );
|
||||
this.xScale = xScale;
|
||||
this.yScale = yScale;
|
||||
}
|
||||
|
||||
|
||||
public void setDimensions( int width, int height )
|
||||
{
|
||||
newWidth = (int) ( width * xScale );
|
||||
newHeight = (int) ( height * yScale );
|
||||
consumer.setDimensions( newWidth, newHeight );
|
||||
}
|
||||
|
||||
public void setPixels( int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize )
|
||||
{
|
||||
int newX = Math.min( (int) ( x * xScale ), newWidth - 1 );
|
||||
int newY = Math.min( (int) ( y * yScale ), newHeight - 1 );
|
||||
int newW = Math.max( (int) ( w * xScale ), 1 );
|
||||
if ( newX + newW > newWidth )
|
||||
newW = newWidth - newX;
|
||||
int newH = Math.max( (int) ( h * yScale ), 1 );
|
||||
if ( newY + newH > newHeight )
|
||||
newH = newHeight - newY;
|
||||
byte[] newPixels = new byte[newW * newH];
|
||||
for ( int newRow = 0; newRow < newH; ++newRow )
|
||||
{
|
||||
int row = (int) ( newRow / yScale );
|
||||
if ( row >= h )
|
||||
continue;
|
||||
for ( int newCol = 0; newCol < newW; ++newCol )
|
||||
{
|
||||
int col = (int) ( newCol / xScale );
|
||||
if ( col >= w )
|
||||
continue;
|
||||
newPixels[newRow * newW + newCol] =
|
||||
pixels[row * scansize + off + col];
|
||||
}
|
||||
}
|
||||
consumer.setPixels( newX, newY, newW, newH, model, newPixels, 0, newW );
|
||||
}
|
||||
|
||||
public void setPixels( int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize )
|
||||
{
|
||||
int newX = Math.min( (int) ( x * xScale ), newWidth - 1 );
|
||||
int newY = Math.min( (int) ( y * yScale ), newHeight - 1 );
|
||||
int newW = Math.max( (int) ( w * xScale ), 1 );
|
||||
if ( newX + newW > newWidth )
|
||||
newW = newWidth - newX;
|
||||
int newH = Math.max( (int) ( h * yScale ), 1 );
|
||||
if ( newY + newH > newHeight )
|
||||
newH = newHeight - newY;
|
||||
int[] newPixels = new int[newW * newH];
|
||||
for ( int newRow = 0; newRow < newH; ++newRow )
|
||||
{
|
||||
int row = (int) ( newRow / yScale );
|
||||
if ( row >= h )
|
||||
continue;
|
||||
for ( int newCol = 0; newCol < newW; ++newCol )
|
||||
{
|
||||
int col = (int) ( newCol / xScale );
|
||||
if ( col >= w )
|
||||
continue;
|
||||
newPixels[newRow * newW + newCol] =
|
||||
pixels[row * scansize + off + col];
|
||||
}
|
||||
}
|
||||
consumer.setPixels( newX, newY, newW, newH, model, newPixels, 0, newW );
|
||||
}
|
||||
|
||||
|
||||
// Main routine for command-line interface.
|
||||
public static void main( String[] args )
|
||||
{
|
||||
ImageFilterPlus filter = null;
|
||||
if ( args.length == 1 )
|
||||
filter = new ScaleCopy( null,
|
||||
Double.valueOf( args[0] ).doubleValue() );
|
||||
else if ( args.length == 2 )
|
||||
filter = new ScaleCopy( null,
|
||||
Double.valueOf( args[0] ).doubleValue(),
|
||||
Double.valueOf( args[1] ).doubleValue() );
|
||||
else
|
||||
usage();
|
||||
System.exit(
|
||||
ImageFilterPlus.filterStream( System.in, System.out, filter ) );
|
||||
}
|
||||
|
||||
private static void usage()
|
||||
{
|
||||
System.err.println( "usage: ScaleCopy scale" );
|
||||
System.err.println( "or: ScaleCopy xScale yScale" );
|
||||
System.exit( 1 );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,144 +0,0 @@
|
|||
// Shear - shear an image by some angle
|
||||
//
|
||||
// Copyright (C) 1997 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Filters;
|
||||
|
||||
import java.awt.image.*;
|
||||
|
||||
/// Shear an image by some angle.
|
||||
// <P>
|
||||
// Shears an image by the specified angle.
|
||||
// The angle is in degrees (floating point), and measures this:
|
||||
// <BLOCKQUOTE><PRE><CODE>
|
||||
// +-------+ +-------+
|
||||
// | | |\ \
|
||||
// | OLD | | \ NEW \
|
||||
// | | |an\ \
|
||||
// +-------+ |gle+-------+
|
||||
// </CODE></PRE></BLOCKQUOTE>
|
||||
// If the angle is negative, it shears the other way:
|
||||
// <BLOCKQUOTE><PRE><CODE>
|
||||
// +-------+ |-an+-------+
|
||||
// | | |gl/ /
|
||||
// | OLD | |e/ NEW /
|
||||
// | | |/ /
|
||||
// +-------+ +-------+
|
||||
// </CODE></PRE></BLOCKQUOTE>
|
||||
// The angle should not get too close to 90 or -90, or the resulting
|
||||
// image will be unreasonably wide. Staying between -45 and 45 is best.
|
||||
// <P>
|
||||
// The shearing is implemented by looping over the source pixels and
|
||||
// distributing fractions to each of the destination pixels.
|
||||
// This has an "anti-aliasing" effect - it avoids jagged edges and similar
|
||||
// artifacts.
|
||||
// <P>
|
||||
// This filter is fast.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Filters/Shear.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
|
||||
public class Shear extends RGBAllFilter
|
||||
{
|
||||
|
||||
private double angle;
|
||||
|
||||
/// Constructor.
|
||||
public Shear( ImageProducer producer, double angle )
|
||||
{
|
||||
super( producer );
|
||||
this.angle = angle * Math.PI / 180.0;
|
||||
}
|
||||
|
||||
|
||||
public void filterRGBAll( int width, int height, int[][] rgbPixels )
|
||||
{
|
||||
double shearfac = Math.tan( angle );
|
||||
if ( shearfac < 0.0 )
|
||||
shearfac = -shearfac;
|
||||
int newWidth = (int) ( height * shearfac + width + 0.999999 );
|
||||
int[][] newPixels = new int[height][newWidth];
|
||||
for ( int row = 0; row < height; ++row )
|
||||
{
|
||||
double new0;
|
||||
if ( angle > 0.0 )
|
||||
new0 = row * shearfac;
|
||||
else
|
||||
new0 = ( height - row ) * shearfac;
|
||||
int intnew0 = (int) new0;
|
||||
double fracnew0 = new0 - intnew0;
|
||||
double omfracnew0 = 1.0 - fracnew0;
|
||||
|
||||
for ( int col = 0; col < newWidth; ++col )
|
||||
newPixels[row][col] = 0x00000000;
|
||||
|
||||
int preva = 0;
|
||||
int prevr = ( rgbPixels[row][0] >> 16 ) & 0xff;
|
||||
int prevg = ( rgbPixels[row][0] >> 8 ) & 0xff;
|
||||
int prevb = rgbPixels[row][0] & 0xff;
|
||||
for ( int col = 0; col < width; ++col )
|
||||
{
|
||||
int rgb = rgbPixels[row][col];
|
||||
int a = ( rgb >> 24 ) & 0xff;
|
||||
int r = ( rgb >> 16 ) & 0xff;
|
||||
int g = ( rgb >> 8 ) & 0xff;
|
||||
int b = rgb & 0xff;
|
||||
newPixels[row][intnew0 + col] =
|
||||
( (int) ( fracnew0 * preva + omfracnew0 * a ) << 24 ) |
|
||||
( (int) ( fracnew0 * prevr + omfracnew0 * r ) << 16 ) |
|
||||
( (int) ( fracnew0 * prevg + omfracnew0 * g ) << 8 ) |
|
||||
( (int) ( fracnew0 * prevb + omfracnew0 * b ) );
|
||||
preva = a;
|
||||
prevr = r;
|
||||
prevg = g;
|
||||
prevb = b;
|
||||
}
|
||||
newPixels[row][intnew0 + width] =
|
||||
( (int) ( fracnew0 * preva ) << 24 ) |
|
||||
( prevr << 16 ) | ( prevg << 8 ) | prevb;
|
||||
}
|
||||
setPixels( newWidth, height, newPixels );
|
||||
}
|
||||
|
||||
|
||||
// Main routine for command-line interface.
|
||||
public static void main( String[] args )
|
||||
{
|
||||
if ( args.length != 1 )
|
||||
usage();
|
||||
ImageFilterPlus filter = new Shear( null, Integer.parseInt( args[0] ) );
|
||||
System.exit(
|
||||
ImageFilterPlus.filterStream( System.in, System.out, filter ) );
|
||||
}
|
||||
|
||||
private static void usage()
|
||||
{
|
||||
System.err.println( "usage: Shear <angle>" );
|
||||
System.exit( 1 );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
// Shrink - an ImageFilter that shrinks by pixel averaging
|
||||
//
|
||||
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Filters;
|
||||
|
||||
import java.awt.image.*;
|
||||
|
||||
/// An ImageFilter that shrinks by pixel averaging.
|
||||
// <P>
|
||||
// Shrinks an image an integral factor by averaging pixels.
|
||||
// Because the resulting pixels might not fit into the input's
|
||||
// color model, the output is always in the default RGB color model.
|
||||
// This filter is somewhat slow.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Filters/Shrink.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
// <P>
|
||||
// @see Enlarge
|
||||
// @see ScaleCopy
|
||||
|
||||
public class Shrink extends RGBAllFilter
|
||||
{
|
||||
|
||||
private int divisor;
|
||||
|
||||
/// Constructor.
|
||||
public Shrink( ImageProducer producer, int divisor )
|
||||
{
|
||||
super( producer );
|
||||
this.divisor = divisor;
|
||||
}
|
||||
|
||||
|
||||
public void filterRGBAll( int width, int height, int[][] rgbPixels )
|
||||
{
|
||||
int divisor2 = divisor * divisor;
|
||||
int newWidth = Math.max( width / divisor, 1 );
|
||||
int newHeight = Math.max( height / divisor, 1 );
|
||||
int[][] newPixels = new int[newHeight][newWidth];
|
||||
for ( int newRow = 0; newRow < newHeight; ++newRow )
|
||||
{
|
||||
for ( int newCol = 0; newCol < newWidth; ++newCol )
|
||||
{
|
||||
int a = 0, r = 0, g = 0, b = 0;
|
||||
for ( int i = 0; i < divisor; ++i )
|
||||
{
|
||||
int row = newRow * divisor + i;
|
||||
if ( row >= height )
|
||||
continue;
|
||||
for ( int j = 0; j < divisor; ++j )
|
||||
{
|
||||
int col = newCol * divisor + j;
|
||||
if ( col >= width )
|
||||
continue;
|
||||
int rgb = rgbPixels[row][col];
|
||||
a += ( rgb >> 24 ) & 0xff;
|
||||
r += ( rgb >> 16 ) & 0xff;
|
||||
g += ( rgb >> 8 ) & 0xff;
|
||||
b += rgb & 0xff;
|
||||
}
|
||||
}
|
||||
a /= divisor2;
|
||||
r /= divisor2;
|
||||
g /= divisor2;
|
||||
b /= divisor2;
|
||||
newPixels[newRow][newCol] =
|
||||
( a << 24 ) | ( r << 16 ) | ( g << 8 ) | b;
|
||||
}
|
||||
}
|
||||
setPixels( newWidth, newHeight, newPixels );
|
||||
}
|
||||
|
||||
|
||||
// Main routine for command-line interface.
|
||||
public static void main( String[] args )
|
||||
{
|
||||
if ( args.length != 1 )
|
||||
usage();
|
||||
ImageFilterPlus filter = new Enlarge(
|
||||
null, Integer.parseInt( args[0] ) );
|
||||
System.exit(
|
||||
ImageFilterPlus.filterStream( System.in, System.out, filter ) );
|
||||
}
|
||||
|
||||
private static void usage()
|
||||
{
|
||||
System.err.println( "usage: Shrink <divisor>" );
|
||||
System.exit( 1 );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
// Smooth - smoothing filter
|
||||
//
|
||||
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Filters;
|
||||
|
||||
import java.awt.image.*;
|
||||
|
||||
/// Smoothing filter.
|
||||
// <P>
|
||||
// Smooths an image by averaging adjacent pixels.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Filters/Smooth.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
|
||||
public class Smooth extends RGBAllFilter
|
||||
{
|
||||
|
||||
private int n;
|
||||
|
||||
/// Constructor.
|
||||
public Smooth( ImageProducer producer, int n )
|
||||
{
|
||||
super( producer );
|
||||
this.n = n;
|
||||
}
|
||||
|
||||
/// Constructor, default value.
|
||||
public Smooth( ImageProducer producer )
|
||||
{
|
||||
this( producer, 1 );
|
||||
}
|
||||
|
||||
|
||||
public void filterRGBAll( int width, int height, int[][] rgbPixels )
|
||||
{
|
||||
int[][] newPixels = new int[height][width];
|
||||
for ( int row = 0; row < height; ++row )
|
||||
for ( int col = 0; col < width; ++col )
|
||||
{
|
||||
int a = 0, r = 0, g = 0, b = 0, c = 0;
|
||||
for ( int subrow = row - n; subrow <= row + n; ++subrow )
|
||||
if ( subrow >= 0 && subrow < height )
|
||||
for ( int subcol = col - n; subcol <= col + n; ++subcol )
|
||||
if ( subcol >= 0 && subcol < width )
|
||||
{
|
||||
int rgb = rgbPixels[subrow][subcol];
|
||||
a += ( rgb >> 24 ) & 0xff;
|
||||
r += ( rgb >> 16 ) & 0xff;
|
||||
g += ( rgb >> 8 ) & 0xff;
|
||||
b += rgb & 0xff;
|
||||
++c;
|
||||
}
|
||||
a /= c;
|
||||
r /= c;
|
||||
g /= c;
|
||||
b /= c;
|
||||
newPixels[row][col] =
|
||||
( a << 24 ) | ( r << 16 ) | ( g << 8 ) | b;
|
||||
}
|
||||
setPixels( width, height, newPixels );
|
||||
}
|
||||
|
||||
|
||||
// Main routine for command-line interface.
|
||||
public static void main( String[] args )
|
||||
{
|
||||
int n = -1;
|
||||
int argc = args.length;
|
||||
int argn;
|
||||
for ( argn = 0; argn < argc && args[argn].charAt( 0 ) == '-'; ++argn )
|
||||
{
|
||||
if ( args[argn].equals( "-n" ) && argn + 1 < argc )
|
||||
{
|
||||
++argn;
|
||||
n = Integer.parseInt( args[argn] );
|
||||
}
|
||||
else
|
||||
usage();
|
||||
}
|
||||
if ( argn != argc )
|
||||
usage();
|
||||
|
||||
ImageFilterPlus filter;
|
||||
if ( n == -1 )
|
||||
filter = new Smooth( null );
|
||||
else
|
||||
filter = new Smooth( null, n );
|
||||
System.exit(
|
||||
ImageFilterPlus.filterStream( System.in, System.out, filter ) );
|
||||
}
|
||||
|
||||
private static void usage()
|
||||
{
|
||||
System.err.println( "usage: Smooth [-n N]" );
|
||||
System.exit( 1 );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
// Tile - an ImageFilter that replicates an image in a tiled pattern
|
||||
//
|
||||
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM.Filters;
|
||||
|
||||
import java.awt.image.*;
|
||||
|
||||
/// An ImageFilter that replicates an image in a tiled pattern.
|
||||
// <P>
|
||||
// Tiles the image onto an output image of a specified size.
|
||||
// The output uses the same color model as the input.
|
||||
// This filter is very fast.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/Filters/Tile.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
|
||||
public class Tile extends ImageFilterPlus
|
||||
{
|
||||
|
||||
private int width, height;
|
||||
private int newWidth, newHeight;
|
||||
private int nWide, nHigh;
|
||||
|
||||
/// Constructor.
|
||||
public Tile( ImageProducer producer, int newWidth, int newHeight )
|
||||
{
|
||||
super( producer, true );
|
||||
this.newWidth = newWidth;
|
||||
this.newHeight = newHeight;
|
||||
}
|
||||
|
||||
|
||||
public void setDimensions( int width, int height )
|
||||
{
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
consumer.setDimensions( newWidth, newHeight );
|
||||
nWide = ( newWidth + width - 1 ) / width;
|
||||
nHigh = ( newHeight + height - 1 ) / height;
|
||||
}
|
||||
|
||||
public void setPixels( int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize )
|
||||
{
|
||||
for ( int r = 0; r < nHigh; ++r )
|
||||
{
|
||||
int ty = r * height + y;
|
||||
int th = h;
|
||||
if ( ty + th > newHeight )
|
||||
th = newHeight - ty;
|
||||
for ( int c = 0; c < nWide; ++c )
|
||||
{
|
||||
int tx = c * width + x;
|
||||
int tw = w;
|
||||
if ( tx + tw > newWidth )
|
||||
tw = newWidth - tx;
|
||||
consumer.setPixels(
|
||||
tx, ty, tw, th, model, pixels, off, scansize );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setPixels( int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize )
|
||||
{
|
||||
for ( int r = 0; r < nHigh; ++r )
|
||||
{
|
||||
int ty = r * height + y;
|
||||
int th = h;
|
||||
if ( ty + th > newHeight )
|
||||
th = newHeight - ty;
|
||||
for ( int c = 0; c < nWide; ++c )
|
||||
{
|
||||
int tx = c * width + x;
|
||||
int tw = w;
|
||||
if ( tx + tw > newWidth )
|
||||
tw = newWidth - tx;
|
||||
consumer.setPixels(
|
||||
tx, ty, tw, th, model, pixels, off, scansize );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Main routine for command-line interface.
|
||||
public static void main( String[] args )
|
||||
{
|
||||
if ( args.length != 2 )
|
||||
usage();
|
||||
ImageFilterPlus filter =
|
||||
new Tile( null,
|
||||
Integer.parseInt( args[0] ), Integer.parseInt( args[1] ) );
|
||||
System.exit(
|
||||
ImageFilterPlus.filterStream( System.in, System.out, filter ) );
|
||||
}
|
||||
|
||||
private static void usage()
|
||||
{
|
||||
System.err.println( "usage: Tile <width> <height>" );
|
||||
System.exit( 1 );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
// JPMUtils - static utility routines for the JPM packages
|
||||
//
|
||||
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme.JPM;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
import Acme.JPM.Filters.*;
|
||||
|
||||
/// Static utility routines for the JPM packages.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/JPM/JPMUtils.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
|
||||
public class JPMUtils
|
||||
{
|
||||
|
||||
/// Filter one image into another.
|
||||
public static Image filterImage( Component comp, ImageFilterPlus filter )
|
||||
{
|
||||
return comp.createImage(
|
||||
new FilteredImageSource( filter.getSource(), filter ) );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,303 +0,0 @@
|
|||
// LruHashtable - a Hashtable that expires least-recently-used objects
|
||||
//
|
||||
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/// A Hashtable that expires least-recently-used objects.
|
||||
// <P>
|
||||
// Use just like java.util.Hashtable, except that the initial-capacity
|
||||
// parameter is required. Instead of growing bigger than that size,
|
||||
// it will throw out objects that haven't been looked at in a while.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/LruHashtable.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
// <P>
|
||||
// @see java.util.Hashtable
|
||||
|
||||
public class LruHashtable extends Hashtable
|
||||
{
|
||||
|
||||
// Number of buckets.
|
||||
private static final int nBuckets = 2;
|
||||
|
||||
// Load factor.
|
||||
private float loadFactor;
|
||||
|
||||
// When count exceeds this threshold, expires the old table.
|
||||
private int threshold;
|
||||
|
||||
// Capacity of each bucket.
|
||||
private int eachCapacity;
|
||||
|
||||
// The tables.
|
||||
private Hashtable oldTable;
|
||||
private Hashtable newTable;
|
||||
|
||||
/// Constructs a new, empty hashtable with the specified initial
|
||||
// capacity and the specified load factor.
|
||||
// Unlike a plain Hashtable, an LruHashtable will never grow or
|
||||
// shrink from this initial capacity.
|
||||
// @param initialCapacity the initial number of buckets
|
||||
// @param loadFactor a number between 0.0 and 1.0, it defines
|
||||
// the threshold for expiring old entries
|
||||
// @exception IllegalArgumentException If the initial capacity
|
||||
// is less than or equal to zero.
|
||||
// @exception IllegalArgumentException If the load factor is
|
||||
// less than or equal to zero.
|
||||
public LruHashtable( int initialCapacity, float loadFactor )
|
||||
{
|
||||
// We have to call a superclass constructor, but we're not actually
|
||||
// going to use it at all. The only reason we want to extend Hashtable
|
||||
// is for type conformance. So, make a parent hash table of minimum
|
||||
// size and then ignore it.
|
||||
super( 1 );
|
||||
|
||||
if ( initialCapacity <= 0 || loadFactor <= 0.0 )
|
||||
throw new IllegalArgumentException();
|
||||
this.loadFactor = loadFactor;
|
||||
threshold = (int) ( initialCapacity * loadFactor ) - 1;
|
||||
eachCapacity = initialCapacity / nBuckets + 1;
|
||||
oldTable = new Hashtable( eachCapacity, loadFactor );
|
||||
newTable = new Hashtable( eachCapacity, loadFactor );
|
||||
}
|
||||
|
||||
/// Constructs a new, empty hashtable with the specified initial
|
||||
// capacity.
|
||||
// Unlike a plain Hashtable, an LruHashtable will never grow or
|
||||
// shrink from this initial capacity.
|
||||
// @param initialCapacity the initial number of buckets
|
||||
public LruHashtable( int initialCapacity )
|
||||
{
|
||||
this( initialCapacity, 0.75F );
|
||||
}
|
||||
|
||||
/// Returns the number of elements contained in the hashtable.
|
||||
public int size()
|
||||
{
|
||||
return newTable.size() + oldTable.size();
|
||||
}
|
||||
|
||||
/// Returns true if the hashtable contains no elements.
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
/// Returns an enumeration of the hashtable's keys.
|
||||
// @see LruHashtable#elements
|
||||
// @see Enumeration
|
||||
public synchronized Enumeration keys()
|
||||
{
|
||||
return new LruHashtableEnumerator( oldTable, newTable, true );
|
||||
}
|
||||
|
||||
/// Returns an enumeration of the elements. Use the Enumeration methods
|
||||
// on the returned object to fetch the elements sequentially.
|
||||
// @see LruHashtable#keys
|
||||
// @see Enumeration
|
||||
public synchronized Enumeration elements()
|
||||
{
|
||||
return new LruHashtableEnumerator( oldTable, newTable, false );
|
||||
}
|
||||
|
||||
/// Returns true if the specified object is an element of the hashtable.
|
||||
// This operation is more expensive than the containsKey() method.
|
||||
// @param value the value that we are looking for
|
||||
// @exception NullPointerException If the value being searched
|
||||
// for is equal to null.
|
||||
// @see LruHashtable#containsKey
|
||||
public synchronized boolean contains( Object value )
|
||||
{
|
||||
if ( newTable.contains( value ) )
|
||||
return true;
|
||||
if ( oldTable.contains( value ) )
|
||||
{
|
||||
// We would like to move the object from the old table to the
|
||||
// new table. However, we need keys to re-add the objects, and
|
||||
// there's no good way to find all the keys for the given object.
|
||||
// We'd have to enumerate through all the keys and check each
|
||||
// one. Yuck. For now we just punt. Anyway, contains() is
|
||||
// probably not a commonly-used operation.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Returns true if the collection contains an element for the key.
|
||||
// @param key the key that we are looking for
|
||||
// @see LruHashtable#contains
|
||||
public synchronized boolean containsKey( Object key )
|
||||
{
|
||||
if ( newTable.containsKey( key ) )
|
||||
return true;
|
||||
if ( oldTable.containsKey( key ) )
|
||||
{
|
||||
// Move object from old table to new table.
|
||||
Object value = oldTable.get( key );
|
||||
newTable.put( key, value );
|
||||
oldTable.remove( key );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Gets the object associated with the specified key in the
|
||||
// hashtable.
|
||||
// @param key the specified key
|
||||
// @returns the element for the key or null if the key
|
||||
// is not defined in the hash table.
|
||||
// @see LruHashtable#put
|
||||
public synchronized Object get( Object key )
|
||||
{
|
||||
Object value;
|
||||
value = newTable.get( key );
|
||||
if ( value != null )
|
||||
return value;
|
||||
value = oldTable.get( key );
|
||||
if ( value != null )
|
||||
{
|
||||
// Move object from old table to new table.
|
||||
newTable.put( key, value );
|
||||
oldTable.remove( key );
|
||||
return value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Puts the specified element into the hashtable, using the specified
|
||||
// key. The element may be retrieved by doing a get() with the same key.
|
||||
// The key and the element cannot be null.
|
||||
// @param key the specified key in the hashtable
|
||||
// @param value the specified element
|
||||
// @exception NullPointerException If the value of the element
|
||||
// is equal to null.
|
||||
// @see LruHashtable#get
|
||||
// @return the old value of the key, or null if it did not have one.
|
||||
public synchronized Object put( Object key, Object value )
|
||||
{
|
||||
Object oldValue = newTable.put( key, value );
|
||||
if ( oldValue != null )
|
||||
return oldValue;
|
||||
oldValue = oldTable.get( key );
|
||||
if ( oldValue != null )
|
||||
oldTable.remove( key );
|
||||
else
|
||||
{
|
||||
if ( size() >= threshold )
|
||||
{
|
||||
// Rotate the tables.
|
||||
oldTable = newTable;
|
||||
newTable = new Hashtable( eachCapacity, loadFactor );
|
||||
}
|
||||
}
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
/// Removes the element corresponding to the key. Does nothing if the
|
||||
// key is not present.
|
||||
// @param key the key that needs to be removed
|
||||
// @return the value of key, or null if the key was not found.
|
||||
public synchronized Object remove( Object key )
|
||||
{
|
||||
Object oldValue = newTable.remove( key );
|
||||
if ( oldValue == null )
|
||||
oldValue = oldTable.remove( key );
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
/// Clears the hash table so that it has no more elements in it.
|
||||
public synchronized void clear()
|
||||
{
|
||||
newTable.clear();
|
||||
oldTable.clear();
|
||||
}
|
||||
|
||||
/// Creates a clone of the hashtable. A shallow copy is made,
|
||||
// the keys and elements themselves are NOT cloned. This is a
|
||||
// relatively expensive operation.
|
||||
public synchronized Object clone()
|
||||
{
|
||||
LruHashtable n = (LruHashtable) super.clone();
|
||||
n.newTable = (Hashtable) n.newTable.clone();
|
||||
n.oldTable = (Hashtable) n.oldTable.clone();
|
||||
return n;
|
||||
}
|
||||
|
||||
// toString() can be inherited.
|
||||
|
||||
}
|
||||
|
||||
|
||||
class LruHashtableEnumerator implements Enumeration
|
||||
{
|
||||
Enumeration oldEnum;
|
||||
Enumeration newEnum;
|
||||
boolean old;
|
||||
|
||||
LruHashtableEnumerator( Hashtable oldTable, Hashtable newTable, boolean keys )
|
||||
{
|
||||
if ( keys )
|
||||
{
|
||||
oldEnum = oldTable.keys();
|
||||
newEnum = newTable.keys();
|
||||
}
|
||||
else
|
||||
{
|
||||
oldEnum = oldTable.elements();
|
||||
newEnum = newTable.elements();
|
||||
}
|
||||
old = true;
|
||||
}
|
||||
|
||||
public boolean hasMoreElements()
|
||||
{
|
||||
boolean r;
|
||||
if ( old )
|
||||
{
|
||||
r = oldEnum.hasMoreElements();
|
||||
if ( ! r )
|
||||
{
|
||||
old = false;
|
||||
r = newEnum.hasMoreElements();
|
||||
}
|
||||
}
|
||||
else
|
||||
r = newEnum.hasMoreElements();
|
||||
return r;
|
||||
}
|
||||
|
||||
public Object nextElement()
|
||||
{
|
||||
if ( old )
|
||||
return oldEnum.nextElement();
|
||||
return newEnum.nextElement();
|
||||
}
|
||||
|
||||
}
|
1053
src/Acme/Utils.java
1053
src/Acme/Utils.java
File diff suppressed because it is too large
Load diff
|
@ -1,147 +0,0 @@
|
|||
// WildcardDictionary - a dictionary with wildcard lookups
|
||||
//
|
||||
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
// Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||
// fine Java utilities: http://www.acme.com/java/
|
||||
|
||||
package Acme;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/// A dictionary with wildcard lookups.
|
||||
// <P>
|
||||
// The keys in this dictionary are wildcard patterns. When you do a get(),
|
||||
// the string you pass in is matched against all the patterns, and the
|
||||
// first match is returned.
|
||||
// <P>
|
||||
// The wildcard matcher is fairly simple, it implements * meaning any
|
||||
// string, ? meaning any single character, and | separating multiple
|
||||
// patterns. All other characters must match literally.
|
||||
// <P>
|
||||
// <A HREF="/resources/classes/Acme/WildcardDictionary.java">Fetch the software.</A><BR>
|
||||
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
|
||||
// <P>
|
||||
// @see Acme.Utils#match
|
||||
|
||||
public class WildcardDictionary extends Dictionary
|
||||
{
|
||||
|
||||
private Vector keys;
|
||||
private Vector elements;
|
||||
|
||||
/// Constructor.
|
||||
public WildcardDictionary()
|
||||
{
|
||||
keys = new Vector();
|
||||
elements = new Vector();
|
||||
}
|
||||
|
||||
/// Returns the number of elements contained within the dictionary.
|
||||
public int size()
|
||||
{
|
||||
return elements.size();
|
||||
}
|
||||
|
||||
/// Returns true if the dictionary contains no elements.
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
/// Returns an enumeration of the dictionary's keys.
|
||||
public Enumeration keys()
|
||||
{
|
||||
return keys.elements();
|
||||
}
|
||||
|
||||
/// Returns an enumeration of the elements. Use the Enumeration methods
|
||||
// on the returned object to fetch the elements sequentially.
|
||||
public Enumeration elements()
|
||||
{
|
||||
return elements.elements();
|
||||
}
|
||||
|
||||
/// Gets the object associated with the specified key in the dictionary.
|
||||
// The key is assumed to be a String, which is matched against
|
||||
// the wildcard-pattern keys in the dictionary.
|
||||
// @param key the string to match
|
||||
// @returns the element for the key, or null if there's no match
|
||||
// @see Acme.Utils#match
|
||||
public synchronized Object get( Object key )
|
||||
{
|
||||
String sKey = (String) key;
|
||||
for ( int i = 0; i < keys.size(); ++i )
|
||||
{
|
||||
String thisKey = (String) keys.elementAt( i );
|
||||
if ( Acme.Utils.match( thisKey, sKey ) )
|
||||
return elements.elementAt( i );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Puts the specified element into the Dictionary, using the specified
|
||||
// key. The element may be retrieved by doing a get() with the same
|
||||
// key. The key and the element cannot be null.
|
||||
// @param key the specified wildcard-pattern key
|
||||
// @param value the specified element
|
||||
// @return the old value of the key, or null if it did not have one.
|
||||
// @exception NullPointerException If the value of the specified
|
||||
// element is null.
|
||||
public synchronized Object put( Object key, Object element )
|
||||
{
|
||||
int i = keys.indexOf( key );
|
||||
if ( i != -1 )
|
||||
{
|
||||
Object oldElement = elements.elementAt( i );
|
||||
elements.setElementAt( element, i );
|
||||
return oldElement;
|
||||
}
|
||||
else
|
||||
{
|
||||
keys.addElement( key );
|
||||
elements.addElement( element );
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the element corresponding to the key. Does nothing if the
|
||||
// key is not present.
|
||||
// @param key the key that needs to be removed
|
||||
// @return the value of key, or null if the key was not found.
|
||||
public synchronized Object remove( Object key )
|
||||
{
|
||||
int i = keys.indexOf( key );
|
||||
if ( i != -1 )
|
||||
{
|
||||
Object oldElement = elements.elementAt( i );
|
||||
keys.removeElementAt( i );
|
||||
elements.removeElementAt( i );
|
||||
return oldElement;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* Copyright 2001 Hannes Wallnoefer
|
||||
*/
|
||||
|
||||
package helma.xmlrpc;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* A callback interface for an asynchronous XML-RPC call.
|
||||
*/
|
||||
|
||||
public interface AsyncCallback {
|
||||
|
||||
/**
|
||||
* Call went ok, handle result.
|
||||
*/
|
||||
public void handleResult (Object result, URL url, String method);
|
||||
|
||||
/**
|
||||
* Something went wrong, handle error.
|
||||
*/
|
||||
public void handleError (Exception exception, URL url, String method);
|
||||
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* Copyright 2000 Hannes Wallnoefer
|
||||
*/
|
||||
|
||||
package helma.xmlrpc;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* An XML-RPC handler that also handles user authentication.
|
||||
*/
|
||||
|
||||
public interface AuthenticatedXmlRpcHandler {
|
||||
|
||||
/**
|
||||
* Return the result, or throw an Exception if something went wrong.
|
||||
*/
|
||||
public Object execute (String method, Vector params, String user, String password) throws Exception;
|
||||
|
||||
}
|
|
@ -1,286 +0,0 @@
|
|||
//////////////////////license & copyright header/////////////////////////
|
||||
// //
|
||||
// Base64 - encode/decode data using the Base64 encoding scheme //
|
||||
// //
|
||||
// Copyright (c) 1998 by Kevin Kelley //
|
||||
// //
|
||||
// This library is free software; you can redistribute it and/or //
|
||||
// modify it under the terms of the GNU Lesser General Public //
|
||||
// License as published by the Free Software Foundation; either //
|
||||
// version 2.1 of the License, or (at your option) any later version. //
|
||||
// //
|
||||
// This library is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU Lesser General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU Lesser General Public //
|
||||
// License along with this library; if not, write to the Free Software //
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA //
|
||||
// 02111-1307, USA, or contact the author: //
|
||||
// //
|
||||
// Kevin Kelley <kelley@ruralnet.net> - 30718 Rd. 28, La Junta, CO, //
|
||||
// 81050 USA. //
|
||||
// //
|
||||
////////////////////end license & copyright header///////////////////////
|
||||
|
||||
package helma.xmlrpc;
|
||||
|
||||
import java.io.*; // needed only for main() method.
|
||||
|
||||
|
||||
/**
|
||||
* Provides encoding of raw bytes to base64-encoded characters, and
|
||||
* decoding of base64 characters to raw bytes.
|
||||
*
|
||||
* @author Kevin Kelley (kelley@ruralnet.net)
|
||||
* @version 1.3
|
||||
* @date 06 August 1998
|
||||
* @modified 14 February 2000
|
||||
* @modified 22 September 2000
|
||||
*/
|
||||
public class Base64 {
|
||||
|
||||
/**
|
||||
* returns an array of base64-encoded characters to represent the
|
||||
* passed data array.
|
||||
*
|
||||
* @param data the array of bytes to encode
|
||||
* @return base64-coded character array.
|
||||
*/
|
||||
static public char[] encode(byte[] data)
|
||||
{
|
||||
char[] out = new char[((data.length + 2) / 3) * 4];
|
||||
|
||||
//
|
||||
// 3 bytes encode to 4 chars. Output is always an even
|
||||
// multiple of 4 characters.
|
||||
//
|
||||
for (int i=0, index=0; i<data.length; i+=3, index+=4) {
|
||||
boolean quad = false;
|
||||
boolean trip = false;
|
||||
|
||||
int val = (0xFF & (int) data[i]);
|
||||
val <<= 8;
|
||||
if ((i+1) < data.length) {
|
||||
val |= (0xFF & (int) data[i+1]);
|
||||
trip = true;
|
||||
}
|
||||
val <<= 8;
|
||||
if ((i+2) < data.length) {
|
||||
val |= (0xFF & (int) data[i+2]);
|
||||
quad = true;
|
||||
}
|
||||
out[index+3] = alphabet[(quad? (val & 0x3F): 64)];
|
||||
val >>= 6;
|
||||
out[index+2] = alphabet[(trip? (val & 0x3F): 64)];
|
||||
val >>= 6;
|
||||
out[index+1] = alphabet[val & 0x3F];
|
||||
val >>= 6;
|
||||
out[index+0] = alphabet[val & 0x3F];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a BASE-64 encoded stream to recover the original
|
||||
* data. White space before and after will be trimmed away,
|
||||
* but no other manipulation of the input will be performed.
|
||||
*
|
||||
* As of version 1.2 this method will properly handle input
|
||||
* containing junk characters (newlines and the like) rather
|
||||
* than throwing an error. It does this by pre-parsing the
|
||||
* input and generating from that a count of VALID input
|
||||
* characters.
|
||||
**/
|
||||
static public byte[] decode(char[] data)
|
||||
{
|
||||
// as our input could contain non-BASE64 data (newlines,
|
||||
// whitespace of any sort, whatever) we must first adjust
|
||||
// our count of USABLE data so that...
|
||||
// (a) we don't misallocate the output array, and
|
||||
// (b) think that we miscalculated our data length
|
||||
// just because of extraneous throw-away junk
|
||||
|
||||
int tempLen = data.length;
|
||||
for( int ix=0; ix<data.length; ix++ )
|
||||
{
|
||||
if( (data[ix] > 255) || codes[ data[ix] ] < 0 )
|
||||
--tempLen; // ignore non-valid chars and padding
|
||||
}
|
||||
// calculate required length:
|
||||
// -- 3 bytes for every 4 valid base64 chars
|
||||
// -- plus 2 bytes if there are 3 extra base64 chars,
|
||||
// or plus 1 byte if there are 2 extra.
|
||||
|
||||
int len = (tempLen / 4) * 3;
|
||||
if ((tempLen % 4) == 3) len += 2;
|
||||
if ((tempLen % 4) == 2) len += 1;
|
||||
|
||||
byte[] out = new byte[len];
|
||||
|
||||
|
||||
|
||||
int shift = 0; // # of excess bits stored in accum
|
||||
int accum = 0; // excess bits
|
||||
int index = 0;
|
||||
|
||||
// we now go through the entire array (NOT using the 'tempLen' value)
|
||||
for (int ix=0; ix<data.length; ix++)
|
||||
{
|
||||
int value = (data[ix]>255)? -1: codes[ data[ix] ];
|
||||
|
||||
if ( value >= 0 ) // skip over non-code
|
||||
{
|
||||
accum <<= 6; // bits shift up by 6 each time thru
|
||||
shift += 6; // loop, with new bits being put in
|
||||
accum |= value; // at the bottom.
|
||||
if ( shift >= 8 ) // whenever there are 8 or more shifted in,
|
||||
{
|
||||
shift -= 8; // write them out (from the top, leaving any
|
||||
out[index++] = // excess at the bottom for next iteration.
|
||||
(byte) ((accum >> shift) & 0xff);
|
||||
}
|
||||
}
|
||||
// we will also have skipped processing a padding null byte ('=') here;
|
||||
// these are used ONLY for padding to an even length and do not legally
|
||||
// occur as encoded data. for this reason we can ignore the fact that
|
||||
// no index++ operation occurs in that special case: the out[] array is
|
||||
// initialized to all-zero bytes to start with and that works to our
|
||||
// advantage in this combination.
|
||||
}
|
||||
|
||||
// if there is STILL something wrong we just have to throw up now!
|
||||
if( index != out.length)
|
||||
{
|
||||
throw new Error("Miscalculated data length (wrote " + index + " instead of " + out.length + ")");
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// code characters for values 0..63
|
||||
//
|
||||
static private char[] alphabet =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
|
||||
.toCharArray();
|
||||
|
||||
//
|
||||
// lookup table for converting base64 characters to value in range 0..63
|
||||
//
|
||||
static private byte[] codes = new byte[256];
|
||||
static {
|
||||
for (int i=0; i<256; i++) codes[i] = -1;
|
||||
for (int i = 'A'; i <= 'Z'; i++) codes[i] = (byte)( i - 'A');
|
||||
for (int i = 'a'; i <= 'z'; i++) codes[i] = (byte)(26 + i - 'a');
|
||||
for (int i = '0'; i <= '9'; i++) codes[i] = (byte)(52 + i - '0');
|
||||
codes['+'] = 62;
|
||||
codes['/'] = 63;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// remainder (main method and helper functions) is
|
||||
// for testing purposes only, feel free to clip it.
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
boolean decode = false;
|
||||
|
||||
if (args.length == 0) {
|
||||
System.out.println("usage: java Base64 [-d[ecode]] filename");
|
||||
System.exit(0);
|
||||
}
|
||||
for (int i=0; i<args.length; i++) {
|
||||
if ("-decode".equalsIgnoreCase(args[i])) decode = true;
|
||||
else if ("-d".equalsIgnoreCase(args[i])) decode = true;
|
||||
}
|
||||
|
||||
String filename = args[args.length-1];
|
||||
File file = new File(filename);
|
||||
if (!file.exists()) {
|
||||
System.out.println("Error: file '" + filename + "' doesn't exist!");
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
if (decode)
|
||||
{
|
||||
char[] encoded = readChars(file);
|
||||
byte[] decoded = decode(encoded);
|
||||
writeBytes(file, decoded);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] decoded = readBytes(file);
|
||||
char[] encoded = encode(decoded);
|
||||
writeChars(file, encoded);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] readBytes(File file)
|
||||
{
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try
|
||||
{
|
||||
InputStream fis = new FileInputStream(file);
|
||||
InputStream is = new BufferedInputStream(fis);
|
||||
int count = 0;
|
||||
byte[] buf = new byte[16384];
|
||||
while ((count=is.read(buf)) != -1) {
|
||||
if (count > 0) baos.write(buf, 0, count);
|
||||
}
|
||||
is.close();
|
||||
}
|
||||
catch (Exception e) { e.printStackTrace(); }
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
private static char[] readChars(File file)
|
||||
{
|
||||
CharArrayWriter caw = new CharArrayWriter();
|
||||
try
|
||||
{
|
||||
Reader fr = new FileReader(file);
|
||||
Reader in = new BufferedReader(fr);
|
||||
int count = 0;
|
||||
char[] buf = new char[16384];
|
||||
while ((count=in.read(buf)) != -1) {
|
||||
if (count > 0) caw.write(buf, 0, count);
|
||||
}
|
||||
in.close();
|
||||
}
|
||||
catch (Exception e) { e.printStackTrace(); }
|
||||
|
||||
return caw.toCharArray();
|
||||
}
|
||||
|
||||
private static void writeBytes(File file, byte[] data) {
|
||||
try {
|
||||
OutputStream fos = new FileOutputStream(file);
|
||||
OutputStream os = new BufferedOutputStream(fos);
|
||||
os.write(data);
|
||||
os.close();
|
||||
}
|
||||
catch (Exception e) { e.printStackTrace(); }
|
||||
}
|
||||
|
||||
private static void writeChars(File file, char[] data) {
|
||||
try {
|
||||
Writer fos = new FileWriter(file);
|
||||
Writer os = new BufferedWriter(fos);
|
||||
os.write(data);
|
||||
os.close();
|
||||
}
|
||||
catch (Exception e) { e.printStackTrace(); }
|
||||
}
|
||||
///////////////////////////////////////////////////
|
||||
// end of test code.
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
package helma.xmlrpc;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
// This class is borrowed from Apache JServ
|
||||
class ServerInputStream extends InputStream {
|
||||
// bytes remaining to be read from the input stream. This is
|
||||
// initialized from CONTENT_LENGTH (or getContentLength()).
|
||||
// This is used in order to correctly return a -1 when all the
|
||||
// data POSTed was read. If this is left to -1, content length is
|
||||
// assumed as unknown and the standard InputStream methods will be used
|
||||
long available = -1;
|
||||
long markedAvailable;
|
||||
|
||||
private BufferedInputStream in;
|
||||
|
||||
public ServerInputStream(BufferedInputStream in, int available) {
|
||||
this.in = in;
|
||||
this.available = available;
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
if (available > 0) {
|
||||
available--;
|
||||
return in.read();
|
||||
} else if (available == -1)
|
||||
return in.read ();
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int read(byte b[]) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
public int read(byte b[], int off, int len) throws IOException {
|
||||
if (available > 0) {
|
||||
if (len > available) {
|
||||
// shrink len
|
||||
len = (int) available;
|
||||
}
|
||||
int read = in.read(b, off, len);
|
||||
if (read != -1) {
|
||||
available -= read;
|
||||
} else {
|
||||
available = -1;
|
||||
}
|
||||
return read;
|
||||
} else if (available == -1)
|
||||
return in.read (b, off, len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
public long skip(long n) throws IOException {
|
||||
long skip = in.skip(n);
|
||||
if (available > 0)
|
||||
available -= skip;
|
||||
return skip;
|
||||
}
|
||||
|
||||
public void mark (int readlimit) {
|
||||
in.mark (readlimit);
|
||||
markedAvailable = available;
|
||||
}
|
||||
|
||||
public void reset () throws IOException {
|
||||
in.reset ();
|
||||
available = markedAvailable;
|
||||
}
|
||||
|
||||
public boolean markSupported () {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,460 +0,0 @@
|
|||
package helma.xmlrpc;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A minimal web server that exclusively handles XML-RPC requests.
|
||||
*/
|
||||
public class WebServer implements Runnable {
|
||||
|
||||
XmlRpcServer xmlrpc;
|
||||
private ServerSocket serverSocket;
|
||||
private int port;
|
||||
private Thread listener;
|
||||
private boolean paranoid;
|
||||
private Vector accept, deny;
|
||||
private Stack threadpool;
|
||||
private ThreadGroup runners;
|
||||
|
||||
|
||||
static final byte[] ctype = "Content-Type: text/xml\r\n".getBytes();
|
||||
static final byte[] clength = "Content-Length: ".getBytes();
|
||||
static final byte[] newline = "\r\n".getBytes();
|
||||
static final byte[] doubleNewline = "\r\n\r\n".getBytes();
|
||||
static final byte[] conkeep = "Connection: Keep-Alive\r\n".getBytes();
|
||||
static final byte[] conclose = "Connection: close\r\n".getBytes();
|
||||
static final byte[] ok = " 200 OK\r\n".getBytes();
|
||||
static final byte[] server = "Server: Helma XML-RPC 1.0\r\n".getBytes();
|
||||
|
||||
|
||||
/**
|
||||
* This <em>can</em> be called from command line, but you'll have to edit and recompile
|
||||
* to change the server port or handler objects. By default, it sets up the following responders:
|
||||
* <ul><li> A java.lang.String object
|
||||
* <li> The java.lang.Math class (making its static methods callable via XML-RPC)
|
||||
* <li> An Echo handler that returns the argument array
|
||||
* </ul>
|
||||
*/
|
||||
public static void main (String args[]) {
|
||||
System.err.println ("Usage: java helma.xmlrpc.WebServer [port]");
|
||||
int p = 8080;
|
||||
if (args.length > 0) try {
|
||||
p = Integer.parseInt (args[0]);
|
||||
} catch (NumberFormatException nfx) {
|
||||
System.err.println ("Error parsing port number: "+args[0]);
|
||||
}
|
||||
// XmlRpc.setDebug (true);
|
||||
XmlRpc.setKeepAlive (true);
|
||||
// XmlRpc.setEncoding ("UTF-8");
|
||||
try {
|
||||
WebServer webserver = new WebServer (p);
|
||||
// webserver.setParanoid (true);
|
||||
// webserver.acceptClient ("192.168.*.*");
|
||||
webserver.addHandler ("string", "Welcome to XML-RPC!");
|
||||
webserver.addHandler ("math", Math.class);
|
||||
webserver.addHandler ("auth", new AuthDemo());
|
||||
webserver.addHandler ("$default", new Echo());
|
||||
// XmlRpcClients can be used as Proxies in XmlRpcServers which is a cool feature for applets.
|
||||
webserver.addHandler ("mttf", new XmlRpcClient ("http://www.mailtothefuture.com:80/RPC2"));
|
||||
System.err.println ("started web server on port "+p);
|
||||
} catch (IOException x) {
|
||||
System.err.println ("Error creating web server: "+x);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a Web server at the specified port number.
|
||||
*/
|
||||
public WebServer (int port) throws IOException {
|
||||
this (port, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a Web server at the specified port number and IP address.
|
||||
*/
|
||||
public WebServer (int port, InetAddress add) throws IOException {
|
||||
this.port = port;
|
||||
xmlrpc = new XmlRpcServer ();
|
||||
accept = new Vector ();
|
||||
deny = new Vector ();
|
||||
threadpool = new Stack ();
|
||||
runners = new ThreadGroup ("XML-RPC Runner");
|
||||
serverSocket = new ServerSocket (port, 50, add);
|
||||
if (port == 0) // do we need to get the actual port of the socket?
|
||||
port = serverSocket.getLocalPort ();
|
||||
listener = new Thread (this, "XML-RPC Weblistener");
|
||||
listener.start();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register a handler object with this name. Methods of this objects will be
|
||||
* callable over XML-RPC as "name.method".
|
||||
*/
|
||||
public void addHandler (String name, Object target) {
|
||||
xmlrpc.addHandler (name, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a handler object that was previously registered with this server.
|
||||
*/
|
||||
public void removeHandler (String name) {
|
||||
xmlrpc.removeHandler (name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch client filtering on/off.
|
||||
* @see acceptClient(java.lang.String)
|
||||
* @see denyClient(java.lang.String)
|
||||
*/
|
||||
public void setParanoid (boolean p) {
|
||||
paranoid = p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the port the server is listening on. Useful when the initial port parameter
|
||||
* was 0 which means that any free port is used.
|
||||
*/
|
||||
public int getServerPort () {
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an IP address to the list of accepted clients. The parameter can contain '*' as wildcard
|
||||
* character, e.g. "192.168.*.*". You must call setParanoid(true) in order for this to have any
|
||||
* effect.
|
||||
*
|
||||
* @see denyClient(java.lang.String)
|
||||
* @see setParanoid(boolean)
|
||||
*/
|
||||
public void acceptClient (String address) throws IllegalArgumentException {
|
||||
try {
|
||||
AddressMatcher m = new AddressMatcher (address);
|
||||
accept.addElement (m);
|
||||
} catch (Exception x) {
|
||||
throw new IllegalArgumentException ("\""+address+"\" does not represent a valid IP address");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an IP address to the list of denied clients. The parameter can contain '*' as wildcard
|
||||
* character, e.g. "192.168.*.*". You must call setParanoid(true) in order for this to have any
|
||||
* effect.
|
||||
*
|
||||
* @see acceptClient(java.lang.String)
|
||||
* @see setParanoid(boolean)
|
||||
*/
|
||||
public void denyClient (String address) throws IllegalArgumentException {
|
||||
try {
|
||||
AddressMatcher m = new AddressMatcher (address);
|
||||
deny.addElement (m);
|
||||
} catch (Exception x) {
|
||||
throw new IllegalArgumentException ("\""+address+"\" does not represent a valid IP address");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkSocket (Socket s) {
|
||||
int l = deny.size ();
|
||||
byte address[] = s.getInetAddress ().getAddress ();
|
||||
for (int i=0; i<l; i++) {
|
||||
AddressMatcher match = (AddressMatcher) deny.elementAt (i);
|
||||
if (match.matches (address))
|
||||
return false;
|
||||
}
|
||||
l = accept.size ();
|
||||
for (int i=0; i<l; i++) {
|
||||
AddressMatcher match = (AddressMatcher) accept.elementAt (i);
|
||||
if (match.matches (address))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for client requests until stopped.
|
||||
*/
|
||||
public void run() {
|
||||
try {
|
||||
while (listener != null) {
|
||||
Socket socket = null;
|
||||
try {
|
||||
socket = serverSocket.accept();
|
||||
if (!paranoid || checkSocket (socket)) {
|
||||
Runner runner = getRunner ();
|
||||
runner.handle (socket);
|
||||
// new Connection (socket);
|
||||
} else
|
||||
socket.close ();
|
||||
} catch (Exception ex) {
|
||||
System.err.println("Exception in XML-RPC listener loop (" + ex + ").");
|
||||
try { socket.close (); } catch (Exception ignore) {}
|
||||
} catch (Error err) {
|
||||
System.err.println("Error in XML-RPC listener loop (" + err + ").");
|
||||
try { socket.close (); } catch (Exception ignore) {}
|
||||
}
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
System.err.println("Error accepting XML-RPC connections (" + exception + ").");
|
||||
}
|
||||
finally {
|
||||
System.err.println("Closing XML-RPC server socket.");
|
||||
try {
|
||||
serverSocket.close();
|
||||
serverSocket = null;
|
||||
}
|
||||
catch (IOException ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stop listening on the server port.
|
||||
*/
|
||||
public void shutdown () {
|
||||
if (listener != null) {
|
||||
Thread l = listener;
|
||||
listener = null;
|
||||
try {
|
||||
serverSocket.close ();
|
||||
} catch (Exception ignore) {}
|
||||
l.interrupt ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private Runner getRunner () {
|
||||
try {
|
||||
return (Runner) threadpool.pop ();
|
||||
} catch (EmptyStackException empty) {
|
||||
if (runners.activeCount () > 255)
|
||||
throw new RuntimeException ("System overload");
|
||||
return new Runner ();
|
||||
}
|
||||
}
|
||||
|
||||
void releaseRunner (Runner runner) {
|
||||
threadpool.push (runner);
|
||||
}
|
||||
|
||||
class Runner implements Runnable {
|
||||
|
||||
Thread thread;
|
||||
Connection con;
|
||||
int count;
|
||||
|
||||
public void handle (Socket socket) throws IOException {
|
||||
con = new Connection (socket);
|
||||
count = 0;
|
||||
if (thread == null || !thread.isAlive()) {
|
||||
thread = new Thread (runners, this);
|
||||
thread.start ();
|
||||
} else {
|
||||
synchronized (this) {
|
||||
notify ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void run () {
|
||||
while (Thread.currentThread () == thread) {
|
||||
con.run ();
|
||||
count++;
|
||||
con = null;
|
||||
|
||||
if (count > 200 || threadpool.size() > 20)
|
||||
return;
|
||||
|
||||
synchronized (this) {
|
||||
releaseRunner (this);
|
||||
try {
|
||||
wait ();
|
||||
} catch (InterruptedException ir) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end class Runner
|
||||
|
||||
|
||||
class Connection implements Runnable {
|
||||
|
||||
private Socket socket;
|
||||
private BufferedInputStream input;
|
||||
private BufferedOutputStream output;
|
||||
private long lastRequest;
|
||||
private String user, password;
|
||||
|
||||
public Connection (Socket socket) throws IOException {
|
||||
// set read timeout to 30 seconds
|
||||
socket.setSoTimeout (30000);
|
||||
|
||||
this.socket = socket;
|
||||
input = new BufferedInputStream (socket.getInputStream());
|
||||
output = new BufferedOutputStream (socket.getOutputStream());
|
||||
}
|
||||
|
||||
|
||||
public void run () {
|
||||
try {
|
||||
boolean keepalive = false;
|
||||
|
||||
do {
|
||||
// reset user authentication
|
||||
user = password = null;
|
||||
String line = readLine ();
|
||||
// Netscape sends an extra \n\r after bodypart, swallow it
|
||||
if ("".equals (line))
|
||||
line = readLine();
|
||||
if (XmlRpc.debug)
|
||||
System.err.println (line);
|
||||
// get time of last request
|
||||
lastRequest = System.currentTimeMillis ();
|
||||
int contentLength = -1;
|
||||
|
||||
// tokenize first line of HTTP request
|
||||
StringTokenizer tokens = new StringTokenizer(line);
|
||||
String method = tokens.nextToken();
|
||||
String uri = tokens.nextToken ();
|
||||
String httpversion = tokens.nextToken ();
|
||||
keepalive = XmlRpc.getKeepAlive() && "HTTP/1.1".equalsIgnoreCase (httpversion);
|
||||
do {
|
||||
line = readLine();
|
||||
if (line != null) {
|
||||
if (XmlRpc.debug)
|
||||
System.err.println (line);
|
||||
String lineLower = line.toLowerCase ();
|
||||
if (lineLower.startsWith ("content-length:"))
|
||||
contentLength = Integer.parseInt (line.substring (15).trim ());
|
||||
if (lineLower.startsWith ("connection:"))
|
||||
keepalive = XmlRpc.getKeepAlive() && lineLower.indexOf ("keep-alive") > -1;
|
||||
if (lineLower.startsWith ("authorization: basic "))
|
||||
parseAuth (line);
|
||||
}
|
||||
} while (line != null && ! line.equals(""));
|
||||
|
||||
if ("POST".equalsIgnoreCase (method)) {
|
||||
ServerInputStream sin = new ServerInputStream (input, contentLength);
|
||||
byte result[] = xmlrpc.execute (sin, user, password);
|
||||
output.write (httpversion.getBytes());
|
||||
output.write (ok);
|
||||
output.write (server);
|
||||
if (keepalive)
|
||||
output.write (conkeep);
|
||||
else
|
||||
output.write (conclose);
|
||||
output.write (ctype);
|
||||
output.write (clength);
|
||||
output.write (Integer.toString (result.length).getBytes());
|
||||
output.write (doubleNewline);
|
||||
output.write (result);
|
||||
output.flush ();
|
||||
} else {
|
||||
output.write (httpversion.getBytes());
|
||||
output.write (" 400 Bad Request\r\n".getBytes());
|
||||
output.write ("Server: helma.XML-RPC\r\n\r\n".getBytes());
|
||||
output.write (("Method "+method+" not implemented (try POST)").getBytes());
|
||||
output.flush ();
|
||||
keepalive = false;
|
||||
}
|
||||
} while (keepalive);
|
||||
} catch (Exception exception) {
|
||||
if (XmlRpc.debug) {
|
||||
System.err.println (exception);
|
||||
exception.printStackTrace ();
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
byte[] buffer;
|
||||
private String readLine () throws IOException {
|
||||
if (buffer == null) {
|
||||
buffer = new byte[512];
|
||||
}
|
||||
int next;
|
||||
int count = 0;
|
||||
for (;;) {
|
||||
next = input.read();
|
||||
if (next < 0 || next == '\n')
|
||||
break;
|
||||
if (next != '\r') {
|
||||
buffer[count++] = (byte) next;
|
||||
}
|
||||
if (count >= 512)
|
||||
throw new IOException ("HTTP Header too long");
|
||||
}
|
||||
return new String (buffer, 0, count);
|
||||
}
|
||||
|
||||
private void parseAuth (String line) {
|
||||
try {
|
||||
byte[] c = Base64.decode (line.substring (21).toCharArray ());
|
||||
String str = new String (c);
|
||||
int col = str.indexOf (":");
|
||||
user = str.substring (0, col);
|
||||
password = str.substring (col+1);
|
||||
} catch (Throwable ignore) {}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class AddressMatcher {
|
||||
|
||||
int pattern[];
|
||||
|
||||
public AddressMatcher (String address) throws Exception {
|
||||
pattern = new int[4];
|
||||
StringTokenizer st = new StringTokenizer (address, ".");
|
||||
if (st.countTokens () != 4)
|
||||
throw new Exception ("\""+address+"\" does not represent a valid IP address");
|
||||
for (int i=0; i<4; i++) {
|
||||
String next = st.nextToken ();
|
||||
if ("*".equals (next))
|
||||
pattern[i] = 256;
|
||||
else
|
||||
pattern[i] = (byte) Integer.parseInt (next);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean matches (byte address[]) {
|
||||
for (int i=0; i<4; i++) {
|
||||
if (pattern[i] > 255) // wildcard
|
||||
continue;
|
||||
if (pattern[i] != address[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// An echo handler for debugging purposes
|
||||
class Echo implements XmlRpcHandler {
|
||||
public Object execute (String method, Vector v) throws Exception {
|
||||
return (v);
|
||||
}
|
||||
}
|
||||
|
||||
// An simple class that implements authentication
|
||||
class AuthDemo implements AuthenticatedXmlRpcHandler {
|
||||
public Object execute (String method, Vector v, String user, String password) throws Exception {
|
||||
// our simplistic authentication guidelines never fail ;)
|
||||
if (user == null || user.startsWith ("script kiddie"))
|
||||
throw new XmlRpcException (5, "Sorry, you're not allowed in here!");
|
||||
return ("Hello "+user);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,628 +0,0 @@
|
|||
/**
|
||||
* Copyright 1999 Hannes Wallnoefer
|
||||
* XML-RPC base class. See http://www.xmlrpc.com/
|
||||
*/
|
||||
|
||||
package helma.xmlrpc;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.text.*;
|
||||
import org.xml.sax.*;
|
||||
|
||||
|
||||
/**
|
||||
* This abstract base class provides basic capabilities for XML-RPC, like parsing of parameters
|
||||
* or encoding Java objects into XML-RPC format. Any XML parser with a <a href=http://www.megginson.com/SAX/>
|
||||
* SAX</a> interface can be used.<p>
|
||||
* XmlRpcServer and XmlRpcClient are the classes that actually implement an XML-RCP server and client.
|
||||
* @see XmlRpcServer
|
||||
* @see XmlRpcClient
|
||||
*/
|
||||
|
||||
public abstract class XmlRpc extends HandlerBase {
|
||||
|
||||
public static final String version = "helma XML-RPC 1.0";
|
||||
|
||||
String methodName;
|
||||
|
||||
// class name of SAX parser to use
|
||||
private static Class parserClass;
|
||||
private static Hashtable saxDrivers = new Hashtable ();
|
||||
static {
|
||||
saxDrivers.put ("xp", "com.jclark.xml.sax.Driver");
|
||||
saxDrivers.put ("ibm1", "com.ibm.xml.parser.SAXDriver");
|
||||
saxDrivers.put ("ibm2", "com.ibm.xml.parsers.SAXParser");
|
||||
saxDrivers.put ("aelfred", "com.microstar.xml.SAXDriver");
|
||||
saxDrivers.put ("oracle1", "oracle.xml.parser.XMLParser");
|
||||
saxDrivers.put ("oracle2", "oracle.xml.parser.v2.SAXParser");
|
||||
saxDrivers.put ("openxml", "org.openxml.parser.XMLSAXParser");
|
||||
saxDrivers.put ("minml", "uk.co.wilson.xml.MinML");
|
||||
}
|
||||
|
||||
|
||||
// the stack we're parsing our values into.
|
||||
Stack values;
|
||||
Value currentValue;
|
||||
|
||||
// formats for parsing and generating dateTime values
|
||||
|
||||
// DateFormat datetime;
|
||||
// now comes wapped into a synchronized class because dateFormat is not threadsafe
|
||||
static Formatter dateformat = new Formatter ();
|
||||
|
||||
// used to collect character data of parameter values
|
||||
StringBuffer cdata;
|
||||
boolean readCdata;
|
||||
|
||||
// XML RPC parameter types used for dataMode
|
||||
static final int STRING = 0;
|
||||
static final int INTEGER = 1;
|
||||
static final int BOOLEAN = 2;
|
||||
static final int DOUBLE = 3;
|
||||
static final int DATE = 4;
|
||||
static final int BASE64 = 5;
|
||||
static final int STRUCT = 6;
|
||||
static final int ARRAY = 7;
|
||||
|
||||
// Error level + message
|
||||
int errorLevel;
|
||||
String errorMsg;
|
||||
|
||||
static final int NONE = 0;
|
||||
static final int RECOVERABLE = 1;
|
||||
static final int FATAL = 2;
|
||||
|
||||
// use HTTP keepalive?
|
||||
static boolean keepalive = false;
|
||||
|
||||
// for debugging output
|
||||
public static boolean debug = false;
|
||||
final static String types[] = {"String", "Integer", "Boolean", "Double", "Date", "Base64", "Struct", "Array"};
|
||||
|
||||
// mapping between java encoding names and "real" names used in XML prolog.
|
||||
// if you use an encoding not listed here send feedback to xmlrpc@helma.org
|
||||
|
||||
|
||||
static String encoding = "ISO8859_1";
|
||||
static Properties encodings = new Properties ();
|
||||
static {
|
||||
encodings.put ("UTF8", "UTF-8");
|
||||
encodings.put ("ISO8859_1", "ISO-8859-1");
|
||||
}
|
||||
private final char[] encdecl = {'e','n','c','o','d','i','n','g','='};
|
||||
|
||||
|
||||
/**
|
||||
* Set the SAX Parser to be used. The argument can either be the full class name or
|
||||
* a user friendly shortcut if the parser is known to this class. The parsers that can
|
||||
* currently be set by shortcut are listed in the main documentation page. If you are using
|
||||
* another parser please send me the name of the SAX driver and I'll include it in a future release.
|
||||
* If setDriver() is never called then the System property "sax.driver" is consulted. If that is not defined
|
||||
* the driver defaults to OpenXML.
|
||||
*/
|
||||
public static void setDriver (String driver) throws ClassNotFoundException {
|
||||
String parserClassName = null;
|
||||
try {
|
||||
parserClassName = (String) saxDrivers.get (driver);
|
||||
if (parserClassName == null)
|
||||
parserClassName = driver;
|
||||
parserClass = Class.forName (parserClassName);
|
||||
} catch (ClassNotFoundException x) {
|
||||
throw new ClassNotFoundException ("SAX driver not found: "+parserClassName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the SAX Parser to be used by directly passing the Class object.
|
||||
*/
|
||||
public static void setDriver (Class driver) {
|
||||
parserClass = driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the encoding of the XML. This should be the name of a Java encoding
|
||||
* contained in the encodings Hashtable.
|
||||
*/
|
||||
public static void setEncoding (String enc) {
|
||||
encoding = enc;
|
||||
}
|
||||
|
||||
public String getEncoding () {
|
||||
return encodings.getProperty (encoding, encoding);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Switch debugging output on/off.
|
||||
*/
|
||||
public static void setDebug (boolean val) {
|
||||
debug = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch HTTP keepalive on/off.
|
||||
*/
|
||||
public static void setKeepAlive (boolean val) {
|
||||
keepalive = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* get current HTTP keepalive mode.
|
||||
*/
|
||||
public static boolean getKeepAlive () {
|
||||
return keepalive;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse the input stream. For each root level object, method <code>objectParsed</code>
|
||||
* is called.
|
||||
*/
|
||||
synchronized void parse (InputStream is) throws Exception {
|
||||
|
||||
// reset values (XmlRpc objects are reusable)
|
||||
errorLevel = NONE;
|
||||
errorMsg = null;
|
||||
values = new Stack ();
|
||||
if (cdata == null)
|
||||
cdata = new StringBuffer (128);
|
||||
else
|
||||
cdata.setLength (0);
|
||||
readCdata = false;
|
||||
currentValue = null;
|
||||
|
||||
long now = System.currentTimeMillis ();
|
||||
if (parserClass == null) {
|
||||
// try to get the name of the SAX driver from the System properties
|
||||
setDriver (System.getProperty ("sax.driver", "uk.co.wilson.xml.MinML"));
|
||||
}
|
||||
|
||||
Parser parser = null;
|
||||
try {
|
||||
parser = (Parser) parserClass.newInstance ();
|
||||
} catch (NoSuchMethodError nsm) {
|
||||
// This is thrown if no constructor exists for the parser class
|
||||
// and is transformed into a regular exception.
|
||||
throw new Exception ("Can't create Parser: "+parserClass);
|
||||
}
|
||||
|
||||
parser.setDocumentHandler (this);
|
||||
parser.setErrorHandler (this);
|
||||
|
||||
parser.parse (new InputSource (getReader (is)));
|
||||
if (debug)
|
||||
System.err.println ("Spent "+(System.currentTimeMillis () - now)+" millis parsing");
|
||||
}
|
||||
|
||||
public Reader getReader (InputStream is) throws IOException {
|
||||
if (is.markSupported ()) {
|
||||
// here we try to get to the encoding declaration in the XML declaration.
|
||||
// we deliberately don't do it right, instead we just scan the first 64 characters
|
||||
// for 'encoding="..."'. Actually this should be done by the parser, but it seems only
|
||||
// the 2+MB parsers like Xerces do.
|
||||
is.mark (64);
|
||||
int matchidx = 0;
|
||||
boolean seenquote = false;
|
||||
StringBuffer encb = new StringBuffer (16);
|
||||
for (int i=0; i<64; i++) {
|
||||
int c = is.read();
|
||||
if (matchidx < encdecl.length) {
|
||||
if (c == encdecl[matchidx])
|
||||
matchidx ++;
|
||||
} else if ('"' == c || '\'' == c) {
|
||||
if (!seenquote)
|
||||
seenquote = true;
|
||||
else {
|
||||
is.reset ();
|
||||
if (encb.length() > 0) {
|
||||
try {
|
||||
return new InputStreamReader (is, encb.toString ());
|
||||
} catch (UnsupportedEncodingException ue) {
|
||||
System.err.println ("Warning: guessed invalid encoding from XML stream: "+ue.getMessage ());
|
||||
return new InputStreamReader (is);
|
||||
}
|
||||
} else {
|
||||
return new InputStreamReader (is);
|
||||
}
|
||||
}
|
||||
} else if (seenquote) {
|
||||
encb.append ((char) c);
|
||||
}
|
||||
}
|
||||
is.reset ();
|
||||
}
|
||||
return new InputStreamReader (is);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the XML representation of a supported Java object to the XML writer.
|
||||
*/
|
||||
void writeObject (Object what, XmlWriter writer) throws XmlRpcException {
|
||||
writer.startElement ("value");
|
||||
if (what instanceof String) {
|
||||
writer.chardata (what.toString ());
|
||||
} else if (what instanceof Integer) {
|
||||
writer.startElement ("int");
|
||||
writer.write (what.toString ());
|
||||
writer.endElement ("int");
|
||||
} else if (what instanceof Boolean) {
|
||||
writer.startElement ("boolean");
|
||||
writer.write (((Boolean) what).booleanValue () ? "1" : "0");
|
||||
writer.endElement ("boolean");
|
||||
} else if (what instanceof Double || what instanceof Float) {
|
||||
writer.startElement ("double");
|
||||
writer.write (what.toString ());
|
||||
writer.endElement ("double");
|
||||
} else if (what instanceof Date) {
|
||||
writer.startElement ("dateTime.iso8601");
|
||||
Date d = (Date) what;
|
||||
writer.write (dateformat.format (d));
|
||||
writer.endElement ("dateTime.iso8601");
|
||||
} else if (what instanceof byte[]) {
|
||||
writer.startElement ("base64");
|
||||
writer.write (Base64.encode ((byte[]) what));
|
||||
writer.endElement ("base64");
|
||||
} else if (what instanceof Vector) {
|
||||
writer.startElement ("array");
|
||||
writer.startElement ("data");
|
||||
Vector v = (Vector) what;
|
||||
int l2 = v.size ();
|
||||
for (int i2=0; i2<l2; i2++)
|
||||
writeObject (v.elementAt (i2), writer);
|
||||
writer.endElement ("data");
|
||||
writer.endElement ("array");
|
||||
} else if (what instanceof Hashtable) {
|
||||
writer.startElement ("struct");
|
||||
Hashtable h = (Hashtable) what;
|
||||
for (Enumeration e = h.keys (); e.hasMoreElements (); ) {
|
||||
try {
|
||||
String nextkey = (String) e.nextElement ();
|
||||
Object nextval = h.get (nextkey);
|
||||
writer.startElement ("member");
|
||||
writer.startElement ("name");
|
||||
writer.write (nextkey);
|
||||
writer.endElement ("name");
|
||||
writeObject (nextval, writer);
|
||||
writer.endElement ("member");
|
||||
} catch (ClassCastException cce) {
|
||||
throw new ClassCastException ("Only Strings may be used as keys in XML-RPC structs, but Hashtable contained "+cce.getMessage());
|
||||
}
|
||||
}
|
||||
writer.endElement ("struct");
|
||||
} else if (what == null) {
|
||||
throw new XmlRpcException (0, "null is not supported as parameter in XML-RPC.");
|
||||
} else {
|
||||
throw new XmlRpcException (0, "Java class not supported in XML-RPC: " + what.getClass ());
|
||||
}
|
||||
writer.endElement ("value");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is called when a root level object has been parsed.
|
||||
*/
|
||||
abstract void objectParsed (Object what);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// methods called by XML parser
|
||||
|
||||
/**
|
||||
* Method called by SAX driver.
|
||||
*/
|
||||
public void characters (char ch[], int start, int length) throws SAXException {
|
||||
if (!readCdata)
|
||||
return;
|
||||
cdata.append (ch, start, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called by SAX driver.
|
||||
*/
|
||||
public void endElement (String name) throws SAXException {
|
||||
|
||||
if (debug)
|
||||
System.err.println ("endElement: "+name);
|
||||
|
||||
// finalize character data, if appropriate
|
||||
if (currentValue != null && readCdata) {
|
||||
currentValue.characterData (cdata.toString ());
|
||||
cdata.setLength (0);
|
||||
readCdata = false;
|
||||
}
|
||||
|
||||
if ("value".equals (name)) {
|
||||
int depth = values.size ();
|
||||
// Only handle top level objects or objects contained in arrays here.
|
||||
// For objects contained in structs, wait for </member> (see code below).
|
||||
if (depth == 0 || values.peek ().hashCode () != STRUCT) {
|
||||
Value v = currentValue;
|
||||
if (depth == 0) {
|
||||
// This is a top-level object
|
||||
objectParsed (v.value);
|
||||
currentValue = null;
|
||||
} else {
|
||||
// add object to sub-array; if current container is a struct, add later (at </member>)
|
||||
currentValue = (Value) values.pop ();
|
||||
currentValue.endElement (v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle objects contained in structs.
|
||||
if ("member".equals (name)) {
|
||||
Value v = currentValue;
|
||||
currentValue = (Value) values.pop ();
|
||||
currentValue.endElement (v);
|
||||
}
|
||||
|
||||
else if ("methodName".equals (name)) {
|
||||
methodName = cdata.toString ();
|
||||
cdata.setLength (0);
|
||||
readCdata = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method called by SAX driver.
|
||||
*/
|
||||
public void startElement (String name, AttributeList atts) throws SAXException {
|
||||
|
||||
if (debug)
|
||||
System.err.println ("startElement: "+name);
|
||||
|
||||
if ("value".equals (name)) {
|
||||
// System.err.println ("starting value");
|
||||
if (currentValue != null)
|
||||
values.push (currentValue);
|
||||
currentValue = new Value ();
|
||||
// cdata object is reused
|
||||
cdata.setLength(0);
|
||||
readCdata = true;
|
||||
}
|
||||
|
||||
else if ("methodName".equals (name)) {
|
||||
cdata.setLength(0);
|
||||
readCdata = true;
|
||||
}
|
||||
|
||||
else if ("name".equals (name)) {
|
||||
cdata.setLength(0);
|
||||
readCdata = true;
|
||||
}
|
||||
|
||||
else if ("string".equals (name)) {
|
||||
cdata.setLength(0);
|
||||
readCdata = true;
|
||||
} else if ("i4".equals (name) || "int".equals (name)) {
|
||||
currentValue.setType (INTEGER);
|
||||
cdata.setLength(0);
|
||||
readCdata = true;
|
||||
} else if ("boolean".equals (name)) {
|
||||
currentValue.setType (BOOLEAN);
|
||||
cdata.setLength(0);
|
||||
readCdata = true;
|
||||
} else if ("double".equals (name)) {
|
||||
currentValue.setType (DOUBLE);
|
||||
cdata.setLength(0);
|
||||
readCdata = true;
|
||||
} else if ("dateTime.iso8601".equals (name)) {
|
||||
currentValue.setType (DATE);
|
||||
cdata.setLength(0);
|
||||
readCdata = true;
|
||||
} else if ("base64".equals (name)) {
|
||||
currentValue.setType (BASE64);
|
||||
cdata.setLength(0);
|
||||
readCdata = true;
|
||||
} else if ("struct".equals (name))
|
||||
currentValue.setType (STRUCT);
|
||||
else if ("array".equals (name))
|
||||
currentValue.setType (ARRAY);
|
||||
}
|
||||
|
||||
|
||||
public void error (SAXParseException e) throws SAXException {
|
||||
System.err.println ("Error parsing XML: "+e);
|
||||
errorLevel = RECOVERABLE;
|
||||
errorMsg = e.toString ();
|
||||
}
|
||||
|
||||
public void fatalError(SAXParseException e) throws SAXException {
|
||||
System.err.println ("Fatal error parsing XML: "+e);
|
||||
errorLevel = FATAL;
|
||||
errorMsg = e.toString ();
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents an XML-RPC Value while the request is being parsed.
|
||||
*/
|
||||
class Value {
|
||||
|
||||
int type;
|
||||
Object value;
|
||||
// the name to use for the next member of struct values
|
||||
String nextMemberName;
|
||||
|
||||
Hashtable struct;
|
||||
Vector array;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public Value () {
|
||||
this.type = STRING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification that a new child element has been parsed.
|
||||
*/
|
||||
public void endElement (Value child) {
|
||||
if (type == ARRAY)
|
||||
array.addElement (child.value);
|
||||
else if (type == STRUCT)
|
||||
struct.put (nextMemberName, child.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of this value. If it's a container, create the corresponding java container.
|
||||
*/
|
||||
public void setType (int type) {
|
||||
// System.err.println ("setting type to "+types[type]);
|
||||
this.type = type;
|
||||
if (type == ARRAY)
|
||||
value = array = new Vector ();
|
||||
if (type == STRUCT)
|
||||
value = struct = new Hashtable ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the character data for the element and interpret it according to the
|
||||
* element type
|
||||
*/
|
||||
public void characterData (String cdata) {
|
||||
switch (type) {
|
||||
case INTEGER:
|
||||
value = new Integer (cdata.trim ());
|
||||
break;
|
||||
case BOOLEAN:
|
||||
value = "1".equals (cdata.trim ()) ? Boolean.TRUE : Boolean.FALSE;
|
||||
break;
|
||||
case DOUBLE:
|
||||
value = new Double (cdata.trim ());
|
||||
break;
|
||||
case DATE:
|
||||
try {
|
||||
value = dateformat.parse (cdata.trim ());
|
||||
} catch (ParseException p) {
|
||||
// System.err.println ("Exception while parsing date: "+p);
|
||||
throw new RuntimeException (p.getMessage ());
|
||||
}
|
||||
break;
|
||||
case BASE64:
|
||||
value = Base64.decode (cdata.toCharArray ());
|
||||
break;
|
||||
case STRING:
|
||||
value = cdata;
|
||||
break;
|
||||
case STRUCT:
|
||||
// this is the name to use for the next member of this struct
|
||||
nextMemberName = cdata;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// This is a performance hack to get the type of a value without casting the Object.
|
||||
// It breaks the contract of method hashCode, but it doesn't matter since
|
||||
// Value objects are never used as keys in Hashtables.
|
||||
public int hashCode () {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
return (types[type]+" element "+value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// A quick and dirty XML writer.
|
||||
class XmlWriter {
|
||||
|
||||
StringBuffer buf;
|
||||
String enc;
|
||||
|
||||
public XmlWriter (StringBuffer buf) {
|
||||
// The encoding used for XML-RPC is ISO-8859-1 for pragmatical reasons (Frontier/Win).
|
||||
this (buf, encoding);
|
||||
}
|
||||
|
||||
public XmlWriter (StringBuffer buf, String enc) {
|
||||
this.buf = buf;
|
||||
buf.setLength (0);
|
||||
this.enc = enc;
|
||||
// get name of encoding for XML prolog
|
||||
String encName = encodings.getProperty (enc, enc);
|
||||
buf.append ("<?xml version=\"1.0\" encoding=\""+encName+"\"?>");
|
||||
}
|
||||
|
||||
public void startElement (String elem) {
|
||||
buf.append ("<");
|
||||
buf.append (elem);
|
||||
buf.append (">");
|
||||
}
|
||||
|
||||
public void endElement (String elem) {
|
||||
buf.append ("</");
|
||||
buf.append (elem);
|
||||
buf.append (">");
|
||||
}
|
||||
|
||||
public void emptyElement (String elem) {
|
||||
buf.append ("<");
|
||||
buf.append (elem);
|
||||
buf.append ("/>");
|
||||
}
|
||||
|
||||
|
||||
public void chardata (String text) {
|
||||
int l = text.length ();
|
||||
for (int i=0; i<l; i++) {
|
||||
char c = text.charAt (i);
|
||||
switch (c) {
|
||||
case '<' :
|
||||
buf.append ("<");
|
||||
break;
|
||||
case '&' :
|
||||
buf.append ("&");
|
||||
break;
|
||||
default :
|
||||
buf.append (c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void write (char[] text) {
|
||||
buf.append (text);
|
||||
}
|
||||
|
||||
public void write (String text) {
|
||||
buf.append (text);
|
||||
}
|
||||
|
||||
public void write (char c) {
|
||||
buf.append (c);
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
return buf.toString ();
|
||||
}
|
||||
|
||||
public byte[] getBytes () throws UnsupportedEncodingException {
|
||||
return buf.toString ().getBytes (enc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// wraps a DateFormat because it's not threadsafe
|
||||
class Formatter {
|
||||
|
||||
private DateFormat f;
|
||||
|
||||
public Formatter () {
|
||||
f = new SimpleDateFormat ("yyyyMMdd'T'HH:mm:ss");
|
||||
}
|
||||
|
||||
public synchronized String format (Date d) {
|
||||
return f.format (d);
|
||||
}
|
||||
|
||||
public synchronized Date parse (String s) throws ParseException {
|
||||
return f.parse (s);
|
||||
}
|
||||
}
|
|
@ -1,365 +0,0 @@
|
|||
/**
|
||||
* Copyright 1999 Hannes Wallnoefer
|
||||
* Implements a XML-RPC client. See http://www.xmlrpc.com/
|
||||
*/
|
||||
|
||||
package helma.xmlrpc;
|
||||
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import org.xml.sax.*;
|
||||
|
||||
/**
|
||||
* A multithreaded, reusable XML-RPC client object. Use this if you need a full-grown
|
||||
* HTTP client (e.g. for Proxy and Cookies support). If you don't need that, <code>XmlRpcClientLite</code>
|
||||
* may work better for you.
|
||||
*/
|
||||
public class XmlRpcClient implements XmlRpcHandler {
|
||||
|
||||
URL url;
|
||||
String auth;
|
||||
int maxThreads = 100;
|
||||
|
||||
// pool of worker instances
|
||||
Stack pool = new Stack ();
|
||||
int workers = 0;
|
||||
int asyncWorkers = 0;
|
||||
|
||||
|
||||
// average roundtrip of this method call. This is used to decide if
|
||||
// additional threads are needed or not in async mode
|
||||
int roundtrip = 1000;
|
||||
|
||||
// a queue of calls to be handled asynchronously
|
||||
CallData first, last;
|
||||
|
||||
/**
|
||||
* Construct a XML-RPC client with this URL.
|
||||
*/
|
||||
public XmlRpcClient (URL url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a XML-RPC client for the URL represented by this String.
|
||||
*/
|
||||
public XmlRpcClient (String url) throws MalformedURLException {
|
||||
this.url = new URL (url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a XML-RPC client for the specified hostname and port.
|
||||
*/
|
||||
public XmlRpcClient (String hostname, int port) throws MalformedURLException {
|
||||
this.url = new URL ("http://"+hostname+":"+port+"/RPC2");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the URL for this XML-RPC client.
|
||||
*/
|
||||
public URL getURL () {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets Authentication for this client. This will be sent as Basic Authentication header
|
||||
* to the server as described in <a href="http://www.ietf.org/rfc/rfc2617.txt">http://www.ietf.org/rfc/rfc2617.txt</a>.
|
||||
*/
|
||||
public void setBasicAuthentication (String user, String password) {
|
||||
if (user == null || password == null)
|
||||
auth = null;
|
||||
else {
|
||||
char[] basicAuth = Base64.encode ((user+":"+password).getBytes());
|
||||
auth = new String (basicAuth).trim();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate an XML-RPC request and send it to the server. Parse the result and
|
||||
* return the corresponding Java object.
|
||||
*
|
||||
* @exception XmlRpcException: If the remote host returned a fault message.
|
||||
* @exception IOException: If the call could not be made because of lower level problems.
|
||||
*/
|
||||
public Object execute (String method, Vector params) throws XmlRpcException, IOException {
|
||||
Worker worker = getWorker (false);
|
||||
long start = System.currentTimeMillis ();
|
||||
try {
|
||||
Object retval = worker.execute (method, params);
|
||||
long end = System.currentTimeMillis ();
|
||||
roundtrip = (int) ((roundtrip*4)+(end-start))/5;
|
||||
return retval;
|
||||
} finally {
|
||||
releaseWorker (worker, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an XML-RPC request and send it to the server in a new thread.
|
||||
* This method returns immediately.
|
||||
* If the callback parameter is not null, it will be called later to handle the result or error when the call is finished.
|
||||
*
|
||||
*/
|
||||
public void executeAsync (String method, Vector params, AsyncCallback callback) {
|
||||
if (asyncWorkers > 2) {
|
||||
enqueue (method, params, callback);
|
||||
return;
|
||||
}
|
||||
Worker worker = null;
|
||||
try {
|
||||
worker = getWorker (true);
|
||||
worker.executeAsync (method, params, callback);
|
||||
} catch (IOException iox) {
|
||||
// make a queued worker that doesn't run immediately
|
||||
enqueue (method, params, callback);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
synchronized Worker getWorker (boolean async) throws IOException {
|
||||
try {
|
||||
Worker w = (Worker) pool.pop ();
|
||||
if (async)
|
||||
asyncWorkers += 1;
|
||||
else
|
||||
workers += 1;
|
||||
return w;
|
||||
} catch (EmptyStackException x) {
|
||||
if (workers < maxThreads) {
|
||||
if (async)
|
||||
asyncWorkers += 1;
|
||||
else
|
||||
workers += 1;
|
||||
return new Worker ();
|
||||
}
|
||||
throw new IOException ("XML-RPC System overload");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Release possibly big per-call object references to allow them to be garbage collected
|
||||
*/
|
||||
synchronized void releaseWorker (Worker w, boolean async) {
|
||||
w.result = null;
|
||||
w.call = null;
|
||||
if (pool.size() < 20 && !w.fault)
|
||||
pool.push (w);
|
||||
if (async)
|
||||
asyncWorkers -= 1;
|
||||
else
|
||||
workers -= 1;
|
||||
}
|
||||
|
||||
|
||||
synchronized void enqueue (String method, Vector params, AsyncCallback callback) {
|
||||
CallData call = new CallData (method, params, callback);
|
||||
if (last == null)
|
||||
first = last = call;
|
||||
else {
|
||||
last.next = call;
|
||||
last = call;
|
||||
}
|
||||
}
|
||||
|
||||
synchronized CallData dequeue () {
|
||||
if (first == null)
|
||||
return null;
|
||||
if (asyncWorkers > 4 && asyncWorkers*4 > roundtrip)
|
||||
return null;
|
||||
CallData call = first;
|
||||
if (first == last)
|
||||
first = last = null;
|
||||
else
|
||||
first = first.next;
|
||||
return call;
|
||||
}
|
||||
|
||||
class Worker extends XmlRpc implements Runnable {
|
||||
|
||||
boolean fault;
|
||||
Object result = null;
|
||||
StringBuffer strbuf;
|
||||
|
||||
CallData call;
|
||||
|
||||
public Worker () {
|
||||
super ();
|
||||
}
|
||||
|
||||
|
||||
public void executeAsync (String method, Vector params, AsyncCallback callback) {
|
||||
this.call = new CallData (method, params, callback);
|
||||
Thread t = new Thread (this);
|
||||
t.start ();
|
||||
}
|
||||
|
||||
public void run () {
|
||||
while (call != null) {
|
||||
runAsync (call.method, call.params, call.callback);
|
||||
call = dequeue ();
|
||||
}
|
||||
releaseWorker (this, true);
|
||||
}
|
||||
|
||||
void runAsync (String method, Vector params, AsyncCallback callback) {
|
||||
Object res = null;
|
||||
long start = System.currentTimeMillis ();
|
||||
try {
|
||||
res = execute (method, params);
|
||||
// notify callback object
|
||||
if (callback != null)
|
||||
callback.handleResult (res, url, method);
|
||||
} catch (Exception x) {
|
||||
if (callback != null) try {
|
||||
callback.handleError (x, url, method);
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
long end = System.currentTimeMillis ();
|
||||
roundtrip = (int) ((roundtrip*4)+(end-start))/5;
|
||||
}
|
||||
|
||||
Object execute (String method, Vector params) throws XmlRpcException, IOException {
|
||||
fault = false;
|
||||
long now = System.currentTimeMillis ();
|
||||
try {
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream ();
|
||||
|
||||
if (strbuf == null)
|
||||
strbuf = new StringBuffer ();
|
||||
|
||||
XmlWriter writer = new XmlWriter (strbuf);
|
||||
writeRequest (writer, method, params);
|
||||
byte[] request = writer.getBytes();
|
||||
|
||||
URLConnection con = url.openConnection ();
|
||||
con.setDoInput (true);
|
||||
con.setDoOutput (true);
|
||||
con.setUseCaches (false);
|
||||
con.setAllowUserInteraction(false);
|
||||
con.setRequestProperty ("Content-Length", Integer.toString (request.length));
|
||||
con.setRequestProperty ("Content-Type", "text/xml");
|
||||
if (auth != null)
|
||||
con.setRequestProperty ("Authorization", "Basic "+auth);
|
||||
// con.connect ();
|
||||
OutputStream out = con.getOutputStream ();
|
||||
out.write (request);
|
||||
out.flush ();
|
||||
InputStream in = con.getInputStream ();
|
||||
parse (in);
|
||||
} catch (Exception x) {
|
||||
x.printStackTrace ();
|
||||
throw new IOException (x.getMessage ());
|
||||
}
|
||||
if (fault) { // generate an XmlRpcException
|
||||
XmlRpcException exception = null;
|
||||
try {
|
||||
Hashtable f = (Hashtable) result;
|
||||
String faultString = (String) f.get ("faultString");
|
||||
int faultCode = Integer.parseInt (f.get ("faultCode").toString ());
|
||||
exception = new XmlRpcException (faultCode, faultString.trim ());
|
||||
} catch (Exception x) {
|
||||
throw new XmlRpcException (0, "Invalid fault response");
|
||||
}
|
||||
throw exception;
|
||||
}
|
||||
if (debug)
|
||||
System.err.println ("Spent "+(System.currentTimeMillis () - now)+" in request");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when the return value has been parsed.
|
||||
*/
|
||||
void objectParsed (Object what) {
|
||||
result = what;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate an XML-RPC request from a method name and a parameter vector.
|
||||
*/
|
||||
void writeRequest (XmlWriter writer, String method, Vector params) throws IOException, XmlRpcException {
|
||||
writer.startElement ("methodCall");
|
||||
|
||||
writer.startElement ("methodName");
|
||||
writer.write (method);
|
||||
writer.endElement ("methodName");
|
||||
|
||||
writer.startElement ("params");
|
||||
int l = params.size ();
|
||||
for (int i=0; i<l; i++) {
|
||||
writer.startElement ("param");
|
||||
writeObject (params.elementAt (i), writer);
|
||||
writer.endElement ("param");
|
||||
}
|
||||
writer.endElement ("params");
|
||||
writer.endElement ("methodCall");
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides method in XmlRpc to handle fault repsonses.
|
||||
*/
|
||||
public void startElement (String name, AttributeList atts) throws SAXException {
|
||||
if ("fault".equals (name))
|
||||
fault = true;
|
||||
else
|
||||
super.startElement (name, atts);
|
||||
}
|
||||
|
||||
|
||||
} // end of inner class Worker
|
||||
|
||||
|
||||
class CallData {
|
||||
|
||||
String method;
|
||||
Vector params;
|
||||
AsyncCallback callback;
|
||||
CallData next;
|
||||
|
||||
/**
|
||||
* Make a call to be queued and then executed by the next free async thread
|
||||
*/
|
||||
public CallData (String method, Vector params, AsyncCallback callback) {
|
||||
this.method = method;
|
||||
this.params = params;
|
||||
this.callback = callback;
|
||||
this.next = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Just for testing.
|
||||
*/
|
||||
public static void main (String args[]) throws Exception {
|
||||
// XmlRpc.setDebug (true);
|
||||
// XmlRpc.setKeepAlive (true);
|
||||
try {
|
||||
String url = args[0];
|
||||
String method = args[1];
|
||||
Vector v = new Vector ();
|
||||
for (int i=2; i<args.length; i++) try {
|
||||
v.addElement (new Integer (Integer.parseInt (args[i])));
|
||||
} catch (NumberFormatException nfx) {
|
||||
v.addElement (args[i]);
|
||||
}
|
||||
XmlRpcClient client = new XmlRpcClientLite (url);
|
||||
try {
|
||||
System.err.println (client.execute (method, v));
|
||||
} catch (Exception ex) {
|
||||
System.err.println ("Error: "+ex.getMessage());
|
||||
}
|
||||
} catch (Exception x) {
|
||||
System.err.println (x);
|
||||
System.err.println ("Usage: java helma.xmlrpc.XmlRpcClient <url> <method> <arg> ....");
|
||||
System.err.println ("Arguments are sent as integers or strings.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,304 +0,0 @@
|
|||
/**
|
||||
* Copyright 1999 Hannes Wallnoefer
|
||||
* Implements a XML-RPC client. See http://www.xmlrpc.com/
|
||||
*/
|
||||
|
||||
package helma.xmlrpc;
|
||||
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import org.xml.sax.*;
|
||||
|
||||
/**
|
||||
* A multithreaded, reusable XML-RPC client object. This version uses a homegrown
|
||||
* HTTP client which can be quite a bit faster than java.net.URLConnection, especially
|
||||
* when used with XmlRpc.setKeepAlive(true).
|
||||
*/
|
||||
public class XmlRpcClientLite extends XmlRpcClient {
|
||||
|
||||
static String auth;
|
||||
|
||||
/**
|
||||
* Construct a XML-RPC client with this URL.
|
||||
*/
|
||||
public XmlRpcClientLite (URL url) {
|
||||
super (url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a XML-RPC client for the URL represented by this String.
|
||||
*/
|
||||
public XmlRpcClientLite (String url) throws MalformedURLException {
|
||||
super (url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a XML-RPC client for the specified hostname and port.
|
||||
*/
|
||||
public XmlRpcClientLite (String hostname, int port) throws MalformedURLException {
|
||||
super (hostname, port);
|
||||
}
|
||||
|
||||
|
||||
synchronized Worker getWorker (boolean async) throws IOException {
|
||||
try {
|
||||
Worker w = (Worker) pool.pop ();
|
||||
if (async)
|
||||
asyncWorkers += 1;
|
||||
else
|
||||
workers += 1;
|
||||
return w;
|
||||
} catch (EmptyStackException x) {
|
||||
if (workers < maxThreads) {
|
||||
if (async)
|
||||
asyncWorkers += 1;
|
||||
else
|
||||
workers += 1;
|
||||
return new LiteWorker ();
|
||||
}
|
||||
throw new IOException ("XML-RPC System overload");
|
||||
}
|
||||
}
|
||||
|
||||
class LiteWorker extends Worker implements Runnable {
|
||||
|
||||
HttpClient client = null;
|
||||
|
||||
public LiteWorker () {
|
||||
super ();
|
||||
}
|
||||
|
||||
|
||||
Object execute (String method, Vector params) throws XmlRpcException, IOException {
|
||||
long now = System.currentTimeMillis ();
|
||||
fault = false;
|
||||
try {
|
||||
if (strbuf == null)
|
||||
strbuf = new StringBuffer ();
|
||||
else
|
||||
strbuf.setLength (0);
|
||||
XmlWriter writer = new XmlWriter (strbuf);
|
||||
writeRequest (writer, method, params);
|
||||
byte[] request = writer.getBytes();
|
||||
|
||||
// and send it to the server
|
||||
if (client == null)
|
||||
client = new HttpClient (url);
|
||||
|
||||
client.write (request);
|
||||
|
||||
InputStream in = client.getInputStream ();
|
||||
|
||||
// parse the response
|
||||
parse (in);
|
||||
|
||||
// client keepalive is always false if XmlRpc.keepalive is false
|
||||
if (!client.keepalive)
|
||||
client.closeConnection ();
|
||||
|
||||
if (debug)
|
||||
System.err.println ("result = "+result);
|
||||
|
||||
// check for errors from the XML parser
|
||||
if (errorLevel == FATAL)
|
||||
throw new Exception (errorMsg);
|
||||
} catch (IOException iox) {
|
||||
// this is a lower level problem, client could not talk to server for some reason.
|
||||
|
||||
throw iox;
|
||||
|
||||
} catch (Exception x) {
|
||||
// same as above, but exception has to be converted to IOException.
|
||||
if (XmlRpc.debug)
|
||||
x.printStackTrace ();
|
||||
|
||||
String msg = x.getMessage ();
|
||||
if (msg == null || msg.length () == 0)
|
||||
msg = x.toString ();
|
||||
throw new IOException (msg);
|
||||
}
|
||||
|
||||
if (fault) {
|
||||
// this is an XML-RPC-level problem, i.e. the server reported an error.
|
||||
// throw an XmlRpcException.
|
||||
|
||||
XmlRpcException exception = null;
|
||||
try {
|
||||
Hashtable f = (Hashtable) result;
|
||||
String faultString = (String) f.get ("faultString");
|
||||
int faultCode = Integer.parseInt (f.get ("faultCode").toString ());
|
||||
exception = new XmlRpcException (faultCode, faultString.trim ());
|
||||
} catch (Exception x) {
|
||||
throw new XmlRpcException (0, "Server returned an invalid fault response.");
|
||||
}
|
||||
throw exception;
|
||||
}
|
||||
if (debug)
|
||||
System.err.println ("Spent "+(System.currentTimeMillis () - now)+" millis in request");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end of class Worker
|
||||
|
||||
|
||||
// A replacement for java.net.URLConnection, which seems very slow on MS Java.
|
||||
class HttpClient {
|
||||
|
||||
String hostname;
|
||||
String host;
|
||||
int port;
|
||||
String uri;
|
||||
Socket socket = null;
|
||||
BufferedOutputStream output;
|
||||
BufferedInputStream input;
|
||||
boolean keepalive;
|
||||
boolean fresh;
|
||||
|
||||
|
||||
public HttpClient (URL url) throws IOException {
|
||||
hostname = url.getHost ();
|
||||
port = url.getPort ();
|
||||
if (port < 1) port = 80;
|
||||
uri = url.getFile ();
|
||||
if (uri == null || "".equals (uri))
|
||||
uri = "/";
|
||||
host = port == 80 ? hostname : hostname+":"+port;
|
||||
initConnection ();
|
||||
}
|
||||
|
||||
protected void initConnection () throws IOException {
|
||||
fresh = true;
|
||||
socket = new Socket (hostname, port);
|
||||
output = new BufferedOutputStream (socket.getOutputStream());
|
||||
input = new BufferedInputStream (socket.getInputStream ());
|
||||
}
|
||||
|
||||
protected void closeConnection () {
|
||||
try {
|
||||
socket.close ();
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
|
||||
public void write (byte[] request) throws IOException {
|
||||
try {
|
||||
output.write (("POST "+uri+" HTTP/1.0\r\n").getBytes());
|
||||
output.write (("User-Agent: "+XmlRpc.version+"\r\n").getBytes());
|
||||
output.write (("Host: "+host+"\r\n").getBytes());
|
||||
if (XmlRpc.getKeepAlive())
|
||||
output.write ("Connection: Keep-Alive\r\n".getBytes());
|
||||
output.write ("Content-Type: text/xml\r\n".getBytes());
|
||||
if (auth != null)
|
||||
output.write (("Authorization: Basic "+auth+"\r\n").getBytes());
|
||||
output.write (("Content-Length: "+request.length).getBytes());
|
||||
output.write ("\r\n\r\n".getBytes());
|
||||
output.write (request);
|
||||
output.flush ();
|
||||
fresh = false;
|
||||
} catch (IOException iox) {
|
||||
// if the connection is not "fresh" (unused), the exception may have occurred
|
||||
// because the server timed the connection out. Give it another try.
|
||||
if (!fresh) {
|
||||
initConnection ();
|
||||
write (request);
|
||||
} else {
|
||||
throw (iox);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public InputStream getInputStream () throws IOException {
|
||||
String line = readLine ();
|
||||
if (XmlRpc.debug)
|
||||
System.err.println (line);
|
||||
int contentLength = -1;
|
||||
try {
|
||||
StringTokenizer tokens = new StringTokenizer (line);
|
||||
String httpversion = tokens.nextToken ();
|
||||
String statusCode = tokens.nextToken();
|
||||
String statusMsg = tokens.nextToken ("\n\r");
|
||||
keepalive = XmlRpc.getKeepAlive() && "HTTP/1.1".equals (httpversion);
|
||||
if (!"200".equals (statusCode))
|
||||
throw new IOException ("Unexpected Response from Server: "+statusMsg);
|
||||
} catch (IOException iox) {
|
||||
throw iox;
|
||||
} catch (Exception x) {
|
||||
// x.printStackTrace ();
|
||||
throw new IOException ("Server returned invalid Response.");
|
||||
}
|
||||
do {
|
||||
line = readLine ();
|
||||
if (line != null) {
|
||||
if (XmlRpc.debug)
|
||||
System.err.println (line);
|
||||
line = line.toLowerCase ();
|
||||
if (line.startsWith ("content-length:"))
|
||||
contentLength = Integer.parseInt (line.substring (15).trim ());
|
||||
if (line.startsWith ("connection:"))
|
||||
keepalive = XmlRpc.getKeepAlive() && line.indexOf ("keep-alive") > -1;
|
||||
}
|
||||
} while (line != null && ! line.equals(""));
|
||||
return new ServerInputStream (input, contentLength);
|
||||
}
|
||||
|
||||
|
||||
byte[] buffer;
|
||||
private String readLine () throws IOException {
|
||||
if (buffer == null)
|
||||
buffer = new byte[512];
|
||||
int next;
|
||||
int count = 0;
|
||||
while (true) {
|
||||
next = input.read();
|
||||
if (next < 0 || next == '\n')
|
||||
break;
|
||||
if (next != '\r')
|
||||
buffer[count++] = (byte) next;
|
||||
if (count >= 512)
|
||||
throw new IOException ("HTTP Header too long");
|
||||
}
|
||||
return new String (buffer, 0, count);
|
||||
}
|
||||
|
||||
|
||||
protected void finalize () throws Throwable {
|
||||
closeConnection ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Just for testing.
|
||||
*/
|
||||
public static void main (String args[]) throws Exception {
|
||||
// XmlRpc.setDebug (true);
|
||||
try {
|
||||
String url = args[0];
|
||||
String method = args[1];
|
||||
XmlRpcClientLite client = new XmlRpcClientLite (url);
|
||||
Vector v = new Vector ();
|
||||
for (int i=2; i<args.length; i++) try {
|
||||
v.addElement (new Integer (Integer.parseInt (args[i])));
|
||||
} catch (NumberFormatException nfx) {
|
||||
v.addElement (args[i]);
|
||||
}
|
||||
// XmlRpc.setEncoding ("UTF-8");
|
||||
try {
|
||||
System.err.println (client.execute (method, v));
|
||||
} catch (Exception ex) {
|
||||
System.err.println ("Error: "+ex.getMessage());
|
||||
}
|
||||
} catch (Exception x) {
|
||||
System.err.println (x);
|
||||
System.err.println ("Usage: java helma.xmlrpc.XmlRpcClient <url> <method> <arg> ....");
|
||||
System.err.println ("Arguments are sent as integers or strings.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
/**
|
||||
* Copyright 1999 Hannes Wallnoefer
|
||||
*/
|
||||
|
||||
package helma.xmlrpc;
|
||||
|
||||
/**
|
||||
* This is thrown by the XmlRpcClient if the remote server reported an error. If something
|
||||
* went wrong at a lower level (e.g. no http connection) an IOException will be thrown instead.
|
||||
*/
|
||||
public class XmlRpcException extends Exception {
|
||||
|
||||
/**
|
||||
* The fault code of the exception. For servers based on this library, this will always be 0.
|
||||
* (If there are predefined error codes, they should be in the XML-RPC spec.)
|
||||
*/
|
||||
public final int code;
|
||||
|
||||
public XmlRpcException (int code, String message) {
|
||||
super (message);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
* Copyright 1999 Hannes Wallnoefer
|
||||
*/
|
||||
|
||||
package helma.xmlrpc;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* The XML-RPC server uses this interface to call a method of an RPC handler. This should
|
||||
* be implemented by any class that wants to directly take control when it is called over RPC. Classes
|
||||
* not implementing this interface will be wrapped into an Invoker
|
||||
* object that tries to find the matching method for an XML-RPC request.
|
||||
*/
|
||||
|
||||
public interface XmlRpcHandler {
|
||||
|
||||
/**
|
||||
* Return the result, or throw an Exception if something went wrong.
|
||||
*/
|
||||
public Object execute (String method, Vector params) throws Exception;
|
||||
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
// Copyright 2000 Hannes Wallnöfer
|
||||
|
||||
package helma.xmlrpc;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.*;
|
||||
import java.io.*;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* A Servlet that acts as a XML-RPC Proxy . <p>
|
||||
*
|
||||
* The URL of the server to connect to is taken from the init parameter <tt>url</tt>.
|
||||
*/
|
||||
|
||||
public class XmlRpcProxyServlet extends HttpServlet {
|
||||
|
||||
private XmlRpcServer xmlrpc;
|
||||
|
||||
public void init (ServletConfig config) throws ServletException {
|
||||
if ("true".equalsIgnoreCase (config.getInitParameter ("debug")))
|
||||
XmlRpc.setDebug (true);
|
||||
String url = config.getInitParameter ("url");
|
||||
xmlrpc = new XmlRpcServer ();
|
||||
try {
|
||||
xmlrpc.addHandler ("$default", new XmlRpcClientLite (url));
|
||||
} catch (Exception x) {
|
||||
throw new ServletException ("Invalid URL: "+url+" ("+x.toString ()+")");
|
||||
}
|
||||
}
|
||||
|
||||
public void doPost(HttpServletRequest req, HttpServletResponse res)
|
||||
throws ServletException, IOException {
|
||||
byte[] result = xmlrpc.execute (req.getInputStream ());
|
||||
res.setContentType("text/xml");
|
||||
res.setContentLength (result.length);
|
||||
OutputStream output = res.getOutputStream();
|
||||
output.write (result);
|
||||
output.flush ();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,296 +0,0 @@
|
|||
/**
|
||||
* Copyright 1999 Hannes Wallnoefer
|
||||
* Implements an XML-RPC server. See http://www.xmlrpc.com/
|
||||
*/
|
||||
|
||||
package helma.xmlrpc;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.lang.reflect.*;
|
||||
|
||||
/**
|
||||
* A multithreaded, reusable XML-RPC server object. The name may be misleading because this does not open any
|
||||
* server sockets. Instead it is fed by passing an XML-RPC input stream to the execute method.
|
||||
* If you want to open a HTTP listener, use the WebServer class instead.
|
||||
*/
|
||||
public class XmlRpcServer {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
Hashtable handlers;
|
||||
|
||||
/**
|
||||
* Construct a new XML-RPC server. You have to register handlers to make it
|
||||
* do something useful.
|
||||
*/
|
||||
public XmlRpcServer () {
|
||||
handlers = new Hashtable ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a handler object with this name. Methods of this objects will be
|
||||
* callable over XML-RPC as "handlername.methodname". For more information
|
||||
* about XML-RPC handlers see the <a href="../index.html#1a">main documentation page</a>.
|
||||
*/
|
||||
public void addHandler (String handlername, Object handler) {
|
||||
if (handler instanceof XmlRpcHandler || handler instanceof AuthenticatedXmlRpcHandler)
|
||||
handlers.put (handlername, handler);
|
||||
else if (handler != null)
|
||||
handlers.put (handlername, new Invoker (handler));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a handler object that was previously registered with this server.
|
||||
*/
|
||||
public void removeHandler (String handlername) {
|
||||
handlers.remove (handlername);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the request and execute the handler method, if one is found. Returns the result as XML.
|
||||
* The calling Java code doesn't need to know whether the call was successful or not since this is all
|
||||
* packed into the response.
|
||||
*/
|
||||
public byte[] execute (InputStream is) {
|
||||
return execute (is, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the request and execute the handler method, if one is found. If the invoked handler is
|
||||
* AuthenticatedXmlRpcHandler, use the credentials to authenticate the user.
|
||||
*/
|
||||
public byte[] execute (InputStream is, String user, String password) {
|
||||
Worker worker = getWorker ();
|
||||
byte[] retval = worker.execute (is, user, password);
|
||||
pool.push (worker);
|
||||
return retval;
|
||||
}
|
||||
|
||||
Stack pool = new Stack ();
|
||||
int workers = 0;
|
||||
|
||||
private final Worker getWorker () {
|
||||
try {
|
||||
return (Worker) pool.pop ();
|
||||
} catch (EmptyStackException x) {
|
||||
if (workers < 100) {
|
||||
workers += 1;
|
||||
return new Worker ();
|
||||
}
|
||||
throw new RuntimeException ("System overload");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Worker extends XmlRpc {
|
||||
|
||||
Vector inParams;
|
||||
Object outParam;
|
||||
byte[] result;
|
||||
StringBuffer strbuf;
|
||||
|
||||
public byte[] execute (InputStream is, String user, String password) {
|
||||
inParams = new Vector ();
|
||||
if (strbuf == null)
|
||||
strbuf = new StringBuffer ();
|
||||
|
||||
long now = System.currentTimeMillis ();
|
||||
|
||||
try {
|
||||
parse (is);
|
||||
if (debug) {
|
||||
System.err.println ("method name: "+methodName);
|
||||
System.err.println ("inparams: "+inParams);
|
||||
}
|
||||
// check for errors from the XML parser
|
||||
if (errorLevel > NONE)
|
||||
throw new Exception (errorMsg);
|
||||
|
||||
Object handler = null;
|
||||
|
||||
String handlerName = null;
|
||||
int dot = methodName.indexOf (".");
|
||||
if (dot > -1) {
|
||||
handlerName = methodName.substring (0, dot);
|
||||
handler = handlers.get (handlerName);
|
||||
if (handler != null)
|
||||
methodName = methodName.substring (dot+1);
|
||||
}
|
||||
|
||||
if (handler == null) {
|
||||
handler = handlers.get ("$default");
|
||||
}
|
||||
|
||||
if (handler == null) {
|
||||
if (dot > -1)
|
||||
throw new Exception ("RPC handler object \""+handlerName+"\" not found and no default handler registered.");
|
||||
else
|
||||
throw new Exception ("RPC handler object not found for \""+methodName+"\": no default handler registered.");
|
||||
}
|
||||
|
||||
if (handler instanceof AuthenticatedXmlRpcHandler)
|
||||
outParam = ((AuthenticatedXmlRpcHandler) handler).execute (methodName, inParams, user, password);
|
||||
else
|
||||
outParam = ((XmlRpcHandler) handler).execute (methodName, inParams);
|
||||
if (debug)
|
||||
System.err.println ("outparam = "+outParam);
|
||||
|
||||
XmlWriter writer = new XmlWriter (strbuf);
|
||||
writeResponse (outParam, writer);
|
||||
result = writer.getBytes ();
|
||||
|
||||
} catch (Exception x) {
|
||||
if (debug)
|
||||
x.printStackTrace ();
|
||||
XmlWriter writer = new XmlWriter (strbuf);
|
||||
String message = x.toString ();
|
||||
// check if XmlRpcException was thrown so we can get an error code
|
||||
int code = x instanceof XmlRpcException ? ((XmlRpcException) x).code : 0;
|
||||
try {
|
||||
writeError (code, message, writer);
|
||||
} catch (XmlRpcException xrx) {
|
||||
// won't happen, we just sent a struct with an int and a string
|
||||
}
|
||||
try {
|
||||
result = writer.getBytes ();
|
||||
} catch (UnsupportedEncodingException encx) {
|
||||
System.err.println ("XmlRpcServer.execute: "+encx);
|
||||
result = writer.toString().getBytes();
|
||||
}
|
||||
}
|
||||
if (debug)
|
||||
System.err.println ("Spent "+(System.currentTimeMillis () - now)+" millis in request");
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an object to be added to the argument list has been parsed.
|
||||
*/
|
||||
void objectParsed (Object what) {
|
||||
inParams.addElement (what);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an XML-RPC response to the XML writer.
|
||||
*/
|
||||
void writeResponse (Object param, XmlWriter writer) throws XmlRpcException {
|
||||
writer.startElement ("methodResponse");
|
||||
// if (param == null) param = ""; // workaround for Frontier bug
|
||||
writer.startElement ("params");
|
||||
writer.startElement ("param");
|
||||
writeObject (param, writer);
|
||||
writer.endElement ("param");
|
||||
writer.endElement ("params");
|
||||
writer.endElement ("methodResponse");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an XML-RPC error response to the XML writer.
|
||||
*/
|
||||
void writeError (int code, String message, XmlWriter writer) throws XmlRpcException {
|
||||
// System.err.println ("error: "+message);
|
||||
Hashtable h = new Hashtable ();
|
||||
h.put ("faultCode", new Integer (code));
|
||||
h.put ("faultString", message);
|
||||
writer.startElement ("methodResponse");
|
||||
writer.startElement ("fault");
|
||||
writeObject (h, writer);
|
||||
writer.endElement ("fault");
|
||||
writer.endElement ("methodResponse");
|
||||
}
|
||||
|
||||
} // end of inner class Worker
|
||||
|
||||
} // XmlRpcServer
|
||||
|
||||
// This class uses Java Reflection to call methods matching an XML-RPC call
|
||||
class Invoker implements XmlRpcHandler {
|
||||
|
||||
private Object invokeTarget;
|
||||
private Class targetClass;
|
||||
|
||||
public Invoker(Object target) {
|
||||
invokeTarget = target;
|
||||
targetClass = invokeTarget instanceof Class ?
|
||||
(Class) invokeTarget : invokeTarget.getClass();
|
||||
if (XmlRpc.debug)
|
||||
System.err.println("Target object is " + targetClass);
|
||||
}
|
||||
|
||||
|
||||
// main method, sucht methode in object, wenn gefunden dann aufrufen.
|
||||
public Object execute (String methodName, Vector params) throws Exception {
|
||||
|
||||
|
||||
// Array mit Classtype bilden, ObjectAry mit Values bilden
|
||||
Class[] argClasses = null;
|
||||
Object[] argValues = null;
|
||||
if(params != null){
|
||||
argClasses = new Class[params.size()];
|
||||
argValues = new Object[params.size()];
|
||||
for(int i = 0; i < params.size(); i++){
|
||||
argValues[i] = params.elementAt(i);
|
||||
if (argValues[i] instanceof Integer)
|
||||
argClasses[i] = Integer.TYPE;
|
||||
else if (argValues[i] instanceof Double)
|
||||
argClasses[i] = Double.TYPE;
|
||||
else if (argValues[i] instanceof Boolean)
|
||||
argClasses[i] = Boolean.TYPE;
|
||||
else
|
||||
argClasses[i] = argValues[i].getClass();
|
||||
}
|
||||
}
|
||||
|
||||
// Methode da ?
|
||||
Method method = null;
|
||||
|
||||
if (XmlRpc.debug) {
|
||||
System.err.println("Searching for method: " + methodName);
|
||||
for(int i = 0; i < argClasses.length; i++)
|
||||
System.err.println("Parameter " + i + ": " + argClasses[i] + " = " + argValues[i]);
|
||||
}
|
||||
|
||||
try {
|
||||
method = targetClass.getMethod(methodName, argClasses);
|
||||
}
|
||||
// Wenn nicht da dann entsprechende Exception returnen
|
||||
catch(NoSuchMethodException nsm_e){
|
||||
throw nsm_e;
|
||||
}
|
||||
catch (SecurityException s_e){
|
||||
throw s_e;
|
||||
}
|
||||
|
||||
// our policy is to make all public methods callable except the ones defined in java.lang.Object
|
||||
if (method.getDeclaringClass () == Class.forName ("java.lang.Object"))
|
||||
throw new XmlRpcException (0, "Invoker can't call methods defined in java.lang.Object");
|
||||
|
||||
// invoke
|
||||
Object returnValue = null;
|
||||
try {
|
||||
returnValue = method.invoke (invokeTarget, argValues);
|
||||
}
|
||||
catch (IllegalAccessException iacc_e){
|
||||
throw iacc_e;
|
||||
}
|
||||
catch (IllegalArgumentException iarg_e){
|
||||
throw iarg_e;
|
||||
}
|
||||
catch (InvocationTargetException it_e) {
|
||||
if (XmlRpc.debug)
|
||||
it_e.getTargetException ().printStackTrace ();
|
||||
// check whether the thrown exception is XmlRpcException
|
||||
Throwable t=it_e.getTargetException();
|
||||
if ( t instanceof XmlRpcException)
|
||||
throw (XmlRpcException) t;
|
||||
// It is some other exception
|
||||
throw new Exception (t.toString ());
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
// Copyright 1999 Hannes Wallnöfer, Raphael Spannocchi
|
||||
|
||||
package helma.xmlrpc;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.*;
|
||||
import java.io.*;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* A prototype servlet to run XML-RPC. <p>
|
||||
*
|
||||
* Note that some clients like the one in Frontier 5 and the first version of XmlRpcApplet
|
||||
* had XML-RPC requests hard-coded to URI /RPC2. To work with these clients, you have
|
||||
* to configure your servlet environment to respond to /RPC2. This has been fixed in the
|
||||
* new version of the XmlRpcApplet.
|
||||
*
|
||||
*/
|
||||
|
||||
public class XmlRpcServlet extends HttpServlet implements XmlRpcHandler {
|
||||
|
||||
public XmlRpcServer xmlrpc;
|
||||
|
||||
public void init(ServletConfig config) throws ServletException {
|
||||
xmlrpc = new XmlRpcServer ();
|
||||
xmlrpc.addHandler ("example", this);
|
||||
}
|
||||
|
||||
public void doPost(HttpServletRequest req, HttpServletResponse res)
|
||||
throws ServletException, IOException {
|
||||
byte[] result = xmlrpc.execute (req.getInputStream ());
|
||||
res.setContentType("text/xml");
|
||||
res.setContentLength (result.length);
|
||||
OutputStream output = res.getOutputStream();
|
||||
output.write (result);
|
||||
output.flush ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method for XML-RPC server
|
||||
*/
|
||||
public Object execute (String methodname, Vector params) {
|
||||
return params;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,170 +0,0 @@
|
|||
// RpcXtension.java
|
||||
// Copyright (c) Hannes Wallnöfer, 1999 - All rights reserved
|
||||
|
||||
package helma.xmlrpc.fesi;
|
||||
|
||||
import helma.xmlrpc.*;
|
||||
|
||||
import FESI.Interpreter.*;
|
||||
import FESI.Exceptions.*;
|
||||
import FESI.Extensions.*;
|
||||
import FESI.Data.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.net.*;
|
||||
|
||||
|
||||
/**
|
||||
* An extension to transparently call and serve XML-RPC from the
|
||||
* <a href=http://home.worldcom.ch/jmlugrin/fesi/>FESI EcmaScript</a> interpreter.
|
||||
* The extension adds constructors for XML-RPC clients and servers to the Global Object.
|
||||
* For more information on how to use this please look at the files <tt>server.es</tt> and
|
||||
* <tt>client.es</tt> in the src/fesi directory of the distribution.
|
||||
*
|
||||
* All argument conversion is done automatically. Currently the following argument and return
|
||||
* types are supported:
|
||||
* <ul>
|
||||
* <li> plain objects (with all properties returned by ESObject.getProperties ())
|
||||
* <li> arrays
|
||||
* <li> strings
|
||||
* <li> date objects
|
||||
* <li> booleans
|
||||
* <li> integer and float numbers (long values are not supported!)
|
||||
* </ul>
|
||||
*
|
||||
*/
|
||||
public class FesiRpcExtension extends Extension {
|
||||
|
||||
Evaluator evaluator;
|
||||
ESObject op;
|
||||
|
||||
public void initializeExtension (Evaluator evaluator) throws EcmaScriptException {
|
||||
// XmlRpc.setDebug (true);
|
||||
this.evaluator = evaluator;
|
||||
GlobalObject go = evaluator.getGlobalObject();
|
||||
FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype();
|
||||
|
||||
op = evaluator.getObjectPrototype();
|
||||
|
||||
go.putHiddenProperty ("Remote", new GlobalObjectRemote ("Remote", evaluator, fp)); // the Remote constructor
|
||||
go.putHiddenProperty ("RemoteServer", new GlobalObjectRemoteServer ("RemoteServer", evaluator, fp)); // the RemoteServer constructor
|
||||
|
||||
}
|
||||
|
||||
|
||||
class GlobalObjectRemote extends BuiltinFunctionObject {
|
||||
|
||||
GlobalObjectRemote (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super(fp, evaluator, name, 1);
|
||||
}
|
||||
|
||||
public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
return doConstruct(thisObject, arguments);
|
||||
}
|
||||
|
||||
public ESObject doConstruct(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
ESObject remote = null;
|
||||
String url = null;
|
||||
String robj = null;
|
||||
if (arguments.length >= 1)
|
||||
url = arguments[0].toString ();
|
||||
if (arguments.length >= 2)
|
||||
robj = arguments[1].toString ();
|
||||
try {
|
||||
remote = new ESRemote (op, this.evaluator, url, robj);
|
||||
} catch (MalformedURLException x) {
|
||||
throw new EcmaScriptException (x.toString ());
|
||||
}
|
||||
return remote;
|
||||
}
|
||||
}
|
||||
|
||||
class GlobalObjectRemoteServer extends BuiltinFunctionObject {
|
||||
|
||||
|
||||
|
||||
GlobalObjectRemoteServer (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super(fp, evaluator, name, 1);
|
||||
}
|
||||
|
||||
public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
return doConstruct(thisObject, arguments);
|
||||
}
|
||||
|
||||
public ESObject doConstruct(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
ESObject remotesrv = null;
|
||||
String globalname = null;
|
||||
if (arguments.length < 1 || arguments.length > 2)
|
||||
throw new EcmaScriptException ("Wrong number of arguments for constructor RemoteServer");
|
||||
int port = arguments[0].toInt32 ();
|
||||
if (arguments.length == 2)
|
||||
globalname = arguments[1].toString ();
|
||||
try {
|
||||
remotesrv = new FesiRpcServer (port, op, this.evaluator);
|
||||
if (globalname != null)
|
||||
this.evaluator.getGlobalObject ().putProperty (globalname, remotesrv, globalname.hashCode ());
|
||||
} catch (IOException x) {
|
||||
throw new EcmaScriptException (x.toString ());
|
||||
}
|
||||
return remotesrv;
|
||||
}
|
||||
}
|
||||
|
||||
class ESRemote extends ObjectPrototype {
|
||||
|
||||
URL url;
|
||||
String remoteObject;
|
||||
|
||||
public ESRemote (ESObject prototype, Evaluator evaluator, String urlstring, String robj) throws MalformedURLException {
|
||||
super (prototype, evaluator);
|
||||
this.url = new URL (urlstring);
|
||||
remoteObject = robj;
|
||||
}
|
||||
|
||||
public ESRemote (ESObject prototype, Evaluator evaluator, URL url, String robj) {
|
||||
super (prototype, evaluator);
|
||||
this.url = url;
|
||||
remoteObject = robj;
|
||||
}
|
||||
|
||||
public ESValue doIndirectCall(Evaluator evaluator, ESObject target, String functionName, ESValue arguments[])
|
||||
throws EcmaScriptException, NoSuchMethodException {
|
||||
// System.out.println ("doIndirectCall called with "+functionName);
|
||||
XmlRpcClient client = new XmlRpcClient (url);
|
||||
long now = System.currentTimeMillis ();
|
||||
Object retval = null;
|
||||
int l = arguments.length;
|
||||
Vector v = new Vector ();
|
||||
for (int i=0; i<l; i++) {
|
||||
Object arg = FesiRpcUtil.convertE2J (arguments[i]);
|
||||
// System.out.println ("converted to J: "+arg.getClass ());
|
||||
v.addElement (arg);
|
||||
}
|
||||
// System.out.println ("spent "+(System.currentTimeMillis ()-now)+" millis in argument conversion");
|
||||
ESObject esretval = ObjectObject.createObject (evaluator);
|
||||
try {
|
||||
String method = remoteObject == null ? functionName : remoteObject+"."+functionName;
|
||||
retval = client.execute (method, v);
|
||||
esretval.putProperty ("error", ESNull.theNull, "error".hashCode());
|
||||
esretval.putProperty ("result", FesiRpcUtil.convertJ2E (retval, this.evaluator), "result".hashCode());
|
||||
} catch (Exception x) {
|
||||
String msg = x.getMessage();
|
||||
if (msg == null || msg.length() == 0)
|
||||
msg = x.toString ();
|
||||
esretval.putProperty ("error", new ESString(msg), "error".hashCode());
|
||||
esretval.putProperty ("result", ESNull.theNull, "result".hashCode());
|
||||
}
|
||||
return esretval;
|
||||
}
|
||||
|
||||
public ESValue getProperty (String name, int hash) throws EcmaScriptException {
|
||||
ESValue sprop = super.getProperty (name, hash);
|
||||
if (sprop != ESUndefined.theUndefined && sprop != ESNull.theNull)
|
||||
return sprop;
|
||||
String newRemoteObject = remoteObject == null ? name : remoteObject+"."+name;
|
||||
return new ESRemote (op, this.evaluator, url, newRemoteObject);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
* Copyright 1999 Hannes Wallnoefer
|
||||
*/
|
||||
|
||||
package helma.xmlrpc.fesi;
|
||||
|
||||
import helma.xmlrpc.*;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import FESI.Data.*;
|
||||
import FESI.Interpreter.*;
|
||||
import FESI.Exceptions.*;
|
||||
|
||||
/**
|
||||
* An ESObject that makes its properties (sub-objects) callable via XML-RPC.
|
||||
* For example, if Server is an instance of FesiRpcServer, the following would make the
|
||||
* functions defined for someObject available to XML-RPC clients:
|
||||
* <pre>
|
||||
* Server.someObject = new SomeObject ();
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
|
||||
public class FesiRpcServer extends ObjectPrototype {
|
||||
|
||||
// This is public (for now) to be able to set access restrictions from the outside.
|
||||
public WebServer srv;
|
||||
Evaluator evaluator;
|
||||
|
||||
/**
|
||||
* Create an XML-RPC server with an already existing WebServer.
|
||||
*/
|
||||
public FesiRpcServer (WebServer srv, ESObject op, Evaluator eval) throws IOException, EcmaScriptException {
|
||||
super (op, eval);
|
||||
this.evaluator = eval;
|
||||
this.srv = srv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an XML-RPC server listening on a specific port.
|
||||
*/
|
||||
public FesiRpcServer (int port, ESObject op, Evaluator eval) throws IOException, EcmaScriptException {
|
||||
super (op, eval);
|
||||
this.evaluator = eval;
|
||||
srv = new WebServer (port);
|
||||
}
|
||||
|
||||
public void putProperty(String propertyName, ESValue propertyValue, int hash) throws EcmaScriptException {
|
||||
if (propertyValue instanceof ESObject)
|
||||
srv.addHandler (propertyName, new FesiInvoker ((ESObject) propertyValue));
|
||||
super.putProperty (propertyName, propertyValue, hash);
|
||||
}
|
||||
|
||||
public boolean deleteProperty (String propertyName, int hash) throws EcmaScriptException {
|
||||
srv.removeHandler (propertyName);
|
||||
super.deleteProperty (propertyName, hash);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
class FesiInvoker implements XmlRpcHandler {
|
||||
|
||||
ESObject target;
|
||||
|
||||
public FesiInvoker (ESObject target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public Object execute (String method, Vector argvec) throws Exception {
|
||||
// convert arguments
|
||||
int l = argvec.size ();
|
||||
|
||||
ESObject callTarget = target;
|
||||
if (method.indexOf (".") > -1) {
|
||||
StringTokenizer st = new StringTokenizer (method, ".");
|
||||
int cnt = st.countTokens ();
|
||||
for (int i=1; i<cnt; i++) {
|
||||
String next = st.nextToken ();
|
||||
try {
|
||||
callTarget = (ESObject) callTarget.getProperty (next, next.hashCode ());
|
||||
} catch (Exception x) {
|
||||
throw new EcmaScriptException ("The property \""+next+"\" is not defined in the remote object.");
|
||||
}
|
||||
}
|
||||
method = st.nextToken ();
|
||||
}
|
||||
|
||||
ESValue args[] = new ESValue[l];
|
||||
for (int i=0; i<l; i++) {
|
||||
args[i] = FesiRpcUtil.convertJ2E (argvec.elementAt (i), evaluator);
|
||||
}
|
||||
Object retval = FesiRpcUtil.convertE2J (callTarget.doIndirectCall (evaluator, callTarget, method, args));
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
// RpcXtension.java
|
||||
// Copyright (c) Hannes Wallnöfer, 1999 - All rights reserved
|
||||
|
||||
package helma.xmlrpc.fesi;
|
||||
|
||||
|
||||
import helma.xmlrpc.*;
|
||||
import helma.scripting.fesi.ESNode;
|
||||
import helma.objectmodel.INode;
|
||||
|
||||
import FESI.Exceptions.*;
|
||||
import FESI.Data.*;
|
||||
import FESI.Interpreter.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class FesiRpcUtil {
|
||||
|
||||
/**
|
||||
* convert a generic Java object to a JavaScript Object.
|
||||
*/
|
||||
public static ESValue convertJ2E (Object what, Evaluator evaluator) throws Exception {
|
||||
if (what == null)
|
||||
return ESNull.theNull;
|
||||
if (what instanceof Vector) {
|
||||
Vector v = (Vector) what;
|
||||
ArrayPrototype retval = new ArrayPrototype (evaluator.getArrayPrototype (), evaluator);
|
||||
int l = v.size ();
|
||||
for (int i=0; i<l; i++)
|
||||
retval.putProperty (i, convertJ2E (v.elementAt (i), evaluator));
|
||||
return retval;
|
||||
}
|
||||
if (what instanceof Hashtable) {
|
||||
Hashtable t = (Hashtable) what;
|
||||
ESObject retval = new ObjectPrototype (evaluator.getObjectPrototype (), evaluator);
|
||||
for (Enumeration e=t.keys(); e.hasMoreElements(); ) {
|
||||
String next = (String) e.nextElement ();
|
||||
retval.putProperty (next, convertJ2E (t.get (next), evaluator), next.hashCode ());
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
if (what instanceof String)
|
||||
return new ESString (what.toString ());
|
||||
if (what instanceof Number)
|
||||
return new ESNumber (new Double (what.toString ()).doubleValue ());
|
||||
if (what instanceof Boolean)
|
||||
return ESBoolean.makeBoolean (((Boolean) what).booleanValue ());
|
||||
if (what instanceof Date)
|
||||
return new DatePrototype (evaluator, (Date) what);
|
||||
return ESLoader.normalizeValue (what, evaluator);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* convert a JavaScript Object object to a generic Java.
|
||||
*/
|
||||
public static Object convertE2J (ESValue what) throws EcmaScriptException {
|
||||
if (XmlRpc.debug)
|
||||
System.out.println ("converting e-2-j: "+what.getClass ());
|
||||
if (what instanceof ESNull)
|
||||
return null;
|
||||
if (what instanceof ArrayPrototype) {
|
||||
ArrayPrototype a = (ArrayPrototype) what;
|
||||
int l = a.size ();
|
||||
Vector v = new Vector ();
|
||||
for (int i=0; i<l; i++) {
|
||||
Object nj = convertE2J (a.getProperty (i));
|
||||
v.addElement (nj);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
if (what instanceof ObjectPrototype) {
|
||||
ObjectPrototype o = (ObjectPrototype) what;
|
||||
Hashtable t = new Hashtable ();
|
||||
for (Enumeration e=o.getProperties (); e.hasMoreElements (); ) {
|
||||
String next = (String) e.nextElement ();
|
||||
if (XmlRpc.debug) System.out.println ("converting object member "+next);
|
||||
// We don't do deep serialization of HopObjects to avoid
|
||||
// that the whole web site structure is sucked out with one
|
||||
// object. Instead we return some kind of "proxy" objects
|
||||
// that only contain the prototype and id of the HopObject property.
|
||||
Object nj = null;
|
||||
ESValue esv = o.getProperty (next, next.hashCode ());
|
||||
if (esv instanceof ESNode) {
|
||||
INode node = ((ESNode) esv).getNode ();
|
||||
if (node != null) {
|
||||
Hashtable nt = new Hashtable ();
|
||||
nt.put ("id", node.getID());
|
||||
if (node.getPrototype() != null)
|
||||
nt.put ("prototype", node.getPrototype ());
|
||||
nj = nt;
|
||||
}
|
||||
} else
|
||||
nj = convertE2J (esv);
|
||||
if (nj != null) // can't put null as value in hashtable
|
||||
t.put (next, nj);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
if (what instanceof ESUndefined || what instanceof ESNull)
|
||||
return null;
|
||||
Object jval = what.toJavaObject ();
|
||||
if (jval instanceof Byte || jval instanceof Short)
|
||||
jval = new Integer (jval.toString ());
|
||||
return jval;
|
||||
}
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
/**
|
||||
* Copyright 1999 Hannes Wallnoefer
|
||||
*/
|
||||
|
||||
package helma.xmlrpc.test;
|
||||
|
||||
import helma.xmlrpc.*;
|
||||
import java.util.*;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
public class AsyncBenchmark implements Runnable {
|
||||
|
||||
XmlRpcClient client;
|
||||
static String url;
|
||||
static int clients = 16;
|
||||
static int loops = 100;
|
||||
|
||||
int calls = 0;
|
||||
|
||||
int gCalls = 0, gErrors = 0;
|
||||
long start;
|
||||
|
||||
|
||||
public AsyncBenchmark () throws Exception {
|
||||
client = new XmlRpcClientLite (url);
|
||||
|
||||
Vector args = new Vector ();
|
||||
// Some JITs (Symantec, IBM) have problems with several Threads
|
||||
// starting all at the same time.
|
||||
// This initial XML-RPC call seems to pacify them.
|
||||
args.addElement (new Integer (123));
|
||||
client.execute ("math.abs", args);
|
||||
|
||||
start = System.currentTimeMillis ();
|
||||
|
||||
for (int i=0; i<clients; i++)
|
||||
new Thread (this).start ();
|
||||
}
|
||||
|
||||
public void run () {
|
||||
int calls = 0;
|
||||
long start = System.currentTimeMillis ();
|
||||
|
||||
for (int i=0; i<loops; i++) {
|
||||
|
||||
Vector args = new Vector ();
|
||||
Integer n = new Integer (Math.round ((int)(Math.random ()*-1000)));
|
||||
args.addElement (n);
|
||||
client.executeAsync ("math.abs", args, new Callback (n));
|
||||
calls += 1;
|
||||
}
|
||||
int millis = (int) (System.currentTimeMillis () - start);
|
||||
System.err.println ("Benchmark thread finished: "+calls+" calls in "+millis+" milliseconds.");
|
||||
}
|
||||
|
||||
public static void main (String args[]) throws Exception {
|
||||
if (args.length > 0 && args.length < 3) {
|
||||
url = args[0];
|
||||
XmlRpc.setKeepAlive (true);
|
||||
if (args.length == 2)
|
||||
XmlRpc.setDriver (args[1]);
|
||||
new AsyncBenchmark ();
|
||||
} else {
|
||||
System.err.println ("Usage: java helma.xmlrpc.Benchmark URL [SAXDriver]");
|
||||
}
|
||||
}
|
||||
|
||||
class Callback implements AsyncCallback {
|
||||
|
||||
|
||||
int n;
|
||||
|
||||
public Callback (Integer n) {
|
||||
this.n = Math.abs (n.intValue());
|
||||
}
|
||||
|
||||
public synchronized void handleResult (Object result, URL url, String method) {
|
||||
if (n == ((Integer) result).intValue ())
|
||||
gCalls += 1;
|
||||
else
|
||||
gErrors += 1;
|
||||
if (gCalls + gErrors >= clients*loops)
|
||||
printStats ();
|
||||
}
|
||||
|
||||
public synchronized void handleError (Exception exception, URL url, String method) {
|
||||
System.err.println (exception);
|
||||
exception.printStackTrace ();
|
||||
gErrors += 1;
|
||||
if (gCalls + gErrors >= clients*loops)
|
||||
printStats ();
|
||||
}
|
||||
|
||||
public void printStats () {
|
||||
System.err.println ("");
|
||||
System.err.println (gCalls+" calls, "+gErrors+" errors in "+(System.currentTimeMillis()-start)+" millis");
|
||||
System.err.println ((1000*(gCalls+gErrors)/(System.currentTimeMillis()-start))+" calls per second");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
/**
|
||||
* Copyright 1999 Hannes Wallnoefer
|
||||
*/
|
||||
|
||||
package helma.xmlrpc.test;
|
||||
|
||||
import helma.xmlrpc.*;
|
||||
import java.util.*;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Benchmark implements Runnable {
|
||||
|
||||
XmlRpcClient client;
|
||||
static String url;
|
||||
static int clients = 16;
|
||||
static int loops = 100;
|
||||
|
||||
int gCalls = 0, gErrors = 0;
|
||||
|
||||
Date date;
|
||||
|
||||
public Benchmark () throws Exception {
|
||||
client = new XmlRpcClientLite (url);
|
||||
|
||||
Vector args = new Vector ();
|
||||
// Some JITs (Symantec, IBM) have problems with several Threads
|
||||
// starting all at the same time.
|
||||
// This initial XML-RPC call seems to pacify them.
|
||||
args.addElement (new Integer (123));
|
||||
client.execute ("math.abs", args);
|
||||
date = new Date ();
|
||||
date = new Date ((date.getTime()/1000)*1000);
|
||||
|
||||
for (int i=0; i<clients; i++)
|
||||
new Thread (this).start ();
|
||||
}
|
||||
|
||||
public void run () {
|
||||
int errors = 0;
|
||||
int calls = 0;
|
||||
long start = System.currentTimeMillis ();
|
||||
try {
|
||||
int val = (int) (-100 * Math.random ());
|
||||
Vector args = new Vector ();
|
||||
|
||||
// ECHO STRING
|
||||
// args.addElement (Integer.toString (val));
|
||||
// ABS INT
|
||||
args.addElement (new Integer (val));
|
||||
// ECHO DATE
|
||||
// args.addElement (date);
|
||||
|
||||
for (int i=0; i<loops; i++) {
|
||||
|
||||
// ABS INT
|
||||
Integer ret = (Integer) client.execute ("math.abs", args);
|
||||
// ECHO
|
||||
// Vector v = (Vector) client.execute ("echo", args);
|
||||
// ECHO DATE
|
||||
// Date d = (Date) v.elementAt (0);
|
||||
|
||||
// ABS INT
|
||||
if (ret.intValue () != Math.abs (val)) {
|
||||
// ECHO DATE
|
||||
// if (date.getTime() != d.getTime()) {
|
||||
// ECHO STRING
|
||||
// if (!Integer.toString(val).equals (v.elementAt (0))) {
|
||||
errors += 1;
|
||||
}
|
||||
calls += 1;
|
||||
}
|
||||
} catch (IOException x) {
|
||||
System.err.println ("Exception in client: "+x);
|
||||
x.printStackTrace ();
|
||||
} catch (XmlRpcException x) {
|
||||
System.err.println ("Server reported error: "+x);
|
||||
} catch (Exception other) {
|
||||
System.err.println ("Exception in Benchmark client: "+other);
|
||||
}
|
||||
int millis = (int) (System.currentTimeMillis () - start);
|
||||
checkout (calls, errors, millis);
|
||||
}
|
||||
|
||||
private synchronized void checkout (int calls, int errors, int millis) {
|
||||
clients--;
|
||||
gCalls += calls;
|
||||
gErrors += errors;
|
||||
System.err.println ("Benchmark thread finished: "+calls+" calls, "+errors+" errors in "+millis+" milliseconds.");
|
||||
if (clients == 0) {
|
||||
System.err.println ("");
|
||||
System.err.println ("Benchmark result: "+(1000*gCalls/millis)+" calls per second.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main (String args[]) throws Exception {
|
||||
if (args.length > 0 && args.length < 3) {
|
||||
url = args[0];
|
||||
XmlRpc.setKeepAlive (true);
|
||||
if (args.length == 2)
|
||||
XmlRpc.setDriver (args[1]);
|
||||
new Benchmark ();
|
||||
} else {
|
||||
System.err.println ("Usage: java helma.xmlrpc.Benchmark URL [SAXDriver]");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
/**
|
||||
* Copyright 1999 Hannes Wallnoefer
|
||||
*/
|
||||
|
||||
package helma.xmlrpc.test;
|
||||
|
||||
import helma.xmlrpc.*;
|
||||
import java.util.*;
|
||||
import java.io.IOException;
|
||||
|
||||
public class TestBase64 implements Runnable {
|
||||
|
||||
XmlRpcClient client;
|
||||
static String url;
|
||||
static int clients = 1; // 6;
|
||||
static int loops = 1; //00;
|
||||
|
||||
int gCalls = 0, gErrors = 0;
|
||||
|
||||
byte[] data;
|
||||
|
||||
public TestBase64 () throws Exception {
|
||||
client = new XmlRpcClientLite (url);
|
||||
|
||||
Vector args = new Vector ();
|
||||
// Some JITs (Symantec, IBM) have problems with several Threads
|
||||
// starting all at the same time.
|
||||
// This initial XML-RPC call seems to pacify them.
|
||||
args.addElement (new Integer (123));
|
||||
client.execute ("math.abs", args);
|
||||
|
||||
data = new byte[20000];
|
||||
for (int j=0; j<data.length; j++)
|
||||
data[j] = (byte) j;
|
||||
|
||||
for (int i=0; i<clients; i++)
|
||||
new Thread (this).start ();
|
||||
}
|
||||
|
||||
public void run () {
|
||||
int errors = 0;
|
||||
int calls = 0;
|
||||
long start = System.currentTimeMillis ();
|
||||
try {
|
||||
int val = (int) (-100 * Math.random ());
|
||||
Vector args = new Vector ();
|
||||
|
||||
args.addElement (data);
|
||||
|
||||
for (int i=0; i<loops; i++) {
|
||||
|
||||
Vector v = (Vector) client.execute ("echo", args);
|
||||
byte[] d = (byte[]) v.elementAt (0);
|
||||
for (int j=0; j<d.length; j++)
|
||||
if (d[j] != (byte) j) errors += 1;
|
||||
calls += 1;
|
||||
}
|
||||
} catch (IOException x) {
|
||||
System.err.println ("Exception in client: "+x);
|
||||
x.printStackTrace ();
|
||||
} catch (XmlRpcException x) {
|
||||
System.err.println ("Server reported error: "+x);
|
||||
} catch (Exception other) {
|
||||
System.err.println ("Exception in Benchmark client: "+other);
|
||||
}
|
||||
int millis = (int) (System.currentTimeMillis () - start);
|
||||
checkout (calls, errors, millis);
|
||||
}
|
||||
|
||||
private synchronized void checkout (int calls, int errors, int millis) {
|
||||
clients--;
|
||||
gCalls += calls;
|
||||
gErrors += errors;
|
||||
System.err.println ("Benchmark thread finished: "+calls+" calls, "+errors+" errors in "+millis+" milliseconds.");
|
||||
if (clients == 0) {
|
||||
System.err.println ("");
|
||||
System.err.println ("Benchmark result: "+(1000*gCalls/millis)+" calls per second.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main (String args[]) throws Exception {
|
||||
if (args.length > 0 && args.length < 3) {
|
||||
url = args[0];
|
||||
XmlRpc.setKeepAlive (true);
|
||||
// XmlRpc.setDebug (true);
|
||||
if (args.length == 2)
|
||||
XmlRpc.setDriver (args[1]);
|
||||
new TestBase64 ();
|
||||
} else {
|
||||
System.err.println ("Usage: java helma.xmlrpc.Benchmark URL [SAXDriver]");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue