Package au.net.causal.projo.prefs.transform

Source Code of au.net.causal.projo.prefs.transform.ColorToStringTransformer

package au.net.causal.projo.prefs.transform;

import java.awt.Color;
import java.awt.Transparency;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import au.net.causal.projo.prefs.PreferencesException;

/**
* Converts between {@link Color} values and strings.
* <p>
*
* The string representation of a color closely resembles that which is used in CSS definitions.
* The following syntaxes are supported:
*
* <ul>
*   <li>
*     {@literal #}(hex): e.g. <code>#FF0000</code></li>.  Alpha is not supported in this representation, and is assumed to be fully opaque.  Both the
*     single-digit and double-digit per component format is allowed.
*   </li>
*   <li>
*     rgb() and rgba() functions: Each component can be either an integer 0-255, a numeric percentage with trailing '%' sign, or
*     a floating point number (with mandatory decimal point) between 0.0 and 1.0.
*   </li>
*   <li>
*     hsl() or hsla() functions: Components are defined the same as rgb() and rgba() functions.
*   </li>
* </ul>
* <p>
*
* For converting to strings, the following rules apply:
* <ul>
*   <li>The double-digit hex form is used if the color is fully opaque</li>
*   <li>Otherwise, the rgba() function is used with floating point components</li>
* </ul>
*
* @author prunge
*/
public class ColorToStringTransformer extends GenericToStringTransformer<Color>
{
  private static final Logger log = LoggerFactory.getLogger(ColorToStringTransformer.class);
 
  public ColorToStringTransformer()
  {
    super(Color.class, true);
  }
 
  private float[] interpretColorFunction(String s, String functionName, int numArgs)
  {
    String expectedStart = functionName + "(";
   
    if (!s.startsWith(expectedStart))
      return(null);
   
    int endBracketIndex = s.indexOf(')');
    if (endBracketIndex < 0)
      return(null);
   
    String body = s.substring(expectedStart.length(), endBracketIndex);
   
    String[] sArgs = body.split(Pattern.quote(","));
    if (sArgs.length != numArgs)
      return(null);
   
    //Interpret each arg
    //Possible forms:
    // - int value between 0 and 255 (clamped)
    // - numeric percentage value with trailing '%' sign
    // - floating point value between 0.0 and 1.0 (clamped)
    float[] args = new float[numArgs];
    for (int i = 0; i < numArgs; i++)
    {
      String sArg = sArgs[i];
      sArg = sArg.trim();
     
      //Percentage
      if (sArg.endsWith("%"))
      {
        String sNum = sArg.substring(0, sArg.length() - 1);
        sNum = sNum.trim();
        try
        {
          float percent = Float.parseFloat(sNum);
          args[i] = percent / 100.0f;
        }
        catch (NumberFormatException e)
        {
          log.debug("Failed to parse number " + sNum + " in " + s + ".", e);
          return(null);
        }
      }
     
      //Floating point number
      else if (sArg.contains("."))
      {
        try
        {
          args[i] = Float.parseFloat(sArg);
        }
        catch (NumberFormatException e)
        {
          log.debug("Failed to parse number " + sArg + " in " + s + ".", e);
          return(null);
        }
      }
      else
      {
        //Integer number
        try
        {
          args[i] = Integer.parseInt(sArg) / 255.0f;
        }
        catch (NumberFormatException e)
        {
          log.debug("Failed to parse number " + sArg + " in " + s + ".", e);
          return(null);
        }
      }
    }
   
    return(args);
  }

  @Override
  protected Color stringToValue(String s) throws PreferencesException
  {
    if (StringUtils.isEmpty(s))
      return(null);
   
    s = s.trim();
   
    //Formats supported:
   
    //rgba(r, g, b, a)
    float[] args = interpretColorFunction(s, "rgba", 4);
    if (args != null)
      return(new Color(args[0], args[1], args[2], args[3]));
   
    //rgb(r, g, b)
    args = interpretColorFunction(s, "rgb", 3);
    if (args != null)
      return(new Color(args[0], args[1], args[2]));
   
    //hsla(h, s, l, a)
    args = interpretColorFunction(s, "hsla", 4);
    if (args != null)
    {
      Color hsbColor = Color.getHSBColor(args[0], args[1], args[2]);
      return(new Color(hsbColor.getRed(), hsbColor.getGreen(), hsbColor.getBlue(), (int)(args[3] * 255)));
    }
   
    //hsl(h, s, l)
    args = interpretColorFunction(s, "hsl", 3);
    if (args != null)
      return(Color.getHSBColor(args[0], args[1], args[2]));
   
    //hex form with preceding #
    String hexForm = s;
    if (hexForm.startsWith("#"))
      hexForm = hexForm.substring(1);
   
    //Single-digit hex representation, convert to double digit form
    if (hexForm.length() == 3)
    {
      hexForm = StringUtils.repeat(hexForm.charAt(0), 2) +
            StringUtils.repeat(hexForm.charAt(1), 2) +
            StringUtils.repeat(hexForm.charAt(2), 2);
    }
   
    //Double-digit hex representation
    try
    {
      int intForm = Integer.parseInt(hexForm, 16);
      return(new Color(intForm));
    }
    catch (NumberFormatException e)
    {
      log.debug("Not in hex form: " + s, e);
    }
   
    //If we get here we could not interpret as color
    throw new PreferencesException("Failed to parse '" + s + "' as a Color.");
  }
 
  @Override
  protected String valueToString(Color value) throws PreferencesException
  {
    if (value == null)
      return(null);
   
    //If fully opaque (no alpha translucency) then write out in hex form
    if (isOpaque(value))
    {
      return("#" + StringUtils.leftPad(Integer.toHexString(value.getRed()), 2, "0") +
            StringUtils.leftPad(Integer.toHexString(value.getGreen()), 2, "0") +
            StringUtils.leftPad(Integer.toHexString(value.getBlue()), 2, "0"));
    }
   
    //Otherwise use rgba representation
    float[] components = value.getRGBComponents(null);
    return("rgba(" + components[0] + ", " + components[1] + ", " + components[2] + ", " + components[3] + ")");
  }
 
  private static boolean isOpaque(Color color)
  {
    return(color.getTransparency() == Transparency.OPAQUE);
  }
}
TOP

Related Classes of au.net.causal.projo.prefs.transform.ColorToStringTransformer

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.