1 /* 2 * Copyright (c) 2000, 2014, 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 * 82 * @author David Mendenhall 83 * @author Alan Kaminsky 84 */ 85 public abstract class ResolutionSyntax implements Serializable, Cloneable { 86 87 private static final long serialVersionUID = 2706743076526672017L; 88 89 /** 90 * Cross feed direction resolution in units of dots per 100 inches (dphi). 91 * @serial 92 */ 93 private int crossFeedResolution; 94 95 /** 96 * Feed direction resolution in units of dots per 100 inches (dphi). 97 * @serial 98 */ 99 private int feedResolution; 100 101 /** 102 * Value to indicate units of dots per inch (dpi). It is actually the 103 * conversion factor by which to multiply dpi to yield dphi (100). 104 */ 105 public static final int DPI = 100; 106 107 /** 108 * Value to indicate units of dots per centimeter (dpcm). It is actually 109 * the conversion factor by which to multiply dpcm to yield dphi (254). 110 */ 111 public static final int DPCM = 254; 112 113 114 /** 115 * Construct a new resolution attribute from the given items. 116 * 117 * @param crossFeedResolution 118 * Cross feed direction resolution. 119 * @param feedResolution 120 * Feed direction resolution. 121 * @param units 122 * Unit conversion factor, e.g. {@link #DPI DPI} or 123 * {@link #DPCM DPCM}. 124 * 125 * @exception IllegalArgumentException 126 * (unchecked exception) Thrown if {@code crossFeedResolution < 1} 127 * or {@code feedResolution < 1} or {@code units < 1}. 128 */ 129 public ResolutionSyntax(int crossFeedResolution, int feedResolution, 130 int units) { 131 132 if (crossFeedResolution < 1) { 133 throw new IllegalArgumentException("crossFeedResolution is < 1"); 134 } 135 if (feedResolution < 1) { 136 throw new IllegalArgumentException("feedResolution is < 1"); 137 } 138 if (units < 1) { 139 throw new IllegalArgumentException("units is < 1"); 140 } 141 142 this.crossFeedResolution = crossFeedResolution * units; 143 this.feedResolution = feedResolution * units; 144 } 145 146 /** 147 * Convert a value from dphi to some other units. The result is rounded to 148 * the nearest integer. 149 * 150 * @param dphi 151 * Value (dphi) to convert. 152 * @param units 153 * Unit conversion factor, e.g. {@link #DPI DPI} or 154 * {@link #DPCM DPCM}. 155 * 156 * @return The value of {@code dphi} converted to the desired units. 157 * 158 * @exception IllegalArgumentException 159 * (unchecked exception) Thrown if {@code units} < 1. 160 */ 161 private static int convertFromDphi(int dphi, int units) { 162 if (units < 1) { 163 throw new IllegalArgumentException(": units is < 1"); 164 } 165 int round = units / 2; 166 return (dphi + round) / units; 167 } 168 169 /** 170 * Get this resolution attribute's resolution values in the given units. 171 * The values are rounded to the nearest integer. 172 * 173 * @param units 174 * Unit conversion factor, e.g. {@link #DPI DPI} or 175 * {@link #DPCM DPCM}. 176 * 177 * @return A two-element array with the cross feed direction resolution 178 * at index 0 and the feed direction resolution at index 1. 179 * 180 * @exception IllegalArgumentException 181 * (unchecked exception) Thrown if {@code units < 1}. 182 */ 183 public int[] getResolution(int units) { 184 return new int[] { getCrossFeedResolution(units), 185 getFeedResolution(units) 186 }; 187 } 188 189 /** 190 * Returns this resolution attribute's cross feed direction resolution in 191 * the given units. The value is rounded to the nearest integer. 192 * 193 * @param units 194 * Unit conversion factor, e.g. {@link #DPI DPI} or 195 * {@link #DPCM DPCM}. 196 * 197 * @return Cross feed direction resolution. 198 * 199 * @exception IllegalArgumentException 200 * (unchecked exception) Thrown if {@code units < 1}. 201 */ 202 public int getCrossFeedResolution(int units) { 203 return convertFromDphi (crossFeedResolution, units); 204 } 205 206 /** 207 * Returns this resolution attribute's feed direction resolution in the 208 * given units. The value is rounded to the nearest integer. 209 * 210 * @param units 211 * Unit conversion factor, e.g. {@link #DPI DPI} or {@link 212 * #DPCM DPCM}. 213 * 214 * @return Feed direction resolution. 215 * 216 * @exception IllegalArgumentException 217 * (unchecked exception) Thrown if {@code units < 1}. 218 */ 219 public int getFeedResolution(int units) { 220 return convertFromDphi (feedResolution, units); 221 } 222 223 /** 224 * Returns a string version of this resolution attribute in the given units. 225 * The string takes the form <code>"<I>C</I>x<I>F</I> <I>U</I>"</code>, 226 * where <I>C</I> is the cross feed direction resolution, <I>F</I> is the 227 * feed direction resolution, and <I>U</I> is the units name. The values are 228 * rounded to the nearest integer. 229 * 230 * @param units 231 * Unit conversion factor, e.g. {@link #DPI CODE>DPI} or {@link 232 * #DPCM DPCM}. 233 * @param unitsName 234 * Units name string, e.g. {@code "dpi"} or {@code "dpcm"}. If 235 * null, no units name is appended to the result. 236 * 237 * @return String version of this resolution attribute. 238 * 239 * @exception IllegalArgumentException 240 * (unchecked exception) Thrown if {@code units < 1}. 241 */ 242 public String toString(int units, String unitsName) { 243 StringBuilder result = new StringBuilder(); 244 result.append(getCrossFeedResolution (units)); 245 result.append('x'); 246 result.append(getFeedResolution (units)); 247 if (unitsName != null) { 248 result.append (' '); 249 result.append (unitsName); 250 } 251 return result.toString(); 252 } 253 254 255 /** 256 * Determine whether this resolution attribute's value is less than or 257 * equal to the given resolution attribute's value. This is true if all 258 * of the following conditions are true: 259 * <UL> 260 * <LI> 261 * This attribute's cross feed direction resolution is less than or equal to 262 * the {@code other} attribute's cross feed direction resolution. 263 * <LI> 264 * This attribute's feed direction resolution is less than or equal to the 265 * {@code other} attribute's feed direction resolution. 266 * </UL> 267 * 268 * @param other Resolution attribute to compare with. 269 * 270 * @return True if this resolution attribute is less than or equal to the 271 * {@code other} resolution attribute, false otherwise. 272 * 273 * @exception NullPointerException 274 * (unchecked exception) Thrown if {@code other} is null. 275 */ 276 public boolean lessThanOrEquals(ResolutionSyntax other) { 277 return (this.crossFeedResolution <= other.crossFeedResolution && 278 this.feedResolution <= other.feedResolution); 279 } 280 281 282 /** 283 * Returns whether this resolution attribute is equivalent to the passed in 284 * object. To be equivalent, all of the following conditions must be true: 285 * <OL TYPE=1> 286 * <LI> 287 * {@code object} is not null. 288 * <LI> 289 * {@code object} is an instance of class ResolutionSyntax. 290 * <LI> 291 * This attribute's cross feed direction resolution is equal to 292 * {@code object}'s cross feed direction resolution. 293 * <LI> 294 * This attribute's feed direction resolution is equal to 295 * {@code object}'s feed direction resolution. 296 * </OL> 297 * 298 * @param object Object to compare to. 299 * 300 * @return True if {@code object} is equivalent to this resolution 301 * attribute, false otherwise. 302 */ 303 public boolean equals(Object object) { 304 305 return(object != null && 306 object instanceof ResolutionSyntax && 307 this.crossFeedResolution == 308 ((ResolutionSyntax) object).crossFeedResolution && 309 this.feedResolution == 310 ((ResolutionSyntax) object).feedResolution); 311 } 312 313 /** 314 * Returns a hash code value for this resolution attribute. 315 */ 316 public int hashCode() { 317 return(((crossFeedResolution & 0x0000FFFF)) | 318 ((feedResolution & 0x0000FFFF) << 16)); 319 } 320 321 /** 322 * Returns a string version of this resolution attribute. The string takes 323 * the form <code>"<I>C</I>x<I>F</I> dphi"</code>, where <I>C</I> is the 324 * cross feed direction resolution and <I>F</I> is the feed direction 325 * resolution. The values are reported in the internal units of dphi. 326 */ 327 public String toString() { 328 StringBuilder result = new StringBuilder(); 329 result.append(crossFeedResolution); 330 result.append('x'); 331 result.append(feedResolution); 332 result.append(" dphi"); 333 return result.toString(); 334 } 335 336 337 /** 338 * Returns this resolution attribute's cross feed direction resolution in 339 * units of dphi. (For use in a subclass.) 340 * 341 * @return Cross feed direction resolution. 342 */ 343 protected int getCrossFeedResolutionDphi() { 344 return crossFeedResolution; 345 } 346 347 /** 348 * Returns this resolution attribute's feed direction resolution in units 349 * of dphi. (For use in a subclass.) 350 * 351 * @return Feed direction resolution. 352 */ 353 protected int getFeedResolutionDphi() { 354 return feedResolution; 355 } 356 357 }