1 /* 2 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 27 package javax.print.attribute; 28 29 import java.io.Serializable; 30 31 /** 32 * Class ResolutionSyntax is an abstract base class providing the common 33 * implementation of all attributes denoting a printer resolution. 34 * <P> 35 * A resolution attribute's value consists of two items, the cross feed 36 * direction resolution and the feed direction resolution. A resolution 37 * attribute may be constructed by supplying the two values and indicating the 38 * units in which the values are measured. Methods are provided to return a 39 * resolution attribute's values, indicating the units in which the values are 40 * to be returned. The two most common resolution units are dots per inch (dpi) 41 * and dots per centimeter (dpcm), and exported constants {@link #DPI 42 * DPI} and {@link #DPCM DPCM} are provided for 43 * indicating those units. 44 * <P> 45 * Once constructed, a resolution attribute's value is immutable. 46 * <P> 47 * <B>Design</B> 48 * <P> 49 * A resolution attribute's cross feed direction resolution and feed direction 50 * resolution values are stored internally using units of dots per 100 inches 51 * (dphi). Storing the values in dphi rather than, say, metric units allows 52 * precise integer arithmetic conversions between dpi and dphi and between dpcm 53 * and dphi: 1 dpi = 100 dphi, 1 dpcm = 254 dphi. Thus, the values can be stored 54 * into and retrieved back from a resolution attribute in either units with no 55 * loss of precision. This would not be guaranteed if a floating point 56 * representation were used. However, roundoff error will in general occur if a 57 * resolution attribute's values are created in one units and retrieved in 58 * different units; for example, 600 dpi will be rounded to 236 dpcm, whereas 59 * the true value (to five figures) is 236.22 dpcm. 60 * <P> 61 * Storing the values internally in common units of dphi lets two resolution 62 * attributes be compared without regard to the units in which they were 63 * created; for example, 300 dpcm will compare equal to 762 dpi, as they both 64 * are stored as 76200 dphi. In particular, a lookup service can 65 * match resolution attributes based on equality of their serialized 66 * representations regardless of the units in which they were created. Again, 67 * using integers for internal storage allows precise equality comparisons to be 68 * done, which would not be guaranteed if a floating point representation were 69 * used. 70 * <P> 71 * The exported constant {@link #DPI DPI} is actually the 72 * conversion factor by which to multiply a value in dpi to get the value in 73 * dphi. Likewise, the exported constant {@link #DPCM DPCM} is the 74 * conversion factor by which to multiply a value in dpcm to get the value in 75 * dphi. A client can specify a resolution value in units other than dpi or dpcm 76 * by supplying its own conversion factor. However, since the internal units of 77 * dphi was chosen with supporting only the external units of dpi and dpcm in 78 * mind, there is no guarantee that the conversion factor for the client's units 79 * will be an exact integer. If the conversion factor isn't an exact integer, 80 * resolution values in the client's units won't be stored precisely. 81 * <P> 82 * 83 * @author David Mendenhall 84 * @author Alan Kaminsky 85 */ 86 public abstract class ResolutionSyntax implements Serializable, Cloneable { 87 88 private static final long serialVersionUID = 2706743076526672017L; 89 90 /** 91 * Cross feed direction resolution in units of dots per 100 inches (dphi). 92 * @serial 93 */ 94 private int crossFeedResolution; 95 96 /** 97 * Feed direction resolution in units of dots per 100 inches (dphi). 98 * @serial 99 */ 100 private int feedResolution; 101 102 /** 103 * Value to indicate units of dots per inch (dpi). It is actually the 104 * conversion factor by which to multiply dpi to yield dphi (100). 105 */ 106 public static final int DPI = 100; 107 108 /** 109 * Value to indicate units of dots per centimeter (dpcm). It is actually 110 * the conversion factor by which to multiply dpcm to yield dphi (254). 111 */ 112 public static final int DPCM = 254; 113 114 115 /** 116 * Construct a new resolution attribute from the given items. 117 * 118 * @param crossFeedResolution 119 * Cross feed direction resolution. 120 * @param feedResolution 121 * Feed direction resolution. 122 * @param units 123 * Unit conversion factor, e.g. {@link #DPI DPI} or 124 * {@link #DPCM DPCM}. 125 * 126 * @exception IllegalArgumentException 127 * (unchecked exception) Thrown if {@code crossFeedResolution < 1} 128 * or {@code feedResolution < 1} or {@code units < 1}. 129 */ 130 public ResolutionSyntax(int crossFeedResolution, int feedResolution, 131 int units) { 132 133 if (crossFeedResolution < 1) { 134 throw new IllegalArgumentException("crossFeedResolution is < 1"); 135 } 136 if (feedResolution < 1) { 137 throw new IllegalArgumentException("feedResolution is < 1"); 138 } 139 if (units < 1) { 140 throw new IllegalArgumentException("units is < 1"); 141 } 142 143 this.crossFeedResolution = crossFeedResolution * units; 144 this.feedResolution = feedResolution * units; 145 } 146 147 /** 148 * Convert a value from dphi to some other units. The result is rounded to 149 * the nearest integer. 150 * 151 * @param dphi 152 * Value (dphi) to convert. 153 * @param units 154 * Unit conversion factor, e.g. {@link #DPI <CODE>DPI</CODE>} or 155 * {@link #DPCM <CODE>DPCM</CODE>}. 156 * 157 * @return The value of <CODE>dphi</CODE> converted to the desired units. 158 * 159 * @exception IllegalArgumentException 160 * (unchecked exception) Thrown if <CODE>units</CODE> < 1. 161 */ 162 private static int convertFromDphi(int dphi, int units) { 163 if (units < 1) { 164 throw new IllegalArgumentException(": units is < 1"); 165 } 166 int round = units / 2; 167 return (dphi + round) / units; 168 } 169 170 /** 171 * Get this resolution attribute's resolution values in the given units. 172 * The values are rounded to the nearest integer. 173 * 174 * @param units 175 * Unit conversion factor, e.g. {@link #DPI DPI} or 176 * {@link #DPCM DPCM}. 177 * 178 * @return A two-element array with the cross feed direction resolution 179 * at index 0 and the feed direction resolution at index 1. 180 * 181 * @exception IllegalArgumentException 182 * (unchecked exception) Thrown if {@code units < 1}. 183 */ 184 public int[] getResolution(int units) { 185 return new int[] { getCrossFeedResolution(units), 186 getFeedResolution(units) 187 }; 188 } 189 190 /** 191 * Returns this resolution attribute's cross feed direction resolution in 192 * the given units. The value is rounded to the nearest integer. 193 * 194 * @param units 195 * Unit conversion factor, e.g. {@link #DPI DPI} or 196 * {@link #DPCM DPCM}. 197 * 198 * @return Cross feed direction resolution. 199 * 200 * @exception IllegalArgumentException 201 * (unchecked exception) Thrown if {@code units < 1}. 202 */ 203 public int getCrossFeedResolution(int units) { 204 return convertFromDphi (crossFeedResolution, units); 205 } 206 207 /** 208 * Returns this resolution attribute's feed direction resolution in the 209 * given units. The value is rounded to the nearest integer. 210 * 211 * @param units 212 * Unit conversion factor, e.g. {@link #DPI DPI} or {@link 213 * #DPCM DPCM}. 214 * 215 * @return Feed direction resolution. 216 * 217 * @exception IllegalArgumentException 218 * (unchecked exception) Thrown if {@code units < 1}. 219 */ 220 public int getFeedResolution(int units) { 221 return convertFromDphi (feedResolution, units); 222 } 223 224 /** 225 * Returns a string version of this resolution attribute in the given units. 226 * The string takes the form <CODE>"<I>C</I>x<I>F</I> <I>U</I>"</CODE>, 227 * where <I>C</I> is the cross feed direction resolution, <I>F</I> is the 228 * feed direction resolution, and <I>U</I> is the units name. The values are 229 * rounded to the nearest integer. 230 * 231 * @param units 232 * Unit conversion factor, e.g. {@link #DPI CODE>DPI} or {@link 233 * #DPCM DPCM}. 234 * @param unitsName 235 * Units name string, e.g. <CODE>"dpi"</CODE> or <CODE>"dpcm"</CODE>. If 236 * null, no units name is appended to the result. 237 * 238 * @return String version of this resolution attribute. 239 * 240 * @exception IllegalArgumentException 241 * (unchecked exception) Thrown if {@code units < 1}. 242 */ 243 public String toString(int units, String unitsName) { 244 StringBuffer result = new StringBuffer(); 245 result.append(getCrossFeedResolution (units)); 246 result.append('x'); 247 result.append(getFeedResolution (units)); 248 if (unitsName != null) { 249 result.append (' '); 250 result.append (unitsName); 251 } 252 return result.toString(); 253 } 254 255 256 /** 257 * Determine whether this resolution attribute's value is less than or 258 * equal to the given resolution attribute's value. This is true if all 259 * of the following conditions are true: 260 * <UL> 261 * <LI> 262 * This attribute's cross feed direction resolution is less than or equal to 263 * the <CODE>other</CODE> attribute's cross feed direction resolution. 264 * <LI> 265 * This attribute's feed direction resolution is less than or equal to the 266 * <CODE>other</CODE> attribute's feed direction resolution. 267 * </UL> 268 * 269 * @param other Resolution attribute to compare with. 270 * 271 * @return True if this resolution attribute is less than or equal to the 272 * <CODE>other</CODE> resolution attribute, false otherwise. 273 * 274 * @exception NullPointerException 275 * (unchecked exception) Thrown if <CODE>other</CODE> is null. 276 */ 277 public boolean lessThanOrEquals(ResolutionSyntax other) { 278 return (this.crossFeedResolution <= other.crossFeedResolution && 279 this.feedResolution <= other.feedResolution); 280 } 281 282 283 /** 284 * Returns whether this resolution attribute is equivalent to the passed in 285 * object. To be equivalent, all of the following conditions must be true: 286 * <OL TYPE=1> 287 * <LI> 288 * <CODE>object</CODE> is not null. 289 * <LI> 290 * <CODE>object</CODE> is an instance of class ResolutionSyntax. 291 * <LI> 292 * This attribute's cross feed direction resolution is equal to 293 * <CODE>object</CODE>'s cross feed direction resolution. 294 * <LI> 295 * This attribute's feed direction resolution is equal to 296 * <CODE>object</CODE>'s feed direction resolution. 297 * </OL> 298 * 299 * @param object Object to compare to. 300 * 301 * @return True if <CODE>object</CODE> is equivalent to this resolution 302 * attribute, false otherwise. 303 */ 304 public boolean equals(Object object) { 305 306 return(object != null && 307 object instanceof ResolutionSyntax && 308 this.crossFeedResolution == 309 ((ResolutionSyntax) object).crossFeedResolution && 310 this.feedResolution == 311 ((ResolutionSyntax) object).feedResolution); 312 } 313 314 /** 315 * Returns a hash code value for this resolution attribute. 316 */ 317 public int hashCode() { 318 return(((crossFeedResolution & 0x0000FFFF)) | 319 ((feedResolution & 0x0000FFFF) << 16)); 320 } 321 322 /** 323 * Returns a string version of this resolution attribute. The string takes 324 * the form <CODE>"<I>C</I>x<I>F</I> dphi"</CODE>, where <I>C</I> is the 325 * cross feed direction resolution and <I>F</I> is the feed direction 326 * resolution. The values are reported in the internal units of dphi. 327 */ 328 public String toString() { 329 StringBuffer result = new StringBuffer(); 330 result.append(crossFeedResolution); 331 result.append('x'); 332 result.append(feedResolution); 333 result.append(" dphi"); 334 return result.toString(); 335 } 336 337 338 /** 339 * Returns this resolution attribute's cross feed direction resolution in 340 * units of dphi. (For use in a subclass.) 341 * 342 * @return Cross feed direction resolution. 343 */ 344 protected int getCrossFeedResolutionDphi() { 345 return crossFeedResolution; 346 } 347 348 /** 349 * Returns this resolution attribute's feed direction resolution in units 350 * of dphi. (For use in a subclass.) 351 * 352 * @return Feed direction resolution. 353 */ 354 protected int getFeedResolutionDphi() { 355 return feedResolution; 356 } 357 358 }