/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @author Igor V. Stolyarov * @version $Revision$ */ package java.awt.image; import java.awt.Image; import java.util.Hashtable; import org.apache.harmony.awt.internal.nls.Messages; public class PixelGrabber implements ImageConsumer { int width; int height; int X; int Y; int offset; int scanline; ImageProducer producer; byte bData[]; int iData[]; ColorModel cm; private int grabberStatus; private int dataType; private boolean isGrabbing; private boolean isRGB; private static final int DATA_TYPE_BYTE = 0; private static final int DATA_TYPE_INT = 1; private static final int DATA_TYPE_UNDEFINED = 2; private static final int ALL_BITS = (ImageObserver.FRAMEBITS | ImageObserver.ALLBITS); private static final int GRABBING_STOP = ALL_BITS | ImageObserver.ERROR; public PixelGrabber(ImageProducer ip, int x, int y, int w, int h, int[] pix, int off, int scansize) { initialize(ip, x, y, w, h, pix, off, scansize, true); } public PixelGrabber(Image img, int x, int y, int w, int h, int[] pix, int off, int scansize) { initialize(img.getSource(), x, y, w, h, pix, off, scansize, true); } public PixelGrabber(Image img, int x, int y, int w, int h, boolean forceRGB) { initialize(img.getSource(), x, y, w, h, null, 0, 0, forceRGB); } public void setProperties(Hashtable<?, ?> props) { return; } public synchronized Object getPixels() { switch(dataType){ case DATA_TYPE_BYTE: return bData; case DATA_TYPE_INT: return iData; default: return null; } } public void setColorModel(ColorModel model) { return; } public void setPixels(int srcX, int srcY, int srcW, int srcH, ColorModel model, byte[] pixels, int srcOff, int srcScan) { if(srcY < Y){ int delta = Y - srcY; if(delta >= height) { return; } srcY += delta; srcH -= delta; srcOff += srcScan * delta; } if(srcY + srcH > Y + height){ srcH = Y + height - srcY; if(srcH <= 0) { return; } } if(srcX < X){ int delta = X - srcX; if(delta >= width) { return; } srcW -= delta; srcX += delta; srcOff += delta; } if(srcX + srcW > X + width){ srcW = X + width - srcX; if(srcW <= 0) { return; } } if(scanline == 0) { scanline = width; } int realOff = offset + (srcY - Y) * scanline + (srcX - X); switch(dataType){ case DATA_TYPE_UNDEFINED: cm = model; if(model != ColorModel.getRGBdefault()){ bData = new byte[width * height]; isRGB = false; dataType = DATA_TYPE_BYTE; }else{ iData = new int[width * height]; isRGB = true; dataType = DATA_TYPE_INT; } case DATA_TYPE_BYTE: if(!isRGB && cm == model){ for(int y = 0; y < srcH; y++){ System.arraycopy(pixels, srcOff, bData, realOff, srcW); srcOff += srcScan; realOff += scanline; } break; } forceToRGB(); case DATA_TYPE_INT: for(int y = 0; y < srcH; y++){ for(int x = 0; x < srcW; x++){ iData[realOff + x] = cm.getRGB(pixels[srcOff + x] & 0xff); } srcOff += srcScan; realOff += scanline; } } return; } public void setPixels(int srcX, int srcY, int srcW, int srcH, ColorModel model, int[] pixels, int srcOff, int srcScan) { if(srcY < Y){ int delta = Y - srcY; if(delta >= height) { return; } srcY += delta; srcH -= delta; srcOff += srcScan * delta; } if(srcY + srcH > Y + height){ srcH = Y + height - srcY; if(srcH <= 0) { return; } } if(srcX < X){ int delta = X - srcX; if(delta >= width) { return; } srcW -= delta; srcX += delta; srcOff += delta; } if(srcX + srcW > X + width){ srcW = X + width - srcX; if(srcW <= 0) { return; } } if(scanline == 0) { scanline = width; } int realOff = offset + (srcY - Y) * scanline + (srcX - X); int mask = 0xFF; switch(dataType){ case DATA_TYPE_UNDEFINED: cm = model; iData = new int[width * height]; dataType = DATA_TYPE_INT; isRGB = (cm == ColorModel.getRGBdefault()); case DATA_TYPE_INT: if(cm == model){ for(int y = 0; y < srcH; y++){ System.arraycopy(pixels, srcOff, iData, realOff, srcW); srcOff += srcScan; realOff += scanline; } break; } mask = 0xFFFFFFFF; case DATA_TYPE_BYTE: forceToRGB(); for(int y = 0; y < srcH; y++){ for(int x = 0; x < srcW; x++){ iData[realOff+x] = cm.getRGB(pixels[srcOff+x] & mask); } srcOff += srcScan; realOff += scanline; } } } public synchronized ColorModel getColorModel() { return cm; } public synchronized boolean grabPixels(long ms) throws InterruptedException { if((grabberStatus & GRABBING_STOP) != 0){ return ((grabberStatus & ALL_BITS) != 0); } long start = System.currentTimeMillis(); if(!isGrabbing){ isGrabbing = true; grabberStatus &= ~ImageObserver.ABORT; producer.startProduction(this); } while((grabberStatus & GRABBING_STOP) == 0){ if(ms != 0){ ms = start + ms - System.currentTimeMillis(); if(ms <= 0) { break; } } wait(ms); } return ((grabberStatus & ALL_BITS) != 0); } public void setDimensions(int w, int h) { if(width < 0) { width = w - X; } if(height < 0) { height = h - Y; } grabberStatus |= ImageObserver.WIDTH | ImageObserver.HEIGHT; if(width <=0 || height <=0){ imageComplete(STATICIMAGEDONE); return; } if(isRGB && dataType == DATA_TYPE_UNDEFINED){ iData = new int[width * height]; dataType = DATA_TYPE_INT; scanline = width; } } public void setHints(int hints) { return; } public synchronized void imageComplete(int status) { switch(status){ case IMAGEABORTED: grabberStatus |= ImageObserver.ABORT; break; case IMAGEERROR: grabberStatus |= ImageObserver.ERROR | ImageObserver.ABORT; break; case SINGLEFRAMEDONE: grabberStatus |= ImageObserver.FRAMEBITS; break; case STATICIMAGEDONE: grabberStatus |= ImageObserver.ALLBITS; break; default: // awt.26A=Incorrect ImageConsumer completion status throw new IllegalArgumentException(Messages.getString("awt.26A")); //$NON-NLS-1$ } isGrabbing = false; producer.removeConsumer(this); notifyAll(); } public boolean grabPixels() throws InterruptedException { return grabPixels(0); } public synchronized void startGrabbing() { if((grabberStatus & GRABBING_STOP) != 0){ return; } if(!isGrabbing){ isGrabbing = true; grabberStatus &= ~ImageObserver.ABORT; producer.startProduction(this); } } public synchronized void abortGrabbing() { imageComplete(IMAGEABORTED); } public synchronized int status() { return grabberStatus; } public synchronized int getWidth() { if(width < 0) { return -1; } return width; } public synchronized int getStatus() { return grabberStatus; } public synchronized int getHeight() { if(height < 0) { return -1; } return height; } private void initialize(ImageProducer ip, int x, int y, int w, int h, int pixels[], int off, int scansize, boolean forceRGB){ producer = ip; X = x; Y = y; width = w; height = h; iData = pixels; dataType = (pixels == null) ? DATA_TYPE_UNDEFINED : DATA_TYPE_INT; offset = off; scanline = scansize; if(forceRGB){ cm = ColorModel.getRGBdefault(); isRGB = true; } } /** * Force pixels to INT RGB mode */ private void forceToRGB(){ if (isRGB) return; switch(dataType){ case DATA_TYPE_BYTE: iData = new int[width * height]; for(int i = 0; i < iData.length; i++){ iData[i] = cm.getRGB(bData[i] & 0xff); } dataType = DATA_TYPE_INT; bData = null; break; case DATA_TYPE_INT: int buff[] = new int[width * height]; for(int i = 0; i < iData.length; i++){ buff[i] = cm.getRGB(iData[i]); } iData = buff; break; } offset = 0; scanline = width; cm = ColorModel.getRGBdefault(); isRGB = true; } }