1/* 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 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 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. 16 */ 17/** 18 * @author Igor V. Stolyarov 19 * @version $Revision$ 20 */ 21package java.awt.image; 22 23import java.awt.Image; 24import java.util.Hashtable; 25 26import org.apache.harmony.awt.internal.nls.Messages; 27 28public class PixelGrabber implements ImageConsumer { 29 30 int width; 31 int height; 32 int X; 33 int Y; 34 int offset; 35 int scanline; 36 ImageProducer producer; 37 38 byte bData[]; 39 int iData[]; 40 ColorModel cm; 41 42 private int grabberStatus; 43 private int dataType; 44 private boolean isGrabbing; 45 private boolean isRGB; 46 47 48 private static final int DATA_TYPE_BYTE = 0; 49 private static final int DATA_TYPE_INT = 1; 50 private static final int DATA_TYPE_UNDEFINED = 2; 51 52 private static final int ALL_BITS = (ImageObserver.FRAMEBITS | 53 ImageObserver.ALLBITS); 54 55 private static final int GRABBING_STOP = ALL_BITS | ImageObserver.ERROR; 56 57 58 59 public PixelGrabber(ImageProducer ip, int x, int y, int w, int h, int[] pix, 60 int off, int scansize) { 61 initialize(ip, x, y, w, h, pix, off, scansize, true); 62 } 63 64 public PixelGrabber(Image img, int x, int y, int w, int h, int[] pix, 65 int off, int scansize) { 66 initialize(img.getSource(), x, y, w, h, pix, off, scansize, true); 67 } 68 69 public PixelGrabber(Image img, int x, int y, int w, int h, boolean forceRGB) { 70 initialize(img.getSource(), x, y, w, h, null, 0, 0, forceRGB); 71 } 72 73 public void setProperties(Hashtable<?, ?> props) { 74 return; 75 } 76 77 public synchronized Object getPixels() { 78 switch(dataType){ 79 case DATA_TYPE_BYTE: 80 return bData; 81 case DATA_TYPE_INT: 82 return iData; 83 default: 84 return null; 85 } 86 } 87 88 public void setColorModel(ColorModel model) { 89 return; 90 } 91 92 public void setPixels(int srcX, int srcY, int srcW, int srcH, 93 ColorModel model, byte[] pixels, int srcOff, int srcScan) { 94 if(srcY < Y){ 95 int delta = Y - srcY; 96 if(delta >= height) { 97 return; 98 } 99 srcY += delta; 100 srcH -= delta; 101 srcOff += srcScan * delta; 102 } 103 104 if(srcY + srcH > Y + height){ 105 srcH = Y + height - srcY; 106 if(srcH <= 0) { 107 return; 108 } 109 } 110 111 if(srcX < X){ 112 int delta = X - srcX; 113 if(delta >= width) { 114 return; 115 } 116 srcW -= delta; 117 srcX += delta; 118 srcOff += delta; 119 } 120 121 if(srcX + srcW > X + width){ 122 srcW = X + width - srcX; 123 if(srcW <= 0) { 124 return; 125 } 126 } 127 if(scanline == 0) { 128 scanline = width; 129 } 130 int realOff = offset + (srcY - Y) * scanline + (srcX - X); 131 switch(dataType){ 132 case DATA_TYPE_UNDEFINED: 133 cm = model; 134 if(model != ColorModel.getRGBdefault()){ 135 bData = new byte[width * height]; 136 isRGB = false; 137 dataType = DATA_TYPE_BYTE; 138 }else{ 139 iData = new int[width * height]; 140 isRGB = true; 141 dataType = DATA_TYPE_INT; 142 } 143 case DATA_TYPE_BYTE: 144 if(!isRGB && cm == model){ 145 for(int y = 0; y < srcH; y++){ 146 System.arraycopy(pixels, srcOff, bData, realOff, srcW); 147 srcOff += srcScan; 148 realOff += scanline; 149 } 150 break; 151 } 152 forceToRGB(); 153 case DATA_TYPE_INT: 154 for(int y = 0; y < srcH; y++){ 155 for(int x = 0; x < srcW; x++){ 156 iData[realOff + x] = cm.getRGB(pixels[srcOff + x] & 0xff); 157 } 158 srcOff += srcScan; 159 realOff += scanline; 160 } 161 } 162 163 return; 164 } 165 166 public void setPixels(int srcX, int srcY, int srcW, int srcH, 167 ColorModel model, int[] pixels, int srcOff, int srcScan) { 168 169 if(srcY < Y){ 170 int delta = Y - srcY; 171 if(delta >= height) { 172 return; 173 } 174 srcY += delta; 175 srcH -= delta; 176 srcOff += srcScan * delta; 177 } 178 179 if(srcY + srcH > Y + height){ 180 srcH = Y + height - srcY; 181 if(srcH <= 0) { 182 return; 183 } 184 } 185 186 if(srcX < X){ 187 int delta = X - srcX; 188 if(delta >= width) { 189 return; 190 } 191 srcW -= delta; 192 srcX += delta; 193 srcOff += delta; 194 } 195 196 if(srcX + srcW > X + width){ 197 srcW = X + width - srcX; 198 if(srcW <= 0) { 199 return; 200 } 201 } 202 if(scanline == 0) { 203 scanline = width; 204 } 205 int realOff = offset + (srcY - Y) * scanline + (srcX - X); 206 207 int mask = 0xFF; 208 209 switch(dataType){ 210 case DATA_TYPE_UNDEFINED: 211 cm = model; 212 iData = new int[width * height]; 213 dataType = DATA_TYPE_INT; 214 isRGB = (cm == ColorModel.getRGBdefault()); 215 216 case DATA_TYPE_INT: 217 if(cm == model){ 218 for(int y = 0; y < srcH; y++){ 219 System.arraycopy(pixels, srcOff, iData, realOff, srcW); 220 srcOff += srcScan; 221 realOff += scanline; 222 } 223 break; 224 } 225 mask = 0xFFFFFFFF; 226 227 case DATA_TYPE_BYTE: 228 forceToRGB(); 229 for(int y = 0; y < srcH; y++){ 230 for(int x = 0; x < srcW; x++){ 231 iData[realOff+x] = cm.getRGB(pixels[srcOff+x] & mask); 232 } 233 srcOff += srcScan; 234 realOff += scanline; 235 } 236 } 237 } 238 239 public synchronized ColorModel getColorModel() { 240 return cm; 241 } 242 243 public synchronized boolean grabPixels(long ms) 244 throws InterruptedException { 245 if((grabberStatus & GRABBING_STOP) != 0){ 246 return ((grabberStatus & ALL_BITS) != 0); 247 } 248 249 long start = System.currentTimeMillis(); 250 251 if(!isGrabbing){ 252 isGrabbing = true; 253 grabberStatus &= ~ImageObserver.ABORT; 254 producer.startProduction(this); 255 } 256 while((grabberStatus & GRABBING_STOP) == 0){ 257 if(ms != 0){ 258 ms = start + ms - System.currentTimeMillis(); 259 if(ms <= 0) { 260 break; 261 } 262 } 263 wait(ms); 264 } 265 266 return ((grabberStatus & ALL_BITS) != 0); 267 } 268 269 public void setDimensions(int w, int h) { 270 if(width < 0) { 271 width = w - X; 272 } 273 if(height < 0) { 274 height = h - Y; 275 } 276 277 grabberStatus |= ImageObserver.WIDTH | ImageObserver.HEIGHT; 278 279 if(width <=0 || height <=0){ 280 imageComplete(STATICIMAGEDONE); 281 return; 282 } 283 284 if(isRGB && dataType == DATA_TYPE_UNDEFINED){ 285 iData = new int[width * height]; 286 dataType = DATA_TYPE_INT; 287 scanline = width; 288 } 289 } 290 291 public void setHints(int hints) { 292 return; 293 } 294 295 public synchronized void imageComplete(int status) { 296 switch(status){ 297 case IMAGEABORTED: 298 grabberStatus |= ImageObserver.ABORT; 299 break; 300 case IMAGEERROR: 301 grabberStatus |= ImageObserver.ERROR | ImageObserver.ABORT; 302 break; 303 case SINGLEFRAMEDONE: 304 grabberStatus |= ImageObserver.FRAMEBITS; 305 break; 306 case STATICIMAGEDONE: 307 grabberStatus |= ImageObserver.ALLBITS; 308 break; 309 default: 310 // awt.26A=Incorrect ImageConsumer completion status 311 throw new IllegalArgumentException(Messages.getString("awt.26A")); //$NON-NLS-1$ 312 } 313 isGrabbing = false; 314 producer.removeConsumer(this); 315 notifyAll(); 316 } 317 318 public boolean grabPixels() throws InterruptedException { 319 return grabPixels(0); 320 } 321 322 public synchronized void startGrabbing() { 323 if((grabberStatus & GRABBING_STOP) != 0){ 324 return; 325 } 326 if(!isGrabbing){ 327 isGrabbing = true; 328 grabberStatus &= ~ImageObserver.ABORT; 329 producer.startProduction(this); 330 } 331 } 332 333 public synchronized void abortGrabbing() { 334 imageComplete(IMAGEABORTED); 335 } 336 337 public synchronized int status() { 338 return grabberStatus; 339 } 340 341 public synchronized int getWidth() { 342 if(width < 0) { 343 return -1; 344 } 345 return width; 346 } 347 348 public synchronized int getStatus() { 349 return grabberStatus; 350 } 351 352 public synchronized int getHeight() { 353 if(height < 0) { 354 return -1; 355 } 356 return height; 357 } 358 359 private void initialize(ImageProducer ip, int x, int y, int w, int h, 360 int pixels[], int off, int scansize, boolean forceRGB){ 361 362 producer = ip; 363 X = x; 364 Y = y; 365 width = w; 366 height = h; 367 iData = pixels; 368 dataType = (pixels == null) ? DATA_TYPE_UNDEFINED : DATA_TYPE_INT; 369 offset = off; 370 scanline = scansize; 371 if(forceRGB){ 372 cm = ColorModel.getRGBdefault(); 373 isRGB = true; 374 } 375 } 376 377 /** 378 * Force pixels to INT RGB mode 379 */ 380 private void forceToRGB(){ 381 if (isRGB) 382 return; 383 384 switch(dataType){ 385 case DATA_TYPE_BYTE: 386 iData = new int[width * height]; 387 for(int i = 0; i < iData.length; i++){ 388 iData[i] = cm.getRGB(bData[i] & 0xff); 389 } 390 dataType = DATA_TYPE_INT; 391 bData = null; 392 break; 393 394 case DATA_TYPE_INT: 395 int buff[] = new int[width * height]; 396 for(int i = 0; i < iData.length; i++){ 397 buff[i] = cm.getRGB(iData[i]); 398 } 399 iData = buff; 400 break; 401 } 402 offset = 0; 403 scanline = width; 404 cm = ColorModel.getRGBdefault(); 405 isRGB = true; 406 } 407 408} 409