3

Using imagez I can get a pixel from an image as [r g b]. Using this colour wheel I have verified that this extraction part is almost certainly working. This is the imagez code that does the extraction:

(defn components-rgb
  "Return the RGB components of a colour value, in a 3-element vector of long values"
  ([^long rgb]
   [(bit-shift-right (bit-and rgb 0x00FF0000) 16)
    (bit-shift-right (bit-and rgb 0x0000FF00) 8)
    (bit-and rgb 0x000000FF)]))

I need to do the opposite of this extraction. Here are some examples of the 'colour value' (or pixel) being extracted:

First pixel: -6700606 (in HEX: FFFFFFFFFF99C1C2)  
Last pixel: -11449516 (in HEX: FFFFFFFFFF514B54)  
First as colour: [153 193 194] (in HEX: 99 C1 C2)   
Last as colour: [81 75 84] (in HEX: 51 4B 54)   

Doing the opposite would mean that [153 193 194] becomes -6700606. This question has been asked before on SO, for example here. Here are two of my attempts which do not work:

;rgb = 0xFFFF * r + 0xFF * g + b
(defn my-rgb-1 [[r g b]]
  (+ (* 0xFFFF r) (* 0xFF g) b))  

;int rgb = ((r&0x0ff)<<16)|((g&0x0ff)<<8)|(b&0x0ff);
(defn my-rgb-2 [[r g b]]
(let [red (bit-shift-left 16 (bit-and r 0x0FF))
      green (bit-shift-left 8 (bit-and g 0x0FF))
      blue (bit-and b 0x0FF)]
 (bit-or red green blue)))

image --1--> extracted-pixel --2--> rgb colour --3--> to-write-pixel --4--> image

Steps 1 and 2 are working, but step 3 is not. If step 3 were working extracted-pixel would be the same as to-write-pixel.

There is an rgb function in imagez, but it too does not work for me. (The author updated me to say it is not supposed to. See here). I might also add that the imagez function get-pixel is first used to get the pixel (step 1), followed by components-rgb (step 2) as shown above.

Take a look here where I have outlined the steps.

Community
  • 1
  • 1
Chris Murphy
  • 6,411
  • 1
  • 24
  • 42
  • 1
    I suggest you post the hexadecimal representation of the colors instead of the decimal one, it will be more clear for you and for us. – m0skit0 Sep 03 '15 at 12:00
  • your `my-rgb-2` attempt: the commented line is a description of what you want? Then you are missing a few `bit-shift-left`s (you do the `bit-and`s and `bit-or`s - but decided to ignore `<<` ?) – birdspider Sep 03 '15 at 14:00
  • also `(format "0x%x" -6700606) => "0xffffffffff99c1c2"` is possiblty helpful when printing bits/hex – birdspider Sep 03 '15 at 14:02
  • `There is an rgb function in imagez, but it too does not work for me.` can you clarify this ? [the function](https://github.com/mikera/imagez/blob/develop/src/main/clojure/mikera/image/colours.clj#L15-L24) looks exactly like what you want ? – birdspider Sep 03 '15 at 14:10
  • https://github.com/chrismurrph/want-pixel/blob/master/src/my/issue.clj clarifies that the existing `rgb` function in imagez does not work for me. Thanks. – Chris Murphy Sep 03 '15 at 15:08
  • so your problem is that `(in HEX: FFFFFFFFFF99C1C2)` != `(in HEX: 99 C1 C2)` - I give you `unchecked-int` : `(format "0x%x" (unchecked-int 0xFFFFFFFFFF99C1C2)) => 0xff99c1c2` - its the "same", just once `long` and once `int` – birdspider Sep 03 '15 at 15:34

2 Answers2

0

If I understand your poblem correctly - the issue you have is that:

"First pixel" in hex is i.e 0xFFFFFFFFF99C1C2
 you convert it to decimal-rgb via `components-rgb` = [153 193 194]
 you re-convert [153 193 194] to int via `rbg` and get 
  0x99C1C2
which by all means is correct

since clojure by default uses long the only thing you need to do is use a unchecked-int to trucate the long to int as so:

(unchecked-int 0xFFFFFFFFFF99C1C2)
-6700606

which is what you want - right ?

birdspider
  • 3,034
  • 1
  • 16
  • 25
  • Looking at issue.clj you can use any of `existing-rgb`, `my-rgb-1` or `my-rgb-2`. Last time I looked none of them returned the right answer. – Chris Murphy Sep 03 '15 at 20:49
0

I had the arguments to bit-shift-left in the wrong order. So this is a basic version of the improved my-rgb-2:

(defn my-rgb-2 [[r g b]]
  (let [red (bit-shift-left r 16)
        green (bit-shift-left g 8)
        blue b]
    (bit-or red green blue)))

I have left off (bit-and a 0x0FF), (where a is r, g or b), simply because it is only necessary if the number is more than 255, which would not be a proper value anyway. For this answer it doesn't really matter whether it is there or not.

The next thing to do is put all the 0xF (all 4 bits filled in) at the beginning. This nearly gets me there:

(defn my-rgb-2 [[r g b]]
  (let [red (bit-shift-left (bit-and r 0x0FF) 16)
        green (bit-shift-left (bit-and g 0x0FF) 8)
        blue (bit-and b 0x0FF)]
    (bit-or 0xFFFFFFFFF000000 (bit-or red green blue))))  

Unfortunately if I put one more 0xF on the last line I get:

Exception in thread "main" java.lang.IllegalArgumentException: bit operation not supported for: class clojure.lang.BigInt

But that can be fixed by borrowing from the answer @birdspider gave:

(defn my-rgb-2 [[r g b]]
  (let [red (bit-shift-left (bit-and r 0x0FF) 16)
        green (bit-shift-left (bit-and g 0x0FF) 8)
        blue (bit-and b 0x0FF)]
    (bit-or (bit-or red green blue) (unchecked-int 0xFFFFFFFFFF000000))))

The imagez library now has this function, but done as a macro for performance reasons.

Chris Murphy
  • 6,411
  • 1
  • 24
  • 42