All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.nasa.worldwind.symbology.AbstractIconRetriever Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2012 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration.
 * All Rights Reserved.
 */

package gov.nasa.worldwind.symbology;

import gov.nasa.worldwind.util.*;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.*;
import java.io.InputStream;
import java.net.URL;

/**
 * Base class for icon retrievers. This class provides methods for loading and manipulating icons.
 * 

*

Icon retrieval

*

* Each symbol in a symbology set must have a unique identifier. The IconRetriever's job is to create a BufferedImage to * represent a symbol given the symbol identifier. Usually this means retrieving an image from the file system or the * network, and optionally manipulating the symbol (for example, changing the color to represent a hostile or friendly * entity). *

* Each instance of AbstractIconRetriever is configured with a retrieval path which specifies the location of a symbol * repository on the file system or the network. {@link #readImage(String) readImage} retrieves images relative to this * base path. The retrieval path may be a file URL to a directory on the local file system (for example, * file:///symbols/mil-std-2525). A URL to a network resource (http://myserver.com/milstd2525/), or a URL to a JAR or * ZIP file (jar:file:milstd2525-symbols.zip!). *

* A simple icon retriever might use a symbol repository that is a simple directory of PNG files, where each file name * matches a symbol identifier. Such an icon retriever could be implemented like this: *

*

 * class SimpleIconRetriever extends AbstractIconRetriever
 * {
 *     public BufferedImage createIcon(String symbolId)
 *     {
 *         // Retrieves retrievalPath/symbolId.png
 *         return this.readImage(symbolId + ".png");
 *     }
 * }
 * 
*

*

Composite icons

*

* Complicated symbols may be made up of several different graphical elements. {@link * #drawImage(java.awt.image.BufferedImage, java.awt.image.BufferedImage) drawImage} helps build a complex symbol from * simple pieces. For example, if a symbol is composed of a frame and an icon, the icon retriever could load the frame * and icon independently, draw the icon over the frame, and return the composite image: *

 * // Load the frame and icon as separate pieces.
 * BufferedImage frame = this.readImage("path/to/frame.png");
 * BufferedImage icon = this.readImage("path/to/icon.png");
 *
 * // Draw the icon on top of the frame. This call modifies the frame image.
 * BufferedImage fullImage = this.drawImage(icon, frame);
 *
 * // Return the composite image.
 * return fullImage;
 * 
*

*

Changing the color of an icon

*

* {@link #multiply(java.awt.image.BufferedImage, java.awt.Color) multiply} can change the color of an image by * multiplying each pixel in the image by a color. The multiplication color will replace any white pixels and black * pixels will be unaffected. For example, a symbol set in which hostile symbols are drawn in red and friendly symbols * are drawn in green could be implemented by creating white icons, and then multiplying by either red or green when the * retriever constructs the icon. * * @author ccrick * @version $Id: AbstractIconRetriever.java 1171 2013-02-11 21:45:02Z dcollins $ */ public abstract class AbstractIconRetriever implements IconRetriever { /** Path in the file system or network to the symbol repository. */ protected String retrieverPath; /** * Create a new retriever that will retrieve icons from the specified location. The retrieval path may be a file URL * to a directory on the local file system (for example, file:///symbols/mil-std-2525). A URL to a network resource * (http://myserver.com/milstd2525/), or a URL to a JAR or ZIP file (jar:file:milstd2525-symbols.zip!). * * @param retrieverPath URL to to the base symbol directory on the local file system or the network. */ public AbstractIconRetriever(String retrieverPath) { if (retrieverPath == null || retrieverPath.length() == 0) { String msg = Logging.getMessage("nullValue.PathIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } this.retrieverPath = retrieverPath; } /** * Indicates the file system or network path of the symbol directory.. The retrieval path may be a file URL to a * directory on the local file system (for example, file:///symbols/mil-std-2525). A URL to a network resource ( * http://myserver.com/milstd2525/), or a URL to a JAR or ZIP file (jar:file:milstd2525-symbols.zip!). * * @return File system or network path to symbol repository. */ public String getRetrieverPath() { return this.retrieverPath; } /** * Indicates whether or not this retriever is equal to another. * * @param o Object to compare. * * @return {@code true} if {@code o} is an instance of AbstractIconRetriever and has the same retrieval path as this * retriever. */ @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || this.getClass() != o.getClass()) return false; AbstractIconRetriever that = (AbstractIconRetriever) o; return this.retrieverPath != null ? this.retrieverPath.equals(that.retrieverPath) : that.retrieverPath == null; } /** {@inheritDoc} */ @Override public int hashCode() { return this.retrieverPath != null ? this.retrieverPath.hashCode() : 0; } /** * Load an image from a local or remote path. The image path is interpreted relative to the retrieval path. For * example, if the retrieval path is http://myserver.com/milstd2525/, calling readImage("icon.png") will attempt to * retrieve an image from http://myserver.com/milstd2525/icon.png. * * @param path Path to the icon resource, relative to this retriever's retrieval path. * * @return The requested icon as a BufferedImage, or null if the icon cannot be loaded. */ protected BufferedImage readImage(String path) { if (path == null) { String msg = Logging.getMessage("nullValue.PathIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } StringBuilder sb = new StringBuilder(); sb.append(WWIO.stripTrailingSeparator(this.getRetrieverPath())); sb.append("/"); sb.append(WWIO.stripLeadingSeparator(path)); InputStream is = null; try { URL url = WWIO.makeURL(sb.toString()); if (url != null) return ImageIO.read(url); is = WWIO.openFileOrResourceStream(sb.toString(), this.getClass()); if (is != null) return ImageIO.read(is); } catch (Exception e) { String msg = Logging.getMessage("generic.ExceptionWhileReading", sb.toString()); Logging.logger().fine(msg); } finally { WWIO.closeStream(is, sb.toString()); } return null; } /** * Draw one image into another image. The image is drawn at location (0, 0). * * @param src Image to draw. * @param dest Image to draw into. * * @return {@code dest} BufferedImage. */ protected BufferedImage drawImage(BufferedImage src, BufferedImage dest) { if (src == null) { String msg = Logging.getMessage("nullValue.SourceIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } if (dest == null) { String msg = Logging.getMessage("nullValue.DestinationIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } Graphics2D g = null; try { g = dest.createGraphics(); g.drawImage(src, 0, 0, null); } finally { if (g != null) g.dispose(); } return dest; } /** * Multiply each pixel in an image by a color. White pixels are replaced by the multiplication color, black pixels * are unaffected. * * @param image Image to operate on. * @param color Color to multiply by. * * @see #replaceColor(java.awt.image.BufferedImage, java.awt.Color) */ protected void multiply(BufferedImage image, Color color) { if (image == null) { String msg = Logging.getMessage("nullValue.ImageIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } if (color == null) { String msg = Logging.getMessage("nullValue.ColorIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } int w = image.getWidth(); int h = image.getHeight(); if (w == 0 || h == 0) return; int[] pixels = new int[w]; int c = color.getRGB(); float ca = ((c >> 24) & 0xff) / 255f; float cr = ((c >> 16) & 0xff) / 255f; float cg = ((c >> 8) & 0xff) / 255f; float cb = (c & 0xff) / 255f; for (int y = 0; y < h; y++) { image.getRGB(0, y, w, 1, pixels, 0, w); for (int x = 0; x < w; x++) { int s = pixels[x]; float sa = ((s >> 24) & 0xff) / 255f; float sr = ((s >> 16) & 0xff) / 255f; float sg = ((s >> 8) & 0xff) / 255f; float sb = (s & 0xff) / 255f; int fa = (int) (ca * sa * 255 + 0.5); int fr = (int) (cr * sr * 255 + 0.5); int fg = (int) (cg * sg * 255 + 0.5); int fb = (int) (cb * sb * 255 + 0.5); pixels[x] = (fa & 0xff) << 24 | (fr & 0xff) << 16 | (fg & 0xff) << 8 | (fb & 0xff); } image.setRGB(0, y, w, 1, pixels, 0, w); } } /** * Replace the color of each pixel in an image. This method retains the alpha channel of each pixel, but completely * replaces the red, green, and blue components with the replacement color. Unlike {@link * #multiply(java.awt.image.BufferedImage, java.awt.Color) multiply}, this method changes the color of all pixels. * * @param image Image to operate on. * @param color Color to apply to to each pixel. * * @see #multiply(java.awt.image.BufferedImage, java.awt.Color) */ protected void replaceColor(BufferedImage image, Color color) { if (image == null) { String msg = Logging.getMessage("nullValue.ImageIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } if (color == null) { String msg = Logging.getMessage("nullValue.ColorIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } int w = image.getWidth(); int h = image.getHeight(); if (w == 0 || h == 0) return; int[] pixels = new int[w]; int c = color.getRGB(); float cr = ((c >> 16) & 0xff) / 255f; float cg = ((c >> 8) & 0xff) / 255f; float cb = (c & 0xff) / 255f; for (int y = 0; y < h; y++) { image.getRGB(0, y, w, 1, pixels, 0, w); for (int x = 0; x < w; x++) { int s = pixels[x]; float sa = ((s >> 24) & 0xff) / 255f; int fa = (int) (sa * 255 + 0.5); int fr = (int) (cr * 255 + 0.5); int fg = (int) (cg * 255 + 0.5); int fb = (int) (cb * 255 + 0.5); pixels[x] = (fa & 0xff) << 24 | (fr & 0xff) << 16 | (fg & 0xff) << 8 | (fb & 0xff); } image.setRGB(0, y, w, 1, pixels, 0, w); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy