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/com/sun/imageio/plugins/common/ImageUtil.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/imageio/plugins/common/ImageUtil.java+1167−0
@@ -0,0 +1,1167 @@
1+/*
2+ * Copyright (c) 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 com.sun.imageio.plugins.common;
27+
28+import java.awt.Point;
29+import java.awt.Rectangle;
30+import java.awt.Transparency;
31+import java.awt.color.ColorSpace;
32+import java.awt.image.BufferedImage;
33+import java.awt.image.ColorModel;
34+import java.awt.image.ComponentColorModel;
35+import java.awt.image.ComponentSampleModel;
36+import java.awt.image.DataBuffer;
37+import java.awt.image.DataBufferByte;
38+import java.awt.image.DataBufferInt;
39+import java.awt.image.DataBufferShort;
40+import java.awt.image.DataBufferUShort;
41+import java.awt.image.DirectColorModel;
42+import java.awt.image.IndexColorModel;
43+import java.awt.image.MultiPixelPackedSampleModel;
44+import java.awt.image.Raster;
45+import java.awt.image.RenderedImage;
46+import java.awt.image.SampleModel;
47+import java.awt.image.SinglePixelPackedSampleModel;
48+import java.awt.image.WritableRaster;
49+import java.util.Arrays;
50+
51+//import javax.imageio.ImageTypeSpecifier;
52+
53+import javax.imageio.IIOException;
54+import javax.imageio.IIOImage;
55+import javax.imageio.ImageTypeSpecifier;
56+import javax.imageio.ImageWriter;
57+import javax.imageio.spi.ImageWriterSpi;
58+
59+public class ImageUtil {
60+ /* XXX testing only
61+ public static void main(String[] args) {
62+ ImageTypeSpecifier bilevel =
63+ ImageTypeSpecifier.createIndexed(new byte[] {(byte)0, (byte)255},
64+ new byte[] {(byte)0, (byte)255},
65+ new byte[] {(byte)0, (byte)255},
66+ null, 1,
67+ DataBuffer.TYPE_BYTE);
68+ ImageTypeSpecifier gray =
69+ ImageTypeSpecifier.createGrayscale(8, DataBuffer.TYPE_BYTE, false);
70+ ImageTypeSpecifier grayAlpha =
71+ ImageTypeSpecifier.createGrayscale(8, DataBuffer.TYPE_BYTE, false,
72+ false);
73+ ImageTypeSpecifier rgb =
74+ ImageTypeSpecifier.createInterleaved(ColorSpace.getInstance(ColorSpace.CS_sRGB),
75+ new int[] {0, 1, 2},
76+ DataBuffer.TYPE_BYTE,
77+ false,
78+ false);
79+ ImageTypeSpecifier rgba =
80+ ImageTypeSpecifier.createInterleaved(ColorSpace.getInstance(ColorSpace.CS_sRGB),
81+ new int[] {0, 1, 2, 3},
82+ DataBuffer.TYPE_BYTE,
83+ true,
84+ false);
85+ ImageTypeSpecifier packed =
86+ ImageTypeSpecifier.createPacked(ColorSpace.getInstance(ColorSpace.CS_sRGB),
87+ 0xff000000,
88+ 0x00ff0000,
89+ 0x0000ff00,
90+ 0x000000ff,
91+ DataBuffer.TYPE_BYTE,
92+ false);
93+
94+ SampleModel bandedSM =
95+ new java.awt.image.BandedSampleModel(DataBuffer.TYPE_BYTE,
96+ 1, 1, 15);
97+
98+ System.out.println(createColorModel(bilevel.getSampleModel()));
99+ System.out.println(createColorModel(gray.getSampleModel()));
100+ System.out.println(createColorModel(grayAlpha.getSampleModel()));
101+ System.out.println(createColorModel(rgb.getSampleModel()));
102+ System.out.println(createColorModel(rgba.getSampleModel()));
103+ System.out.println(createColorModel(packed.getSampleModel()));
104+ System.out.println(createColorModel(bandedSM));
105+ }
106+ */
107+
108+ /**
109+ * Creates a <code>ColorModel</code> that may be used with the
110+ * specified <code>SampleModel</code>. If a suitable
111+ * <code>ColorModel</code> cannot be found, this method returns
112+ * <code>null</code>.
113+ *
114+ * <p> Suitable <code>ColorModel</code>s are guaranteed to exist
115+ * for all instances of <code>ComponentSampleModel</code>.
116+ * For 1- and 3- banded <code>SampleModel</code>s, the returned
117+ * <code>ColorModel</code> will be opaque. For 2- and 4-banded
118+ * <code>SampleModel</code>s, the output will use alpha transparency
119+ * which is not premultiplied. 1- and 2-banded data will use a
120+ * grayscale <code>ColorSpace</code>, and 3- and 4-banded data a sRGB
121+ * <code>ColorSpace</code>. Data with 5 or more bands will have a
122+ * <code>BogusColorSpace</code>.</p>
123+ *
124+ * <p>An instance of <code>DirectColorModel</code> will be created for
125+ * instances of <code>SinglePixelPackedSampleModel</code> with no more
126+ * than 4 bands.</p>
127+ *
128+ * <p>An instance of <code>IndexColorModel</code> will be created for
129+ * instances of <code>MultiPixelPackedSampleModel</code>. The colormap
130+ * will be a grayscale ramp with <code>1&nbsp;<<&nbsp;numberOfBits</code>
131+ * entries ranging from zero to at most 255.</p>
132+ *
133+ * @return An instance of <code>ColorModel</code> that is suitable for
134+ * the supplied <code>SampleModel</code>, or <code>null</code>.
135+ *
136+ * @throws IllegalArgumentException If <code>sampleModel</code> is
137+ * <code>null</code>.
138+ */
139+ public static final ColorModel createColorModel(SampleModel sampleModel) {
140+ // Check the parameter.
141+ if(sampleModel == null) {
142+ throw new IllegalArgumentException("sampleModel == null!");
143+ }
144+
145+ // Get the data type.
146+ int dataType = sampleModel.getDataType();
147+
148+ // Check the data type
149+ switch(dataType) {
150+ case DataBuffer.TYPE_BYTE:
151+ case DataBuffer.TYPE_USHORT:
152+ case DataBuffer.TYPE_SHORT:
153+ case DataBuffer.TYPE_INT:
154+ case DataBuffer.TYPE_FLOAT:
155+ case DataBuffer.TYPE_DOUBLE:
156+ break;
157+ default:
158+ // Return null for other types.
159+ return null;
160+ }
161+
162+ // The return variable.
163+ ColorModel colorModel = null;
164+
165+ // Get the sample size.
166+ int[] sampleSize = sampleModel.getSampleSize();
167+
168+ // Create a Component ColorModel.
169+ if(sampleModel instanceof ComponentSampleModel) {
170+ // Get the number of bands.
171+ int numBands = sampleModel.getNumBands();
172+
173+ // Determine the color space.
174+ ColorSpace colorSpace = null;
175+ if(numBands <= 2) {
176+ colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
177+ } else if(numBands <= 4) {
178+ colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
179+ } else {
180+ colorSpace = new BogusColorSpace(numBands);
181+ }
182+
183+ boolean hasAlpha = (numBands == 2) || (numBands == 4);
184+ boolean isAlphaPremultiplied = false;
185+ int transparency = hasAlpha ?
186+ Transparency.TRANSLUCENT : Transparency.OPAQUE;
187+
188+ colorModel = new ComponentColorModel(colorSpace,
189+ sampleSize,
190+ hasAlpha,
191+ isAlphaPremultiplied,
192+ transparency,
193+ dataType);
194+ } else if (sampleModel.getNumBands() <= 4 &&
195+ sampleModel instanceof SinglePixelPackedSampleModel) {
196+ SinglePixelPackedSampleModel sppsm =
197+ (SinglePixelPackedSampleModel)sampleModel;
198+
199+ int[] bitMasks = sppsm.getBitMasks();
200+ int rmask = 0;
201+ int gmask = 0;
202+ int bmask = 0;
203+ int amask = 0;
204+
205+ int numBands = bitMasks.length;
206+ if (numBands <= 2) {
207+ rmask = gmask = bmask = bitMasks[0];
208+ if (numBands == 2) {
209+ amask = bitMasks[1];
210+ }
211+ } else {
212+ rmask = bitMasks[0];
213+ gmask = bitMasks[1];
214+ bmask = bitMasks[2];
215+ if (numBands == 4) {
216+ amask = bitMasks[3];
217+ }
218+ }
219+
220+ int bits = 0;
221+ for (int i = 0; i < sampleSize.length; i++) {
222+ bits += sampleSize[i];
223+ }
224+
225+ return new DirectColorModel(bits, rmask, gmask, bmask, amask);
226+
227+ } else if(sampleModel instanceof MultiPixelPackedSampleModel) {
228+ // Load the colormap with a ramp.
229+ int bitsPerSample = sampleSize[0];
230+ int numEntries = 1 << bitsPerSample;
231+ byte[] map = new byte[numEntries];
232+ for (int i = 0; i < numEntries; i++) {
233+ map[i] = (byte)(i*255/(numEntries - 1));
234+ }
235+
236+ colorModel = new IndexColorModel(bitsPerSample, numEntries,
237+ map, map, map);
238+
239+ }
240+
241+ return colorModel;
242+ }
243+
244+ /**
245+ * For the case of binary data (<code>isBinary()</code> returns
246+ * <code>true</code>), return the binary data as a packed byte array.
247+ * The data will be packed as eight bits per byte with no bit offset,
248+ * i.e., the first bit in each image line will be the left-most of the
249+ * first byte of the line. The line stride in bytes will be
250+ * <code>(int)((getWidth()+7)/8)</code>. The length of the returned
251+ * array will be the line stride multiplied by <code>getHeight()</code>
252+ *
253+ * @return the binary data as a packed array of bytes with zero offset
254+ * of <code>null</code> if the data are not binary.
255+ * @throws IllegalArgumentException if <code>isBinary()</code> returns
256+ * <code>false</code> with the <code>SampleModel</code> of the
257+ * supplied <code>Raster</code> as argument.
258+ */
259+ public static byte[] getPackedBinaryData(Raster raster,
260+ Rectangle rect) {
261+ SampleModel sm = raster.getSampleModel();
262+ if(!isBinary(sm)) {
263+ throw new IllegalArgumentException(I18N.getString("ImageUtil0"));
264+ }
265+
266+ int rectX = rect.x;
267+ int rectY = rect.y;
268+ int rectWidth = rect.width;
269+ int rectHeight = rect.height;
270+
271+ DataBuffer dataBuffer = raster.getDataBuffer();
272+
273+ int dx = rectX - raster.getSampleModelTranslateX();
274+ int dy = rectY - raster.getSampleModelTranslateY();
275+
276+ MultiPixelPackedSampleModel mpp = (MultiPixelPackedSampleModel)sm;
277+ int lineStride = mpp.getScanlineStride();
278+ int eltOffset = dataBuffer.getOffset() + mpp.getOffset(dx, dy);
279+ int bitOffset = mpp.getBitOffset(dx);
280+
281+ int numBytesPerRow = (rectWidth + 7)/8;
282+ if(dataBuffer instanceof DataBufferByte &&
283+ eltOffset == 0 && bitOffset == 0 &&
284+ numBytesPerRow == lineStride &&
285+ ((DataBufferByte)dataBuffer).getData().length ==
286+ numBytesPerRow*rectHeight) {
287+ return ((DataBufferByte)dataBuffer).getData();
288+ }
289+
290+ byte[] binaryDataArray = new byte[numBytesPerRow*rectHeight];
291+
292+ int b = 0;
293+
294+ if(bitOffset == 0) {
295+ if(dataBuffer instanceof DataBufferByte) {
296+ byte[] data = ((DataBufferByte)dataBuffer).getData();
297+ int stride = numBytesPerRow;
298+ int offset = 0;
299+ for(int y = 0; y < rectHeight; y++) {
300+ System.arraycopy(data, eltOffset,
301+ binaryDataArray, offset,
302+ stride);
303+ offset += stride;
304+ eltOffset += lineStride;
305+ }
306+ } else if(dataBuffer instanceof DataBufferShort ||
307+ dataBuffer instanceof DataBufferUShort) {
308+ short[] data = dataBuffer instanceof DataBufferShort ?
309+ ((DataBufferShort)dataBuffer).getData() :
310+ ((DataBufferUShort)dataBuffer).getData();
311+
312+ for(int y = 0; y < rectHeight; y++) {
313+ int xRemaining = rectWidth;
314+ int i = eltOffset;
315+ while(xRemaining > 8) {
316+ short datum = data[i++];
317+ binaryDataArray[b++] = (byte)((datum >>> 8) & 0xFF);
318+ binaryDataArray[b++] = (byte)(datum & 0xFF);
319+ xRemaining -= 16;
320+ }
321+ if(xRemaining > 0) {
322+ binaryDataArray[b++] = (byte)((data[i] >>> 8) & 0XFF);
323+ }
324+ eltOffset += lineStride;
325+ }
326+ } else if(dataBuffer instanceof DataBufferInt) {
327+ int[] data = ((DataBufferInt)dataBuffer).getData();
328+
329+ for(int y = 0; y < rectHeight; y++) {
330+ int xRemaining = rectWidth;
331+ int i = eltOffset;
332+ while(xRemaining > 24) {
333+ int datum = data[i++];
334+ binaryDataArray[b++] = (byte)((datum >>> 24) & 0xFF);
335+ binaryDataArray[b++] = (byte)((datum >>> 16) & 0xFF);
336+ binaryDataArray[b++] = (byte)((datum >>> 8) & 0xFF);
337+ binaryDataArray[b++] = (byte)(datum & 0xFF);
338+ xRemaining -= 32;
339+ }
340+ int shift = 24;
341+ while(xRemaining > 0) {
342+ binaryDataArray[b++] =
343+ (byte)((data[i] >>> shift) & 0xFF);
344+ shift -= 8;
345+ xRemaining -= 8;
346+ }
347+ eltOffset += lineStride;
348+ }
349+ }
350+ } else { // bitOffset != 0
351+ if(dataBuffer instanceof DataBufferByte) {
352+ byte[] data = ((DataBufferByte)dataBuffer).getData();
353+
354+ if((bitOffset & 7) == 0) {
355+ int stride = numBytesPerRow;
356+ int offset = 0;
357+ for(int y = 0; y < rectHeight; y++) {
358+ System.arraycopy(data, eltOffset,
359+ binaryDataArray, offset,
360+ stride);
361+ offset += stride;
362+ eltOffset += lineStride;
363+ }
364+ } else { // bitOffset % 8 != 0
365+ int leftShift = bitOffset & 7;
366+ int rightShift = 8 - leftShift;
367+ for(int y = 0; y < rectHeight; y++) {
368+ int i = eltOffset;
369+ int xRemaining = rectWidth;
370+ while(xRemaining > 0) {
371+ if(xRemaining > rightShift) {
372+ binaryDataArray[b++] =
373+ (byte)(((data[i++]&0xFF) << leftShift) |
374+ ((data[i]&0xFF) >>> rightShift));
375+ } else {
376+ binaryDataArray[b++] =
377+ (byte)((data[i]&0xFF) << leftShift);
378+ }
379+ xRemaining -= 8;
380+ }
381+ eltOffset += lineStride;
382+ }
383+ }
384+ } else if(dataBuffer instanceof DataBufferShort ||
385+ dataBuffer instanceof DataBufferUShort) {
386+ short[] data = dataBuffer instanceof DataBufferShort ?
387+ ((DataBufferShort)dataBuffer).getData() :
388+ ((DataBufferUShort)dataBuffer).getData();
389+
390+ for(int y = 0; y < rectHeight; y++) {
391+ int bOffset = bitOffset;
392+ for(int x = 0; x < rectWidth; x += 8, bOffset += 8) {
393+ int i = eltOffset + bOffset/16;
394+ int mod = bOffset % 16;
395+ int left = data[i] & 0xFFFF;
396+ if(mod <= 8) {
397+ binaryDataArray[b++] = (byte)(left >>> (8 - mod));
398+ } else {
399+ int delta = mod - 8;
400+ int right = data[i+1] & 0xFFFF;
401+ binaryDataArray[b++] =
402+ (byte)((left << delta) |
403+ (right >>> (16 - delta)));
404+ }
405+ }
406+ eltOffset += lineStride;
407+ }
408+ } else if(dataBuffer instanceof DataBufferInt) {
409+ int[] data = ((DataBufferInt)dataBuffer).getData();
410+
411+ for(int y = 0; y < rectHeight; y++) {
412+ int bOffset = bitOffset;
413+ for(int x = 0; x < rectWidth; x += 8, bOffset += 8) {
414+ int i = eltOffset + bOffset/32;
415+ int mod = bOffset % 32;
416+ int left = data[i];
417+ if(mod <= 24) {
418+ binaryDataArray[b++] =
419+ (byte)(left >>> (24 - mod));
420+ } else {
421+ int delta = mod - 24;
422+ int right = data[i+1];
423+ binaryDataArray[b++] =
424+ (byte)((left << delta) |
425+ (right >>> (32 - delta)));
426+ }
427+ }
428+ eltOffset += lineStride;
429+ }
430+ }
431+ }
432+
433+ return binaryDataArray;
434+ }
435+
436+ /**
437+ * Returns the binary data unpacked into an array of bytes.
438+ * The line stride will be the width of the <code>Raster</code>.
439+ *
440+ * @throws IllegalArgumentException if <code>isBinary()</code> returns
441+ * <code>false</code> with the <code>SampleModel</code> of the
442+ * supplied <code>Raster</code> as argument.
443+ */
444+ public static byte[] getUnpackedBinaryData(Raster raster,
445+ Rectangle rect) {
446+ SampleModel sm = raster.getSampleModel();
447+ if(!isBinary(sm)) {
448+ throw new IllegalArgumentException(I18N.getString("ImageUtil0"));
449+ }
450+
451+ int rectX = rect.x;
452+ int rectY = rect.y;
453+ int rectWidth = rect.width;
454+ int rectHeight = rect.height;
455+
456+ DataBuffer dataBuffer = raster.getDataBuffer();
457+
458+ int dx = rectX - raster.getSampleModelTranslateX();
459+ int dy = rectY - raster.getSampleModelTranslateY();
460+
461+ MultiPixelPackedSampleModel mpp = (MultiPixelPackedSampleModel)sm;
462+ int lineStride = mpp.getScanlineStride();
463+ int eltOffset = dataBuffer.getOffset() + mpp.getOffset(dx, dy);
464+ int bitOffset = mpp.getBitOffset(dx);
465+
466+ byte[] bdata = new byte[rectWidth*rectHeight];
467+ int maxY = rectY + rectHeight;
468+ int maxX = rectX + rectWidth;
469+ int k = 0;
470+
471+ if(dataBuffer instanceof DataBufferByte) {
472+ byte[] data = ((DataBufferByte)dataBuffer).getData();
473+ for(int y = rectY; y < maxY; y++) {
474+ int bOffset = eltOffset*8 + bitOffset;
475+ for(int x = rectX; x < maxX; x++) {
476+ byte b = data[bOffset/8];
477+ bdata[k++] =
478+ (byte)((b >>> (7 - bOffset & 7)) & 0x0000001);
479+ bOffset++;
480+ }
481+ eltOffset += lineStride;
482+ }
483+ } else if(dataBuffer instanceof DataBufferShort ||
484+ dataBuffer instanceof DataBufferUShort) {
485+ short[] data = dataBuffer instanceof DataBufferShort ?
486+ ((DataBufferShort)dataBuffer).getData() :
487+ ((DataBufferUShort)dataBuffer).getData();
488+ for(int y = rectY; y < maxY; y++) {
489+ int bOffset = eltOffset*16 + bitOffset;
490+ for(int x = rectX; x < maxX; x++) {
491+ short s = data[bOffset/16];
492+ bdata[k++] =
493+ (byte)((s >>> (15 - bOffset % 16)) &
494+ 0x0000001);
495+ bOffset++;
496+ }
497+ eltOffset += lineStride;
498+ }
499+ } else if(dataBuffer instanceof DataBufferInt) {
500+ int[] data = ((DataBufferInt)dataBuffer).getData();
501+ for(int y = rectY; y < maxY; y++) {
502+ int bOffset = eltOffset*32 + bitOffset;
503+ for(int x = rectX; x < maxX; x++) {
504+ int i = data[bOffset/32];
505+ bdata[k++] =
506+ (byte)((i >>> (31 - bOffset % 32)) &
507+ 0x0000001);
508+ bOffset++;
509+ }
510+ eltOffset += lineStride;
511+ }
512+ }
513+
514+ return bdata;
515+ }
516+
517+ /**
518+ * Sets the supplied <code>Raster</code>'s data from an array
519+ * of packed binary data of the form returned by
520+ * <code>getPackedBinaryData()</code>.
521+ *
522+ * @throws IllegalArgumentException if <code>isBinary()</code> returns
523+ * <code>false</code> with the <code>SampleModel</code> of the
524+ * supplied <code>Raster</code> as argument.
525+ */
526+ public static void setPackedBinaryData(byte[] binaryDataArray,
527+ WritableRaster raster,
528+ Rectangle rect) {
529+ SampleModel sm = raster.getSampleModel();
530+ if(!isBinary(sm)) {
531+ throw new IllegalArgumentException(I18N.getString("ImageUtil0"));
532+ }
533+
534+ int rectX = rect.x;
535+ int rectY = rect.y;
536+ int rectWidth = rect.width;
537+ int rectHeight = rect.height;
538+
539+ DataBuffer dataBuffer = raster.getDataBuffer();
540+
541+ int dx = rectX - raster.getSampleModelTranslateX();
542+ int dy = rectY - raster.getSampleModelTranslateY();
543+
544+ MultiPixelPackedSampleModel mpp = (MultiPixelPackedSampleModel)sm;
545+ int lineStride = mpp.getScanlineStride();
546+ int eltOffset = dataBuffer.getOffset() + mpp.getOffset(dx, dy);
547+ int bitOffset = mpp.getBitOffset(dx);
548+
549+ int b = 0;
550+
551+ if(bitOffset == 0) {
552+ if(dataBuffer instanceof DataBufferByte) {
553+ byte[] data = ((DataBufferByte)dataBuffer).getData();
554+ if(data == binaryDataArray) {
555+ // Optimal case: simply return.
556+ return;
557+ }
558+ int stride = (rectWidth + 7)/8;
559+ int offset = 0;
560+ for(int y = 0; y < rectHeight; y++) {
561+ System.arraycopy(binaryDataArray, offset,
562+ data, eltOffset,
563+ stride);
564+ offset += stride;
565+ eltOffset += lineStride;
566+ }
567+ } else if(dataBuffer instanceof DataBufferShort ||
568+ dataBuffer instanceof DataBufferUShort) {
569+ short[] data = dataBuffer instanceof DataBufferShort ?
570+ ((DataBufferShort)dataBuffer).getData() :
571+ ((DataBufferUShort)dataBuffer).getData();
572+
573+ for(int y = 0; y < rectHeight; y++) {
574+ int xRemaining = rectWidth;
575+ int i = eltOffset;
576+ while(xRemaining > 8) {
577+ data[i++] =
578+ (short)(((binaryDataArray[b++] & 0xFF) << 8) |
579+ (binaryDataArray[b++] & 0xFF));
580+ xRemaining -= 16;
581+ }
582+ if(xRemaining > 0) {
583+ data[i++] =
584+ (short)((binaryDataArray[b++] & 0xFF) << 8);
585+ }
586+ eltOffset += lineStride;
587+ }
588+ } else if(dataBuffer instanceof DataBufferInt) {
589+ int[] data = ((DataBufferInt)dataBuffer).getData();
590+
591+ for(int y = 0; y < rectHeight; y++) {
592+ int xRemaining = rectWidth;
593+ int i = eltOffset;
594+ while(xRemaining > 24) {
595+ data[i++] =
596+ (int)(((binaryDataArray[b++] & 0xFF) << 24) |
597+ ((binaryDataArray[b++] & 0xFF) << 16) |
598+ ((binaryDataArray[b++] & 0xFF) << 8) |
599+ (binaryDataArray[b++] & 0xFF));
600+ xRemaining -= 32;
601+ }
602+ int shift = 24;
603+ while(xRemaining > 0) {
604+ data[i] |=
605+ (int)((binaryDataArray[b++] & 0xFF) << shift);
606+ shift -= 8;
607+ xRemaining -= 8;
608+ }
609+ eltOffset += lineStride;
610+ }
611+ }
612+ } else { // bitOffset != 0
613+ int stride = (rectWidth + 7)/8;
614+ int offset = 0;
615+ if(dataBuffer instanceof DataBufferByte) {
616+ byte[] data = ((DataBufferByte)dataBuffer).getData();
617+
618+ if((bitOffset & 7) == 0) {
619+ for(int y = 0; y < rectHeight; y++) {
620+ System.arraycopy(binaryDataArray, offset,
621+ data, eltOffset,
622+ stride);
623+ offset += stride;
624+ eltOffset += lineStride;
625+ }
626+ } else { // bitOffset % 8 != 0
627+ int rightShift = bitOffset & 7;
628+ int leftShift = 8 - rightShift;
629+ int leftShift8 = 8 + leftShift;
630+ int mask = (byte)(255<<leftShift);
631+ int mask1 = (byte)~mask;
632+
633+ for(int y = 0; y < rectHeight; y++) {
634+ int i = eltOffset;
635+ int xRemaining = rectWidth;
636+ while(xRemaining > 0) {
637+ byte datum = binaryDataArray[b++];
638+
639+ if (xRemaining > leftShift8) {
640+ // when all the bits in this BYTE will be set
641+ // into the data buffer.
642+ data[i] = (byte)((data[i] & mask ) |
643+ ((datum&0xFF) >>> rightShift));
644+ data[++i] = (byte)((datum & 0xFF) << leftShift);
645+ } else if (xRemaining > leftShift) {
646+ // All the "leftShift" high bits will be set
647+ // into the data buffer. But not all the
648+ // "rightShift" low bits will be set.
649+ data[i] = (byte)((data[i] & mask ) |
650+ ((datum&0xFF) >>> rightShift));
651+ i++;
652+ data[i] =
653+ (byte)((data[i] & mask1) | ((datum & 0xFF) << leftShift));
654+ }
655+ else {
656+ // Less than "leftShift" high bits will be set.
657+ int remainMask = (1 << leftShift - xRemaining) - 1;
658+ data[i] =
659+ (byte)((data[i] & (mask | remainMask)) |
660+ (datum&0xFF) >>> rightShift & ~remainMask);
661+ }
662+ xRemaining -= 8;
663+ }
664+ eltOffset += lineStride;
665+ }
666+ }
667+ } else if(dataBuffer instanceof DataBufferShort ||
668+ dataBuffer instanceof DataBufferUShort) {
669+ short[] data = dataBuffer instanceof DataBufferShort ?
670+ ((DataBufferShort)dataBuffer).getData() :
671+ ((DataBufferUShort)dataBuffer).getData();
672+
673+ int rightShift = bitOffset & 7;
674+ int leftShift = 8 - rightShift;
675+ int leftShift16 = 16 + leftShift;
676+ int mask = (short)(~(255 << leftShift));
677+ int mask1 = (short)(65535 << leftShift);
678+ int mask2 = (short)~mask1;
679+
680+ for(int y = 0; y < rectHeight; y++) {
681+ int bOffset = bitOffset;
682+ int xRemaining = rectWidth;
683+ for(int x = 0; x < rectWidth;
684+ x += 8, bOffset += 8, xRemaining -= 8) {
685+ int i = eltOffset + (bOffset >> 4);
686+ int mod = bOffset & 15;
687+ int datum = binaryDataArray[b++] & 0xFF;
688+ if(mod <= 8) {
689+ // This BYTE is set into one SHORT
690+ if (xRemaining < 8) {
691+ // Mask the bits to be set.
692+ datum &= 255 << 8 - xRemaining;
693+ }
694+ data[i] = (short)((data[i] & mask) | (datum << leftShift));
695+ } else if (xRemaining > leftShift16) {
696+ // This BYTE will be set into two SHORTs
697+ data[i] = (short)((data[i] & mask1) | ((datum >>> rightShift)&0xFFFF));
698+ data[++i] =
699+ (short)((datum << leftShift)&0xFFFF);
700+ } else if (xRemaining > leftShift) {
701+ // This BYTE will be set into two SHORTs;
702+ // But not all the low bits will be set into SHORT
703+ data[i] = (short)((data[i] & mask1) | ((datum >>> rightShift)&0xFFFF));
704+ i++;
705+ data[i] =
706+ (short)((data[i] & mask2) | ((datum << leftShift)&0xFFFF));
707+ } else {
708+ // Only some of the high bits will be set into
709+ // SHORTs
710+ int remainMask = (1 << leftShift - xRemaining) - 1;
711+ data[i] = (short)((data[i] & (mask1 | remainMask)) |
712+ ((datum >>> rightShift)&0xFFFF & ~remainMask));
713+ }
714+ }
715+ eltOffset += lineStride;
716+ }
717+ } else if(dataBuffer instanceof DataBufferInt) {
718+ int[] data = ((DataBufferInt)dataBuffer).getData();
719+ int rightShift = bitOffset & 7;
720+ int leftShift = 8 - rightShift;
721+ int leftShift32 = 32 + leftShift;
722+ int mask = 0xFFFFFFFF << leftShift;
723+ int mask1 = ~mask;
724+
725+ for(int y = 0; y < rectHeight; y++) {
726+ int bOffset = bitOffset;
727+ int xRemaining = rectWidth;
728+ for(int x = 0; x < rectWidth;
729+ x += 8, bOffset += 8, xRemaining -= 8) {
730+ int i = eltOffset + (bOffset >> 5);
731+ int mod = bOffset & 31;
732+ int datum = binaryDataArray[b++] & 0xFF;
733+ if(mod <= 24) {
734+ // This BYTE is set into one INT
735+ int shift = 24 - mod;
736+ if (xRemaining < 8) {
737+ // Mask the bits to be set.
738+ datum &= 255 << 8 - xRemaining;
739+ }
740+ data[i] = (data[i] & (~(255 << shift))) | (datum << shift);
741+ } else if (xRemaining > leftShift32) {
742+ // All the bits of this BYTE will be set into two INTs
743+ data[i] = (data[i] & mask) | (datum >>> rightShift);
744+ data[++i] = datum << leftShift;
745+ } else if (xRemaining > leftShift) {
746+ // This BYTE will be set into two INTs;
747+ // But not all the low bits will be set into INT
748+ data[i] = (data[i] & mask) | (datum >>> rightShift);
749+ i++;
750+ data[i] = (data[i] & mask1) | (datum << leftShift);
751+ } else {
752+ // Only some of the high bits will be set into INT
753+ int remainMask = (1 << leftShift - xRemaining) - 1;
754+ data[i] = (data[i] & (mask | remainMask)) |
755+ (datum >>> rightShift & ~remainMask);
756+ }
757+ }
758+ eltOffset += lineStride;
759+ }
760+ }
761+ }
762+ }
763+
764+ /**
765+ * Copies data into the packed array of the <code>Raster</code>
766+ * from an array of unpacked data of the form returned by
767+ * <code>getUnpackedBinaryData()</code>.
768+ *
769+ * <p> If the data are binary, then the target bit will be set if
770+ * and only if the corresponding byte is non-zero.
771+ *
772+ * @throws IllegalArgumentException if <code>isBinary()</code> returns
773+ * <code>false</code> with the <code>SampleModel</code> of the
774+ * supplied <code>Raster</code> as argument.
775+ */
776+ public static void setUnpackedBinaryData(byte[] bdata,
777+ WritableRaster raster,
778+ Rectangle rect) {
779+ SampleModel sm = raster.getSampleModel();
780+ if(!isBinary(sm)) {
781+ throw new IllegalArgumentException(I18N.getString("ImageUtil0"));
782+ }
783+
784+ int rectX = rect.x;
785+ int rectY = rect.y;
786+ int rectWidth = rect.width;
787+ int rectHeight = rect.height;
788+
789+ DataBuffer dataBuffer = raster.getDataBuffer();
790+
791+ int dx = rectX - raster.getSampleModelTranslateX();
792+ int dy = rectY - raster.getSampleModelTranslateY();
793+
794+ MultiPixelPackedSampleModel mpp = (MultiPixelPackedSampleModel)sm;
795+ int lineStride = mpp.getScanlineStride();
796+ int eltOffset = dataBuffer.getOffset() + mpp.getOffset(dx, dy);
797+ int bitOffset = mpp.getBitOffset(dx);
798+
799+ int k = 0;
800+
801+ if(dataBuffer instanceof DataBufferByte) {
802+ byte[] data = ((DataBufferByte)dataBuffer).getData();
803+ for(int y = 0; y < rectHeight; y++) {
804+ int bOffset = eltOffset*8 + bitOffset;
805+ for(int x = 0; x < rectWidth; x++) {
806+ if(bdata[k++] != (byte)0) {
807+ data[bOffset/8] |=
808+ (byte)(0x00000001 << (7 - bOffset & 7));
809+ }
810+ bOffset++;
811+ }
812+ eltOffset += lineStride;
813+ }
814+ } else if(dataBuffer instanceof DataBufferShort ||
815+ dataBuffer instanceof DataBufferUShort) {
816+ short[] data = dataBuffer instanceof DataBufferShort ?
817+ ((DataBufferShort)dataBuffer).getData() :
818+ ((DataBufferUShort)dataBuffer).getData();
819+ for(int y = 0; y < rectHeight; y++) {
820+ int bOffset = eltOffset*16 + bitOffset;
821+ for(int x = 0; x < rectWidth; x++) {
822+ if(bdata[k++] != (byte)0) {
823+ data[bOffset/16] |=
824+ (short)(0x00000001 <<
825+ (15 - bOffset % 16));
826+ }
827+ bOffset++;
828+ }
829+ eltOffset += lineStride;
830+ }
831+ } else if(dataBuffer instanceof DataBufferInt) {
832+ int[] data = ((DataBufferInt)dataBuffer).getData();
833+ for(int y = 0; y < rectHeight; y++) {
834+ int bOffset = eltOffset*32 + bitOffset;
835+ for(int x = 0; x < rectWidth; x++) {
836+ if(bdata[k++] != (byte)0) {
837+ data[bOffset/32] |=
838+ (int)(0x00000001 <<
839+ (31 - bOffset % 32));
840+ }
841+ bOffset++;
842+ }
843+ eltOffset += lineStride;
844+ }
845+ }
846+ }
847+
848+ public static boolean isBinary(SampleModel sm) {
849+ return sm instanceof MultiPixelPackedSampleModel &&
850+ ((MultiPixelPackedSampleModel)sm).getPixelBitStride() == 1 &&
851+ sm.getNumBands() == 1;
852+ }
853+
854+ public static ColorModel createColorModel(ColorSpace colorSpace,
855+ SampleModel sampleModel) {
856+ ColorModel colorModel = null;
857+
858+ if(sampleModel == null) {
859+ throw new IllegalArgumentException(I18N.getString("ImageUtil1"));
860+ }
861+
862+ int numBands = sampleModel.getNumBands();
863+ if (numBands < 1 || numBands > 4) {
864+ return null;
865+ }
866+
867+ int dataType = sampleModel.getDataType();
868+ if (sampleModel instanceof ComponentSampleModel) {
869+ if (dataType < DataBuffer.TYPE_BYTE ||
870+ //dataType == DataBuffer.TYPE_SHORT ||
871+ dataType > DataBuffer.TYPE_DOUBLE) {
872+ return null;
873+ }
874+
875+ if (colorSpace == null)
876+ colorSpace =
877+ numBands <= 2 ?
878+ ColorSpace.getInstance(ColorSpace.CS_GRAY) :
879+ ColorSpace.getInstance(ColorSpace.CS_sRGB);
880+
881+ boolean useAlpha = (numBands == 2) || (numBands == 4);
882+ int transparency = useAlpha ?
883+ Transparency.TRANSLUCENT : Transparency.OPAQUE;
884+
885+ boolean premultiplied = false;
886+
887+ int dataTypeSize = DataBuffer.getDataTypeSize(dataType);
888+ int[] bits = new int[numBands];
889+ for (int i = 0; i < numBands; i++) {
890+ bits[i] = dataTypeSize;
891+ }
892+
893+ colorModel = new ComponentColorModel(colorSpace,
894+ bits,
895+ useAlpha,
896+ premultiplied,
897+ transparency,
898+ dataType);
899+ } else if (sampleModel instanceof SinglePixelPackedSampleModel) {
900+ SinglePixelPackedSampleModel sppsm =
901+ (SinglePixelPackedSampleModel)sampleModel;
902+
903+ int[] bitMasks = sppsm.getBitMasks();
904+ int rmask = 0;
905+ int gmask = 0;
906+ int bmask = 0;
907+ int amask = 0;
908+
909+ numBands = bitMasks.length;
910+ if (numBands <= 2) {
911+ rmask = gmask = bmask = bitMasks[0];
912+ if (numBands == 2) {
913+ amask = bitMasks[1];
914+ }
915+ } else {
916+ rmask = bitMasks[0];
917+ gmask = bitMasks[1];
918+ bmask = bitMasks[2];
919+ if (numBands == 4) {
920+ amask = bitMasks[3];
921+ }
922+ }
923+
924+ int[] sampleSize = sppsm.getSampleSize();
925+ int bits = 0;
926+ for (int i = 0; i < sampleSize.length; i++) {
927+ bits += sampleSize[i];
928+ }
929+
930+ if (colorSpace == null)
931+ colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
932+
933+ colorModel =
934+ new DirectColorModel(colorSpace,
935+ bits, rmask, gmask, bmask, amask,
936+ false,
937+ sampleModel.getDataType());
938+ } else if (sampleModel instanceof MultiPixelPackedSampleModel) {
939+ int bits =
940+ ((MultiPixelPackedSampleModel)sampleModel).getPixelBitStride();
941+ int size = 1 << bits;
942+ byte[] comp = new byte[size];
943+
944+ for (int i = 0; i < size; i++)
945+ comp[i] = (byte)(255 * i / (size - 1));
946+
947+ colorModel = new IndexColorModel(bits, size, comp, comp, comp);
948+ }
949+
950+ return colorModel;
951+ }
952+
953+ public static int getElementSize(SampleModel sm) {
954+ int elementSize = DataBuffer.getDataTypeSize(sm.getDataType());
955+
956+ if (sm instanceof MultiPixelPackedSampleModel) {
957+ MultiPixelPackedSampleModel mppsm =
958+ (MultiPixelPackedSampleModel)sm;
959+ return mppsm.getSampleSize(0) * mppsm.getNumBands();
960+ } else if (sm instanceof ComponentSampleModel) {
961+ return sm.getNumBands() * elementSize;
962+ } else if (sm instanceof SinglePixelPackedSampleModel) {
963+ return elementSize;
964+ }
965+
966+ return elementSize * sm.getNumBands();
967+
968+ }
969+
970+ public static long getTileSize(SampleModel sm) {
971+ int elementSize = DataBuffer.getDataTypeSize(sm.getDataType());
972+
973+ if (sm instanceof MultiPixelPackedSampleModel) {
974+ MultiPixelPackedSampleModel mppsm =
975+ (MultiPixelPackedSampleModel)sm;
976+ return (mppsm.getScanlineStride() * mppsm.getHeight() +
977+ (mppsm.getDataBitOffset() + elementSize -1) / elementSize) *
978+ ((elementSize + 7) / 8);
979+ } else if (sm instanceof ComponentSampleModel) {
980+ ComponentSampleModel csm = (ComponentSampleModel)sm;
981+ int[] bandOffsets = csm.getBandOffsets();
982+ int maxBandOff = bandOffsets[0];
983+ for (int i=1; i<bandOffsets.length; i++)
984+ maxBandOff = Math.max(maxBandOff, bandOffsets[i]);
985+
986+ long size = 0;
987+ int pixelStride = csm.getPixelStride();
988+ int scanlineStride = csm.getScanlineStride();
989+ if (maxBandOff >= 0)
990+ size += maxBandOff + 1;
991+ if (pixelStride > 0)
992+ size += pixelStride * (sm.getWidth() - 1);
993+ if (scanlineStride > 0)
994+ size += scanlineStride * (sm.getHeight() - 1);
995+
996+ int[] bankIndices = csm.getBankIndices();
997+ maxBandOff = bankIndices[0];
998+ for (int i=1; i<bankIndices.length; i++)
999+ maxBandOff = Math.max(maxBandOff, bankIndices[i]);
1000+ return size * (maxBandOff + 1) * ((elementSize + 7) / 8);
1001+ } else if (sm instanceof SinglePixelPackedSampleModel) {
1002+ SinglePixelPackedSampleModel sppsm =
1003+ (SinglePixelPackedSampleModel)sm;
1004+ long size = sppsm.getScanlineStride() * (sppsm.getHeight() - 1) +
1005+ sppsm.getWidth();
1006+ return size * ((elementSize + 7) / 8);
1007+ }
1008+
1009+ return 0;
1010+ }
1011+
1012+ public static long getBandSize(SampleModel sm) {
1013+ int elementSize = DataBuffer.getDataTypeSize(sm.getDataType());
1014+
1015+ if (sm instanceof ComponentSampleModel) {
1016+ ComponentSampleModel csm = (ComponentSampleModel)sm;
1017+ int pixelStride = csm.getPixelStride();
1018+ int scanlineStride = csm.getScanlineStride();
1019+ long size = Math.min(pixelStride, scanlineStride);
1020+
1021+ if (pixelStride > 0)
1022+ size += pixelStride * (sm.getWidth() - 1);
1023+ if (scanlineStride > 0)
1024+ size += scanlineStride * (sm.getHeight() - 1);
1025+ return size * ((elementSize + 7) / 8);
1026+ } else
1027+ return getTileSize(sm);
1028+ }
1029+ /**
1030+ * Tests whether the color indices represent a gray-scale image.
1031+ *
1032+ * @param r The red channel color indices.
1033+ * @param g The green channel color indices.
1034+ * @param b The blue channel color indices.
1035+ * @return If all the indices have 256 entries, and are identical mappings,
1036+ * return <code>true</code>; otherwise, return <code>false</code>.
1037+ */
1038+ public static boolean isIndicesForGrayscale(byte[] r, byte[] g, byte[] b) {
1039+ if (r.length != g.length || r.length != b.length)
1040+ return false;
1041+
1042+ int size = r.length;
1043+
1044+ if (size != 256)
1045+ return false;
1046+
1047+ for (int i = 0; i < size; i++) {
1048+ byte temp = (byte) i;
1049+
1050+ if (r[i] != temp || g[i] != temp || b[i] != temp)
1051+ return false;
1052+ }
1053+
1054+ return true;
1055+ }
1056+
1057+ /** Converts the provided object to <code>String</code> */
1058+ public static String convertObjectToString(Object obj) {
1059+ if (obj == null)
1060+ return "";
1061+
1062+ String s = "";
1063+ if (obj instanceof byte[]) {
1064+ byte[] bArray = (byte[])obj;
1065+ for (int i = 0; i < bArray.length; i++)
1066+ s += bArray[i] + " ";
1067+ return s;
1068+ }
1069+
1070+ if (obj instanceof int[]) {
1071+ int[] iArray = (int[])obj;
1072+ for (int i = 0; i < iArray.length; i++)
1073+ s += iArray[i] + " " ;
1074+ return s;
1075+ }
1076+
1077+ if (obj instanceof short[]) {
1078+ short[] sArray = (short[])obj;
1079+ for (int i = 0; i < sArray.length; i++)
1080+ s += sArray[i] + " " ;
1081+ return s;
1082+ }
1083+
1084+ return obj.toString();
1085+
1086+ }
1087+
1088+ /** Checks that the provided <code>ImageWriter</code> can encode
1089+ * the provided <code>ImageTypeSpecifier</code> or not. If not, an
1090+ * <code>IIOException</code> will be thrown.
1091+ * @param writer The provided <code>ImageWriter</code>.
1092+ * @param type The image to be tested.
1093+ * @throws IIOException If the writer cannot encoded the provided image.
1094+ */
1095+ public static final void canEncodeImage(ImageWriter writer,
1096+ ImageTypeSpecifier type)
1097+ throws IIOException {
1098+ ImageWriterSpi spi = writer.getOriginatingProvider();
1099+
1100+ if(type != null && spi != null && !spi.canEncodeImage(type)) {
1101+ throw new IIOException(I18N.getString("ImageUtil2")+" "+
1102+ writer.getClass().getName());
1103+ }
1104+ }
1105+
1106+ /** Checks that the provided <code>ImageWriter</code> can encode
1107+ * the provided <code>ColorModel</code> and <code>SampleModel</code>.
1108+ * If not, an <code>IIOException</code> will be thrown.
1109+ * @param writer The provided <code>ImageWriter</code>.
1110+ * @param colorModel The provided <code>ColorModel</code>.
1111+ * @param sampleModel The provided <code>SampleModel</code>.
1112+ * @throws IIOException If the writer cannot encoded the provided image.
1113+ */
1114+ public static final void canEncodeImage(ImageWriter writer,
1115+ ColorModel colorModel,
1116+ SampleModel sampleModel)
1117+ throws IIOException {
1118+ ImageTypeSpecifier type = null;
1119+ if (colorModel != null && sampleModel != null)
1120+ type = new ImageTypeSpecifier(colorModel, sampleModel);
1121+ canEncodeImage(writer, type);
1122+ }
1123+
1124+ /**
1125+ * Returns whether the image has contiguous data across rows.
1126+ */
1127+ public static final boolean imageIsContiguous(RenderedImage image) {
1128+ SampleModel sm;
1129+ if(image instanceof BufferedImage) {
1130+ WritableRaster ras = ((BufferedImage)image).getRaster();
1131+ sm = ras.getSampleModel();
1132+ } else {
1133+ sm = image.getSampleModel();
1134+ }
1135+
1136+ if (sm instanceof ComponentSampleModel) {
1137+ // Ensure image rows samples are stored contiguously
1138+ // in a single bank.
1139+ ComponentSampleModel csm = (ComponentSampleModel)sm;
1140+
1141+ if (csm.getPixelStride() != csm.getNumBands()) {
1142+ return false;
1143+ }
1144+
1145+ int[] bandOffsets = csm.getBandOffsets();
1146+ for (int i = 0; i < bandOffsets.length; i++) {
1147+ if (bandOffsets[i] != i) {
1148+ return false;
1149+ }
1150+ }
1151+
1152+ int[] bankIndices = csm.getBankIndices();
1153+ for (int i = 0; i < bandOffsets.length; i++) {
1154+ if (bankIndices[i] != 0) {
1155+ return false;
1156+ }
1157+ }
1158+
1159+ return true;
1160+ }
1161+
1162+ // Otherwise true if and only if it's a bilevel image with
1163+ // a MultiPixelPackedSampleModel, 1 bit per pixel, and 1 bit
1164+ // pixel stride.
1165+ return ImageUtil.isBinary(sm);
1166+ }
1167+}