What does "Error on int" mean?

Now I understand why you wanted findClosestPaletteColor() to be a regular instance method: You’ve got rid of its 1st parameter!

Instead the previous parameter became a clone of the current C3 instance.

Just so you know, you can keep both static & non-static versions for findClosestPaletteColor().

And those new r(), g() & b() helper functions can be converted to static inside C3Base:

static abstract class C3Base {
  static final color r(final color c) {
    return c >> 020 & 0xff;
  }

  static final color g(final color c) {
    return c >> 010 & 0xff;
  }

  static final color b(final color c) {
    return c & 0xff;
  }

  static final C3 findClosestPaletteColor(final C3 c, final C3[] palette) {
    C3 closest = null;
    int dif = MAX_INT;

    for (final C3 n : palette) if (n.diff(c) < dif) dif = (closest = n).diff(c);

    return closest;
  }
}

Notice now that I’ve got rid of class PGraph & its corresponding static pg field in C3Base.

In its place I’m using this formula: b | g << 010 | r << 020 | PImage.ALPHA_MASK.

Here’s latest version for class C3 w/ even more cool features: :mage:

class C3 extends C3Base implements Comparable<C3>, Cloneable {
  color r, g, b;

  C3(final color c) {
    r = r(c);
    g = g(c);
    b = b(c);
  }

  C3(final color r, final color g, final color b) {
    set(r, g, b);
  }

  C3 set(final color x, final color y, final color z) {
    r = x;
    g = y;
    b = z;

    return clamp();
  }

  C3 add(final C3 c) {
    return new C3(r + c.r, g + c.g, b + c.b);
  }

  C3 sub(final C3 c) {
    return new C3(r - c.r, g - c.g, b - c.b);
  }

  C3 mul(final int d) {
    return new C3(d * r, d * g, d * b);
  }

  C3 mul(final float d) {
    return new C3((int) (d * r), (int) (d * g), (int) (d * b));
  }

  int diff(final C3 c) {
    final color
      rDiff = c.r - r, 
      gDiff = c.g - g, 
      bDiff = c.b - b;

    return rDiff * rDiff + gDiff * gDiff + bDiff * bDiff;
  }

  final C3 findClosestPaletteColor(final C3... palette) {
    return findClosestPaletteColor(this, palette);
  }

  C3 clone() {
    try {
      return (C3) super.clone();
    }
    catch (final CloneNotSupportedException e) {
      throw new RuntimeException(e);
    }
  }

  C3 clamp() {
    r = constrain(r, 0, 255);
    g = constrain(g, 0, 255);
    b = constrain(b, 0, 255);

    return this;
  }

  color toColor() {
    return clamp().hashCode();
  }

  int hashCode() {
    return b | g << 010 | r << 020 | PImage.ALPHA_MASK;
  }

  boolean equals(final Object o) {
    return o instanceof C3? o.hashCode() == hashCode() : false;
  }

  int compareTo(final C3 c) {
    return
      (hashCode() & ~PImage.ALPHA_MASK) -
      (c.hashCode() & ~PImage.ALPHA_MASK);
  }

  String toString() {
    return '#' + hex(hashCode(), 6) + ": [ " + r + ", " + g + ", " + b + " ]";
  }
}

Edit 1: changed: return C3.findClosestPaletteColor(clone(), palette);
to just: return C3.findClosestPaletteColor(this, palette);

No need to use clone() for this operation, given neither passed object arguments are mutated in anyway inside static method findClosestPaletteColor().


Edit 2: Created a set() method and changed 2nd constructor to use that:

  C3(final color r, final color g, final color b) {
    set(r, g, b);
  }

  C3 set(final color x, final color y, final color z) {
    r = x;
    g = y;
    b = z;

    return clamp();
  }

Edit 3: No need to prefix w/ C3 at return C3.findClosestPaletteColor(this, palette);:
return findClosestPaletteColor(this, palette);