1 /* Copyright (C) 2005-2011 Fabio Riccardi */ 2 3 package com.lightcrafts.image.metadata.values; 4 5 import java.io.IOException; 6 import java.io.ObjectInput; 7 import java.io.ObjectOutput; 8 9 import com.lightcrafts.image.metadata.ImageMetaType; 10 import com.lightcrafts.utils.LCArrays; 11 import com.lightcrafts.utils.Rational; 12 13 import static com.lightcrafts.image.metadata.ImageMetaType.META_SRATIONAL; 14 15 /** 16 * A <code>RationalMetaValue</code> is-a {@link NumericMetaValue} for holding a 17 * {@link Rational} metadata value. 18 * 19 * @author Paul J. Lucas [paul@lightcrafts.com] 20 */ 21 public class RationalMetaValue extends NumericMetaValue { 22 23 ////////// public ///////////////////////////////////////////////////////// 24 25 /** 26 * Construct a <code>RationalMetaValue</code>. 27 * This constructor exists only for externalization. 28 */ RationalMetaValue()29 public RationalMetaValue() { 30 // do nothing 31 } 32 33 /** 34 * Construct a <code>RationalMetaValue</code>. 35 * 36 * @param numerator The numerator. 37 * @param denominator The denominator. It must not be zero. 38 */ RationalMetaValue( int numerator, int denominator )39 public RationalMetaValue( int numerator, int denominator ) { 40 this( new Rational( numerator, denominator ) ); 41 } 42 43 /** 44 * Construct a <code>RationalMetaValue</code>. 45 * 46 * @param values The array of values. 47 */ RationalMetaValue( Rational... values )48 public RationalMetaValue( Rational... values ) { 49 m_value = values; 50 } 51 52 /** 53 * Construct a <code>RationalMetaValue</code>. 54 * 55 * @param values The array of values. 56 */ RationalMetaValue( String... values )57 public RationalMetaValue( String... values ) { 58 setValuesImpl( values ); 59 } 60 61 /** 62 * {@inheritDoc} 63 */ clone()64 public RationalMetaValue clone() { 65 final RationalMetaValue copy = (RationalMetaValue)super.clone(); 66 copy.m_value = m_value.clone(); 67 return copy; 68 } 69 70 /** 71 * {@inheritDoc} 72 */ compareTo( Object o )73 public final int compareTo( Object o ) { 74 if ( o instanceof NumericMetaValue ) { 75 final NumericMetaValue rightVal = (NumericMetaValue)o; 76 final double leftDouble = getDoubleValue(); 77 final double rightDouble = rightVal.getDoubleValue(); 78 return Double.compare( leftDouble, rightDouble ); 79 } 80 return super.compareTo( o ); 81 } 82 83 /** 84 * Compares this <code>ImageMetaValue</code> to a {@link String}. The 85 * string is first parsed as a {@link Rational}, then a numeric comparison 86 * is done. 87 * 88 * @param s The {@link String} to compare to. 89 * @return Returns a negative integer, zero, or a positive integer as this 90 * <code>ImageMetaValue</code> is less than, equal to, or greater than the 91 * {@link Rational} value of the string. If the string can not be parsed 92 * as a {@link Rational}, returns 1. 93 * @see #compareTo(Object) 94 */ compareTo( String s )95 public final int compareTo( String s ) { 96 try { 97 final Rational rightRational = Rational.parseRational( s ); 98 final Rational leftRational = getRationalValue(); 99 return leftRational.compareTo( rightRational ); 100 } 101 catch ( NumberFormatException e ) { 102 return 1; 103 } 104 } 105 106 /** 107 * {@inheritDoc} 108 */ getDoubleValue()109 public final double getDoubleValue() { 110 return getRationalValue().doubleValue(); 111 } 112 113 /** 114 * {@inheritDoc} 115 */ getLongValueAt(int index)116 public final long getLongValueAt(int index) { 117 return m_value[index].longValue(); 118 } 119 120 /** 121 * Get the first {@link Rational} value. 122 * 123 * @return Returns said value. 124 */ getRationalValue()125 public final Rational getRationalValue() { 126 return m_value[0]; 127 } 128 129 /** 130 * Get the native {@link Rational} array value. 131 * 132 * @return Returns said array. 133 */ getRationalValues()134 public final Rational[] getRationalValues() { 135 return m_value; 136 } 137 138 /** 139 * Gets the type of this metadata value. 140 * 141 * @return Always returns <code>META_RATIONAL</code>. 142 */ getType()143 public ImageMetaType getType() { 144 return META_SRATIONAL; 145 } 146 147 /** 148 * {@inheritDoc} 149 */ getValueCount()150 public final int getValueCount() { 151 return m_value != null ? m_value.length : 0; 152 } 153 154 /** 155 * {@inheritDoc} 156 */ isLegalValue( String value )157 public boolean isLegalValue( String value ) { 158 try { 159 Rational.parseRational( value ); 160 return true; 161 } 162 catch ( IllegalArgumentException e ) { 163 return false; 164 } 165 } 166 167 /** 168 * {@inheritDoc} 169 */ setLongValue( long newValue )170 public void setLongValue( long newValue ) { 171 setRationalValueAt( new Rational( (int)newValue, 1 ), 0 ); 172 } 173 174 /** 175 * Sets the {@link Rational} value at the given index. 176 * 177 * @param newValue The new value. 178 * @param index The index to set the value of. 179 */ setRationalValueAt( Rational newValue, int index )180 public final synchronized void setRationalValueAt( Rational newValue, 181 int index ) { 182 checkIsEditable(); 183 if ( m_value == null ) 184 m_value = new Rational[ index + 1 ]; 185 else if ( index >= m_value.length ) 186 m_value = (Rational[])LCArrays.resize( m_value, index + 1 ); 187 m_value[ index ] = newValue; 188 dirty(); 189 } 190 191 /** 192 * {@inheritDoc} 193 */ readExternal( ObjectInput in )194 public final void readExternal( ObjectInput in ) throws IOException { 195 final int length = readHeader( in ); 196 m_value = new Rational[ length ]; 197 for ( int i = 0; i < length; ++i ) 198 m_value[i] = new Rational( in.readInt(), in.readInt() ); 199 } 200 201 /** 202 * @serialData The header (see {@link #writeHeader(ObjectOutput)}) followed 203 * by the {@link Rational} values where each is a pair of <code>int</code> 204 * comprising the numerator and denominator. 205 */ writeExternal( ObjectOutput out )206 public final void writeExternal( ObjectOutput out ) throws IOException { 207 writeHeader( out ); 208 for ( Rational value : m_value ) { 209 out.writeInt( value.numerator() ); 210 out.writeInt( value.denominator() ); 211 } 212 } 213 214 ////////// protected ////////////////////////////////////////////////////// 215 216 /** 217 * Parse and append a new value. 218 * 219 * @param newValue The new value. 220 */ appendValueImpl( String newValue )221 protected final void appendValueImpl( String newValue ) { 222 final Rational newRational = Rational.parseRational( newValue ); 223 if ( m_value == null ) 224 m_value = new Rational[] { newRational }; 225 else { 226 m_value = (Rational[])LCArrays.resize( m_value, m_value.length + 1 ); 227 m_value[ m_value.length - 1 ] = newRational; 228 } 229 } 230 231 /** 232 * Gets the values as an array of {@link String}. 233 * 234 * @return Returns said array. 235 */ getValuesImpl()236 protected final String[] getValuesImpl() { 237 if ( m_value == null ) 238 return null; 239 final String[] value = new String[ m_value.length ]; 240 for ( int i = 0; i < m_value.length; ++i ) 241 value[i] = m_value[i].toString(); 242 return value; 243 } 244 245 /** 246 * Parse and set the values. 247 * 248 * @param newValue The array of new values. 249 * @throws IllegalArgumentException if any one of the {@link String}s do 250 * not contain a parseable {@link Rational}. 251 */ setValuesImpl( String[] newValue )252 protected final void setValuesImpl( String[] newValue ) { 253 if ( m_value == null || m_value.length != newValue.length ) 254 m_value = new Rational[ newValue.length ]; 255 for ( int i = 0; i < newValue.length; ++i ) 256 m_value[i] = Rational.parseRational( newValue[i] ); 257 } 258 259 /** 260 * Convert this value to its {@link String} representation. Multiple 261 * values are separated by commas. 262 * 263 * @return Returns said string. 264 */ toStringImpl()265 protected final String toStringImpl() { 266 if ( m_value == null ) 267 return null; 268 final StringBuilder sb = new StringBuilder(); 269 boolean comma = false; 270 for ( Rational value : m_value ) { 271 if ( !comma ) 272 comma = true; 273 else 274 sb.append( ',' ); 275 sb.append( value.toString() ); 276 } 277 return sb.toString(); 278 } 279 280 ////////// private //////////////////////////////////////////////////////// 281 282 private Rational[] m_value; 283 } 284 /* vim:set et sw=4 ts=4: */ 285