// ********************************************************************** // ********************************************************************** package com.bbn.openmap.layer.location.generic; import java.awt.Toolkit; import java.awt.Color; import java.awt.Font; import java.awt.Polygon; import java.awt.font.FontRenderContext; import java.awt.font.TextLayout; import java.awt.Image; import java.awt.AlphaComposite; import java.awt.image.BufferedImage; import java.awt.Graphics2D; import java.awt.RenderingHints; import javax.swing.ImageIcon; import java.util.Map; import java.util.Hashtable; //------------------------------ import java.io.File; import javax.imageio.ImageIO; //------------------------------ import com.bbn.openmap.omGraphics.OMGraphic; import com.bbn.openmap.omGraphics.OMRaster; import com.bbn.openmap.layer.location.Location; import com.bbn.openmap.layer.location.BasicLocation; import com.bbn.openmap.layer.location.URLRasterLocation; /** * * @See http://weblogs.java.net/blog/kirillcool/archive/2005/02/how_to_create_y.html */ public class IconFactory { protected static Map imageCache; static { imageCache = new Hashtable(); } // ------------------------------ public IconFactory() { } /** * Create an OMRaster at a latitude/longitude, from a image URL. * * @param lat latitide in decimal degrees * @param lon longitude in decimal degrees. * @param iconURL a URL for an image */ public static OMRaster getIconRaster(float lat, float lon, ImageIcon icon) { OMRaster retVal = null; if (icon != null) { int offX = icon.getIconWidth() / 2; int offY = icon.getIconHeight() / 2; retVal = new OMRaster(lat, lon, -offX, -offY, icon); } return retVal; } //////////////////////////////////////////////////////////////////// /** * Method: getBaseImage * This method does... * @param width * @param height * @return BufferedImage * @ */ public static BufferedImage getBaseImage(int width, int height) { BufferedImage retVal = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); /* // set completely transparent for (int col = 0; col < width; col++) { for (int row = 0; row < height; row++) { retVal.setRGB(col, row, 0x0);} return retVal; } // for */ Graphics2D g = (Graphics2D) retVal.getGraphics(); g.setComposite(AlphaComposite.Src); g.setColor(new Color(0)); g.fillRect(0, 0, width, height); return retVal; }// Method: getBaseImage //////////////////////////////////////////////////////////////////// /** * Method: getRenderingContext * This method does... * @param image * @param param2 * @return Graphics2D * @ */ public static Graphics2D getRenderingContext(BufferedImage image) { Graphics2D retVal = (Graphics2D) image.getGraphics(); retVal.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); retVal.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); return retVal; }// Method: getRenderingContext //////////////////////////////////////////////////////////////////// /** * Method: makeDot * This method does... * @param image * @param dim Dimention * @return void * @ */ public static void makeDot(BufferedImage image, int imagedim) { // create a whitish spot in the left-top corner of the icon double id4 = imagedim / 4.0; double spotX = id4; double spotY = id4; for (int col = 0; col < imagedim; col++) { for (int row = 0; row < imagedim; row++) { // distance to spot double dx = col - spotX; double dy = row - spotY; double dist = Math.sqrt(dx * dx + dy * dy); // distance of 0.0 - comes 90% to Color.white // distance of ICON_DIMENSION - stays the same if (dist > imagedim) { dist = imagedim; } int currColor = image.getRGB(col, row); int transp = (currColor >>> 24) & 0xFF; int oldR = (currColor >>> 16) & 0xFF; int oldG = (currColor >>> 8) & 0xFF; int oldB = (currColor >>> 0) & 0xFF; double coef = 0.9 - 0.9 * dist / imagedim; int dr = 255 - oldR; int dg = 255 - oldG; int db = 255 - oldB; int newR = (int) (oldR + coef * dr); int newG = (int) (oldG + coef * dg); int newB = (int) (oldB + coef * db); int newColor = (transp << 24) | (newR << 16) | (newG << 8) | newB; image.setRGB(col, row, newColor); } } }// Method: makeDot //////////////////////////////////////////////////////////////////// /** * Method: drawLetter * This method does... * @param graphics * @param letter * @param imagedim * @return void * @ */ public static void drawLetter(Graphics2D graphics, char letter, int imagedim, Color fgcol) { letter = Character.toUpperCase(letter); graphics.setFont(new Font("Arial", Font.BOLD, imagedim-5)); FontRenderContext frc = graphics.getFontRenderContext(); TextLayout mLayout = new TextLayout("" + letter, graphics.getFont(), frc); float x = (float) (-.5 + (imagedim - mLayout.getBounds() .getWidth()) / 2); float y = imagedim - (float) ((imagedim - mLayout.getBounds().getHeight()) / 2); graphics.setColor(fgcol); // draw the letter graphics.drawString("" + letter, x, y); }// Method: DrawLetter //////////////////////////////////////////////////////////////////// /** * Method: drawLetter * This method does... * @param graphics * @param letter * @param imagedim * @return void * @ */ public static void drawString(Graphics2D graphics, String str, int imagedim) { // str = Character.toUpperCase(str); graphics.setFont(new Font("Arial", Font.BOLD, imagedim-5)); FontRenderContext frc = graphics.getFontRenderContext(); TextLayout mLayout = new TextLayout(str, graphics.getFont(), frc); float x = (float) (-.5 + (imagedim - mLayout.getBounds().getWidth()) / 2); float y = imagedim - (float) ((imagedim - mLayout.getBounds().getHeight()) / 2); // draw the letter graphics.drawString(str, x, y); }// Method: DrawLetter //////////////////////////////////////////////////////////////////// /** * Method: drawPlus * This method does... * @param graphics * @param height * @return void * @ */ public static void drawPlus(Graphics2D graphics, int width, int height) { // int height = 6; BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); // set completely transparent for (int col = 0; col < width; col++) { for (int row = 0; row < height; row++) { image.setRGB(col, row, 0x0); } } }// Method: drawPlus //////////////////////////////////////////////////////////////////// /** * Method: drawArrow * Set antialiasing hint and draw an arrow of specified color: * @param graphics * @param color * @param width * @return void * @ */ public static void drawArrow(Graphics2D graphics, Color color, int width) { graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // draw arrow Polygon pol = new Polygon(); int ya = 3; pol.addPoint(1, ya); pol.addPoint(width / 2 + 3, ya); pol.addPoint(width / 2 + 3, ya + 2); pol.addPoint(width - 1, ya); pol.addPoint(width / 2 + 3, ya - 2); pol.addPoint(width / 2 + 3, ya); graphics.setColor(color); graphics.drawPolygon(pol); }// Method: drawArrow //////////////////////////////////////////////////////////////////// /** * Method: drawHalo * And now for the tricky part - we have to compute the halo. * Here, if an arrow pixel was completely opaque, it should have * less transparent halo than arrow pixel that was only partly * opaque (as on arrow's head for example). * Here, we create another image with the halo footprint, * and then draw the original arrow on top of it. * Each arrow pixel contributes to its 8 neighbouring pixels. * The final opacity of the halo footprint is the maximal opacity of * all neighbouring arrow pixels: * @param graphics * @param color * @return void * @ */ public static void drawHalo(BufferedImage image, Color color) { int width = image.getWidth(); int height = image.getHeight(); // create semi-transparent halo around arrow (to make it stand // out) /* BufferedImage fimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); // set completely transparent for (int col = 0; col < width; col++) { for (int row = 0; row < height; row++) { fimage.setRGB(col, row, 0x0); } } */ BufferedImage fimage = getBaseImage(width, height); Graphics2D fgraphics = (Graphics2D) fimage.getGraphics(); for (int col = 0; col < width; col++) { int xs = Math.max(0, col - 1); int xe = Math.min(width - 1, col + 1); for (int row = 0; row < height; row++) { int ys = Math.max(0, row - 1); int ye = Math.min(height - 1, row + 1); int currColor = image.getRGB(col, row); int opacity = (currColor >>> 24) & 0xFF; if (opacity > 0) { // mark all pixels in 3*3 area for (int x = xs; x <= xe; x++) { for (int y = ys; y <= ye; y++) { int oldOpacity = (fimage.getRGB(x, y) >>> 24) & 0xFF; int newOpacity = Math.max(oldOpacity, opacity); // set semi-transparent white int newColor = (newOpacity << 24) | (255 << 16) | (255 << 8) | 255; fimage.setRGB(x, y, newColor); } } } } } // reduce opacity of all pixels by 30% for (int col = 0; col < width; col++) { for (int row = 0; row < height; row++) { int oldOpacity = (fimage.getRGB(col, row) >>> 24) & 0xFF; int newOpacity = (int)(0.7*oldOpacity); int newColor = (newOpacity << 24) | (255 << 16) | (255 << 8) | 255; fimage.setRGB(col, row, newColor); } } // draw the original arrow image on top of the halo fgraphics.drawImage(image, 0, 0, null); //Going back to the original image (the letter and optional plus sign) - draw the arrow image on top of it: // BufferedImage arrowImage = getArrowImage(color, height); // graphics.drawImage(arrowImage, 0, height - arrowImage.getHeight(), null); // drawArrow(graphics, }// Method: drawHalo //////////////////////////////////////////////////////////////////// /** * Method: getBasicIcon * This method does... * @param imagedim * @param height * @return BufferedImage * @ */ public static BufferedImage getBasicImage(int imagedim, Color col) { return getBasicImage(imagedim, col, true);} // ------------------------ public static BufferedImage getBasicImage(int imagedim, Color col, boolean drawoutline) { BufferedImage retVal = getBaseImage(imagedim, imagedim); if(retVal != null) { Graphics2D graphics = getRenderingContext(retVal); graphics.setColor(col); graphics.fillOval(0, 0, imagedim - 1, imagedim - 1); makeDot(retVal, imagedim); // draw outline of the icon if(drawoutline) { graphics.setColor(Color.black); graphics.drawOval(0, 0, imagedim - 1, imagedim - 1); } } return retVal; }// Method: getBasicIcon //////////////////////////////////////////////////////////////////// /** * Method: getIcon * This method does... * @param imagedim * @param height * @return BufferedImage * @ */ public static Image getImage(int imagedim, String colname, Color col, char letter) { return getImage(imagedim, colname, col, letter, false);} public static Image getImage(int imagedim, String colname, Color col, char letter, boolean save) { String imagename = colname + Integer.toString(imagedim) +'_'+ letter; imagename = imagename.toUpperCase(); Image retVal = (Image)imageCache.get(imagename); if(retVal == null) { BufferedImage opImage = IconFactory.getBasicImage(imagedim, col, false); Graphics2D graphics = IconFactory.getRenderingContext(opImage); if(letter != ' ') { IconFactory.drawLetter(graphics, Character.toUpperCase(letter), imagedim, Color.BLACK);} // IconFactory.drawString(graphics, "NW", imagedim); if(save) { // String iconPath = "/J_Projects/GIS/openmap-4.6.3/src/openmap/com/bbn/openmap/layer/location/generic/"; String iconPath = "./"; File outputFile = new File(iconPath + imagename+".png"); try { ImageIO.write(opImage, "PNG", outputFile);} catch (Exception e) { throw new RuntimeException(e); } } // if(save) retVal = Toolkit.getDefaultToolkit().createImage(opImage.getSource()); imageCache.put(imagename, retVal); } return retVal; } }