/**
   * Create string representation of a fop-rgb-icc (or fop-rgb-named-color) function call from the
   * given color.
   *
   * @param color the color to turn into a function call
   * @return the string representing the internal fop-rgb-icc() or fop-rgb-named-color() function
   *     call
   */
  private static String toFunctionCall(ColorWithAlternatives color) {
    ColorSpace cs = color.getColorSpace();
    if (cs.isCS_sRGB() && !color.hasAlternativeColors()) {
      return toRGBFunctionCall(color);
    }
    if (cs instanceof CIELabColorSpace) {
      return toCIELabFunctionCall(color);
    }

    Color specColor = color;
    if (color.hasAlternativeColors()) {
      Color alt = color.getAlternativeColors()[0];
      if (ColorSpaces.isDeviceColorSpace(alt.getColorSpace())) {
        cs = alt.getColorSpace();
        specColor = alt;
      }
    }
    ColorSpaceOrigin origin = ColorSpaces.getColorSpaceOrigin(cs);
    String functionName;

    Color fallbackColor = getsRGBFallback(color);
    float[] rgb = fallbackColor.getColorComponents(null);
    assert rgb.length == 3;
    StringBuffer sb = new StringBuffer(40);
    sb.append("(");
    sb.append(rgb[0]).append(",");
    sb.append(rgb[1]).append(",");
    sb.append(rgb[2]).append(",");
    String profileName = origin.getProfileName();
    sb.append(profileName).append(",");
    if (origin.getProfileURI() != null) {
      sb.append("\"").append(origin.getProfileURI()).append("\"");
    }

    if (cs instanceof NamedColorSpace) {
      NamedColorSpace ncs = (NamedColorSpace) cs;
      if (SEPARATION_PSEUDO_PROFILE.equalsIgnoreCase(profileName)) {
        functionName = "fop-rgb-icc";
      } else {
        functionName = "fop-rgb-named-color";
      }
      sb.append(",").append(ncs.getColorName());
    } else {
      functionName = "fop-rgb-icc";
      float[] colorComponents = specColor.getColorComponents(null);
      for (float colorComponent : colorComponents) {
        sb.append(",");
        sb.append(colorComponent);
      }
    }
    sb.append(")");
    return functionName + sb.toString();
  }
  /**
   * Construct an OpImage given a String representation of a URL, a resolution, and a sub-image
   * index.
   *
   * @param URLSpec The URL of the IIP image including the FIF cimmand if needed and possibly an SDS
   *     command.
   * @param level The resolution level with 0 as the lowest resolution.
   * @param subImage The subimage number.
   * @param layout The layout hint; may be null.
   */
  public IIPResolutionOpImage(Map config, String URLSpec, int level, int subImage) {
    super(
        (Vector) null, // the image is sourceless
        layoutHelper(URLSpec, level, subImage),
        config,
        false);

    this.renderHints = (RenderingHints) config;

    // Cache the constructor parameters.
    URLString = URLSpec;
    this.subImage = subImage;

    // Retrieve required parameters from server.
    String[] cmd = new String[] {"OBJ=Resolution-number"};
    InputStream stream = postCommands(cmd);
    String label = null;
    while ((label = getLabel(stream)) != null) {
      if (label.equals("resolution-number")) {
        String data = getDataAsString(stream, false);
        int numRes = Integer.valueOf(data).intValue();
        if (level < 0) {
          resolution = 0;
        } else if (level >= numRes) {
          resolution = numRes - 1;
        } else {
          resolution = level;
        }
      } else {
        checkError(label, stream, true);
      }
    }
    endResponse(stream);

    // Cache some values which will be used repetitively.
    ColorSpace cs = colorModel.getColorSpace();
    if (cs.isCS_sRGB()) {
      colorSpaceType = CS_NIFRGB;
    } else if (cs.equals(ColorSpace.getInstance(ColorSpace.CS_GRAY))) {
      colorSpaceType = CS_MONOCHROME;
    } else {
      colorSpaceType = CS_PHOTOYCC;
    }
    hasAlpha = colorModel.hasAlpha();
    isAlphaPremultilpied = colorModel.isAlphaPremultiplied();
    minTileX = getMinTileX();
    minTileY = getMinTileY();
    numXTiles = getNumXTiles();
  }