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
26package com.sun.imageio.plugins.common;
27
28import java.awt.Point;
29import java.awt.Rectangle;
30import java.awt.Transparency;
31import java.awt.color.ColorSpace;
32import java.awt.image.BufferedImage;
33import java.awt.image.ColorModel;
34import java.awt.image.ComponentColorModel;
35import java.awt.image.ComponentSampleModel;
36import java.awt.image.DataBuffer;
37import java.awt.image.DataBufferByte;
38import java.awt.image.DataBufferInt;
39import java.awt.image.DataBufferShort;
40import java.awt.image.DataBufferUShort;
41import java.awt.image.DirectColorModel;
42import java.awt.image.IndexColorModel;
43import java.awt.image.MultiPixelPackedSampleModel;
44import java.awt.image.Raster;
45import java.awt.image.RenderedImage;
46import java.awt.image.SampleModel;
47import java.awt.image.SinglePixelPackedSampleModel;
48import java.awt.image.WritableRaster;
49import java.util.Arrays;
50
51//import javax.imageio.ImageTypeSpecifier;
52
53import javax.imageio.IIOException;
54import javax.imageio.IIOImage;
55import javax.imageio.ImageTypeSpecifier;
56import javax.imageio.ImageWriter;
57import javax.imageio.spi.ImageWriterSpi;
58
59public 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}