Package org.vfny.geoserver.config

Source Code of org.vfny.geoserver.config.PaletteManager

/* Copyright (c) 2001, 2007 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, availible at the root
* application directory.
*/
package org.vfny.geoserver.config;

import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.IndexColorModel;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Iterator;
import java.util.logging.Logger;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.stream.ImageInputStream;

import org.geotools.image.palette.InverseColorMapOp;
import org.geotools.util.SoftValueHashMap;
import org.vfny.geoserver.global.GeoserverDataDirectory;

/**
* Allows access to palettes (implemented as {@link IndexColorModel} classes)
*
* @author Andrea Aime - TOPP
* @author Simone Giannecchini - GeoSolutions
*
*/
public class PaletteManager {
    private static final Logger LOG = org.geotools.util.logging.Logging.getLogger("PaletteManager");

    /**
     * Safe palette, a 6x6x6 color cube, followed by a 39 elements gray scale,
     * and a final transparent element. See the internet safe color palette for
     * a reference <a href="http://www.intuitive.com/coolweb/colors.html">
     */
    public static final String SAFE = "SAFE";
    public static final IndexColorModel safePalette = buildDefaultPalette();
    static SoftValueHashMap paletteCache = new SoftValueHashMap();

  private static InverseColorMapOp safePaletteInversion= new InverseColorMapOp(safePalette);
    /**
     * TODO: we should probably provide the data directory as a constructor
     * parameter here
     */
    private PaletteManager() {
    }

  /**
   * Loads a PaletteManager
   *
   * @param name
   * @return
   * @throws Exception
   */
  public static InverseColorMapOp getPalette(String name)
      throws Exception {
    // check for safe paletteInverter
    if ("SAFE".equals(name.toUpperCase())) {
      return safePaletteInversion;
    }

    // check for cached one, making sure it's not stale
    final PaletteCacheEntry entry = (PaletteCacheEntry) paletteCache
        .get(name);
    if (entry != null) {
      if (entry.isStale()) {
        paletteCache.remove(name);
      } else {
        return entry.eicm;
      }
    }

    // ok, load it. for the moment we load palettes from .png and .gif
    // files, but we may want to extend this ability to other file formats
    // (Gimp palettes for example), in this case we'll adopt the classic
    // plugin approach using either the Spring context of the SPI

    // hum... loading the paletteDir could be done once, but then if the
    // users
    // adds the paletteInverter dir with a running Geoserver, we won't find it
    // anymore...
    final File root = GeoserverDataDirectory.getGeoserverDataDirectory();
    final File paletteDir = GeoserverDataDirectory.findConfigDir(root,
        "palettes");
    final String[] names = new String[] { name + ".gif", name + ".png",
        name + ".pal", name + ".tif" };
    final File[] paletteFiles = paletteDir.listFiles(new FilenameFilter() {
      public boolean accept(File dir, String name) {
        for (int i = 0; i < names.length; i++) {
          if (name.toLowerCase().equals(names[i])) {
            return true;
          }
        }

        return false;
      }
    });

    // scan the files found (we may have multiple files with different
    // extensions and return the first paletteInverter you find
    for (int i = 0; i < paletteFiles.length; i++) {
      final File file = paletteFiles[i];
      final String fileName = file.getName();
      if (fileName.endsWith("pal")) {
        final IndexColorModel icm = new PALFileLoader(file)
            .getIndexColorModel();

        if (icm != null) {
          final InverseColorMapOp eicm = new InverseColorMapOp(
              icm);
          paletteCache.put(name, new PaletteCacheEntry(file, eicm));
          return eicm;
        }
      } else {
        ImageInputStream iis = ImageIO.createImageInputStream(file);
                final Iterator it = ImageIO.getImageReaders(iis);
        if (it.hasNext()) {
          final ImageReader reader = (ImageReader) it.next();
          reader.setInput(iis);
          final ColorModel cm = ((ImageTypeSpecifier) reader
              .getImageTypes(0).next()).getColorModel();
          if (cm instanceof IndexColorModel) {
            final IndexColorModel icm = (IndexColorModel) cm;
            final InverseColorMapOp eicm = new InverseColorMapOp(
                icm);
            paletteCache.put(name,
                new PaletteCacheEntry(file, eicm));
            return eicm;
          }
        }
      }
      LOG
          .warning("Skipping paletteInverter file "
              + file.getName()
              + " since color model is not indexed (no 256 colors paletteInverter)");
    }

    return null;
  }

  /**
   * Builds the internet safe paletteInverter
   */
  static IndexColorModel buildDefaultPalette() {
    int[] cmap = new int[256];

    // Create the standard 6x6x6 color cube (all elements do cycle
    // between 00, 33, 66, 99, CC and FF, the decimal difference is 51)
    // The color is made of alpha, red, green and blue, in this order, from
    // the most significant bit onwards.
    int i = 0;
    int opaqueAlpha = 255 << 24;

    for (int r = 0; r < 256; r += 51) {
      for (int g = 0; g < 256; g += 51) {
        for (int b = 0; b < 256; b += 51) {
          cmap[i] = opaqueAlpha | (r << 16) | (g << 8) | b;
          i++;
        }
      }
    }

    // The gray scale. Make sure we end up with gray == 255
    int grayIncr = 256 / (255 - i);
    int gray = 255 - ((255 - i - 1) * grayIncr);

    for (; i < 255; i++) {
      cmap[i] = opaqueAlpha | (gray << 16) | (gray << 8) | gray;
      gray += grayIncr;
    }

    // setup the transparent color (alpha == 0)
    cmap[255] = (255 << 16) | (255 << 8) | 255;

    // create the color model
    return new IndexColorModel(8, 256, cmap, 0, true, 255,
        DataBuffer.TYPE_BYTE);
  }

  /**
   * An entry in the paletteInverter cache. Can determine wheter it's stale or not,
   * too
   */
  private static class PaletteCacheEntry {
    File file;

    long lastModified;

    InverseColorMapOp eicm;

    public PaletteCacheEntry(File file,
        InverseColorMapOp eicm) {
      this.file = file;
      this.eicm = eicm;
      this.lastModified = file.lastModified();
    }

    /**
     * Returns true if the backing file does not exist any more, or has been
     * modified
     *
     * @return
     */
    public boolean isStale() {
      return !file.exists() || (file.lastModified() != lastModified);
    }
  }
}
TOP

Related Classes of org.vfny.geoserver.config.PaletteManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.