#FEATURE by cg
authorClaus Gittinger <cg@exept.de>
Tue, 29 Aug 2017 21:59:53 +0200
changeset 8126 10c304b0f4db
parent 8125 4deac40e67b0
child 8127 826558a642a9
#FEATURE by cg class: Color class changed: #best:ditherColorsForImage:
Color.st
--- a/Color.st	Tue Aug 29 20:08:35 2017 +0200
+++ b/Color.st	Tue Aug 29 21:59:53 2017 +0200
@@ -3550,9 +3550,9 @@
 best:numColors ditherColorsForImage:anImage 
     "work in progress"
     
-    |bigCube boxMax numBits numGray usedColors 
+    |cube boxMaxR boxMaxG boxMaxB numBitsR numBitsG numBitsB numGray usedColors 
      minRed maxRed minGreen maxGreen minBlue maxBlue
-     boundaryColors boxesSegmented segments boxesToDo enumerateNeighbors
+     boundaryColors boxesAlreadySegmented segments boxesToDo enumerateNeighbors
      firstTry segmentColors|
 
     ((anImage photometric == #blackIs0) or:[anImage photometric == #whiteIs0]) ifTrue:[
@@ -3567,13 +3567,18 @@
         ].    
     ].    
 
-    boxMax := 63.
-    numBits := 6.
+    numBitsR := 7.
+    numBitsG := 8.
+    numBitsB := 5.
+
     firstTry := true.
 
     [
-        "/ first, a rough cube with less precision...
-        bigCube := IntegerArray new:(boxMax+1)*(boxMax+1)*(boxMax+1).
+        boxMaxR := (1 << numBitsR) - 1.
+        boxMaxG := (1 << numBitsG) - 1.
+        boxMaxB := (1 << numBitsB) - 1.
+
+        cube := IntegerArray new:(boxMaxR+1)*(boxMaxG+1)*(boxMaxB+1).
 
         firstTry ifTrue:[
             usedColors := Set new.
@@ -3591,11 +3596,11 @@
                 greenByte := (rgb rightShift:8) bitAnd:16rFF.
                 blueByte := (rgb) bitAnd:16rFF.
 
-                r := redByte rightShift:(8-numBits).
-                g := greenByte rightShift:(8-numBits).
-                b := blueByte rightShift:(8-numBits).
-                idx := (((r * (boxMax+1))+g)*(boxMax+1))+b+1.
-                oldCount := bigCube at:idx.
+                r := redByte rightShift:(8-numBitsR).
+                g := greenByte rightShift:(8-numBitsG).
+                b := blueByte rightShift:(8-numBitsB).
+                idx := (((r * (boxMaxG+1))+g)*(boxMaxB+1))+b+1.
+                oldCount := cube at:idx.
 
                 firstTry ifTrue:[
                     redByte < minRed ifTrue:[minRed := redByte] ifFalse:[redByte > maxRed ifTrue:[maxRed := redByte]].
@@ -3606,7 +3611,7 @@
                         usedColors add:rgb.
                     ].    
                 ].    
-                bigCube at:idx put:oldCount+1.
+                cube at:idx put:oldCount+1.
             ].    
 
         firstTry ifTrue:[
@@ -3642,7 +3647,7 @@
         "/
         "/ find and generate connected subarea box sets
         "/
-        boxesSegmented := Set new.
+        boxesAlreadySegmented := Set new.
         segments := OrderedCollection new.    
 
         boxesToDo := OrderedCollection new.
@@ -3653,17 +3658,17 @@
             [:rgb :aBlock|
                 |r g b|
 
-                r := (rgb rightShift:(numBits+numBits)) bitAnd:boxMax.
-                g := (rgb rightShift:numBits) bitAnd:boxMax.
-                b := (rgb) bitAnd:boxMax.
+                r := (rgb rightShift:(numBitsG+numBitsB)) bitAnd:boxMaxR.
+                g := (rgb rightShift:numBitsB) bitAnd:boxMaxG.
+                b := (rgb) bitAnd:boxMaxB.
                 r-1 to:r+1 do:[:n_r |
-                    (n_r between:0 and:boxMax) ifTrue:[
+                    (n_r between:0 and:boxMaxR) ifTrue:[
                         g-1 to:g+1 do:[:n_g |
-                            (n_g between:0 and:boxMax) ifTrue:[
+                            (n_g between:0 and:boxMaxG) ifTrue:[
                                 b-1 to:b+1 do:[:n_b |
-                                    (n_b between:0 and:boxMax) ifTrue:[
+                                    (n_b between:0 and:boxMaxB) ifTrue:[
                                         ((n_r == r) and:[n_g == g and:[n_b == b]]) ifFalse:[
-                                            aBlock value:((((n_r * (boxMax+1))+n_g)*(boxMax+1))+n_b).
+                                            aBlock value:((((n_r * (boxMaxG+1))+n_g)*(boxMaxB+1))+n_b).
                                         ]
                                     ]
                                 ]
@@ -3673,14 +3678,14 @@
                 ].
             ].
 
-        0 to:boxMax do:[:r |
-            0 to:boxMax do:[:g |
-                0 to:boxMax do:[:b |
+        0 to:boxMaxR do:[:r |
+            0 to:boxMaxG do:[:g |
+                0 to:boxMaxB do:[:b |
                     |rgb|
 
-                    rgb := (((r * (boxMax+1))+g)*(boxMax+1))+b.
-                    (bigCube at:rgb+1) ~~ 0 ifTrue:[
-                        (boxesSegmented includes:rgb) ifFalse:[
+                    rgb := (((r * (boxMaxG+1))+g)*(boxMaxB+1))+b.
+                    (cube at:rgb+1) ~~ 0 ifTrue:[
+                        (boxesAlreadySegmented includes:rgb) ifFalse:[
                             |currentSegment|
 
                             "/ start a segment
@@ -3688,7 +3693,7 @@
                             segments add:currentSegment.
 
                             boxesToDo add:rgb.
-                            boxesSegmented add:rgb.
+                            boxesAlreadySegmented add:rgb.
 
                             [boxesToDo notEmpty] whileTrue:[
                                 |rgb|
@@ -3697,11 +3702,11 @@
                                 currentSegment add:rgb.
 
                                 enumerateNeighbors value:rgb value:[:n_rgb |
-                                    (bigCube at:n_rgb+1) ~~ 0 ifTrue:[
+                                    (cube at:n_rgb+1) ~~ 0 ifTrue:[
                                         "/ neighbor has used pixels as well...
-                                        (boxesSegmented includes:n_rgb) ifFalse:[
+                                        (boxesAlreadySegmented includes:n_rgb) ifFalse:[
                                             "/ neighbor was not processed...
-                                            boxesSegmented add:rgb.
+                                            boxesAlreadySegmented add:rgb.
                                             boxesToDo add:n_rgb.
                                         ].
                                     ].    
@@ -3727,28 +3732,29 @@
                                     eachSegment do:[:rgbOfBoxInSegment |
                                         |r g b idx count|
                                         
-                                        r := (rgbOfBoxInSegment rightShift:(numBits+numBits)) bitAnd:boxMax.
-                                        g := (rgbOfBoxInSegment rightShift:numBits) bitAnd:boxMax.
-                                        b := (rgbOfBoxInSegment) bitAnd:boxMax.
-
-                                        idx := (((r * (boxMax+1))+g)*(boxMax+1))+b+1.
-                                        count := bigCube at:idx.
-
-                                        sumRed := sumRed + r.
-                                        sumGreen := sumGreen + g.
-                                        sumBlue := sumBlue + b.
+                                        r := (rgbOfBoxInSegment rightShift:(numBitsG+numBitsB)) bitAnd:boxMaxR.
+                                        g := (rgbOfBoxInSegment rightShift:numBitsB) bitAnd:boxMaxG.
+                                        b := (rgbOfBoxInSegment) bitAnd:boxMaxB.
+
+                                        idx := (((r * (boxMaxG+1))+g)*(boxMaxB+1))+b+1.
+                                        count := cube at:idx.
+
+                                        sumRed := sumRed + (r * count).
+                                        sumGreen := sumGreen + (g * count).
+                                        sumBlue := sumBlue + (b * count).
+                                        
                                         sumWeight := sumWeight + count. 
                                     ].
                                     centerRed := (sumRed / sumWeight) rounded.
                                     centerGreen := (sumGreen / sumWeight) rounded.
                                     centerBlue := (sumBlue / sumWeight) rounded.
 
-                                    centerRed := (centerRed bitShift:(8-numBits))
-                                                 bitOr:(centerRed bitShift:(8-numBits-numBits)). 
-                                    centerGreen := (centerGreen bitShift:(8-numBits))
-                                                 bitOr:(centerGreen bitShift:(8-numBits-numBits)). 
-                                    centerBlue := (centerBlue bitShift:(8-numBits))
-                                                 bitOr:(centerBlue bitShift:(8-numBits-numBits)). 
+                                    centerRed := (centerRed bitShift:(8-numBitsR))
+                                                 bitOr:(centerRed bitShift:(8-numBitsR-numBitsR)). 
+                                    centerGreen := (centerGreen bitShift:(8-numBitsG))
+                                                 bitOr:(centerGreen bitShift:(8-numBitsG-numBitsG)). 
+                                    centerBlue := (centerBlue bitShift:(8-numBitsB))
+                                                 bitOr:(centerBlue bitShift:(8-numBitsB-numBitsB)). 
                                     
                                     Color redByte:centerRed greenByte:centerGreen blueByte:centerBlue.
                                 ]
@@ -3771,10 +3777,11 @@
             ^ segmentColors.
         ].
         
-        numBits := numBits - 1.
-        boxMax := ((boxMax+1) // 2) - 1.
+        numBitsR > 2 ifTrue:[ numBitsR := numBitsR - 1 ].
+        numBitsG > 2 ifTrue:[ numBitsG := numBitsG - 1 ].
+        numBitsB > 2 ifTrue:[ numBitsB := numBitsB - 1 ].
         
-        numBits == 0 ifTrue:[
+        ((numBitsR == 0) or:[numBitsG == 0 or:[numBitsB == 0]]) ifTrue:[
             self error.
         ].    
     ] loop.
@@ -3795,7 +3802,7 @@
     "
 
     "Created: / 29-08-2017 / 14:31:19 / cg"
-    "Modified: / 29-08-2017 / 20:04:36 / cg"
+    "Modified: / 29-08-2017 / 21:53:47 / cg"
 !
 
 browserColors