2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 * @author Igor V. Stolyarov
22 * Created on 22.12.2004
25 package org.apache.harmony.awt.gl.image;
27 import java.awt.Graphics;
28 import java.awt.Image;
29 import java.awt.image.BufferedImage;
30 import java.awt.image.ColorModel;
31 import java.awt.image.ComponentColorModel;
32 import java.awt.image.DataBuffer;
33 import java.awt.image.DataBufferByte;
34 import java.awt.image.DataBufferInt;
35 import java.awt.image.DirectColorModel;
36 import java.awt.image.ImageConsumer;
37 import java.awt.image.ImageObserver;
38 import java.awt.image.ImageProducer;
39 import java.awt.image.IndexColorModel;
40 import java.awt.image.WritableRaster;
41 import java.util.Hashtable;
42 import java.util.Vector;
44 import org.apache.harmony.awt.gl.ImageSurface;
45 import org.apache.harmony.awt.internal.nls.Messages;
49 * This class represent implementation of abstract Image class
51 public class OffscreenImage extends Image implements ImageConsumer {
53 static final ColorModel rgbCM = ColorModel.getRGBdefault();
57 WritableRaster raster;
59 Hashtable<?, ?> properties;
60 Vector<ImageObserver> observers;
65 private boolean producing;
66 private ImageSurface imageSurf;
68 public OffscreenImage(ImageProducer ip){
73 observers = new Vector<ImageObserver>();
78 public Object getProperty(String name, ImageObserver observer) {
80 // awt.38=Property name is not defined
81 throw new NullPointerException(Messages.getString("awt.38")); //$NON-NLS-1$
83 if(properties == null){
84 addObserver(observer);
86 if(properties == null) {
90 Object prop = properties.get(name);
92 prop = UndefinedProperty;
98 public ImageProducer getSource() {
103 public int getWidth(ImageObserver observer) {
104 if((imageState & ImageObserver.WIDTH) == 0){
105 addObserver(observer);
107 if((imageState & ImageObserver.WIDTH) == 0) {
115 public int getHeight(ImageObserver observer) {
116 if((imageState & ImageObserver.HEIGHT) == 0){
117 addObserver(observer);
119 if((imageState & ImageObserver.HEIGHT) == 0) {
127 public Graphics getGraphics() {
128 // awt.39=This method is not implemented for image obtained from ImageProducer
129 throw new UnsupportedOperationException(Messages.getString("awt.39")); //$NON-NLS-1$
133 public void flush() {
135 imageUpdate(this, ImageObserver.ABORT, -1, -1, -1, -1);
136 imageState &= ~ImageObserver.ERROR;
146 public void setProperties(Hashtable<?, ?> properties) {
147 this.properties = properties;
148 imageUpdate(this, ImageObserver.PROPERTIES, 0, 0, width, height);
151 public void setColorModel(ColorModel cm) {
156 * We suppose what in case loading JPEG image then image has DirectColorModel
157 * and for infill image Raster will use setPixels method with int array.
159 * In case loading GIF image, for raster infill, is used setPixels method with
160 * byte array and Color Model is IndexColorModel. But Color Model may
161 * be changed during this process. Then is called setPixels method with
162 * int array and image force to default color model - int ARGB. The rest
163 * pixels are sending in DirectColorModel.
165 public void setPixels(int x, int y, int w, int h, ColorModel model,
166 int[] pixels, int off, int scansize) {
170 // awt.3A=Color Model is null
171 throw new NullPointerException(Messages.getString("awt.3A")); //$NON-NLS-1$
185 if(cm == model && model.getTransferType() == DataBuffer.TYPE_INT &&
186 raster.getNumDataElements() == 1){
188 DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer();
189 int data[] = dbi.getData();
190 int scanline = raster.getWidth();
191 int rof = dbi.getOffset() + y * scanline + x;
192 for(int lineOff = off, line = y; line < y + h;
193 line++, lineOff += scansize, rof += scanline){
195 System.arraycopy(pixels, lineOff, data, rof, w);
199 int buff[] = new int[w];
200 DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer();
201 int data[] = dbi.getData();
202 int scanline = raster.getWidth();
203 int rof = dbi.getOffset() + y * scanline + x;
204 for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize,
207 for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
208 buff[idx] = model.getRGB(pixels[sOff + idx]);
210 System.arraycopy(buff, 0, data, rof, w);
214 for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize) {
215 for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
216 int rgb = model.getRGB(pixels[sOff + idx]);
217 buf = cm.getDataElements(rgb, buf);
218 raster.setDataElements(sx, sy, buf);
223 if (imageSurf != null) {
224 imageSurf.invalidate();
227 imageUpdate(this, ImageObserver.SOMEBITS, 0, 0, width, height);
230 public void setPixels(int x, int y, int w, int h, ColorModel model,
231 byte[] pixels, int off, int scansize) {
236 // awt.3A=Color Model is null
237 throw new NullPointerException(Messages.getString("awt.3A")); //$NON-NLS-1$
251 int buff[] = new int[w];
252 IndexColorModel icm = (IndexColorModel) model;
253 int colorMap[] = new int[icm.getMapSize()];
254 icm.getRGBs(colorMap);
255 DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer();
256 int data[] = dbi.getData();
257 int scanline = raster.getWidth();
258 int rof = dbi.getOffset() + y * scanline + x;
259 if(model instanceof IndexColorModel){
261 for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize,
263 for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
264 buff[idx] = colorMap[pixels[sOff + idx] & 0xff];
266 System.arraycopy(buff, 0, data, rof, w);
270 for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize,
272 for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
273 buff[idx] = model.getRGB(pixels[sOff + idx] & 0xff);
275 System.arraycopy(buff, 0, data, rof, w);
278 }else if(model == cm && model.getTransferType() == DataBuffer.TYPE_BYTE &&
279 raster.getNumDataElements() == 1){
281 DataBufferByte dbb = (DataBufferByte)raster.getDataBuffer();
282 byte data[] = dbb.getData();
283 int scanline = raster.getWidth();
284 int rof = dbb.getOffset() + y * scanline + x;
285 for(int lineOff = off, line = y; line < y + h;
286 line++, lineOff += scansize, rof += scanline){
287 System.arraycopy(pixels, lineOff, data, rof, w);
289 // BEGIN android-added (taken from newer Harmony)
290 }else if(model == cm && model.getTransferType() == DataBuffer.TYPE_BYTE &&
291 cm instanceof ComponentColorModel){
293 int nc = cm.getNumComponents();
294 byte stride[] = new byte[scansize];
295 for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize) {
296 System.arraycopy(pixels, sOff, stride, 0, scansize);
298 raster.setDataElements(x, sy, w, 1, stride);
302 for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize) {
303 for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
304 int rgb = model.getRGB(pixels[sOff + idx] & 0xff);
305 raster.setDataElements(sx, sy, cm.getDataElements(rgb, null));
310 if (imageSurf != null) {
311 imageSurf.invalidate();
314 imageUpdate(this, ImageObserver.SOMEBITS, 0, 0, width, height);
317 public void setDimensions(int width, int height) {
318 if(width <= 0 || height <= 0){
319 imageComplete(ImageObserver.ERROR);
324 this.height = height;
325 imageUpdate(this, (ImageObserver.HEIGHT | ImageObserver.WIDTH),
326 0, 0, width, height);
329 public void setHints(int hints) {
333 public void imageComplete(int state) {
337 flag = ImageObserver.ABORT;
340 flag = ImageObserver.ERROR | ImageObserver.ABORT;
342 case SINGLEFRAMEDONE:
343 flag = ImageObserver.FRAMEBITS;
345 case STATICIMAGEDONE:
346 flag = ImageObserver.ALLBITS;
349 // awt.3B=Incorrect ImageConsumer completion status
350 throw new IllegalArgumentException(Messages.getString("awt.3B")); //$NON-NLS-1$
352 imageUpdate(this, flag, 0, 0, width, height);
354 if((flag & (ImageObserver.ERROR | ImageObserver.ABORT |
355 ImageObserver.ALLBITS)) != 0 ) {
357 observers.removeAllElements();
361 public /*synchronized*/ BufferedImage getBufferedImage(){
363 ColorModel model = getColorModel();
364 WritableRaster wr = getRaster();
365 if(model != null && wr != null) {
366 image = new BufferedImage(model, wr, model.isAlphaPremultiplied(), null);
372 public /*synchronized*/ int checkImage(ImageObserver observer){
373 addObserver(observer);
377 public /*synchronized*/ boolean prepareImage(ImageObserver observer){
378 if((imageState & ImageObserver.ERROR) != 0){
379 if(observer != null){
380 observer.imageUpdate(this, ImageObserver.ERROR |
381 ImageObserver.ABORT, -1, -1, -1, -1);
385 if((imageState & ImageObserver.ALLBITS) != 0) {
388 addObserver(observer);
390 return ((imageState & ImageObserver.ALLBITS) != 0);
393 public /*synchronized*/ ColorModel getColorModel(){
400 public /*synchronized*/ WritableRaster getRaster(){
407 public int getState(){
411 private /*synchronized*/ void addObserver(ImageObserver observer){
412 if(observer != null){
413 if(observers.contains(observer)) {
416 if((imageState & ImageObserver.ERROR) != 0){
417 observer.imageUpdate(this, ImageObserver.ERROR |
418 ImageObserver.ABORT, -1, -1, -1, -1);
421 if((imageState & ImageObserver.ALLBITS) != 0){
422 observer.imageUpdate(this, imageState, 0, 0, width, height);
425 observers.addElement(observer);
429 private synchronized void startProduction(){
431 imageState &= ~ImageObserver.ABORT;
433 src.startProduction(this);
437 private synchronized void stopProduction(){
439 src.removeConsumer(this);
442 private void createRaster(){
444 raster = cm.createCompatibleWritableRaster(width, height);
446 if(cm instanceof DirectColorModel){
447 DirectColorModel dcm = (DirectColorModel) cm;
448 if(dcm.getTransferType() == DataBuffer.TYPE_INT &&
449 dcm.getRedMask() == 0xff0000 &&
450 dcm.getGreenMask() == 0xff00 &&
451 dcm.getBlueMask() == 0xff){
456 cm = ColorModel.getRGBdefault();
457 raster = cm.createCompatibleWritableRaster(width, height);
462 private /*synchronized*/ void imageUpdate(Image img, int infoflags, int x, int y,
463 int width, int height){
465 imageState |= infoflags;
466 for (ImageObserver observer : observers) {
467 observer.imageUpdate(this, infoflags, x, y, width, height);
473 private void forceToIntARGB(){
475 int w = raster.getWidth();
476 int h = raster.getHeight();
478 WritableRaster destRaster = rgbCM.createCompatibleWritableRaster(w, h);
481 int pixels[] = new int[w];
483 if(cm instanceof IndexColorModel){
484 IndexColorModel icm = (IndexColorModel) cm;
485 int colorMap[] = new int[icm.getMapSize()];
486 icm.getRGBs(colorMap);
488 for (int y = 0; y < h; y++) {
489 obj = raster.getDataElements(0, y, w, 1, obj);
490 byte ba[] = (byte[]) obj;
491 for (int x = 0; x < ba.length; x++) {
492 pixels[x] = colorMap[ba[x] & 0xff];
494 destRaster.setDataElements(0, y, w, 1, pixels);
498 for(int y = 0; y < h; y++){
499 for(int x = 0; x < w; x++){
500 obj = raster.getDataElements(x, y, obj);
501 pixels[x] = cm.getRGB(obj);
503 destRaster.setDataElements(0, y, w, 1, pixels);
508 if(imageSurf != null){
522 public ImageSurface getImageSurface() {
523 if (imageSurf == null) {
524 ColorModel model = getColorModel();
525 WritableRaster wr = getRaster();
526 if(model != null && wr != null) {
527 imageSurf = new ImageSurface(model, wr);