public String generate(Iterable<Map> optionsList) {
   List<String> components = new ArrayList<String>();
   for (Map options : optionsList) {
     components.add(generate(options));
   }
   return StringUtils.join(components, "/");
 }
 @Override
 public String toString() {
   ArrayList<String> rects = new ArrayList<String>();
   for (Rectangle rect : this.coordinates) {
     rects.add(rect.x + "," + rect.y + "," + rect.width + "," + rect.height);
   }
   return StringUtils.join(rects, "|");
 }
  private static String normRangeValue(Object objectValue) {
    if (objectValue == null) return null;
    String value = objectValue.toString();
    if (StringUtils.isEmpty(value)) return null;

    Matcher matcher = RANGE_VALUE_RE.matcher(value);

    if (!matcher.matches()) {
      return null;
    }

    String modifier = "";
    if (matcher.groupCount() == 2 && !StringUtils.isEmpty(matcher.group(2))) {
      modifier = "p";
    }
    return matcher.group(1) + modifier;
  }
 public Coordinates(String stringCoords) throws IllegalArgumentException {
   Collection<Rectangle> coordinates = new ArrayList<Rectangle>();
   for (String stringRect : stringCoords.split("\\|")) {
     if (StringUtils.isEmpty(stringRect)) continue;
     String[] elements = stringRect.split(",");
     if (elements.length != 4) {
       throw new IllegalArgumentException(
           String.format(
               "Must supply exactly 4 values for coordinates (x,y,width,height) %d supplied: %s",
               elements.length, stringRect));
     }
     coordinates.add(
         new Rectangle(
             Integer.parseInt(elements[0]),
             Integer.parseInt(elements[1]),
             Integer.parseInt(elements[2]),
             Integer.parseInt(elements[3])));
   }
   this.coordinates = coordinates;
 }
  public String generate(Map options) {
    boolean isResponsive =
        ObjectUtils.asBoolean(options.get("responsive_width"), defaultIsResponsive);

    String size = (String) options.get("size");
    if (size != null) {
      String[] size_components = size.split("x");
      options.put("width", size_components[0]);
      options.put("height", size_components[1]);
    }
    String width = this.htmlWidth = ObjectUtils.asString(options.get("width"));
    String height = this.htmlHeight = ObjectUtils.asString(options.get("height"));
    boolean hasLayer =
        StringUtils.isNotBlank((String) options.get("overlay"))
            || StringUtils.isNotBlank((String) options.get("underlay"));

    String crop = (String) options.get("crop");
    String angle = StringUtils.join(ObjectUtils.asArray(options.get("angle")), ".");

    boolean noHtmlSizes =
        hasLayer || StringUtils.isNotBlank(angle) || "fit".equals(crop) || "limit".equals(crop);
    if (width != null
        && (width.equals("auto") || Float.parseFloat(width) < 1 || noHtmlSizes || isResponsive)) {
      this.htmlWidth = null;
    }
    if (height != null && (Float.parseFloat(height) < 1 || noHtmlSizes || isResponsive)) {
      this.htmlHeight = null;
    }

    String background = (String) options.get("background");
    if (background != null) {
      background = background.replaceFirst("^#", "rgb:");
    }

    String color = (String) options.get("color");
    if (color != null) {
      color = color.replaceFirst("^#", "rgb:");
    }

    List transformations = ObjectUtils.asArray(options.get("transformation"));
    boolean allNamed = true;
    for (Object baseTransformation : transformations) {
      if (baseTransformation instanceof Map) {
        allNamed = false;
        break;
      }
    }
    String namedTransformation = null;
    if (allNamed) {
      namedTransformation = StringUtils.join(transformations, ".");
      transformations = new ArrayList();
    } else {
      List ts = transformations;
      transformations = new ArrayList();
      for (Object baseTransformation : ts) {
        String transformationString;
        if (baseTransformation instanceof Map) {
          transformationString = generate((Map) baseTransformation);
        } else {
          Map map = new HashMap();
          map.put("transformation", baseTransformation);
          transformationString = generate(map);
        }
        transformations.add(transformationString);
      }
    }

    String flags = StringUtils.join(ObjectUtils.asArray(options.get("flags")), ".");

    String duration = normRangeValue(options.get("duration"));
    String startOffset = normRangeValue(options.get("start_offset"));
    String endOffset = normRangeValue(options.get("end_offset"));
    String[] offset = splitRange(options.get("offset"));
    if (offset != null) {
      startOffset = normRangeValue(offset[0]);
      endOffset = normRangeValue(offset[1]);
    }

    String videoCodec = processVideoCodecParam(options.get("video_codec"));
    String dpr =
        ObjectUtils.asString(options.get("dpr"), null == defaultDPR ? null : defaultDPR.toString());

    SortedMap<String, String> params = new TreeMap<String, String>();
    params.put("a", angle);
    params.put("b", background);
    params.put("c", crop);
    params.put("co", color);
    params.put("dpr", dpr);
    params.put("du", duration);
    params.put("eo", endOffset);
    params.put("fl", flags);
    params.put("h", height);
    params.put("so", startOffset);
    params.put("t", namedTransformation);
    params.put("vc", videoCodec);
    params.put("w", width);

    String[] simple_params =
        new String[] {
          "ac", "audio_codec",
          "af", "audio_frequency",
          "bo", "border",
          "br", "bit_rate",
          "cs", "color_space",
          "d", "default_image",
          "dl", "delay",
          "dn", "density",
          "e", "effect",
          "f", "fetch_format",
          "g", "gravity",
          "l", "overlay",
          "o", "opacity",
          "p", "prefix",
          "pg", "page",
          "q", "quality",
          "r", "radius",
          "u", "underlay",
          "vs", "video_sampling",
          "x", "x",
          "y", "y",
          "z", "zoom"
        };

    for (int i = 0; i < simple_params.length; i += 2) {
      params.put(simple_params[i], ObjectUtils.asString(options.get(simple_params[i + 1])));
    }
    List<String> components = new ArrayList<String>();
    for (Map.Entry<String, String> param : params.entrySet()) {
      if (StringUtils.isNotBlank(param.getValue())) {
        components.add(param.getKey() + "_" + param.getValue());
      }
    }
    String raw_transformation = (String) options.get("raw_transformation");
    if (raw_transformation != null) {
      components.add(raw_transformation);
    }
    if (!components.isEmpty()) {
      transformations.add(StringUtils.join(components, ","));
    }

    if (isResponsive) {
      transformations.add(generate(getResponsiveWidthTransformation()));
    }

    if ("auto".equals(width) || isResponsive) {
      this.isResponsive = true;
    }

    if ("auto".equals(dpr)) {
      this.hiDPI = true;
    }

    return StringUtils.join(transformations, "/");
  }