001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Igor V. Stolyarov
019: * @version $Revision$
020: */package java.awt.image;
021:
022: import java.awt.Graphics;
023: import java.awt.Graphics2D;
024: import java.awt.GraphicsEnvironment;
025: import java.awt.Image;
026: import java.awt.Point;
027: import java.awt.Rectangle;
028: import java.awt.Transparency;
029: import java.awt.color.ColorSpace;
030: import java.util.Enumeration;
031: import java.util.Hashtable;
032: import java.util.Vector;
033:
034: import org.apache.harmony.awt.gl.ImageSurface;
035: import org.apache.harmony.awt.gl.Surface;
036: import org.apache.harmony.awt.gl.image.BufferedImageSource;
037: import org.apache.harmony.awt.internal.nls.Messages;
038:
039: public class BufferedImage extends Image implements
040: WritableRenderedImage, Transparency {
041:
042: public static final int TYPE_CUSTOM = 0;
043:
044: public static final int TYPE_INT_RGB = 1;
045:
046: public static final int TYPE_INT_ARGB = 2;
047:
048: public static final int TYPE_INT_ARGB_PRE = 3;
049:
050: public static final int TYPE_INT_BGR = 4;
051:
052: public static final int TYPE_3BYTE_BGR = 5;
053:
054: public static final int TYPE_4BYTE_ABGR = 6;
055:
056: public static final int TYPE_4BYTE_ABGR_PRE = 7;
057:
058: public static final int TYPE_USHORT_565_RGB = 8;
059:
060: public static final int TYPE_USHORT_555_RGB = 9;
061:
062: public static final int TYPE_BYTE_GRAY = 10;
063:
064: public static final int TYPE_USHORT_GRAY = 11;
065:
066: public static final int TYPE_BYTE_BINARY = 12;
067:
068: public static final int TYPE_BYTE_INDEXED = 13;
069:
070: private static final int ALPHA_MASK = 0xff000000;
071:
072: private static final int RED_MASK = 0x00ff0000;
073:
074: private static final int GREEN_MASK = 0x0000ff00;
075:
076: private static final int BLUE_MASK = 0x000000ff;
077:
078: private static final int RED_BGR_MASK = 0x000000ff;
079:
080: private static final int GREEN_BGR_MASK = 0x0000ff00;
081:
082: private static final int BLUE_BGR_MASK = 0x00ff0000;
083:
084: private static final int RED_565_MASK = 0xf800;
085:
086: private static final int GREEN_565_MASK = 0x07e0;
087:
088: private static final int BLUE_565_MASK = 0x001f;
089:
090: private static final int RED_555_MASK = 0x7c00;
091:
092: private static final int GREEN_555_MASK = 0x03e0;
093:
094: private static final int BLUE_555_MASK = 0x001f;
095:
096: private ColorModel cm;
097:
098: private final WritableRaster raster;
099:
100: private final int imageType;
101:
102: private Hashtable<?, ?> properties;
103:
104: // Surface of the Buffered Image - used for blitting one Buffered Image
105: // on the other one or on the Component
106: private final ImageSurface imageSurf;
107:
108: public BufferedImage(ColorModel cm, WritableRaster raster,
109: boolean isRasterPremultiplied, Hashtable<?, ?> properties) {
110: if (!cm.isCompatibleRaster(raster)) {
111: // awt.4D=The raster is incompatible with this ColorModel
112: throw new IllegalArgumentException(Messages
113: .getString("awt.4D")); //$NON-NLS-1$
114: }
115:
116: if (raster.getMinX() != 0 || raster.getMinY() != 0) {
117: // awt.228=minX or minY of this raster not equal to zero
118: throw new IllegalArgumentException(Messages
119: .getString("awt.228")); //$NON-NLS-1$
120: }
121:
122: this .cm = cm;
123: this .raster = raster;
124: this .properties = properties;
125:
126: coerceData(isRasterPremultiplied);
127:
128: imageType = Surface.getType(cm, raster);
129:
130: imageSurf = createImageSurface(imageType);
131: }
132:
133: public BufferedImage(int width, int height, int imageType,
134: IndexColorModel cm) {
135: switch (imageType) {
136: case TYPE_BYTE_BINARY:
137: if (cm.hasAlpha()) {
138: // awt.227=This image type can't have alpha
139: throw new IllegalArgumentException(Messages
140: .getString("awt.227")); //$NON-NLS-1$
141: }
142: int pixel_bits = 0;
143: int mapSize = cm.getMapSize();
144: if (mapSize <= 2) {
145: pixel_bits = 1;
146: } else if (mapSize <= 4) {
147: pixel_bits = 2;
148: } else if (mapSize <= 16) {
149: pixel_bits = 4;
150: } else {
151: // awt.221=The imageType is TYPE_BYTE_BINARY and the color map has more than 16 entries
152: throw new IllegalArgumentException(Messages
153: .getString("awt.221")); //$NON-NLS-1$
154: }
155:
156: raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
157: width, height, 1, pixel_bits, null);
158: break;
159:
160: case TYPE_BYTE_INDEXED:
161: raster = Raster.createInterleavedRaster(
162: DataBuffer.TYPE_BYTE, width, height, 1, null);
163: break;
164:
165: default:
166: // awt.222=The imageType is not TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED
167: throw new IllegalArgumentException(Messages
168: .getString("awt.222")); //$NON-NLS-1$
169:
170: }
171:
172: if (!cm.isCompatibleRaster(raster)) {
173: // awt.223=The imageType is not compatible with ColorModel
174: throw new IllegalArgumentException(Messages
175: .getString("awt.223")); //$NON-NLS-1$
176: }
177:
178: this .cm = cm;
179: this .imageType = imageType;
180: imageSurf = createImageSurface(imageType);
181:
182: }
183:
184: public BufferedImage(int width, int height, int imageType) {
185:
186: switch (imageType) {
187: case TYPE_INT_RGB:
188: cm = new DirectColorModel(24, RED_MASK, GREEN_MASK,
189: BLUE_MASK);
190: raster = cm.createCompatibleWritableRaster(width, height);
191: break;
192:
193: case TYPE_INT_ARGB:
194: cm = ColorModel.getRGBdefault();
195: raster = cm.createCompatibleWritableRaster(width, height);
196: break;
197:
198: case TYPE_INT_ARGB_PRE:
199: cm = new DirectColorModel(ColorSpace
200: .getInstance(ColorSpace.CS_sRGB), 32, RED_MASK,
201: GREEN_MASK, BLUE_MASK, ALPHA_MASK, true,
202: DataBuffer.TYPE_INT);
203:
204: raster = cm.createCompatibleWritableRaster(width, height);
205: break;
206:
207: case TYPE_INT_BGR:
208: cm = new DirectColorModel(24, RED_BGR_MASK, GREEN_BGR_MASK,
209: BLUE_BGR_MASK);
210:
211: raster = cm.createCompatibleWritableRaster(width, height);
212: break;
213:
214: case TYPE_3BYTE_BGR: {
215: int bits[] = { 8, 8, 8 };
216: int bandOffsets[] = { 2, 1, 0 };
217: cm = new ComponentColorModel(ColorSpace
218: .getInstance(ColorSpace.CS_sRGB), bits, false,
219: false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
220:
221: raster = Raster.createInterleavedRaster(
222: DataBuffer.TYPE_BYTE, width, height, width * 3, 3,
223: bandOffsets, null);
224: }
225: break;
226:
227: case TYPE_4BYTE_ABGR: {
228: int bits[] = { 8, 8, 8, 8 };
229: int bandOffsets[] = { 3, 2, 1, 0 };
230: cm = new ComponentColorModel(ColorSpace
231: .getInstance(ColorSpace.CS_sRGB), bits, true,
232: false, Transparency.TRANSLUCENT,
233: DataBuffer.TYPE_BYTE);
234:
235: raster = Raster.createInterleavedRaster(
236: DataBuffer.TYPE_BYTE, width, height, width * 4, 4,
237: bandOffsets, null);
238: }
239: break;
240:
241: case TYPE_4BYTE_ABGR_PRE: {
242: int bits[] = { 8, 8, 8, 8 };
243: int bandOffsets[] = { 3, 2, 1, 0 };
244: cm = new ComponentColorModel(ColorSpace
245: .getInstance(ColorSpace.CS_sRGB), bits, true, true,
246: Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
247:
248: raster = Raster.createInterleavedRaster(
249: DataBuffer.TYPE_BYTE, width, height, width * 4, 4,
250: bandOffsets, null);
251: }
252: break;
253:
254: case TYPE_USHORT_565_RGB:
255: cm = new DirectColorModel(ColorSpace
256: .getInstance(ColorSpace.CS_sRGB), 16, RED_565_MASK,
257: GREEN_565_MASK, BLUE_565_MASK, 0, false,
258: DataBuffer.TYPE_USHORT);
259:
260: raster = cm.createCompatibleWritableRaster(width, height);
261: break;
262:
263: case TYPE_USHORT_555_RGB:
264: cm = new DirectColorModel(ColorSpace
265: .getInstance(ColorSpace.CS_sRGB), 15, RED_555_MASK,
266: GREEN_555_MASK, BLUE_555_MASK, 0, false,
267: DataBuffer.TYPE_USHORT);
268:
269: raster = cm.createCompatibleWritableRaster(width, height);
270: break;
271:
272: case TYPE_BYTE_GRAY: {
273: int bits[] = { 8 };
274: cm = new ComponentColorModel(ColorSpace
275: .getInstance(ColorSpace.CS_GRAY), bits, false,
276: false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
277:
278: raster = cm.createCompatibleWritableRaster(width, height);
279: }
280: break;
281:
282: case TYPE_USHORT_GRAY: {
283: int bits[] = { 16 };
284: cm = new ComponentColorModel(ColorSpace
285: .getInstance(ColorSpace.CS_GRAY), bits, false,
286: false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT);
287: raster = cm.createCompatibleWritableRaster(width, height);
288: }
289: break;
290:
291: case TYPE_BYTE_BINARY: {
292: int colorMap[] = { 0, 0xffffff };
293: cm = new IndexColorModel(1, 2, colorMap, 0, false, -1,
294: DataBuffer.TYPE_BYTE);
295:
296: raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
297: width, height, 1, 1, null);
298: }
299: break;
300:
301: case TYPE_BYTE_INDEXED: {
302: int colorMap[] = new int[256];
303: int i = 0;
304: for (int r = 0; r < 256; r += 51) {
305: for (int g = 0; g < 256; g += 51) {
306: for (int b = 0; b < 256; b += 51) {
307: colorMap[i] = (r << 16) | (g << 8) | b;
308: i++;
309: }
310: }
311: }
312:
313: int gray = 0x12;
314: for (; i < 256; i++, gray += 6) {
315: colorMap[i] = (gray << 16) | (gray << 8) | gray;
316: }
317: cm = new IndexColorModel(8, 256, colorMap, 0, false, -1,
318: DataBuffer.TYPE_BYTE);
319: raster = Raster.createInterleavedRaster(
320: DataBuffer.TYPE_BYTE, width, height, 1, null);
321:
322: }
323: break;
324: default:
325: // awt.224=Unknown image type
326: throw new IllegalArgumentException(Messages
327: .getString("awt.224")); //$NON-NLS-1$
328: }
329: this .imageType = imageType;
330: imageSurf = createImageSurface(imageType);
331: }
332:
333: @Override
334: public Object getProperty(String name, ImageObserver observer) {
335: return getProperty(name);
336: }
337:
338: public Object getProperty(String name) {
339: if (name == null) {
340: // awt.225=Property name is null
341: throw new NullPointerException(Messages
342: .getString("awt.225")); //$NON-NLS-1$
343: }
344: if (properties == null) {
345: return Image.UndefinedProperty;
346: }
347: Object property = properties.get(name);
348: if (property == null) {
349: property = Image.UndefinedProperty;
350: }
351: return property;
352: }
353:
354: public WritableRaster copyData(WritableRaster outRaster) {
355: if (outRaster == null) {
356: outRaster = Raster.createWritableRaster(raster
357: .getSampleModel(), new Point(raster
358: .getSampleModelTranslateX(), raster
359: .getSampleModelTranslateY()));
360: }
361:
362: int w = outRaster.getWidth();
363: int h = outRaster.getHeight();
364: int minX = outRaster.getMinX();
365: int minY = outRaster.getMinY();
366:
367: Object data = null;
368:
369: data = raster.getDataElements(minX, minY, w, h, data);
370: outRaster.setDataElements(minX, minY, w, h, data);
371:
372: return outRaster;
373: }
374:
375: public Raster getData(Rectangle rect) {
376: int minX = rect.x;
377: int minY = rect.y;
378: int w = rect.width;
379: int h = rect.height;
380:
381: SampleModel sm = raster.getSampleModel();
382: SampleModel nsm = sm.createCompatibleSampleModel(w, h);
383: WritableRaster outr = Raster.createWritableRaster(nsm, rect
384: .getLocation());
385: Object data = null;
386:
387: data = raster.getDataElements(minX, minY, w, h, data);
388: outr.setDataElements(minX, minY, w, h, data);
389: return outr;
390: }
391:
392: public Vector<RenderedImage> getSources() {
393: return null;
394: }
395:
396: public String[] getPropertyNames() {
397: if (properties == null) {
398: return null;
399: }
400: Vector<String> v = new Vector<String>();
401: for (Enumeration<?> e = properties.keys(); e.hasMoreElements();) {
402: try {
403: v.add((String) e.nextElement());
404: } catch (ClassCastException ex) {
405: }
406: }
407: int size = v.size();
408: if (size > 0) {
409: String names[] = new String[size];
410: for (int i = 0; i < size; i++) {
411: names[i] = v.elementAt(i);
412: }
413: return names;
414: }
415: return null;
416: }
417:
418: @Override
419: public String toString() {
420: return "BufferedImage@" + Integer.toHexString(hashCode()) + //$NON-NLS-1$
421: ": type = " + imageType + " " + cm + " " + raster; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
422: }
423:
424: public WritableRaster getWritableTile(int tileX, int tileY) {
425: return raster;
426: }
427:
428: public WritableRaster getRaster() {
429: return raster;
430: }
431:
432: public WritableRaster getAlphaRaster() {
433: return cm.getAlphaRaster(raster);
434: }
435:
436: public void removeTileObserver(TileObserver to) {
437: }
438:
439: public void addTileObserver(TileObserver to) {
440: }
441:
442: public SampleModel getSampleModel() {
443: return raster.getSampleModel();
444: }
445:
446: public void setData(Raster r) {
447:
448: Rectangle from = r.getBounds();
449: Rectangle to = raster.getBounds();
450: Rectangle intersection = to.intersection(from);
451:
452: int minX = intersection.x;
453: int minY = intersection.y;
454: int w = intersection.width;
455: int h = intersection.height;
456:
457: Object data = null;
458:
459: data = r.getDataElements(minX, minY, w, h, data);
460: raster.setDataElements(minX, minY, w, h, data);
461: }
462:
463: public Raster getTile(int tileX, int tileY) {
464: if (tileX == 0 && tileY == 0) {
465: return raster;
466: }
467: // awt.226=Both tileX and tileY are not equal to 0
468: throw new ArrayIndexOutOfBoundsException(Messages
469: .getString("awt.226")); //$NON-NLS-1$
470: }
471:
472: public Raster getData() {
473: int w = raster.getWidth();
474: int h = raster.getHeight();
475: int minX = raster.getMinX();
476: int minY = raster.getMinY();
477:
478: WritableRaster outr = Raster.createWritableRaster(raster
479: .getSampleModel(), new Point(raster
480: .getSampleModelTranslateX(), raster
481: .getSampleModelTranslateY()));
482:
483: Object data = null;
484:
485: data = raster.getDataElements(minX, minY, w, h, data);
486: outr.setDataElements(minX, minY, w, h, data);
487:
488: return outr;
489: }
490:
491: @Override
492: public ImageProducer getSource() {
493: return new BufferedImageSource(this , properties);
494: }
495:
496: @Override
497: public int getWidth(ImageObserver observer) {
498: return raster.getWidth();
499: }
500:
501: @Override
502: public int getHeight(ImageObserver observer) {
503: return raster.getHeight();
504: }
505:
506: public ColorModel getColorModel() {
507: return cm;
508: }
509:
510: public BufferedImage getSubimage(int x, int y, int w, int h) {
511: WritableRaster wr = raster.createWritableChild(x, y, w, h, 0,
512: 0, null);
513: return new BufferedImage(cm, wr, cm.isAlphaPremultiplied(),
514: properties);
515: }
516:
517: public Point[] getWritableTileIndices() {
518: Point points[] = new Point[1];
519: points[0] = new Point(0, 0);
520: return points;
521: }
522:
523: public Graphics2D createGraphics() {
524: GraphicsEnvironment ge = GraphicsEnvironment
525: .getLocalGraphicsEnvironment();
526: return ge.createGraphics(this );
527: }
528:
529: @Override
530: public Graphics getGraphics() {
531: return createGraphics();
532: }
533:
534: public void coerceData(boolean isAlphaPremultiplied) {
535: if (cm.hasAlpha()
536: && cm.isAlphaPremultiplied() != isAlphaPremultiplied) {
537: cm = cm.coerceData(raster, isAlphaPremultiplied);
538: }
539: }
540:
541: public int[] getRGB(int startX, int startY, int w, int h,
542: int[] rgbArray, int offset, int scansize) {
543: if (rgbArray == null) {
544: rgbArray = new int[offset + h * scansize];
545: }
546:
547: int off = offset;
548: for (int y = startY; y < startY + h; y++, off += scansize) {
549: int i = off;
550: for (int x = startX; x < startX + w; x++, i++) {
551: rgbArray[i] = cm.getRGB(raster.getDataElements(x, y,
552: null));
553: }
554: }
555: return rgbArray;
556: }
557:
558: public void setRGB(int startX, int startY, int w, int h,
559: int[] rgbArray, int offset, int scansize) {
560: int off = offset;
561: for (int y = startY; y < startY + h; y++, off += scansize) {
562: int i = off;
563: for (int x = startX; x < startX + w; x++, i++) {
564: raster.setDataElements(x, y, cm.getDataElements(
565: rgbArray[i], null));
566: }
567: }
568: }
569:
570: public synchronized void setRGB(int x, int y, int rgb) {
571: raster.setDataElements(x, y, cm.getDataElements(rgb, null));
572: }
573:
574: public boolean isTileWritable(int tileX, int tileY) {
575: if (tileX == 0 && tileY == 0) {
576: return true;
577: }
578: // awt.226=Both tileX and tileY are not equal to 0
579: throw new IllegalArgumentException(Messages
580: .getString("awt.226")); //$NON-NLS-1$
581: }
582:
583: public void releaseWritableTile(int tileX, int tileY) {
584: }
585:
586: public int getRGB(int x, int y) {
587: return cm.getRGB(raster.getDataElements(x, y, null));
588: }
589:
590: public boolean isAlphaPremultiplied() {
591: return cm.isAlphaPremultiplied();
592: }
593:
594: public boolean hasTileWriters() {
595: return true;
596: }
597:
598: @Override
599: public void flush() {
600: imageSurf.dispose();
601: }
602:
603: public int getWidth() {
604: return raster.getWidth();
605: }
606:
607: public int getType() {
608: return imageType;
609: }
610:
611: public int getTileWidth() {
612: return raster.getWidth();
613: }
614:
615: public int getTileHeight() {
616: return raster.getHeight();
617: }
618:
619: public int getTileGridYOffset() {
620: return raster.getSampleModelTranslateY();
621: }
622:
623: public int getTileGridXOffset() {
624: return raster.getSampleModelTranslateX();
625: }
626:
627: public int getNumYTiles() {
628: return 1;
629: }
630:
631: public int getNumXTiles() {
632: return 1;
633: }
634:
635: public int getMinY() {
636: return raster.getMinY();
637: }
638:
639: public int getMinX() {
640: return raster.getMinX();
641: }
642:
643: public int getMinTileY() {
644: return 0;
645: }
646:
647: public int getMinTileX() {
648: return 0;
649: }
650:
651: public int getHeight() {
652: return raster.getHeight();
653: }
654:
655: private ImageSurface createImageSurface(int type) {
656: return new ImageSurface(getColorModel(), getRaster(), type);
657: }
658:
659: ImageSurface getImageSurface() {
660: return imageSurf;
661: }
662:
663: public int getTransparency() {
664: return cm.getTransparency();
665: }
666: }
|