History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/imageio/ImageTypeSpecifier.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/imageio/ImageTypeSpecifier.java+1241−0
@@ -0,0 +1,1241 @@
1+/*
2+ * Copyright (c) 2000, 2003, 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+package javax.imageio;
27+
28+import java.awt.Point;
29+import java.awt.Transparency;
30+import java.awt.image.BandedSampleModel;
31+import java.awt.image.BufferedImage;
32+import java.awt.image.ColorModel;
33+import java.awt.color.ColorSpace;
34+import java.awt.image.IndexColorModel;
35+import java.awt.image.ComponentColorModel;
36+import java.awt.image.DataBuffer;
37+import java.awt.image.DirectColorModel;
38+import java.awt.image.MultiPixelPackedSampleModel;
39+import java.awt.image.PixelInterleavedSampleModel;
40+import java.awt.image.SinglePixelPackedSampleModel;
41+import java.awt.image.Raster;
42+import java.awt.image.RenderedImage;
43+import java.awt.image.SampleModel;
44+import java.awt.image.WritableRaster;
45+import java.util.Hashtable;
46+
47+/**
48+ * A class that allows the format of an image (in particular, its
49+ * <code>SampleModel</code> and <code>ColorModel</code>) to be
50+ * specified in a convenient manner.
51+ *
52+ */
53+public class ImageTypeSpecifier {
54+
55+ /**
56+ * The <code>ColorModel</code> to be used as a prototype.
57+ */
58+ protected ColorModel colorModel;
59+
60+ /**
61+ * A <code>SampleModel</code> to be used as a prototype.
62+ */
63+ protected SampleModel sampleModel;
64+
65+ /**
66+ * Cached specifiers for all of the standard
67+ * <code>BufferedImage</code> types.
68+ */
69+ private static ImageTypeSpecifier[] BISpecifier;
70+ private static ColorSpace sRGB;
71+ // Initialize the standard specifiers
72+ static {
73+ sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);
74+
75+ BISpecifier =
76+ new ImageTypeSpecifier[BufferedImage.TYPE_BYTE_INDEXED + 1];
77+ }
78+
79+ /**
80+ * A constructor to be used by inner subclasses only.
81+ */
82+ private ImageTypeSpecifier() {}
83+
84+ /**
85+ * Constructs an <code>ImageTypeSpecifier</code> directly
86+ * from a <code>ColorModel</code> and a <code>SampleModel</code>.
87+ * It is the caller's responsibility to supply compatible
88+ * parameters.
89+ *
90+ * @param colorModel a <code>ColorModel</code>.
91+ * @param sampleModel a <code>SampleModel</code>.
92+ *
93+ * @exception IllegalArgumentException if either parameter is
94+ * <code>null</code>.
95+ * @exception IllegalArgumentException if <code>sampleModel</code>
96+ * is not compatible with <code>colorModel</code>.
97+ */
98+ public ImageTypeSpecifier(ColorModel colorModel, SampleModel sampleModel) {
99+ if (colorModel == null) {
100+ throw new IllegalArgumentException("colorModel == null!");
101+ }
102+ if (sampleModel == null) {
103+ throw new IllegalArgumentException("sampleModel == null!");
104+ }
105+ if (!colorModel.isCompatibleSampleModel(sampleModel)) {
106+ throw new IllegalArgumentException
107+ ("sampleModel is incompatible with colorModel!");
108+ }
109+ this.colorModel = colorModel;
110+ this.sampleModel = sampleModel;
111+ }
112+
113+ /**
114+ * Constructs an <code>ImageTypeSpecifier</code> from a
115+ * <code>RenderedImage</code>. If a <code>BufferedImage</code> is
116+ * being used, one of the factory methods
117+ * <code>createFromRenderedImage</code> or
118+ * <code>createFromBufferedImageType</code> should be used instead in
119+ * order to get a more accurate result.
120+ *
121+ * @param image a <code>RenderedImage</code>.
122+ *
123+ * @exception IllegalArgumentException if the argument is
124+ * <code>null</code>.
125+ */
126+ public ImageTypeSpecifier(RenderedImage image) {
127+ if (image == null) {
128+ throw new IllegalArgumentException("image == null!");
129+ }
130+ colorModel = image.getColorModel();
131+ sampleModel = image.getSampleModel();
132+ }
133+
134+ // Packed
135+
136+ static class Packed extends ImageTypeSpecifier {
137+ ColorSpace colorSpace;
138+ int redMask;
139+ int greenMask;
140+ int blueMask;
141+ int alphaMask;
142+ int transferType;
143+ boolean isAlphaPremultiplied;
144+
145+ public Packed(ColorSpace colorSpace,
146+ int redMask,
147+ int greenMask,
148+ int blueMask,
149+ int alphaMask, // 0 if no alpha
150+ int transferType,
151+ boolean isAlphaPremultiplied) {
152+ if (colorSpace == null) {
153+ throw new IllegalArgumentException("colorSpace == null!");
154+ }
155+ if (colorSpace.getType() != ColorSpace.TYPE_RGB) {
156+ throw new IllegalArgumentException
157+ ("colorSpace is not of type TYPE_RGB!");
158+ }
159+ if (transferType != DataBuffer.TYPE_BYTE &&
160+ transferType != DataBuffer.TYPE_USHORT &&
161+ transferType != DataBuffer.TYPE_INT) {
162+ throw new IllegalArgumentException
163+ ("Bad value for transferType!");
164+ }
165+ if (redMask == 0 && greenMask == 0 &&
166+ blueMask == 0 && alphaMask == 0) {
167+ throw new IllegalArgumentException
168+ ("No mask has at least 1 bit set!");
169+ }
170+ this.colorSpace = colorSpace;
171+ this.redMask = redMask;
172+ this.greenMask = greenMask;
173+ this.blueMask = blueMask;
174+ this.alphaMask = alphaMask;
175+ this.transferType = transferType;
176+ this.isAlphaPremultiplied = isAlphaPremultiplied;
177+
178+ int bits = 32;
179+ this.colorModel =
180+ new DirectColorModel(colorSpace,
181+ bits,
182+ redMask, greenMask, blueMask,
183+ alphaMask, isAlphaPremultiplied,
184+ transferType);
185+ this.sampleModel = colorModel.createCompatibleSampleModel(1, 1);
186+ }
187+ }
188+
189+ /**
190+ * Returns a specifier for a packed image format that will use a
191+ * <code>DirectColorModel</code> and a packed
192+ * <code>SampleModel</code> to store each pixel packed into in a
193+ * single byte, short, or int.
194+ *
195+ * @param colorSpace the desired <code>ColorSpace</code>.
196+ * @param redMask a contiguous mask indicated the position of the
197+ * red channel.
198+ * @param greenMask a contiguous mask indicated the position of the
199+ * green channel.
200+ * @param blueMask a contiguous mask indicated the position of the
201+ * blue channel.
202+ * @param alphaMask a contiguous mask indicated the position of the
203+ * alpha channel.
204+ * @param transferType the desired <code>SampleModel</code> transfer type.
205+ * @param isAlphaPremultiplied <code>true</code> if the color channels
206+ * will be premultipled by the alpha channel.
207+ *
208+ * @return an <code>ImageTypeSpecifier</code> with the desired
209+ * characteristics.
210+ *
211+ * @exception IllegalArgumentException if <code>colorSpace</code>
212+ * is <code>null</code>.
213+ * @exception IllegalArgumentException if <code>colorSpace</code>
214+ * is not of type <code>TYPE_RGB</code>.
215+ * @exception IllegalArgumentException if no mask has at least 1
216+ * bit set.
217+ * @exception IllegalArgumentException if
218+ * <code>transferType</code> if not one of
219+ * <code>DataBuffer.TYPE_BYTE</code>,
220+ * <code>DataBuffer.TYPE_USHORT</code>, or
221+ * <code>DataBuffer.TYPE_INT</code>.
222+ */
223+ public static ImageTypeSpecifier
224+ createPacked(ColorSpace colorSpace,
225+ int redMask,
226+ int greenMask,
227+ int blueMask,
228+ int alphaMask, // 0 if no alpha
229+ int transferType,
230+ boolean isAlphaPremultiplied) {
231+ return new ImageTypeSpecifier.Packed(colorSpace,
232+ redMask,
233+ greenMask,
234+ blueMask,
235+ alphaMask, // 0 if no alpha
236+ transferType,
237+ isAlphaPremultiplied);
238+ }
239+
240+ static ColorModel createComponentCM(ColorSpace colorSpace,
241+ int numBands,
242+ int dataType,
243+ boolean hasAlpha,
244+ boolean isAlphaPremultiplied) {
245+ int transparency =
246+ hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE;
247+
248+ int[] numBits = new int[numBands];
249+ int bits = DataBuffer.getDataTypeSize(dataType);
250+
251+ for (int i = 0; i < numBands; i++) {
252+ numBits[i] = bits;
253+ }
254+
255+ return new ComponentColorModel(colorSpace,
256+ numBits,
257+ hasAlpha,
258+ isAlphaPremultiplied,
259+ transparency,
260+ dataType);
261+ }
262+
263+ // Interleaved
264+
265+ static class Interleaved extends ImageTypeSpecifier {
266+ ColorSpace colorSpace;
267+ int[] bandOffsets;
268+ int dataType;
269+ boolean hasAlpha;
270+ boolean isAlphaPremultiplied;
271+
272+ public Interleaved(ColorSpace colorSpace,
273+ int[] bandOffsets,
274+ int dataType,
275+ boolean hasAlpha,
276+ boolean isAlphaPremultiplied) {
277+ if (colorSpace == null) {
278+ throw new IllegalArgumentException("colorSpace == null!");
279+ }
280+ if (bandOffsets == null) {
281+ throw new IllegalArgumentException("bandOffsets == null!");
282+ }
283+ int numBands = colorSpace.getNumComponents() +
284+ (hasAlpha ? 1 : 0);
285+ if (bandOffsets.length != numBands) {
286+ throw new IllegalArgumentException
287+ ("bandOffsets.length is wrong!");
288+ }
289+ if (dataType != DataBuffer.TYPE_BYTE &&
290+ dataType != DataBuffer.TYPE_SHORT &&
291+ dataType != DataBuffer.TYPE_USHORT &&
292+ dataType != DataBuffer.TYPE_INT &&
293+ dataType != DataBuffer.TYPE_FLOAT &&
294+ dataType != DataBuffer.TYPE_DOUBLE) {
295+ throw new IllegalArgumentException
296+ ("Bad value for dataType!");
297+ }
298+ this.colorSpace = colorSpace;
299+ this.bandOffsets = (int[])bandOffsets.clone();
300+ this.dataType = dataType;
301+ this.hasAlpha = hasAlpha;
302+ this.isAlphaPremultiplied = isAlphaPremultiplied;
303+
304+ this.colorModel =
305+ ImageTypeSpecifier.createComponentCM(colorSpace,
306+ bandOffsets.length,
307+ dataType,
308+ hasAlpha,
309+ isAlphaPremultiplied);
310+
311+ int minBandOffset = bandOffsets[0];
312+ int maxBandOffset = minBandOffset;
313+ for (int i = 0; i < bandOffsets.length; i++) {
314+ int offset = bandOffsets[i];
315+ minBandOffset = Math.min(offset, minBandOffset);
316+ maxBandOffset = Math.max(offset, maxBandOffset);
317+ }
318+ int pixelStride = maxBandOffset - minBandOffset + 1;
319+
320+ int w = 1;
321+ int h = 1;
322+ this.sampleModel =
323+ new PixelInterleavedSampleModel(dataType,
324+ w, h,
325+ pixelStride,
326+ w*pixelStride,
327+ bandOffsets);
328+ }
329+
330+ public boolean equals(Object o) {
331+ if ((o == null) ||
332+ !(o instanceof ImageTypeSpecifier.Interleaved)) {
333+ return false;
334+ }
335+
336+ ImageTypeSpecifier.Interleaved that =
337+ (ImageTypeSpecifier.Interleaved)o;
338+
339+ if ((!(this.colorSpace.equals(that.colorSpace))) ||
340+ (this.dataType != that.dataType) ||
341+ (this.hasAlpha != that.hasAlpha) ||
342+ (this.isAlphaPremultiplied != that.isAlphaPremultiplied) ||
343+ (this.bandOffsets.length != that.bandOffsets.length)) {
344+ return false;
345+ }
346+
347+ for (int i = 0; i < bandOffsets.length; i++) {
348+ if (this.bandOffsets[i] != that.bandOffsets[i]) {
349+ return false;
350+ }
351+ }
352+
353+ return true;
354+ }
355+
356+ public int hashCode() {
357+ return (super.hashCode() +
358+ (4 * bandOffsets.length) +
359+ (25 * dataType) +
360+ (hasAlpha ? 17 : 18));
361+ }
362+ }
363+
364+ /**
365+ * Returns a specifier for an interleaved image format that will
366+ * use a <code>ComponentColorModel</code> and a
367+ * <code>PixelInterleavedSampleModel</code> to store each pixel
368+ * component in a separate byte, short, or int.
369+ *
370+ * @param colorSpace the desired <code>ColorSpace</code>.
371+ * @param bandOffsets an array of <code>int</code>s indicating the
372+ * offsets for each band.
373+ * @param dataType the desired data type, as one of the enumerations
374+ * from the <code>DataBuffer</code> class.
375+ * @param hasAlpha <code>true</code> if an alpha channel is desired.
376+ * @param isAlphaPremultiplied <code>true</code> if the color channels
377+ * will be premultipled by the alpha channel.
378+ *
379+ * @return an <code>ImageTypeSpecifier</code> with the desired
380+ * characteristics.
381+ *
382+ * @exception IllegalArgumentException if <code>colorSpace</code>
383+ * is <code>null</code>.
384+ * @exception IllegalArgumentException if <code>bandOffsets</code>
385+ * is <code>null</code>.
386+ * @exception IllegalArgumentException if <code>dataType</code> is
387+ * not one of the legal <code>DataBuffer.TYPE_*</code> constants.
388+ * @exception IllegalArgumentException if
389+ * <code>bandOffsets.length</code> does not equal the number of
390+ * color space components, plus 1 if <code>hasAlpha</code> is
391+ * <code>true</code>.
392+ */
393+ public static ImageTypeSpecifier
394+ createInterleaved(ColorSpace colorSpace,
395+ int[] bandOffsets,
396+ int dataType,
397+ boolean hasAlpha,
398+ boolean isAlphaPremultiplied) {
399+ return new ImageTypeSpecifier.Interleaved(colorSpace,
400+ bandOffsets,
401+ dataType,
402+ hasAlpha,
403+ isAlphaPremultiplied);
404+ }
405+
406+ // Banded
407+
408+ static class Banded extends ImageTypeSpecifier {
409+ ColorSpace colorSpace;
410+ int[] bankIndices;
411+ int[] bandOffsets;
412+ int dataType;
413+ boolean hasAlpha;
414+ boolean isAlphaPremultiplied;
415+
416+ public Banded(ColorSpace colorSpace,
417+ int[] bankIndices,
418+ int[] bandOffsets,
419+ int dataType,
420+ boolean hasAlpha,
421+ boolean isAlphaPremultiplied) {
422+ if (colorSpace == null) {
423+ throw new IllegalArgumentException("colorSpace == null!");
424+ }
425+ if (bankIndices == null) {
426+ throw new IllegalArgumentException("bankIndices == null!");
427+ }
428+ if (bandOffsets == null) {
429+ throw new IllegalArgumentException("bandOffsets == null!");
430+ }
431+ if (bankIndices.length != bandOffsets.length) {
432+ throw new IllegalArgumentException
433+ ("bankIndices.length != bandOffsets.length!");
434+ }
435+ if (dataType != DataBuffer.TYPE_BYTE &&
436+ dataType != DataBuffer.TYPE_SHORT &&
437+ dataType != DataBuffer.TYPE_USHORT &&
438+ dataType != DataBuffer.TYPE_INT &&
439+ dataType != DataBuffer.TYPE_FLOAT &&
440+ dataType != DataBuffer.TYPE_DOUBLE) {
441+ throw new IllegalArgumentException
442+ ("Bad value for dataType!");
443+ }
444+ int numBands = colorSpace.getNumComponents() +
445+ (hasAlpha ? 1 : 0);
446+ if (bandOffsets.length != numBands) {
447+ throw new IllegalArgumentException
448+ ("bandOffsets.length is wrong!");
449+ }
450+
451+ this.colorSpace = colorSpace;
452+ this.bankIndices = (int[])bankIndices.clone();
453+ this.bandOffsets = (int[])bandOffsets.clone();
454+ this.dataType = dataType;
455+ this.hasAlpha = hasAlpha;
456+ this.isAlphaPremultiplied = isAlphaPremultiplied;
457+
458+ this.colorModel =
459+ ImageTypeSpecifier.createComponentCM(colorSpace,
460+ bankIndices.length,
461+ dataType,
462+ hasAlpha,
463+ isAlphaPremultiplied);
464+
465+ int w = 1;
466+ int h = 1;
467+ this.sampleModel = new BandedSampleModel(dataType,
468+ w, h,
469+ w,
470+ bankIndices,
471+ bandOffsets);
472+ }
473+
474+ public boolean equals(Object o) {
475+ if ((o == null) ||
476+ !(o instanceof ImageTypeSpecifier.Banded)) {
477+ return false;
478+ }
479+
480+ ImageTypeSpecifier.Banded that =
481+ (ImageTypeSpecifier.Banded)o;
482+
483+ if ((!(this.colorSpace.equals(that.colorSpace))) ||
484+ (this.dataType != that.dataType) ||
485+ (this.hasAlpha != that.hasAlpha) ||
486+ (this.isAlphaPremultiplied != that.isAlphaPremultiplied) ||
487+ (this.bankIndices.length != that.bankIndices.length) ||
488+ (this.bandOffsets.length != that.bandOffsets.length)) {
489+ return false;
490+ }
491+
492+ for (int i = 0; i < bankIndices.length; i++) {
493+ if (this.bankIndices[i] != that.bankIndices[i]) {
494+ return false;
495+ }
496+ }
497+
498+ for (int i = 0; i < bandOffsets.length; i++) {
499+ if (this.bandOffsets[i] != that.bandOffsets[i]) {
500+ return false;
501+ }
502+ }
503+
504+ return true;
505+ }
506+
507+ public int hashCode() {
508+ return (super.hashCode() +
509+ (3 * bandOffsets.length) +
510+ (7 * bankIndices.length) +
511+ (21 * dataType) +
512+ (hasAlpha ? 19 : 29));
513+ }
514+ }
515+
516+ /**
517+ * Returns a specifier for a banded image format that will use a
518+ * <code>ComponentColorModel</code> and a
519+ * <code>BandedSampleModel</code> to store each channel in a
520+ * separate array.
521+ *
522+ * @param colorSpace the desired <code>ColorSpace</code>.
523+ * @param bankIndices an array of <code>int</code>s indicating the
524+ * bank in which each band will be stored.
525+ * @param bandOffsets an array of <code>int</code>s indicating the
526+ * starting offset of each band within its bank.
527+ * @param dataType the desired data type, as one of the enumerations
528+ * from the <code>DataBuffer</code> class.
529+ * @param hasAlpha <code>true</code> if an alpha channel is desired.
530+ * @param isAlphaPremultiplied <code>true</code> if the color channels
531+ * will be premultipled by the alpha channel.
532+ *
533+ * @return an <code>ImageTypeSpecifier</code> with the desired
534+ * characteristics.
535+ *
536+ * @exception IllegalArgumentException if <code>colorSpace</code>
537+ * is <code>null</code>.
538+ * @exception IllegalArgumentException if <code>bankIndices</code>
539+ * is <code>null</code>.
540+ * @exception IllegalArgumentException if <code>bandOffsets</code>
541+ * is <code>null</code>.
542+ * @exception IllegalArgumentException if the lengths of
543+ * <code>bankIndices</code> and <code>bandOffsets</code> differ.
544+ * @exception IllegalArgumentException if
545+ * <code>bandOffsets.length</code> does not equal the number of
546+ * color space components, plus 1 if <code>hasAlpha</code> is
547+ * <code>true</code>.
548+ * @exception IllegalArgumentException if <code>dataType</code> is
549+ * not one of the legal <code>DataBuffer.TYPE_*</code> constants.
550+ */
551+ public static ImageTypeSpecifier
552+ createBanded(ColorSpace colorSpace,
553+ int[] bankIndices,
554+ int[] bandOffsets,
555+ int dataType,
556+ boolean hasAlpha,
557+ boolean isAlphaPremultiplied) {
558+ return new ImageTypeSpecifier.Banded(colorSpace,
559+ bankIndices,
560+ bandOffsets,
561+ dataType,
562+ hasAlpha,
563+ isAlphaPremultiplied);
564+ }
565+
566+ // Grayscale
567+
568+ static class Grayscale extends ImageTypeSpecifier {
569+ int bits;
570+ int dataType;
571+ boolean isSigned;
572+ boolean hasAlpha;
573+ boolean isAlphaPremultiplied;
574+
575+ public Grayscale(int bits,
576+ int dataType,
577+ boolean isSigned,
578+ boolean hasAlpha,
579+ boolean isAlphaPremultiplied)
580+ {
581+ if (bits != 1 && bits != 2 && bits != 4 &&
582+ bits != 8 && bits != 16)
583+ {
584+ throw new IllegalArgumentException("Bad value for bits!");
585+ }
586+ if (dataType != DataBuffer.TYPE_BYTE &&
587+ dataType != DataBuffer.TYPE_SHORT &&
588+ dataType != DataBuffer.TYPE_USHORT)
589+ {
590+ throw new IllegalArgumentException
591+ ("Bad value for dataType!");
592+ }
593+ if (bits > 8 && dataType == DataBuffer.TYPE_BYTE) {
594+ throw new IllegalArgumentException
595+ ("Too many bits for dataType!");
596+ }
597+
598+ this.bits = bits;
599+ this.dataType = dataType;
600+ this.isSigned = isSigned;
601+ this.hasAlpha = hasAlpha;
602+ this.isAlphaPremultiplied = isAlphaPremultiplied;
603+
604+ ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
605+
606+ if ((bits == 8 && dataType == DataBuffer.TYPE_BYTE) ||
607+ (bits == 16 &&
608+ (dataType == DataBuffer.TYPE_SHORT ||
609+ dataType == DataBuffer.TYPE_USHORT))) {
610+ // Use component color model & sample model
611+
612+ int numBands = hasAlpha ? 2 : 1;
613+ int transparency =
614+ hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE;
615+
616+
617+ int[] nBits = new int[numBands];
618+ nBits[0] = bits;
619+ if (numBands == 2) {
620+ nBits[1] = bits;
621+ }
622+ this.colorModel =
623+ new ComponentColorModel(colorSpace,
624+ nBits,
625+ hasAlpha,
626+ isAlphaPremultiplied,
627+ transparency,
628+ dataType);
629+
630+ int[] bandOffsets = new int[numBands];
631+ bandOffsets[0] = 0;
632+ if (numBands == 2) {
633+ bandOffsets[1] = 1;
634+ }
635+
636+ int w = 1;
637+ int h = 1;
638+ this.sampleModel =
639+ new PixelInterleavedSampleModel(dataType,
640+ w, h,
641+ numBands, w*numBands,
642+ bandOffsets);
643+ } else {
644+ int numEntries = 1 << bits;
645+ byte[] arr = new byte[numEntries];
646+ for (int i = 0; i < numEntries; i++) {
647+ arr[i] = (byte)(i*255/(numEntries - 1));
648+ }
649+ this.colorModel =
650+ new IndexColorModel(bits, numEntries, arr, arr, arr);
651+
652+ this.sampleModel =
653+ new MultiPixelPackedSampleModel(dataType, 1, 1, bits);
654+ }
655+ }
656+ }
657+
658+ /**
659+ * Returns a specifier for a grayscale image format that will pack
660+ * pixels of the given bit depth into array elements of
661+ * the specified data type.
662+ *
663+ * @param bits the number of bits per gray value (1, 2, 4, 8, or 16).
664+ * @param dataType the desired data type, as one of the enumerations
665+ * from the <code>DataBuffer</code> class.
666+ * @param isSigned <code>true</code> if negative values are to
667+ * be represented.
668+ *
669+ * @return an <code>ImageTypeSpecifier</code> with the desired
670+ * characteristics.
671+ *
672+ * @exception IllegalArgumentException if <code>bits</code> is
673+ * not one of 1, 2, 4, 8, or 16.
674+ * @exception IllegalArgumentException if <code>dataType</code> is
675+ * not one of <code>DataBuffer.TYPE_BYTE</code>,
676+ * <code>DataBuffer.TYPE_SHORT</code>, or
677+ * <code>DataBuffer.TYPE_USHORT</code>.
678+ * @exception IllegalArgumentException if <code>bits</code> is
679+ * larger than the bit size of the given <code>dataType</code>.
680+ */
681+ public static ImageTypeSpecifier
682+ createGrayscale(int bits,
683+ int dataType,
684+ boolean isSigned) {
685+ return new ImageTypeSpecifier.Grayscale(bits,
686+ dataType,
687+ isSigned,
688+ false,
689+ false);
690+ }
691+
692+ /**
693+ * Returns a specifier for a grayscale plus alpha image format
694+ * that will pack pixels of the given bit depth into array
695+ * elements of the specified data type.
696+ *
697+ * @param bits the number of bits per gray value (1, 2, 4, 8, or 16).
698+ * @param dataType the desired data type, as one of the enumerations
699+ * from the <code>DataBuffer</code> class.
700+ * @param isSigned <code>true</code> if negative values are to
701+ * be represented.
702+ * @param isAlphaPremultiplied <code>true</code> if the luminance channel
703+ * will be premultipled by the alpha channel.
704+ *
705+ * @return an <code>ImageTypeSpecifier</code> with the desired
706+ * characteristics.
707+ *
708+ * @exception IllegalArgumentException if <code>bits</code> is
709+ * not one of 1, 2, 4, 8, or 16.
710+ * @exception IllegalArgumentException if <code>dataType</code> is
711+ * not one of <code>DataBuffer.TYPE_BYTE</code>,
712+ * <code>DataBuffer.TYPE_SHORT</code>, or
713+ * <code>DataBuffer.TYPE_USHORT</code>.
714+ * @exception IllegalArgumentException if <code>bits</code> is
715+ * larger than the bit size of the given <code>dataType</code>.
716+ */
717+ public static ImageTypeSpecifier
718+ createGrayscale(int bits,
719+ int dataType,
720+ boolean isSigned,
721+ boolean isAlphaPremultiplied) {
722+ return new ImageTypeSpecifier.Grayscale(bits,
723+ dataType,
724+ isSigned,
725+ true,
726+ isAlphaPremultiplied);
727+ }
728+
729+ // Indexed
730+
731+ static class Indexed extends ImageTypeSpecifier {
732+ byte[] redLUT;
733+ byte[] greenLUT;
734+ byte[] blueLUT;
735+ byte[] alphaLUT = null;
736+ int bits;
737+ int dataType;
738+
739+ public Indexed(byte[] redLUT,
740+ byte[] greenLUT,
741+ byte[] blueLUT,
742+ byte[] alphaLUT,
743+ int bits,
744+ int dataType) {
745+ if (redLUT == null || greenLUT == null || blueLUT == null) {
746+ throw new IllegalArgumentException("LUT is null!");
747+ }
748+ if (bits != 1 && bits != 2 && bits != 4 &&
749+ bits != 8 && bits != 16) {
750+ throw new IllegalArgumentException("Bad value for bits!");
751+ }
752+ if (dataType != DataBuffer.TYPE_BYTE &&
753+ dataType != DataBuffer.TYPE_SHORT &&
754+ dataType != DataBuffer.TYPE_USHORT &&
755+ dataType != DataBuffer.TYPE_INT) {
756+ throw new IllegalArgumentException
757+ ("Bad value for dataType!");
758+ }
759+ if ((bits > 8 && dataType == DataBuffer.TYPE_BYTE) ||
760+ (bits > 16 && dataType != DataBuffer.TYPE_INT)) {
761+ throw new IllegalArgumentException
762+ ("Too many bits for dataType!");
763+ }
764+
765+ int len = 1 << bits;
766+ if (redLUT.length != len ||
767+ greenLUT.length != len ||
768+ blueLUT.length != len ||
769+ (alphaLUT != null && alphaLUT.length != len)) {
770+ throw new IllegalArgumentException("LUT has improper length!");
771+ }
772+ this.redLUT = (byte[])redLUT.clone();
773+ this.greenLUT = (byte[])greenLUT.clone();
774+ this.blueLUT = (byte[])blueLUT.clone();
775+ if (alphaLUT != null) {
776+ this.alphaLUT = (byte[])alphaLUT.clone();
777+ }
778+ this.bits = bits;
779+ this.dataType = dataType;
780+
781+ if (alphaLUT == null) {
782+ this.colorModel = new IndexColorModel(bits,
783+ redLUT.length,
784+ redLUT,
785+ greenLUT,
786+ blueLUT);
787+ } else {
788+ this.colorModel = new IndexColorModel(bits,
789+ redLUT.length,
790+ redLUT,
791+ greenLUT,
792+ blueLUT,
793+ alphaLUT);
794+ }
795+
796+ if ((bits == 8 && dataType == DataBuffer.TYPE_BYTE) ||
797+ (bits == 16 &&
798+ (dataType == DataBuffer.TYPE_SHORT ||
799+ dataType == DataBuffer.TYPE_USHORT))) {
800+ int[] bandOffsets = { 0 };
801+ this.sampleModel =
802+ new PixelInterleavedSampleModel(dataType,
803+ 1, 1, 1, 1,
804+ bandOffsets);
805+ } else {
806+ this.sampleModel =
807+ new MultiPixelPackedSampleModel(dataType, 1, 1, bits);
808+ }
809+ }
810+ }
811+
812+ /**
813+ * Returns a specifier for an indexed-color image format that will pack
814+ * index values of the given bit depth into array elements of
815+ * the specified data type.
816+ *
817+ * @param redLUT an array of <code>byte</code>s containing
818+ * the red values for each index.
819+ * @param greenLUT an array of <code>byte</code>s containing * the
820+ * green values for each index.
821+ * @param blueLUT an array of <code>byte</code>s containing the
822+ * blue values for each index.
823+ * @param alphaLUT an array of <code>byte</code>s containing the
824+ * alpha values for each index, or <code>null</code> to create a
825+ * fully opaque LUT.
826+ * @param bits the number of bits in each index.
827+ * @param dataType the desired output type, as one of the enumerations
828+ * from the <code>DataBuffer</code> class.
829+ *
830+ * @return an <code>ImageTypeSpecifier</code> with the desired
831+ * characteristics.
832+ *
833+ * @exception IllegalArgumentException if <code>redLUT</code> is
834+ * <code>null</code>.
835+ * @exception IllegalArgumentException if <code>greenLUT</code> is
836+ * <code>null</code>.
837+ * @exception IllegalArgumentException if <code>blueLUT</code> is
838+ * <code>null</code>.
839+ * @exception IllegalArgumentException if <code>bits</code> is
840+ * not one of 1, 2, 4, 8, or 16.
841+ * @exception IllegalArgumentException if the
842+ * non-<code>null</code> LUT parameters do not have lengths of
843+ * exactly <code>1 << bits</code>.
844+ * @exception IllegalArgumentException if <code>dataType</code> is
845+ * not one of <code>DataBuffer.TYPE_BYTE</code>,
846+ * <code>DataBuffer.TYPE_SHORT</code>,
847+ * <code>DataBuffer.TYPE_USHORT</code>,
848+ * or <code>DataBuffer.TYPE_INT</code>.
849+ * @exception IllegalArgumentException if <code>bits</code> is
850+ * larger than the bit size of the given <code>dataType</code>.
851+ */
852+ public static ImageTypeSpecifier
853+ createIndexed(byte[] redLUT,
854+ byte[] greenLUT,
855+ byte[] blueLUT,
856+ byte[] alphaLUT,
857+ int bits,
858+ int dataType) {
859+ return new ImageTypeSpecifier.Indexed(redLUT,
860+ greenLUT,
861+ blueLUT,
862+ alphaLUT,
863+ bits,
864+ dataType);
865+ }
866+
867+ /**
868+ * Returns an <code>ImageTypeSpecifier</code> that encodes
869+ * one of the standard <code>BufferedImage</code> types
870+ * (other than <code>TYPE_CUSTOM</code>).
871+ *
872+ * @param bufferedImageType an int representing one of the standard
873+ * <code>BufferedImage</code> types.
874+ *
875+ * @return an <code>ImageTypeSpecifier</code> with the desired
876+ * characteristics.
877+ *
878+ * @exception IllegalArgumentException if
879+ * <code>bufferedImageType</code> is not one of the standard
880+ * types, or is equal to <code>TYPE_CUSTOM</code>.
881+ *
882+ * @see java.awt.image.BufferedImage
883+ * @see java.awt.image.BufferedImage#TYPE_INT_RGB
884+ * @see java.awt.image.BufferedImage#TYPE_INT_ARGB
885+ * @see java.awt.image.BufferedImage#TYPE_INT_ARGB_PRE
886+ * @see java.awt.image.BufferedImage#TYPE_INT_BGR
887+ * @see java.awt.image.BufferedImage#TYPE_3BYTE_BGR
888+ * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR
889+ * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR_PRE
890+ * @see java.awt.image.BufferedImage#TYPE_USHORT_565_RGB
891+ * @see java.awt.image.BufferedImage#TYPE_USHORT_555_RGB
892+ * @see java.awt.image.BufferedImage#TYPE_BYTE_GRAY
893+ * @see java.awt.image.BufferedImage#TYPE_USHORT_GRAY
894+ * @see java.awt.image.BufferedImage#TYPE_BYTE_BINARY
895+ * @see java.awt.image.BufferedImage#TYPE_BYTE_INDEXED
896+ */
897+ public static
898+ ImageTypeSpecifier createFromBufferedImageType(int bufferedImageType) {
899+ if (bufferedImageType >= BufferedImage.TYPE_INT_RGB &&
900+ bufferedImageType <= BufferedImage.TYPE_BYTE_INDEXED) {
901+ return getSpecifier(bufferedImageType);
902+ } else if (bufferedImageType == BufferedImage.TYPE_CUSTOM) {
903+ throw new IllegalArgumentException("Cannot create from TYPE_CUSTOM!");
904+ } else {
905+ throw new IllegalArgumentException("Invalid BufferedImage type!");
906+ }
907+ }
908+
909+ /**
910+ * Returns an <code>ImageTypeSpecifier</code> that encodes the
911+ * layout of a <code>RenderedImage</code> (which may be a
912+ * <code>BufferedImage</code>).
913+ *
914+ * @param image a <code>RenderedImage</code>.
915+ *
916+ * @return an <code>ImageTypeSpecifier</code> with the desired
917+ * characteristics.
918+ *
919+ * @exception IllegalArgumentException if <code>image</code> is
920+ * <code>null</code>.
921+ */
922+ public static
923+ ImageTypeSpecifier createFromRenderedImage(RenderedImage image) {
924+ if (image == null) {
925+ throw new IllegalArgumentException("image == null!");
926+ }
927+
928+ if (image instanceof BufferedImage) {
929+ int bufferedImageType = ((BufferedImage)image).getType();
930+ if (bufferedImageType != BufferedImage.TYPE_CUSTOM) {
931+ return getSpecifier(bufferedImageType);
932+ }
933+ }
934+
935+ return new ImageTypeSpecifier(image);
936+ }
937+
938+ /**
939+ * Returns an int containing one of the enumerated constant values
940+ * describing image formats from <code>BufferedImage</code>.
941+ *
942+ * @return an <code>int</code> representing a
943+ * <code>BufferedImage</code> type.
944+ *
945+ * @see java.awt.image.BufferedImage
946+ * @see java.awt.image.BufferedImage#TYPE_CUSTOM
947+ * @see java.awt.image.BufferedImage#TYPE_INT_RGB
948+ * @see java.awt.image.BufferedImage#TYPE_INT_ARGB
949+ * @see java.awt.image.BufferedImage#TYPE_INT_ARGB_PRE
950+ * @see java.awt.image.BufferedImage#TYPE_INT_BGR
951+ * @see java.awt.image.BufferedImage#TYPE_3BYTE_BGR
952+ * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR
953+ * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR_PRE
954+ * @see java.awt.image.BufferedImage#TYPE_USHORT_565_RGB
955+ * @see java.awt.image.BufferedImage#TYPE_USHORT_555_RGB
956+ * @see java.awt.image.BufferedImage#TYPE_BYTE_GRAY
957+ * @see java.awt.image.BufferedImage#TYPE_USHORT_GRAY
958+ * @see java.awt.image.BufferedImage#TYPE_BYTE_BINARY
959+ * @see java.awt.image.BufferedImage#TYPE_BYTE_INDEXED
960+ */
961+ public int getBufferedImageType() {
962+ BufferedImage bi = createBufferedImage(1, 1);
963+ return bi.getType();
964+ }
965+
966+ /**
967+ * Return the number of color components
968+ * specified by this object. This is the same value as returned by
969+ * <code>ColorModel.getNumComponents</code>
970+ *
971+ * @return the number of components in the image.
972+ */
973+ public int getNumComponents() {
974+ return colorModel.getNumComponents();
975+ }
976+
977+ /**
978+ * Return the number of bands
979+ * specified by this object. This is the same value as returned by
980+ * <code>SampleModel.getNumBands</code>
981+ *
982+ * @return the number of bands in the image.
983+ */
984+ public int getNumBands() {
985+ return sampleModel.getNumBands();
986+ }
987+
988+ /**
989+ * Return the number of bits used to represent samples of the given band.
990+ *
991+ * @param band the index of the band to be queried, as an
992+ * int.
993+ *
994+ * @return an int specifying a number of bits.
995+ *
996+ * @exception IllegalArgumentException if <code>band</code> is
997+ * negative or greater than the largest band index.
998+ */
999+ public int getBitsPerBand(int band) {
1000+ if (band < 0 | band >= getNumBands()) {
1001+ throw new IllegalArgumentException("band out of range!");
1002+ }
1003+ return sampleModel.getSampleSize(band);
1004+ }
1005+
1006+ /**
1007+ * Returns a <code>SampleModel</code> based on the settings
1008+ * encapsulated within this object. The width and height of the
1009+ * <code>SampleModel</code> will be set to arbitrary values.
1010+ *
1011+ * @return a <code>SampleModel</code> with arbitrary dimensions.
1012+ */
1013+ public SampleModel getSampleModel() {
1014+ return sampleModel;
1015+ }
1016+
1017+ /**
1018+ * Returns a <code>SampleModel</code> based on the settings
1019+ * encapsulated within this object. The width and height of the
1020+ * <code>SampleModel</code> will be set to the supplied values.
1021+ *
1022+ * @param width the desired width of the returned <code>SampleModel</code>.
1023+ * @param height the desired height of the returned
1024+ * <code>SampleModel</code>.
1025+ *
1026+ * @return a <code>SampleModel</code> with the given dimensions.
1027+ *
1028+ * @exception IllegalArgumentException if either <code>width</code> or
1029+ * <code>height</code> are negative or zero.
1030+ * @exception IllegalArgumentException if the product of
1031+ * <code>width</code> and <code>height</code> is greater than
1032+ * <code>Integer.MAX_VALUE</code>
1033+ */
1034+ public SampleModel getSampleModel(int width, int height) {
1035+ if ((long)width*height > Integer.MAX_VALUE) {
1036+ throw new IllegalArgumentException
1037+ ("width*height > Integer.MAX_VALUE!");
1038+ }
1039+ return sampleModel.createCompatibleSampleModel(width, height);
1040+ }
1041+
1042+ /**
1043+ * Returns the <code>ColorModel</code> specified by this object.
1044+ *
1045+ * @return a <code>ColorModel</code>.
1046+ */
1047+ public ColorModel getColorModel() {
1048+ return colorModel;
1049+ }
1050+
1051+ /**
1052+ * Creates a <code>BufferedImage</code> with a given width and
1053+ * height according to the specification embodied in this object.
1054+ *
1055+ * @param width the desired width of the returned
1056+ * <code>BufferedImage</code>.
1057+ * @param height the desired height of the returned
1058+ * <code>BufferedImage</code>.
1059+ *
1060+ * @return a new <code>BufferedImage</code>
1061+ *
1062+ * @exception IllegalArgumentException if either <code>width</code> or
1063+ * <code>height</code> are negative or zero.
1064+ * @exception IllegalArgumentException if the product of
1065+ * <code>width</code> and <code>height</code> is greater than
1066+ * <code>Integer.MAX_VALUE</code>, or if the number of array
1067+ * elements needed to store the image is greater than
1068+ * <code>Integer.MAX_VALUE</code>.
1069+ */
1070+ public BufferedImage createBufferedImage(int width, int height) {
1071+ try {
1072+ SampleModel sampleModel = getSampleModel(width, height);
1073+ WritableRaster raster =
1074+ Raster.createWritableRaster(sampleModel,
1075+ new Point(0, 0));
1076+ return new BufferedImage(colorModel, raster,
1077+ colorModel.isAlphaPremultiplied(),
1078+ new Hashtable());
1079+ } catch (NegativeArraySizeException e) {
1080+ // Exception most likely thrown from a DataBuffer constructor
1081+ throw new IllegalArgumentException
1082+ ("Array size > Integer.MAX_VALUE!");
1083+ }
1084+ }
1085+
1086+ /**
1087+ * Returns <code>true</code> if the given <code>Object</code> is
1088+ * an <code>ImageTypeSpecifier</code> and has a
1089+ * <code>SampleModel</code> and <code>ColorModel</code> that are
1090+ * equal to those of this object.
1091+ *
1092+ * @param o the <code>Object</code> to be compared for equality.
1093+ *
1094+ * @return <code>true</code> if the given object is an equivalent
1095+ * <code>ImageTypeSpecifier</code>.
1096+ */
1097+ public boolean equals(Object o) {
1098+ if ((o == null) || !(o instanceof ImageTypeSpecifier)) {
1099+ return false;
1100+ }
1101+
1102+ ImageTypeSpecifier that = (ImageTypeSpecifier)o;
1103+ return (colorModel.equals(that.colorModel)) &&
1104+ (sampleModel.equals(that.sampleModel));
1105+ }
1106+
1107+ /**
1108+ * Returns the hash code for this ImageTypeSpecifier.
1109+ *
1110+ * @return a hash code for this ImageTypeSpecifier
1111+ */
1112+ public int hashCode() {
1113+ return (9 * colorModel.hashCode()) + (14 * sampleModel.hashCode());
1114+ }
1115+
1116+ private static ImageTypeSpecifier getSpecifier(int type) {
1117+ if (BISpecifier[type] == null) {
1118+ BISpecifier[type] = createSpecifier(type);
1119+ }
1120+ return BISpecifier[type];
1121+ }
1122+
1123+ private static ImageTypeSpecifier createSpecifier(int type) {
1124+ switch(type) {
1125+ case BufferedImage.TYPE_INT_RGB:
1126+ return createPacked(sRGB,
1127+ 0x00ff0000,
1128+ 0x0000ff00,
1129+ 0x000000ff,
1130+ 0x0,
1131+ DataBuffer.TYPE_INT,
1132+ false);
1133+
1134+ case BufferedImage.TYPE_INT_ARGB:
1135+ return createPacked(sRGB,
1136+ 0x00ff0000,
1137+ 0x0000ff00,
1138+ 0x000000ff,
1139+ 0xff000000,
1140+ DataBuffer.TYPE_INT,
1141+ false);
1142+
1143+ case BufferedImage.TYPE_INT_ARGB_PRE:
1144+ return createPacked(sRGB,
1145+ 0x00ff0000,
1146+ 0x0000ff00,
1147+ 0x000000ff,
1148+ 0xff000000,
1149+ DataBuffer.TYPE_INT,
1150+ true);
1151+
1152+ case BufferedImage.TYPE_INT_BGR:
1153+ return createPacked(sRGB,
1154+ 0x000000ff,
1155+ 0x0000ff00,
1156+ 0x00ff0000,
1157+ 0x0,
1158+ DataBuffer.TYPE_INT,
1159+ false);
1160+
1161+ case BufferedImage.TYPE_3BYTE_BGR:
1162+ return createInterleaved(sRGB,
1163+ new int[] { 2, 1, 0 },
1164+ DataBuffer.TYPE_BYTE,
1165+ false,
1166+ false);
1167+
1168+ case BufferedImage.TYPE_4BYTE_ABGR:
1169+ return createInterleaved(sRGB,
1170+ new int[] { 3, 2, 1, 0 },
1171+ DataBuffer.TYPE_BYTE,
1172+ true,
1173+ false);
1174+
1175+ case BufferedImage.TYPE_4BYTE_ABGR_PRE:
1176+ return createInterleaved(sRGB,
1177+ new int[] { 3, 2, 1, 0 },
1178+ DataBuffer.TYPE_BYTE,
1179+ true,
1180+ true);
1181+
1182+ case BufferedImage.TYPE_USHORT_565_RGB:
1183+ return createPacked(sRGB,
1184+ 0xF800,
1185+ 0x07E0,
1186+ 0x001F,
1187+ 0x0,
1188+ DataBuffer.TYPE_USHORT,
1189+ false);
1190+
1191+ case BufferedImage.TYPE_USHORT_555_RGB:
1192+ return createPacked(sRGB,
1193+ 0x7C00,
1194+ 0x03E0,
1195+ 0x001F,
1196+ 0x0,
1197+ DataBuffer.TYPE_USHORT,
1198+ false);
1199+
1200+ case BufferedImage.TYPE_BYTE_GRAY:
1201+ return createGrayscale(8,
1202+ DataBuffer.TYPE_BYTE,
1203+ false);
1204+
1205+ case BufferedImage.TYPE_USHORT_GRAY:
1206+ return createGrayscale(16,
1207+ DataBuffer.TYPE_USHORT,
1208+ false);
1209+
1210+ case BufferedImage.TYPE_BYTE_BINARY:
1211+ return createGrayscale(1,
1212+ DataBuffer.TYPE_BYTE,
1213+ false);
1214+
1215+ case BufferedImage.TYPE_BYTE_INDEXED:
1216+ {
1217+
1218+ BufferedImage bi =
1219+ new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_INDEXED);
1220+ IndexColorModel icm = (IndexColorModel)bi.getColorModel();
1221+ int mapSize = icm.getMapSize();
1222+ byte[] redLUT = new byte[mapSize];
1223+ byte[] greenLUT = new byte[mapSize];
1224+ byte[] blueLUT = new byte[mapSize];
1225+ byte[] alphaLUT = new byte[mapSize];
1226+
1227+ icm.getReds(redLUT);
1228+ icm.getGreens(greenLUT);
1229+ icm.getBlues(blueLUT);
1230+ icm.getAlphas(alphaLUT);
1231+
1232+ return createIndexed(redLUT, greenLUT, blueLUT, alphaLUT,
1233+ 8,
1234+ DataBuffer.TYPE_BYTE);
1235+ }
1236+ default:
1237+ throw new IllegalArgumentException("Invalid BufferedImage type!");
1238+ }
1239+ }
1240+
1241+}