import java.lang.*; import java.io.*; import java.awt.*; import java.awt.image.*; import java.util.*; import BitmapInputStream; import BitmapOutputStream; // Windows and OS/2 bitmap class final public class Bitmap extends Object implements Cloneable, ImageProducer, ImageConsumer { private int _cx, _cy; private int _aaiPixels[][]; private Vector _vecConsumers = new Vector(); private boolean _fAbort = false, _fComplete = false; final static ColorModel _colorModel = new DirectColorModel(24, 0xff0000, 0x00ff00, 0x0000ff); // offsets of structures; final static short BITMAP_TYPE = 0x4d42; final static int FILE_HEADER_SIZE = 14; final static int USTYPE = 0, CBSIZE = 2, XHOTSPOT = 6, YHOTSPOT = 8, OFFBITS = 10; final static int VER1_HEADER_SIZE = 12; final static int CBFIX = 0; final static int CX_1 = 4, CY_1 = 6, CPLANES_1 = 8, CBITCOUNT_1 = 10; final static int VER2_DEFAULT_HEADER_SIZE = 40; final static int CX_2 = 4, CY_2 = 8, CPLANES_2 = 12, CBITCOUNT_2 = 14, ULCOMPRESSION = 16, CBIMAGE = 20, CXRESOLUTION = 24, CYRESOLUTION = 28, CCLRUSED = 32, CCLRIMPORTANT = 36; final static int VER2_DEFAULT_OFFBITS = (FILE_HEADER_SIZE + VER2_DEFAULT_HEADER_SIZE + 3) & ~3; // constructors; Bitmap() { _cx = _cy = 0; _aaiPixels = null; } Bitmap(int cx, int cy) { _cx = cx; _cy = cy; _aaiPixels = new int[cy][cx]; } Bitmap(Bitmap bitmap) { _cx = bitmap._cx; _cy = bitmap._cy; _aaiPixels = new int[_cy][_cx]; for (int y = 0; y < _cy; y++) { System.arraycopy(bitmap._aaiPixels[y], 0, _aaiPixels[y], 0, _cx); } } Bitmap(InputStream in) throws IOException { read(in); } Bitmap(String strFilename) throws IOException { FileInputStream in = new FileInputStream(strFilename); read(in); in.close(); } final private void read(InputStream in) throws IOException { BitmapInputStream bitmapIn = new BitmapInputStream(in); _cx = bitmapIn.xSize(); _cy = bitmapIn.ySize(); _aaiPixels = new int[_cy][]; for (int y = 0; y < _cy; y++) { _aaiPixels[y] = bitmapIn.readLine(); } } // ImageProducer functions; final public void addConsumer(ImageConsumer imageConsumer) { startProduction(imageConsumer); } final public boolean isConsumer(ImageConsumer imageConsumer) { return _vecConsumers.contains(imageConsumer); } final public void removeConsumer(ImageConsumer imageConsumer) { _vecConsumers.removeElement(imageConsumer); _fAbort = true; } final public void startProduction(ImageConsumer imageConsumer) { if (!_vecConsumers.contains(imageConsumer)) { _vecConsumers.addElement(imageConsumer); } _fAbort = false; imageConsumer.setHints(ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME | ImageConsumer.COMPLETESCANLINES); imageConsumer.setColorModel(_colorModel); imageConsumer.setDimensions(_cx, _cy); for (int yDest = 0, ySource = _cy - 1; ySource >= 0; yDest++, ySource--) { if (_fAbort && !_vecConsumers.contains(imageConsumer)) { _fAbort = false; imageConsumer.imageComplete(ImageConsumer.IMAGEABORTED); return; } imageConsumer.setPixels(0, yDest, _cx, 1, _colorModel, _aaiPixels[ySource], 0, _cx); } imageConsumer.imageComplete(ImageConsumer.STATICIMAGEDONE); } final public void requestTopDownLeftRightResend(ImageConsumer imageConsumer) { // ignore; } // ImageConsumer functions; final public synchronized void setDimensions(int cx, int cy) { _cx = cx; _cy = cy; _aaiPixels = new int[cy][cx]; _fComplete = false; } final public void setProperties(Hashtable hash) { // ignore; } final public void setColorModel(ColorModel colorModel) { // ignore; } final public void setHints(int iHints) { // ignore; } final public void setPixels(int x, int y, int cx, int cy, ColorModel colorModel, byte pbPixels[], int iOff, int iScanSize) { y = _cy - y; int yLimit = y - cy; while (--y >= yLimit) { int pixels[] = _aaiPixels[y]; for (int xOffset = 0; xOffset < cx; xOffset++) { pixels[x + xOffset] = colorModel.getRGB(pbPixels[iOff + xOffset] & 0xff); } iOff += iScanSize; } } final public void setPixels(int x, int y, int cx, int cy, ColorModel colorModel, int piPixels[], int iOff, int iScanSize) { y = _cy - y; int yLimit = y - cy; while (--y >= yLimit) { int pixels[] = _aaiPixels[y]; for (int xOffset = 0; xOffset < cx; xOffset++) { pixels[x + xOffset] = colorModel.getRGB(piPixels[iOff + xOffset]); } iOff += iScanSize; } } final public void imageComplete(int iStatus) { _fComplete = true; } final public boolean isCompleted() { return _fComplete; } // Cloneable functions; final public Object clone() { return new Bitmap(this); } // other functions; final public void writeTo(OutputStream out) throws IOException { BitmapOutputStream bitmapOut = new BitmapOutputStream(out, _cx, _cy); for (int y = 0; y < _cy; y++) { bitmapOut.writeLine(_aaiPixels[y], 0); } } final public void writeTo(String strFilename) throws IOException { FileOutputStream out = new FileOutputStream(strFilename); writeTo(out); out.close(); } final public int xSize() { return _cx; } final public int ySize() { return _cy; } final public Dimension size() { return new Dimension(_cx, _cy); } final public int at(int x, int y) { return _aaiPixels[y][x]; } final public int[] line(int y) { return _aaiPixels[y]; } final public static int interpolate(int color1, int color2, double dRatio) { double dRatioComp = 1 - dRatio; return ((int)(((color1 >>> 16) & 255) * dRatio + ((color2 >>> 16) & 255) * dRatioComp + 0.5) << 16) | ((int)(((color1 >>> 8) & 255) * dRatio + ((color2 >>> 8) & 255) * dRatioComp + 0.5) << 8) | (int)((color1 & 255) * dRatio + (color2 & 255) * dRatioComp + 0.5); } final public int at(double x, double y) { int xPel0 = (int)Math.floor(x), yPel0 = (int)Math.floor(y); double xRatio = x - xPel0, yRatio = y - yPel0; xPel0 = (xPel0 % _cx + _cx) % _cx; yPel0 = (yPel0 % _cy + _cy) % _cy; int xPel1 = (xPel0 + 1) % _cx, yPel1 = (yPel0 + 1) % _cy; return interpolate(interpolate(_aaiPixels[yPel0][xPel0], _aaiPixels[yPel0][xPel1], xRatio), interpolate(_aaiPixels[yPel1][xPel0], _aaiPixels[yPel1][xPel1], xRatio), yRatio); } final public void put(int x, int y, int color) { _aaiPixels[y][x] = color; } final public boolean copy(int xDest, int yDest, Bitmap bitmapSource, int xSource, int ySource, int cx, int cy) { int iOverflow; if ((iOverflow = Math.max(xDest + cx - _cx, xSource + cx - bitmapSource._cx)) > 0) { cx -= iOverflow; } if ((iOverflow = Math.min(xDest, xSource)) < 0) { xSource -= iOverflow; xDest -= iOverflow; cx += iOverflow; } if (cx <= 0) { return false; } if ((iOverflow = Math.max(yDest + cy - _cy, ySource + cy - bitmapSource._cy)) > 0) { cy -= iOverflow; } if ((iOverflow = Math.min(yDest, ySource)) < 0) { ySource -= iOverflow; yDest -= iOverflow; cy += iOverflow; } if (cy <= 0) { return false; } if (this == bitmapSource && yDest > ySource && yDest < ySource + cx) { ySource += cy - 1; yDest += cy - 1; do { System.arraycopy(_aaiPixels[ySource--], xSource, _aaiPixels[yDest--], xDest, cx); } while (--cy > 0); } else { do { System.arraycopy(bitmapSource._aaiPixels[ySource++], xSource, _aaiPixels[yDest++], xDest, cx); } while (--cy > 0); } return true; } }