38 |
|
|
39 |
package javax.imageio; |
package javax.imageio; |
40 |
|
|
41 |
|
import java.awt.Transparency; |
42 |
|
import java.awt.color.ColorSpace; |
43 |
|
import java.awt.image.DataBuffer; |
44 |
|
import java.awt.image.BandedSampleModel; |
45 |
|
import java.awt.image.BufferedImage; |
46 |
import java.awt.image.ColorModel; |
import java.awt.image.ColorModel; |
47 |
|
import java.awt.image.ComponentColorModel; |
48 |
|
import java.awt.image.DirectColorModel; |
49 |
|
import java.awt.image.IndexColorModel; |
50 |
|
import java.awt.image.MultiPixelPackedSampleModel; |
51 |
|
import java.awt.image.PixelInterleavedSampleModel; |
52 |
import java.awt.image.RenderedImage; |
import java.awt.image.RenderedImage; |
53 |
import java.awt.image.SampleModel; |
import java.awt.image.SampleModel; |
54 |
|
|
55 |
|
/** |
56 |
|
* ImageTypeSpecifier store the color and sample models associated |
57 |
|
* with an IIOImage. |
58 |
|
*/ |
59 |
public class ImageTypeSpecifier |
public class ImageTypeSpecifier |
60 |
{ |
{ |
61 |
|
/** |
62 |
|
* The image's color model. |
63 |
|
*/ |
64 |
protected ColorModel colorModel; |
protected ColorModel colorModel; |
65 |
|
|
66 |
|
/** |
67 |
|
* The image's sample model. |
68 |
|
*/ |
69 |
protected SampleModel sampleModel; |
protected SampleModel sampleModel; |
70 |
|
|
71 |
|
/** |
72 |
|
* Construct an image type specifier with the given models. |
73 |
|
* |
74 |
|
* @param colorModel the color model |
75 |
|
* @param sampleModel the sample model |
76 |
|
* |
77 |
|
* @exception IllegalArgumentException if either model argument is |
78 |
|
* null |
79 |
|
* @exception IllegalArgumentException if the models are |
80 |
|
* incompatible with one another |
81 |
|
*/ |
82 |
public ImageTypeSpecifier(ColorModel colorModel, SampleModel sampleModel) |
public ImageTypeSpecifier(ColorModel colorModel, SampleModel sampleModel) |
83 |
{ |
{ |
84 |
if (colorModel == null) |
if (colorModel == null) |
95 |
this.sampleModel = sampleModel; |
this.sampleModel = sampleModel; |
96 |
} |
} |
97 |
|
|
98 |
|
/** |
99 |
|
* Construct an image type specifier that describes the given |
100 |
|
* rendered image. |
101 |
|
* |
102 |
|
* @param image a rendered image |
103 |
|
* |
104 |
|
* @exception IllegalArgumentException if image is null |
105 |
|
*/ |
106 |
public ImageTypeSpecifier(RenderedImage image) |
public ImageTypeSpecifier(RenderedImage image) |
107 |
{ |
{ |
108 |
if (image == null) |
if (image == null) |
112 |
this.sampleModel = image.getSampleModel(); |
this.sampleModel = image.getSampleModel(); |
113 |
} |
} |
114 |
|
|
115 |
|
/** |
116 |
|
* Create an image type specifier for a banded image using a |
117 |
|
* component color model and a banded sample model. |
118 |
|
* |
119 |
|
* @param colorSpace the color space |
120 |
|
* @param bankIndices the bank indices at which each band will be |
121 |
|
* stored |
122 |
|
* @param bandOffsets the starting band offset for each band within |
123 |
|
* its bank |
124 |
|
* @param dataType the data type, a DataBuffer constant |
125 |
|
* @param hasAlpha true if this image type specifier should have an |
126 |
|
* alpha component, false otherwise |
127 |
|
* @param isAlphaPremultiplied true if other color components should |
128 |
|
* be premultiplied by the alpha component, false otherwise |
129 |
|
* |
130 |
|
* @return a banded image type specifier |
131 |
|
* |
132 |
|
* @exception IllegalArgumentException if any of colorSpace, |
133 |
|
* bankIndices or bankOffsets is null |
134 |
|
* @exception IllegalArgumentException if bankIndices and |
135 |
|
* bankOffsets differ in length |
136 |
|
* @excpetion IllegalArgumentException if the number of color space |
137 |
|
* components, including the alpha component if requested, is |
138 |
|
* different from bandOffsets.length |
139 |
|
* @exception if dataType is not a valid DataBuffer constant |
140 |
|
*/ |
141 |
|
public static ImageTypeSpecifier createBanded (ColorSpace colorSpace, |
142 |
|
int[] bankIndices, |
143 |
|
int[] bankOffsets, |
144 |
|
int dataType, |
145 |
|
boolean hasAlpha, |
146 |
|
boolean isAlphaPremultiplied) |
147 |
|
{ |
148 |
|
if (colorSpace == null || bankIndices == null || bankOffsets == null) |
149 |
|
throw new IllegalArgumentException ("null argument"); |
150 |
|
|
151 |
|
if (bankIndices.length != bankOffsets.length) |
152 |
|
throw new IllegalArgumentException ("array lengths differ"); |
153 |
|
|
154 |
|
if (bankOffsets.length != (colorSpace.getNumComponents() + (hasAlpha ? 1 : 0))) |
155 |
|
throw new IllegalArgumentException ("invalid bankOffsets length"); |
156 |
|
|
157 |
|
return new ImageTypeSpecifier (new ComponentColorModel (colorSpace, |
158 |
|
hasAlpha, |
159 |
|
isAlphaPremultiplied, |
160 |
|
hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE, |
161 |
|
dataType), |
162 |
|
new BandedSampleModel (dataType, 1, 1, 1, |
163 |
|
bankIndices, |
164 |
|
bankOffsets)); |
165 |
|
} |
166 |
|
|
167 |
|
/** |
168 |
|
* Create a buffered image with the given dimensions using that has |
169 |
|
* the characteristics specified by this image type specifier. |
170 |
|
* |
171 |
|
* @param the width of the buffered image, in pixels |
172 |
|
* @param the height of the buffered image, in pixels |
173 |
|
* |
174 |
|
* @return a buffered image |
175 |
|
* |
176 |
|
* @exception IllegalArgumentException if either width or height is |
177 |
|
* less than or equal to zero |
178 |
|
* @exception IllegalArgumentException if width * height is greater |
179 |
|
* than Integer.MAX_VALUE or if the storage required is greater than |
180 |
|
* Integer.MAX_VALUE |
181 |
|
*/ |
182 |
|
public BufferedImage createBufferedImage (int width, int height) |
183 |
|
{ |
184 |
|
if (width <= 0 || height <= 0) |
185 |
|
throw new IllegalArgumentException ("dimension <= 0"); |
186 |
|
|
187 |
|
// test for overflow |
188 |
|
if (width * height < Math.min (width, height)) |
189 |
|
throw new IllegalArgumentException ("width * height > Integer.MAX_VALUE"); |
190 |
|
|
191 |
|
if (width * height * sampleModel.getNumBands() < Math.min (width, height)) |
192 |
|
throw new IllegalArgumentException ("storage required >" |
193 |
|
+ " Integer.MAX_VALUE"); |
194 |
|
|
195 |
|
// FIXME: this is probably wrong: |
196 |
|
return new BufferedImage (width, height, BufferedImage.TYPE_INT_RGB); |
197 |
|
} |
198 |
|
|
199 |
|
/** |
200 |
|
* Create an image type specifier that describes the given buffered |
201 |
|
* image type. |
202 |
|
* |
203 |
|
* @param bufferedImageType the buffered image type to represent |
204 |
|
* with the returned image type specifier |
205 |
|
* |
206 |
|
* @return a new image type specifier |
207 |
|
* |
208 |
|
* @exception IllegalArgumentException if bufferedImageType is not a |
209 |
|
* BufferedImage constant or is BufferedImage.TYPE_CUSTOM |
210 |
|
*/ |
211 |
|
public static ImageTypeSpecifier createFromBufferedImageType (int bufferedImageType) |
212 |
|
{ |
213 |
|
if (bufferedImageType <= BufferedImage.TYPE_CUSTOM |
214 |
|
|| bufferedImageType > BufferedImage.TYPE_BYTE_INDEXED) |
215 |
|
throw new IllegalArgumentException ("invalid buffered image type"); |
216 |
|
|
217 |
|
return new ImageTypeSpecifier (new BufferedImage (1, 1, bufferedImageType)); |
218 |
|
} |
219 |
|
|
220 |
|
/** |
221 |
|
* Create an image type specifier that describes the given rendered |
222 |
|
* image's type. |
223 |
|
* |
224 |
|
* @param image the rendered image |
225 |
|
* |
226 |
|
* @return a new image type specifier |
227 |
|
* |
228 |
|
* @exception IllegalArgumentException if image is null |
229 |
|
*/ |
230 |
|
public static ImageTypeSpecifier createFromRenderedImage (RenderedImage image) |
231 |
|
{ |
232 |
|
if (image == null) |
233 |
|
throw new IllegalArgumentException ("image null"); |
234 |
|
|
235 |
|
return new ImageTypeSpecifier (image); |
236 |
|
} |
237 |
|
|
238 |
|
/** |
239 |
|
* Create a grayscale image type specifier, given the number of |
240 |
|
* bits, data type and whether or not the data is signed. |
241 |
|
* |
242 |
|
* @param bits the number of bits used to specify a greyscale value |
243 |
|
* @param dataType a DataBuffer type constant |
244 |
|
* @param isSigned true if this type specifier should support |
245 |
|
* negative values, false otherwise |
246 |
|
* |
247 |
|
* @return a greyscal image type specifier |
248 |
|
* |
249 |
|
* @exception IllegalArgumentException if bits is not 1, 2, 4, 8 or 16 |
250 |
|
* @exception IllegalArgumentException if dataType is not |
251 |
|
* DataBuffer.TYPE_BYTE, DataBuffer.TYPE_SHORT or |
252 |
|
* DataBuffer.TYPE_USHORT |
253 |
|
* @exception if bits is larger than the number of bits in the given |
254 |
|
* data type |
255 |
|
*/ |
256 |
|
public static ImageTypeSpecifier createGrayscale (int bits, int dataType, boolean isSigned) |
257 |
|
{ |
258 |
|
return createGrayscale (bits, dataType, isSigned, false); |
259 |
|
} |
260 |
|
|
261 |
|
/** |
262 |
|
* Create a grayscale image type specifier, given the number of |
263 |
|
* bits, data type and whether or not the data is signed. |
264 |
|
* |
265 |
|
* @param bits the number of bits used to specify a greyscale value |
266 |
|
* @param dataType a DataBuffer type constant |
267 |
|
* @param isSigned true if this type specifier should support |
268 |
|
* negative values, false otherwise |
269 |
|
* |
270 |
|
* @return a greyscal image type specifier |
271 |
|
* |
272 |
|
* @exception IllegalArgumentException if bits is not 1, 2, 4, 8 or |
273 |
|
* 16 |
274 |
|
* @exception IllegalArgumentException if dataType is not |
275 |
|
* DataBuffer.TYPE_BYTE, DataBuffer.TYPE_SHORT or |
276 |
|
* DataBuffer.TYPE_USHORT |
277 |
|
* @exception if bits is larger than the number of bits in the given |
278 |
|
* data type |
279 |
|
*/ |
280 |
|
public static ImageTypeSpecifier createGrayscale (int bits, int dataType, |
281 |
|
boolean isSigned, |
282 |
|
boolean isAlphaPremultiplied) |
283 |
|
{ |
284 |
|
if (bits != 1 && bits != 2 && bits != 4 && bits != 8 && bits != 16) |
285 |
|
throw new IllegalArgumentException ("invalid bit size"); |
286 |
|
|
287 |
|
if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_SHORT |
288 |
|
&& dataType != DataBuffer.TYPE_USHORT) |
289 |
|
throw new IllegalArgumentException ("invalid data type"); |
290 |
|
|
291 |
|
if (dataType == DataBuffer.TYPE_BYTE && bits > 8) |
292 |
|
throw new IllegalArgumentException ("number of bits too large for data type"); |
293 |
|
|
294 |
|
// FIXME: this is probably wrong: |
295 |
|
return new ImageTypeSpecifier (new DirectColorModel (bits, 0xff, 0x0, |
296 |
|
0x0, 0xff), |
297 |
|
new MultiPixelPackedSampleModel (dataType, |
298 |
|
1, 1, |
299 |
|
bits)); |
300 |
|
} |
301 |
|
|
302 |
|
/** |
303 |
|
* Return an image type specifier for an image that uses an indexed |
304 |
|
* colour model where each colour value has the specified number of |
305 |
|
* bits and type and where the colour tables are those given. |
306 |
|
* |
307 |
|
* @param redLUT the red index values |
308 |
|
* @param greenLUT the green index values |
309 |
|
* @param blueLUT the blue index values |
310 |
|
* @param alphaLUT the alpha index values |
311 |
|
* @param bits the number of bits per index value |
312 |
|
* @param dataType the type of each index value |
313 |
|
* |
314 |
|
* @return an indexed image type specifier |
315 |
|
* |
316 |
|
* @exception IllegalArgumentException if any of the colour arrays, |
317 |
|
* not including alphaLUT, is null |
318 |
|
* @exception IllegalArgumentException if bits is not 1, 2, 4, 8 or |
319 |
|
* 16 |
320 |
|
* @exception IllegalArgumentException if dataType is not |
321 |
|
* DataBuffer.TYPE_BYTE, DataBuffer.TYPE_SHORT or |
322 |
|
* DataBuffer.TYPE_USHORT |
323 |
|
* @exception if bits is larger than the number of bits in the given |
324 |
|
* data type |
325 |
|
*/ |
326 |
|
public static ImageTypeSpecifier createIndexed (byte[] redLUT, |
327 |
|
byte[] greenLUT, |
328 |
|
byte[] blueLUT, |
329 |
|
byte[] alphaLUT, |
330 |
|
int bits, |
331 |
|
int dataType) |
332 |
|
{ |
333 |
|
if (redLUT == null || greenLUT == null || blueLUT == null) |
334 |
|
throw new IllegalArgumentException ("null colour table"); |
335 |
|
|
336 |
|
if (bits != 1 && bits != 2 && bits != 4 && bits != 8 && bits != 16) |
337 |
|
throw new IllegalArgumentException ("invalid bit size"); |
338 |
|
|
339 |
|
if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_SHORT |
340 |
|
&& dataType != DataBuffer.TYPE_USHORT) |
341 |
|
throw new IllegalArgumentException ("invalid data type"); |
342 |
|
|
343 |
|
if (dataType == DataBuffer.TYPE_BYTE && bits > 8) |
344 |
|
throw new IllegalArgumentException ("number of bits too large for data type"); |
345 |
|
|
346 |
|
// FIXME: this is probably wrong: |
347 |
|
return new ImageTypeSpecifier (new IndexColorModel (bits, redLUT.length, |
348 |
|
redLUT, greenLUT, blueLUT, |
349 |
|
alphaLUT), |
350 |
|
new MultiPixelPackedSampleModel (dataType, |
351 |
|
1, 1, |
352 |
|
bits)); |
353 |
|
} |
354 |
|
|
355 |
|
/** |
356 |
|
* Create an image type specifier that uses a component colour model |
357 |
|
* and a pixel interleaved sample model. Each pixel component will |
358 |
|
* be stored in a separate value of the given data type. |
359 |
|
* |
360 |
|
* @param colorSpace the colour space used by the colour model |
361 |
|
* @param bandOffsets the starting band offset for each band within |
362 |
|
* its bank |
363 |
|
* @param dataType the type of each pixel value |
364 |
|
* @param hasAlpha true if an alpha channel should be specified, |
365 |
|
* false otherwise |
366 |
|
* @param isAlphaPremultiplied true if other colour channels should |
367 |
|
* be premultiplied by the alpha value, false otherwise |
368 |
|
* |
369 |
|
* @return an interleaved image type specifier |
370 |
|
* |
371 |
|
* @exception IllegalArgumentException if either colorSpace or |
372 |
|
* bandOffsets is null |
373 |
|
* @excpetion IllegalArgumentException if the number of color space |
374 |
|
* components, including the alpha component if requested, is |
375 |
|
* different from bandOffsets.length |
376 |
|
* @exception if dataType is not a valid DataBuffer constant |
377 |
|
*/ |
378 |
|
public static ImageTypeSpecifier createInterleaved (ColorSpace colorSpace, |
379 |
|
int[] bandOffsets, |
380 |
|
int dataType, |
381 |
|
boolean hasAlpha, |
382 |
|
boolean isAlphaPremultiplied) |
383 |
|
{ |
384 |
|
if (colorSpace == null || bandOffsets == null) |
385 |
|
throw new IllegalArgumentException ("null argument"); |
386 |
|
|
387 |
|
if (bandOffsets.length != (colorSpace.getNumComponents() + (hasAlpha ? 1 : 0))) |
388 |
|
throw new IllegalArgumentException ("invalid bankOffsets length"); |
389 |
|
|
390 |
|
return new ImageTypeSpecifier (new ComponentColorModel (colorSpace, |
391 |
|
hasAlpha, |
392 |
|
isAlphaPremultiplied, |
393 |
|
hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE, |
394 |
|
dataType), |
395 |
|
new PixelInterleavedSampleModel (dataType, 1, 1, 1, 1, |
396 |
|
bandOffsets)); |
397 |
|
} |
398 |
|
|
399 |
|
/** |
400 |
|
* Create an image type specifier using a direct color model and a |
401 |
|
* packed sample model. All pixel components will be packed into |
402 |
|
* one value of the given data type. |
403 |
|
* |
404 |
|
* @param colorSpace the color space to use in the color model |
405 |
|
* @param redMask the bitmask for the red bits |
406 |
|
* @param greenMask the bitmask for the green bits |
407 |
|
* @param blueMask the bitmask for the blue bits |
408 |
|
* @param alphaMask the bitmask for the alpha bits |
409 |
|
* @param transferType the data type used to store pixel values |
410 |
|
* @param isAlphaPremultiplied true if other colour channels should |
411 |
|
* be premultiplied by the alpha value, false otherwise |
412 |
|
* |
413 |
|
* @return a packed image type specifier |
414 |
|
* |
415 |
|
* @exception IllegalArgumentException if colorSpace is null |
416 |
|
* @exception IllegalArgumentException if colorSpace does not have |
417 |
|
* type ColorSpace.TYPE_RGB |
418 |
|
* @exception IllegalArgumentException if all masks are 0 |
419 |
|
* @exception IllegalArgumentException if dataType is not |
420 |
|
* DataBuffer.TYPE_BYTE, DataBuffer.TYPE_SHORT or |
421 |
|
* DataBuffer.TYPE_INT |
422 |
|
*/ |
423 |
|
public static ImageTypeSpecifier createPacked (ColorSpace colorSpace, |
424 |
|
int redMask, |
425 |
|
int greenMask, |
426 |
|
int blueMask, |
427 |
|
int alphaMask, |
428 |
|
int transferType, |
429 |
|
boolean isAlphaPremultiplied) |
430 |
|
{ |
431 |
|
if (colorSpace == null) |
432 |
|
throw new IllegalArgumentException ("null color space"); |
433 |
|
|
434 |
|
if (colorSpace.getType() != ColorSpace.TYPE_RGB) |
435 |
|
throw new IllegalArgumentException ("invalid color space type"); |
436 |
|
|
437 |
|
if (redMask == 0 && greenMask == 0 && blueMask == 0 && alphaMask == 0) |
438 |
|
throw new IllegalArgumentException ("no non-zero mask"); |
439 |
|
|
440 |
|
if (transferType != DataBuffer.TYPE_BYTE && transferType != DataBuffer.TYPE_USHORT |
441 |
|
&& transferType != DataBuffer.TYPE_INT) |
442 |
|
throw new IllegalArgumentException ("invalid data type"); |
443 |
|
|
444 |
|
// Assume DataBuffer.TYPE_BYTE. |
445 |
|
int numBits = 8; |
446 |
|
|
447 |
|
if (transferType == DataBuffer.TYPE_SHORT) |
448 |
|
numBits = 16; |
449 |
|
else if (transferType == DataBuffer.TYPE_INT) |
450 |
|
numBits = 32; |
451 |
|
|
452 |
|
return new ImageTypeSpecifier (new DirectColorModel (colorSpace, |
453 |
|
numBits, |
454 |
|
redMask, |
455 |
|
greenMask, |
456 |
|
blueMask, |
457 |
|
alphaMask, |
458 |
|
isAlphaPremultiplied, |
459 |
|
transferType), |
460 |
|
new MultiPixelPackedSampleModel (transferType, |
461 |
|
1, 1, numBits)); |
462 |
|
} |
463 |
|
|
464 |
|
/** |
465 |
|
* Get the number of bits per sample in the given band. |
466 |
|
* |
467 |
|
* @param band the band from which to get the number of bits |
468 |
|
* |
469 |
|
* @return the number of bits in the given band |
470 |
|
* |
471 |
|
* @exception IllegalArgumentException if band is out-of-bounds |
472 |
|
*/ |
473 |
|
public int getBitsPerBand (int band) |
474 |
|
{ |
475 |
|
if (band < 0 || band > sampleModel.getNumBands()) |
476 |
|
throw new IllegalArgumentException ("band out-of-bounds"); |
477 |
|
|
478 |
|
return sampleModel.getSampleSize (band); |
479 |
|
} |
480 |
|
|
481 |
|
/** |
482 |
|
* Get the buffered image constant specified by this image type |
483 |
|
* specifier. |
484 |
|
* |
485 |
|
* @return a buffered image constant |
486 |
|
*/ |
487 |
|
public int getBufferedImageType () |
488 |
|
{ |
489 |
|
// FIXME: |
490 |
|
return BufferedImage.TYPE_INT_RGB; |
491 |
|
} |
492 |
|
|
493 |
|
/** |
494 |
|
* Create a sample model that is compatible with the one specified |
495 |
|
* by this image type specifier, with the given dimensions. |
496 |
|
* |
497 |
|
* @param width the width of the returned sample model |
498 |
|
* @param height the height of the returned sample model |
499 |
|
* |
500 |
|
* @return a sample model compatible with the one in this image type |
501 |
|
* specifier, with the given dimensions |
502 |
|
* |
503 |
|
* @exception IllegalArgumentException if either width or height is |
504 |
|
* less than or equal to 0 |
505 |
|
* @exception IllegalArgumentException if width * height is greater |
506 |
|
* than Intere.MAX_VALUE |
507 |
|
*/ |
508 |
|
public SampleModel getSampleModel (int width, int height) |
509 |
|
{ |
510 |
|
if (width <= 0 || height <= 0) |
511 |
|
throw new IllegalArgumentException ("invalid dimension"); |
512 |
|
|
513 |
|
// test for overflow |
514 |
|
if (width * height < Math.min (width, height)) |
515 |
|
throw new IllegalArgumentException ("width * height > Integer.MAX_VALUE"); |
516 |
|
|
517 |
|
return sampleModel.createCompatibleSampleModel (width, height); |
518 |
|
} |
519 |
|
|
520 |
|
/** |
521 |
|
* Get the color model specified by this image type specifier. |
522 |
|
* |
523 |
|
* @return the color model |
524 |
|
*/ |
525 |
public ColorModel getColorModel() |
public ColorModel getColorModel() |
526 |
{ |
{ |
527 |
return colorModel; |
return colorModel; |
528 |
} |
} |
529 |
|
|
530 |
|
/** |
531 |
|
* Get the number of bands specified by this image type specifier's |
532 |
|
* sample model. |
533 |
|
* |
534 |
|
* @return the number of bands in the sample model |
535 |
|
*/ |
536 |
public int getNumBands() |
public int getNumBands() |
537 |
{ |
{ |
538 |
return sampleModel.getNumBands(); |
return sampleModel.getNumBands(); |
539 |
} |
} |
540 |
|
|
541 |
|
/** |
542 |
|
* Get the number of components specified by this image type |
543 |
|
* specifier's color model. |
544 |
|
* |
545 |
|
* @return the number of color components per pixel |
546 |
|
*/ |
547 |
public int getNumComponents() |
public int getNumComponents() |
548 |
{ |
{ |
549 |
return colorModel.getNumComponents(); |
return colorModel.getNumComponents(); |
550 |
} |
} |
551 |
|
|
552 |
|
/** |
553 |
|
* Get the sample model specified by this image type specifier. |
554 |
|
* |
555 |
|
* @return the sample model |
556 |
|
*/ |
557 |
public SampleModel getSampleModel() |
public SampleModel getSampleModel() |
558 |
{ |
{ |
559 |
return sampleModel; |
return sampleModel; |