I just started messing around with Java's `BufferedImage`. I had an idea to try to encode a message into a picture by coloring each pixel a certain color that corresponds to a certain character.

I needed a way of enumerating colors to match colors to characters.

To do this, I decided to treat the RGB color as a 3-digit, base-255 number, then just incrementing each channel as though I was counting (increment the rightmost channel until it gets to 255, then make it 0 and increment the channel to the left). I used this for a previous project, and although it's slow, it was acceptable.

    (defn inc-permutation
      "\"Counts\" arbitrary symbols.
      Example: (inc-permutation \\a \\c #(char (inc (int %))) [\\a \\b \\b])
      returns [\\a \\b \\c], then [\\a \\c \\a], [\\a \\c \\b], [\\a \\c \\c], [\\b \\a \\a], [\\b \\a \\lein pomb]...
      Quite slow."
      [first-symbol last-symbol inc-f current-permutation]
      (let [current-ones (last current-permutation)
            carry? (= current-ones last-symbol)
            overflown? (empty? current-permutation)
            last-i (dec (count current-permutation))]
    
        (cond
          carry? (conj
                   (inc-permutation first-symbol last-symbol inc-f (subvec current-permutation 0 last-i))
                   first-symbol)
    
          overflown? []
    
          :else (assoc current-permutation last-i (inc-f current-ones)))))

It works, but it seems like a hack more than anything.

I calculated that to cover the entire range of colors with a char, I would need to increment each color 174540 times * `(- (int (character) 32)`. At 88ms per increment, it will take a little over 8 seconds to increment a `\~` to `[253 3 19]`, which for a message of any length is unacceptable.

Below is the full code. The last method, `color-of-char` is where it's all tied together.

    (ns bits.image.color-encode.conversion-helper)
    
    (def min-char-code 32)
    (def max-char-code "inclusive" 127)
    
    (def total-colors (int (Math/pow 255 3)))
    (def color-code-mult (int (inc (/ total-colors (- max-char-code min-char-code)))))
    
    (def starting-color [0 0 0])
    
    (defn inc-permutation ...)

    (defn advance-color [color color-step]
      (let [f #(g/inc-permutation 0 255 inc %)]
        (if (= color-step 1)
          (f color)
          (reduce (fn [c _] ; Faster than `iterate`
                    (f c))
                  color
                  (range color-step)))))
    
    (defn color-of-char [chr]
      (let [code (- (int chr) min-char-code)]
        (advance-color [0 0 0]
                       (* code color-code-mult))))

`(color-of-char \a)` -> `[173 29 13]`, but it takes an average of 5.879696 seconds to get there (according to Criterium).

1. Is there anything I can do to speed up the current way? Any general comments would be welcome too.

2. Is there a better way to "increment a RGB color"? Alternatively, is there a way to get some nth color, that isn't `O(n)`?