package javaforce; import java.awt.*; import java.awt.image.*; import java.awt.font.*; import javax.swing.*; import java.io.*; import java.util.*; import javax.imageio.*; /** * Encapsules BufferedImage to provide more functions. * Implements javax.swing.Icon so it can also be used with JLabel. * * @author Peter Quiring */ public class JFImage extends JComponent implements Icon { private BufferedImage bi; private Graphics2D g2d; private int buffer[]; private ResizeOperation resizeOperation = ResizeOperation.CLEAR; private int imageType; //BufferedImage.TYPE_INT_... public enum ResizeOperation { CLEAR, //reset image CHOP, //copy/chop image SCALE //scale image }; public JFImage() { imageType = BufferedImage.TYPE_INT_ARGB; } public JFImage(boolean alpha) { if (alpha) imageType = BufferedImage.TYPE_INT_ARGB; else imageType = BufferedImage.TYPE_INT_RGB; } public JFImage(int x, int y) { imageType = BufferedImage.TYPE_INT_ARGB; setImageSize(x, y); } public JFImage(int x, int y, boolean alpha) { if (alpha) imageType = BufferedImage.TYPE_INT_ARGB; else imageType = BufferedImage.TYPE_INT_RGB; setImageSize(x, y); } private void init() { g2d = bi.createGraphics(); buffer = ((DataBufferInt) bi.getRaster().getDataBuffer()).getData(); fill(0,0,getWidth(),getHeight(), 0); //fill with black opaque (the default varies by platform) } private void initImage(int x, int y) { // System.out.println("JFImage.initImage:" + x + "," + y); bi = new BufferedImage(x, y, imageType); init(); setPreferredSize(new Dimension(x, y)); } public void setImageSize(int x, int y) { setSize(x, y); initImage(x, y); } public void setBounds(int x, int y, int w, int h) { //usually called from LayoutManager / ScrollPane // System.out.println("JFImage.setBounds:" + x + "," + y + "," + w + "," + h); super.setBounds(x, y, w, h); if (bi != null) { BufferedImage oldbi = bi; int oldw = getWidth(); int oldh = getHeight(); Composite org; switch (resizeOperation) { case CLEAR: initImage(w, h); break; case CHOP: initImage(w, h); org = g2d.getComposite(); g2d.setComposite(AlphaComposite.Src); g2d.drawImage(oldbi, 0, 0, null); g2d.setComposite(org); break; case SCALE: initImage(w, h); org = g2d.getComposite(); g2d.setComposite(AlphaComposite.Src); g2d.drawImage(oldbi, 0, 0, w, h, 0, 0, oldw, oldh, null); g2d.setComposite(org); break; } } else { initImage(w, h); } } public void setSize(int x, int y) { // System.out.println("JFImage.setSize:" + x + "," + y); super.setSize(x, y); //just calls setBounds(getLocation(),x,y); } public void setSize(Dimension d) { // System.out.println("JFImage.setSize:" + d); super.setSize(d); } /** * Controls how this image is resized by layout managers. */ public void setResizeOperation(ResizeOperation ro) { resizeOperation = ro; } public Image getImage() { return bi; } public BufferedImage getBufferedImage() { return bi; } /** * Replaced BufferedImage. * Must be TYPE_INT_ARGB or TYPE_INT_RGB type. * @param bi - new BufferedImage */ public void setBufferedImage(BufferedImage bi) { int newType = bi.getType(); if (newType != BufferedImage.TYPE_INT_ARGB || newType != BufferedImage.TYPE_INT_RGB) { JFLog.log("JFImage.setBufferedImage() : Input image is not INT_RGB/INT_ARGB type"); return; } this.bi = bi; imageType = bi.getType(); init(); } public Graphics getGraphics() { return g2d; } public Graphics2D getGraphics2D() { return g2d; } /** Paint this image onto Graphics. */ public void paint(Graphics g) { //System.out.println("paint"); if (bi == null) { return; } g.drawImage(getImage(), 0, 0, null); } public int getWidth() { if (bi == null) { return -1; } return bi.getWidth(); } public int getHeight() { if (bi == null) { return -1; } return bi.getHeight(); } public boolean load(InputStream in) { //use ImageIO (the returned Image is type TYPE_CUSTOM which is slow so copy pixels to an TYPE_INT_ARGB) BufferedImage tmp; try { tmp = ImageIO.read(in); in.close(); } catch (Exception e) { JFLog.log(e); return false; } if (tmp == null) { return false; } int x = tmp.getWidth(); int y = tmp.getHeight(); int px[] = tmp.getRGB(0, 0, x, y, null, 0, x); //tmp may not be int[] buffer setImageSize(x, y); putPixels(px, 0, 0, x, y, 0); return true; } public boolean save(OutputStream out, String fmt) { boolean ret; if (fmt.equals("jpg")) ret = saveJPG(out); //Must convert image type else if (fmt.equals("ico")) ret = saveICO(out); //ImageIO doesn't support ICO else if (fmt.equals("icns")) ret = saveICNS(out); //ImageIO doesn't support ICNS else if (fmt.equals("bmp")) ret = saveBMP(out); //ImageIO doesn't support BMP (except Windows) else { try { ret = ImageIO.write(bi, fmt, out); } catch (Exception e) { JFLog.log(e); ret = false; } } try {out.close();} catch (Exception e) {} return ret; } public boolean load(String filename) { try { return load(new FileInputStream(filename)); } catch (Exception e) { return false; } } public boolean save(String filename, String fmt) { try { return save(new FileOutputStream(filename), fmt); } catch (Exception e) { return false; } } public boolean loadJPG(InputStream in) { return load(in); } public boolean saveJPG(OutputStream out) { //Do NOT use a BufferedImage of type TYPE_INT_ARGB //On Windows it creates a 4 channel image which is mistake in CMYK format (which gives it a pinkish tint) //On Linux it throws an exception!!! //See http://stackoverflow.com/questions/3432388/imageio-not-able-to-write-a-jpeg-file //So convert BufferedImage to type TYPE_3BYTE_BGR instead and it works on all platforms try { int w = bi.getWidth(); int h = bi.getHeight(); int px[] = new int[w * h]; BufferedImage tmp = new BufferedImage(bi.getWidth(),bi.getHeight(),BufferedImage.TYPE_3BYTE_BGR); bi.getRGB(0,0,w,h,px,0,w); tmp.setRGB(0,0,w,h,px,0,w); return ImageIO.write(tmp, "jpg", out); } catch (Exception e) { JFLog.log(e); } return false; } public boolean loadJPG(String filename) { try { return loadJPG(new FileInputStream(filename)); } catch (Exception e) { return false; } } public boolean saveJPG(String filename) { try { return saveJPG(new FileOutputStream(filename)); } catch (Exception e) { return false; } } public boolean loadPNG(InputStream in) { return load(in); } public boolean savePNG(OutputStream out) { return save(out, "png"); } public boolean loadPNG(String filename) { try { return loadPNG(new FileInputStream(filename)); } catch (Exception e) { return false; } } public boolean savePNG(String filename) { try { return savePNG(new FileOutputStream(filename)); } catch (Exception e) { return false; } } //NOTE : Not all JREs support "bmp" so I use custom code public boolean loadBMP(String filename) { try { return loadBMP(new FileInputStream(filename)); } catch (Exception e) { return false; } } public boolean saveBMP(String filename) { try { return saveBMP(new FileOutputStream(filename)); } catch (Exception e) { return false; } } public boolean loadBMP(InputStream in) { int buf[]; Dimension size = new Dimension(0, 0); buf = bmp.load(in, size); try {in.close();} catch (Exception e) {} if (buf == null) { return false; } if (size.width == 0 || size.height == 0) { return false; } setImageSize(size.width, size.height); putPixels(buf, 0, 0, size.width, size.height, 0); return true; } public boolean saveBMP(OutputStream out) { int pixels[]; pixels = getPixels(0, 0, getWidth(), getHeight()); Dimension size = new Dimension(getWidth(), getHeight()); return bmp.save24(out, pixels, size, false); } //save ICO (no loading supported) public boolean saveICO(String filename) { try { return saveICO(new FileOutputStream(filename)); } catch (Exception e) { return false; } } public boolean saveICO(OutputStream out) { int pixels[]; pixels = getPixels(0, 0, getWidth(), getHeight()); Dimension size = new Dimension(getWidth(), getHeight()); return bmp.save32(out, pixels, size, false, true); } /** save icns (Mac icon) */ public boolean saveICNS(String filename) { try { return saveICNS(new FileOutputStream(filename)); } catch (Exception e) { return false; } } /** save icns (Mac icon) */ public boolean saveICNS(OutputStream out) { //see http://en.wikipedia.org/wiki/Apple_Icon_Image_format //use one of the PNG formats byte header[] = new byte[4*4]; //scale image to one of supported sizes int w = getWidth(); int h = getHeight(); if (w > h) h = w; if (h > w) w = h; int newSize = 16; String OSType = "icp4"; /* if (w > 512) { newSize = 1024; //also retina 512x512@2x ??? OSType = "ic10"; } else */ if (w > 256) { newSize = 512; OSType = "ic09"; } else if (w > 128) { newSize = 256; OSType = "ic08"; } else if (w > 64) { newSize = 128; OSType = "ic07"; } else if (w > 32) { newSize = 64; OSType = "icp6"; } else if (w > 16) { newSize = 32; OSType = "icp5"; } if (w != newSize || h != newSize) { // System.out.println("Scaling icns to:" + newSize + "x" + newSize); setResizeOperation(ResizeOperation.SCALE); setSize(newSize, newSize); } ByteArrayOutputStream baos = new ByteArrayOutputStream(); savePNG(baos); // System.out.println("png.size=" + baos.size()); System.arraycopy("icns".getBytes(), 0, header, 0, 4); //file header "icns" BE.setuint32(header, 4, 4*4 + baos.size()); //file size System.arraycopy(OSType.getBytes(), 0, header, 8, 4); //image type BE.setuint32(header, 12, 4*2 + baos.size()); //image size try { out.write(header); out.write(baos.toByteArray()); } catch (Exception e) { return false; } return true; } public boolean loadSVG(String filename) { try { return loadSVG(new FileInputStream(filename)); } catch (Exception e) { return false; } } public boolean saveSVG(String filename) { try { return saveSVG(new FileOutputStream(filename)); } catch (Exception e) { return false; } } public boolean loadSVG(InputStream in) { int buf[]; Dimension size = new Dimension(0, 0); buf = svg.load(in, size); try {in.close();} catch (Exception e) {} if (buf == null) { return false; } if (size.width == 0 || size.height == 0) { return false; } setImageSize(size.width, size.height); putPixels(buf, 0, 0, size.width, size.height, 0); return true; } public boolean saveSVG(OutputStream out) { ByteArrayOutputStream png_data = new ByteArrayOutputStream(); savePNG(png_data); Dimension size = new Dimension(getWidth(), getHeight()); boolean ret = svg.save(out, png_data.toByteArray(), size); try {out.close();} catch (Exception e) {} return ret; } public boolean loadXPM(String filename) { try { return loadXPM(new FileInputStream(filename)); } catch (Exception e) { return false; } } public boolean loadXPM(InputStream in) { int buf[]; Dimension size = new Dimension(0, 0); buf = new xpm().load(in, size); if (buf == null) { return false; } if (size.width == 0 || size.height == 0) { return false; } setImageSize(size.width, size.height); putPixels(buf, 0, 0, size.width, size.height, 0); return true; } /** Puts pixels . */ public void putJFImage(JFImage img, int x, int y) { int px[] = img.getPixels(); putPixels(px, x, y, img.getWidth(), img.getHeight(), 0); } /** Puts pixels unless src pixel == keyclr */ public void putJFImageKeyClr(JFImage img, int x, int y, int keyClr) { int px[] = img.getPixels(); putPixelsKeyClr(px, x, y, img.getWidth(), img.getHeight(), 0, keyClr); } /** Puts pixels blending using img alpha (dest alpha is ignored) */ public void putJFImageBlend(JFImage img, int x, int y, boolean keepAlpha) { int px[] = img.getPixels(0, 0, img.getWidth(), img.getHeight()); putPixelsBlend(px, x, y, img.getWidth(), img.getHeight(), 0, keepAlpha); } /** Puts pixels scaling image to fit */ public void putJFImageScale(JFImage img, int x, int y, int width, int height) { g2d.drawImage(img.getImage(), x, y, x+width-1, y+height-1, 0, 0, img.getWidth()-1, img.getHeight()-1, null); } /** Returns an area of this image as a new JFImage. */ public JFImage getJFImage(int x, int y, int w, int h) { JFImage ret = new JFImage(); ret.bi = bi.getSubimage(x, y, w, h); ret.init(); return ret; } public static final int ALPHA_MASK = 0xff000000; //Alpha public static final int OPAQUE = 0xff000000; public static final int TRANSPARENT = 0x00000000; public static final int RED_MASK = 0x00ff0000; public static final int GREEN_MASK = 0x0000ff00; public static final int BLUE_MASK = 0x000000ff; public static final int RGB_MASK = 0x00ffffff; /** Draws one pixel using r,g,b values (alpha assumed opaque) */ public void putPixel(int x, int y, int r, int g, int b) { buffer[y * getWidth() + x] = OPAQUE | r << 16 | g << 8 | b; } /** Draws one pixel using rgb value (alpha assumed opaque) */ public void putPixel(int x, int y, int c) { buffer[y * getWidth() + x] = OPAQUE | c; } /** Returns rgb value of pixel at x,y */ public int getPixel(int x, int y) { return buffer[y * getWidth() + x] & RGB_MASK; } /** Returns alpha value of pixel at x,y */ public int getAlpha(int x, int y) { return (buffer[y * getWidth() + x] & ALPHA_MASK) >>> 24; } /** Sets alpha value at x,y */ public void putAlpha(int x, int y, int lvl) { int offset = y * getWidth() + x; int px = buffer[offset] & RGB_MASK; px |= (lvl << 24); buffer[offset] = px; } /** Puts pixels */ public void putPixels(int[] px, int x, int y, int w, int h, int offset) { putPixels(px, x, y, w, h, offset, w); } /** Puts pixels (supports padding at end of each scan line) */ public void putPixels(int[] px, int x, int y, int w, int h, int offset, int scansize) { //do clipping int ow = w; //org width int bw = getWidth(); int bh = getHeight(); if (y < 0) { y *= -1; h -= y; if (h <= 0) { return; } offset += y * scansize; y = 0; } if (x < 0) { x *= -1; w -= x; if (w <= 0) { return; } offset += x; x = 0; } if (x + w > bw) { w = bw - x; if (w <= 0) { return; } } if (y + h > bh) { h = bh - y; if (h <= 0) { return; } } int dst = y * bw + x; if (w == bw && scansize == w) { System.arraycopy(px, offset, buffer, dst, w * h); } else { for(int i=0;i<h;i++) { System.arraycopy(px, offset, buffer, dst, w); offset += scansize; dst += bw; } } } /** Put Pixels unless src pixel == keyclr */ public void putPixelsKeyClr(int[] px, int x, int y, int w, int h, int offset, int keyclr) { //do clipping int scansize = w; int bw = getWidth(); int bh = getHeight(); if (y < 0) { y *= -1; h -= y; if (h <= 0) { return; } offset += y * scansize; y = 0; } if (x < 0) { x *= -1; w -= x; if (w <= 0) { return; } offset += x; x = 0; } if (x + w > bw) { w = bw - x; if (w <= 0) { return; } } if (y + h > bh) { h = bh - y; if (h <= 0) { return; } } int dst = y * bw + x; for(int i=0;i<h;i++) { for(int j=0;j<w;j++) { if ((px[offset + j] & RGB_MASK) != keyclr) { buffer[dst + j] = px[offset + j]; } } offset += scansize; dst += bw; } } /** Puts pixels blending using src alpha (dest alpha is ignored). * if keepAlpha is true then dest alpha is preserved. * if keepAlpha is false then src alpha is copied to dest. */ public void putPixelsBlend(int[] px, int x, int y, int w, int h, int offset, boolean keepAlpha) { //do clipping int scansize = w; int bw = getWidth(); int bh = getHeight(); if (y < 0) { y *= -1; h -= y; if (h <= 0) { return; } offset += y * scansize; y = 0; } if (x < 0) { x *= -1; w -= x; if (w <= 0) { return; } offset += x; x = 0; } if (x + w > bw) { w = bw - x; if (w <= 0) { return; } } if (y + h > bh) { h = bh - y; if (h <= 0) { return; } } int dst = y * bw + x; int sp, slvl, dp, dlvl, sa, da; for(int i=0;i<h;i++) { for(int j=0;j<w;j++) { sp = px[offset + j]; sa = sp & ALPHA_MASK; sp &= RGB_MASK; slvl = sa >>> 24; if (slvl > 0) { slvl++; } dlvl = 0x100 - slvl; dp = buffer[dst + j]; da = dp & ALPHA_MASK; dp &= RGB_MASK; buffer[dst + j] = (keepAlpha ? da : sa) + ((((dp & RED_MASK) * dlvl) >> 8) & RED_MASK) + ((((dp & GREEN_MASK) * dlvl) >> 8) & GREEN_MASK) + ((((dp & BLUE_MASK) * dlvl) >> 8) & BLUE_MASK) + ((((sp & RED_MASK) * slvl) >> 8) & RED_MASK) + ((((sp & GREEN_MASK) * slvl) >> 8) & GREEN_MASK) + ((((sp & BLUE_MASK) * slvl) >> 8) & BLUE_MASK); } offset += scansize; dst += bw; } } /** Puts pixels blending using src alpha (dest alpha is ignored) unless src pixel == keyclr. * if keepAlpha is true then dest alpha is preserved. * if keepAlpha is false then src alpha is copied to dest. */ public void putPixelsBlendKeyClr(int[] px, int x, int y, int w, int h, int offset, boolean keepAlpha, int keyclr) { //do clipping int scansize = w; int bw = getWidth(); int bh = getHeight(); if (y < 0) { y *= -1; h -= y; if (h <= 0) { return; } offset += y * scansize; y = 0; } if (x < 0) { x *= -1; w -= x; if (w <= 0) { return; } offset += x; x = 0; } if (x + w > bw) { w = bw - x; if (w <= 0) { return; } } if (y + h > bh) { h = bh - y; if (h <= 0) { return; } } int dst = y * bw + x; int sp, slvl, dp, dlvl, sa, da; for(int i=0;i<h;i++) { for(int j=0;j<w;j++) { sp = px[offset + j]; sa = sp & ALPHA_MASK; sp &= RGB_MASK; if (sp == keyclr) continue; slvl = sa >>> 24; if (slvl > 0) { slvl++; } dlvl = 0x100 - slvl; dp = buffer[dst + j]; da = dp & ALPHA_MASK; dp &= RGB_MASK; buffer[dst + j] = (keepAlpha ? da : sa) + ((((dp & RED_MASK) * dlvl) >> 8) & RED_MASK) + ((((dp & GREEN_MASK) * dlvl) >> 8) & GREEN_MASK) + ((((dp & BLUE_MASK) * dlvl) >> 8) & BLUE_MASK) + ((((sp & RED_MASK) * slvl) >> 8) & RED_MASK) + ((((sp & GREEN_MASK) * slvl) >> 8) & GREEN_MASK) + ((((sp & BLUE_MASK) * slvl) >> 8) & BLUE_MASK); } offset += scansize; dst += bw; } } /** Gets a rectangle of pixels (including alpha) */ public int[] getPixels(int x, int y, int w, int h) { int ret[] = new int[w * h]; int scansize = w; int offset = 0; int bw = getWidth(); int bh = getHeight(); if (y < 0) { y *= -1; h -= y; if (h <= 0) { return null; } offset += y * scansize; y = 0; } if (x < 0) { x *= -1; w -= x; if (w <= 0) { return null; } offset += x; x = 0; } if (x + w > bw) { w = bw - x; if (w <= 0) { return null; } } if (y + h > bh) { h = bh - y; if (h <= 0) { return null; } } int src = y * bw + x; if (w == bw && scansize == w) { System.arraycopy(buffer, src, ret, offset, w * h); } else { for(int i=0;i<h;i++) { System.arraycopy(buffer, src, ret, offset, w); offset += scansize; src += bw; } } return ret; } /** Returns a copy of the buffer */ public int[] getPixels() { int px[] = new int[buffer.length]; System.arraycopy(buffer, 0, px, 0, buffer.length); return px; } /** Returns the data buffer */ public int[] getBuffer() { return buffer; } /** Clears the image to black with opaque alpha. */ public void clear() { fill(0,0,getWidth(),getHeight(),0); } /** Fills a rectangle with clr (assumes OPAQUE alpha) */ public void fill(int x, int y, int w, int h, int clr) { fill(x,y,w,h,clr,false); } /** Fills a rectangle with clr */ public void fill(int x, int y, int w, int h, int clr, boolean hasAlpha) { if (!hasAlpha) clr |= OPAQUE; int scansize = w; int bw = getWidth(); int bh = getHeight(); if (y < 0) { y *= -1; h -= y; if (h <= 0) { return; } y = 0; } if (x < 0) { x *= -1; w -= x; if (w <= 0) { return; } x = 0; } if (x + w > bw) { w = bw - x; if (w <= 0) { return; } } if (y + h > bh) { h = bh - y; if (h <= 0) { return; } } int dst = y * bw + x; if (w == bw && scansize == w) { Arrays.fill(buffer, dst, dst + w * h, clr); } else { for(int i=0;i<h;i++) { Arrays.fill(buffer, dst, dst + w, clr); dst += bw; } } } /** Fills the alpha channel with lvl (doesn't touch rgb values) */ public void fillAlpha(int x, int y, int w, int h, int lvl) { lvl <<= 24; int scansize = w; int bw = getWidth(); int bh = getHeight(); if (y < 0) { y *= -1; h -= y; if (h <= 0) { return; } y = 0; } if (x < 0) { x *= -1; w -= x; if (w <= 0) { return; } x = 0; } if (x + w > bw) { w = bw - x; if (w <= 0) { return; } } if (y + h > bh) { h = bh - y; if (h <= 0) { return; } } int dst = y * bw + x; if (w == bw && scansize == w) { int cnt = w * h; for(int i=0;i<cnt;i++) { buffer[dst] = (buffer[dst] & RGB_MASK) | lvl; dst++; } } else { int odst; for(int i=0;i<h;i++) { odst = dst; for(int j=0;j<w;j++) { buffer[dst] = (buffer[dst] & RGB_MASK) | lvl; dst++; } dst = odst + bw; } } } /** Fills alpha channel with lvl ONLY where dest pixel == keyClr */ public void fillAlphaKeyClr(int x, int y, int w, int h, int lvl, int keyClr) { lvl <<= 24; //do clipping int scansize = w; int bw = getWidth(); int bh = getHeight(); if (y < 0) { y *= -1; h -= y; if (h <= 0) { return; } y = 0; } if (x < 0) { x *= -1; w -= x; if (w <= 0) { return; } x = 0; } if (x + w > bw) { w = bw - x; if (w <= 0) { return; } } if (y + h > bh) { h = bh - y; if (h <= 0) { return; } } int dst = y * bw + x; if (w == bw && scansize == w) { int cnt = w * h; for(int i=0;i<cnt;i++) { if ((buffer[dst] & RGB_MASK) == keyClr) { buffer[dst] &= RGB_MASK; buffer[dst] |= lvl; } dst++; } } else { for(int i=0;i<h;i++) { int odst = dst; for(int j=0;j<w;j++) { if ((buffer[dst] & RGB_MASK) == keyClr) { buffer[dst] &= RGB_MASK; buffer[dst] |= lvl; } dst++; } dst = odst + bw; } } } /** Draw a rectangle outline in clr (assumes opaque). */ public void box(int x, int y, int w, int h, int clr) { clr |= OPAQUE; g2d.setColor(new Color(clr)); g2d.drawRect(x,y,w,h); } /** Draw a horizontal line */ public void hline(int x1, int x2, int y, int clr) { line(x1, y, x2, y, clr); } /** Draw a vertical line */ public void vline(int x, int y1, int y2, int clr) { line(x, y1, x, y2, clr); } /** Draw a line */ public void line(int x1, int y1, int x2, int y2, int clr) { clr |= OPAQUE; g2d.setColor(new Color(clr)); g2d.drawLine(x1, y1, x2, y2); } /** Draw a circle/oval */ public void oval(int x, int y, int w, int h, int clr) { clr |= OPAQUE; g2d.setColor(new Color(clr)); g2d.drawOval(x, y, w, h); } /** Draw an arc */ public void arc(int x,int y, int w, int h, int startAngle, int arcAngle, int clr) { clr |= OPAQUE; g2d.setColor(new Color(clr)); g2d.drawArc(x, y, w, h, startAngle, arcAngle); } /** Draw a filled circle/oval */ public void fillOval(int x, int y, int w, int h, int clr) { clr |= OPAQUE; g2d.setColor(new Color(clr)); g2d.fillOval(x, y, w, h); } /** Draw a filled arc */ public void fillArc(int x,int y, int w, int h, int startAngle, int arcAngle, int clr) { clr |= OPAQUE; g2d.setColor(new Color(clr)); g2d.fillArc(x, y, w, h, startAngle, arcAngle); } /** Returns font metrics for a given font/text. * * @param fnt - Font * @param txt - sample text * @return * [0] = width required to draw text in font * [1] = ascent * [2] = descent * NOTE : total height required = ascent + descent * Note : add ascent to y coordinate of print() to start printing below your coordinates * For a static version see JF.java */ public int[] getFontMetrics(Font fnt, String txt) { FontRenderContext frc = g2d.getFontRenderContext(); TextLayout tl = new TextLayout(txt, fnt, frc); int ret[] = new int[3]; ret[0] = (int) tl.getBounds().getWidth(); ret[1] = (int) tl.getAscent(); ret[2] = (int) tl.getDescent(); return ret; } /** Draws text in font at x,y in clr */ public void print(Font fnt, int x, int y, String txt, int clr) { g2d.setColor(new Color(clr)); g2d.setFont(fnt); g2d.drawString(txt, x, y); //x,y = baseline of font } /** Sets the font in the Graphics object (if this JFImage is used as a JComponent) */ public void setFont(Font font) { //this is a little confusing because setFont() is inherited from JComponent which is what you probably don't want getGraphics().setFont(font); } //interface Icon public int getIconHeight() { return getHeight(); } public int getIconWidth() { return getWidth(); } public void paintIcon(Component c, Graphics g, int x, int y) { g.drawImage(getImage(), x, y, null); } /** Uses java.awt.Robot to capture and return a screen image. */ public static JFImage createScreenCapture() { return createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize())); } /** Uses java.awt.Robot to capture and return a screen image of specified rectangle. */ public static JFImage createScreenCapture(Rectangle rect) { try { JFImage img = new JFImage(); BufferedImage cap = new Robot().createScreenCapture(rect); int width = cap.getWidth(); int height = cap.getHeight(); if (cap.getType() == BufferedImage.TYPE_INT_ARGB) { img.bi = cap; img.init(); return img; } else if (cap.getType() == BufferedImage.TYPE_INT_RGB) { img.setSize(width, height); int src[] = ((DataBufferInt) cap.getRaster().getDataBuffer()).getData(); int cnt = width * height; for(int a=0;a<cnt;a++) { img.buffer[a] = src[a] | 0xff000000; } return img; } else { //slow performance JFLog.log("JFImage.createScreenCapture() unknown type=" + cap.getType()); int px[] = cap.getRGB(0, 0, width, height, null, 0, width); img.setSize(width, height); img.putPixels(px, 0, 0, width, height, 0); return img; } } catch (Exception e) { JFLog.log(e); return null; } } /** Gets color Layer (RGB) : pixels & bits */ public int[] getLayer(int bits) { int px[] = getPixels(); for(int a=0;a<px.length;a++) { px[a] &= bits; px[a] |= OPAQUE; } return px; } /** Puts color Layer (RGB) : (pixels | bits) */ public void putLayer(int px[], int bits) { if (px.length != buffer.length) return; int mask = 0xffffffff - bits; for(int a=0;a<px.length;a++) { buffer[a] &= mask; buffer[a] |= (px[a] & RGB_MASK); } } /** Gets alpha Layer as grey scale */ public int[] getAlphaLayer() { int px[] = getPixels(); int p1, p2; for(int a=0;a<px.length;a++) { p1 = px[a] & 0xff000000; p1 >>>= 8; p2 = OPAQUE | p1 | (p1 >> 8) | (p1 >> 16); px[a] = p2; } return px; } /** Puts alpha Layer from grey scale */ public void putAlphaLayer(int px[]) { //just use red color if (px.length != buffer.length) return; for(int a=0;a<px.length;a++) { buffer[a] &= RGB_MASK; buffer[a] |= (px[a] & 0x00ff0000) << 8; } } };