diff -r 86cf12ddc8fd -r 32e373ae50fa ImageEditor.st --- a/ImageEditor.st Thu Feb 26 21:54:40 2015 +0100 +++ b/ImageEditor.st Thu Feb 26 23:04:44 2015 +0100 @@ -1843,196 +1843,198 @@ ^ - #(FullSpec - name: windowSpec - window: - (WindowSpec - label: 'Image Editor' - name: 'Image Editor' - min: (Point 400 320) - bounds: (Rectangle 0 0 450 350) - menu: menu - icon: defaultIcon - ) - component: - (SpecCollection - collection: ( - (MenuPanelSpec - name: 'menuToolbarView' - layout: (LayoutFrame 0 0.0 0 0 0 1.0 32 0) - style: (FontDescription helvetica medium roman 10) - menu: menuToolbar - showSeparatingLines: true - ) - (VariableHorizontalPanelSpec - name: 'mainPanel' - layout: (LayoutFrame 0 0.0 34 0.0 0 1.0 -26 1.0) - snapMode: both - barLevel: 0 - component: - (SpecCollection - collection: ( - (ViewSpec - name: 'leftView' - level: 1 - component: - (SpecCollection - collection: ( - (VariableVerticalPanelSpec - name: 'verticalPanel' - layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0) - level: 0 - snapMode: both - component: - (SpecCollection - collection: ( - (ViewSpec - name: 'View1' - component: - (SpecCollection - collection: ( - (MenuPanelSpec - name: 'MouseButtonColorToolBar' - layout: (LayoutFrame 0 0.0 0 0 0 1.0 24 0) - level: 0 - menu: menuMouseButtonColors - ) - (DataSetSpec - name: 'colorDataSetView' - layout: (LayoutFrame 0 0.0 26 0.0 0 1.0 0 1.0) - activeHelpKey: colorMapTable - style: (FontDescription helvetica medium roman 10) - model: selectionOfColor - menu: colorMapMenu - hasHorizontalScrollBar: true - hasVerticalScrollBar: true - miniScrollerHorizontal: true - miniScrollerVertical: true - dataList: listOfColors - has3Dseparators: true - doubleClickSelector: doubleClickOnColor: - columnHolder: colorTableColumns - verticalSpacing: 1 - columnAdaptor: colorColumnAdaptor - ) + #(FullSpec + name: windowSpec + window: + (WindowSpec + label: 'Image Editor' + name: 'Image Editor' + min: (Point 400 320) + bounds: (Rectangle 0 0 450 350) + menu: menu + icon: defaultIcon + ) + component: + (SpecCollection + collection: ( + (MenuPanelSpec + name: 'menuToolbarView' + layout: (LayoutFrame 0 0.0 0 0 0 1.0 32 0) + style: (FontDescription helvetica medium roman 10) + menu: menuToolbar + showSeparatingLines: true + ) + (VariableHorizontalPanelSpec + name: 'mainPanel' + layout: (LayoutFrame 0 0.0 34 0.0 0 1.0 -26 1.0) + snapMode: both + barLevel: 0 + component: + (SpecCollection + collection: ( + (ViewSpec + name: 'leftView' + level: 1 + component: + (SpecCollection + collection: ( + (VariableVerticalPanelSpec + name: 'verticalPanel' + layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0) + level: 0 + snapMode: both + component: + (SpecCollection + collection: ( + (ViewSpec + name: 'View1' + component: + (SpecCollection + collection: ( + (MenuPanelSpec + name: 'MouseButtonColorToolBar' + layout: (LayoutFrame 0 0.0 0 0 0 1.0 24 0) + level: 0 + menu: menuMouseButtonColors ) - - ) - ) - (ArbitraryComponentSpec - name: 'imagePreView' - activeHelpKey: previewView - menu: previewMenu - hasHorizontalScrollBar: true - hasVerticalScrollBar: true - miniScrollerHorizontal: false - miniScrollerVertical: false - hasBorder: false - component: ImageView - ) + (DataSetSpec + name: 'colorDataSetView' + layout: (LayoutFrame 0 0.0 26 0.0 0 1.0 0 1.0) + activeHelpKey: colorMapTable + style: (FontDescription helvetica medium roman 10) + model: selectedColors + menu: colorMapMenu + hasHorizontalScrollBar: true + hasVerticalScrollBar: true + miniScrollerHorizontal: true + miniScrollerVertical: true + dataList: listOfColors + has3Dseparators: true + doubleClickSelector: doubleClickOnColor: + columnHolder: colorTableColumns + multipleSelectOk: true + verticalSpacing: 1 + columnAdaptor: colorColumnAdaptor + ) + ) + + ) ) - - ) - handles: (Any 0.5 1.0) - ) + (ArbitraryComponentSpec + name: 'imagePreView' + activeHelpKey: previewView + menu: previewMenu + hasHorizontalScrollBar: true + hasVerticalScrollBar: true + miniScrollerHorizontal: false + miniScrollerVertical: false + hasBorder: false + component: ImageView + ) + ) + + ) + handles: (Any 0.5 1.0) ) - - ) - ) - (ViewSpec - name: 'rightView' - component: - (SpecCollection - collection: ( - (MenuPanelSpec - name: 'ToolBar1' - layout: (LayoutFrame 0 0 0 0.0 28 0 0 1.0) - level: 1 - menu: toolsMenuToolbar - verticalLayout: true - centerItems: true - textDefault: true - ) - (ViewSpec - name: 'editingView' - layout: (LayoutFrame 28 0.0 0 0.0 0 1.0 0 1.0) - level: 1 - component: - (SpecCollection - collection: ( - (ArbitraryComponentSpec - name: 'imageEditView' - layout: (LayoutFrame 2 0.0 2 0.0 -2 1.0 -24 1.0) - hasHorizontalScrollBar: true - hasVerticalScrollBar: true - hasBorder: false - component: ImageEditView - ) - (LabelSpec - name: 'coordLabel' - layout: (LayoutFrame 2 0.0 -22 1 -83 1.0 0 1.0) - level: -1 - labelChannel: imageInfoHolder - resizeForLabel: false - adjust: left - ) - (ArrowButtonSpec - name: 'magnifyDownButton' - layout: (LayoutFrame -80 1 -22 1 -58 1 0 1) - activeHelpKey: magnifyImageDown - model: doMagnifyDown - enableChannel: imageIsLoadedHolder - isTriggerOnDown: true - direction: left - ) - (ArrowButtonSpec - name: 'magnifyUpButton' - layout: (LayoutFrame -24 1 -22 1 -2 1 0 1) - activeHelpKey: magnifyImageUp - model: doMagnifyUp - enableChannel: imageIsLoadedHolder - isTriggerOnDown: true - direction: right - ) - (InputFieldSpec - name: 'magnificationInputField' - layout: (LayoutFrame -57 1 -22 1 -26 1 0 1) - activeHelpKey: magnificationNumber - enableChannel: imageIsLoadedHolder - model: magnificationHolder - type: numberInRange - acceptOnReturn: true - acceptOnTab: true - numChars: 2 - minValue: 1 - maxValue: 99 - acceptOnPointerLeave: true - ) + ) + + ) + ) + (ViewSpec + name: 'rightView' + component: + (SpecCollection + collection: ( + (MenuPanelSpec + name: 'ToolBar1' + layout: (LayoutFrame 0 0 0 0.0 28 0 0 1.0) + level: 1 + menu: toolsMenuToolbar + verticalLayout: true + centerItems: true + textDefault: true + ) + (ViewSpec + name: 'editingView' + layout: (LayoutFrame 28 0.0 0 0.0 0 1.0 0 1.0) + level: 1 + component: + (SpecCollection + collection: ( + (ArbitraryComponentSpec + name: 'imageEditView' + layout: (LayoutFrame 2 0.0 2 0.0 -2 1.0 -24 1.0) + hasHorizontalScrollBar: true + hasVerticalScrollBar: true + hasBorder: false + component: ImageEditView + ) + (LabelSpec + name: 'coordLabel' + layout: (LayoutFrame 2 0.0 -22 1 -83 1.0 0 1.0) + level: -1 + translateLabel: true + labelChannel: imageInfoHolder + resizeForLabel: false + adjust: left ) - - ) - ) + (ArrowButtonSpec + name: 'magnifyDownButton' + layout: (LayoutFrame -80 1 -22 1 -58 1 0 1) + activeHelpKey: magnifyImageDown + translateLabel: true + model: doMagnifyDown + enableChannel: imageIsLoadedHolder + isTriggerOnDown: true + direction: left + ) + (ArrowButtonSpec + name: 'magnifyUpButton' + layout: (LayoutFrame -24 1 -22 1 -2 1 0 1) + activeHelpKey: magnifyImageUp + translateLabel: true + model: doMagnifyUp + enableChannel: imageIsLoadedHolder + isTriggerOnDown: true + direction: right + ) + (InputFieldSpec + name: 'magnificationInputField' + layout: (LayoutFrame -57 1 -22 1 -26 1 0 1) + activeHelpKey: magnificationNumber + enableChannel: imageIsLoadedHolder + model: magnificationHolder + type: numberInRange + acceptOnReturn: true + acceptOnTab: true + numChars: 2 + minValue: 1 + maxValue: 99 + acceptOnPointerLeave: true + ) + ) + + ) ) - - ) - ) + ) + + ) ) - - ) - handles: (Any 0.288889 1.0) - ) - (UISubSpecification - name: 'infoBarSubSpec' - layout: (LayoutFrame 0 0.0 -24 1 0 1.0 0 1.0) - majorKey: ToolApplicationModel - minorKey: windowSpecForInfoBar - ) + ) + + ) + handles: (Any 0.28888900000000006 1.0) ) - - ) - ) - - "Modified: / 04-07-2010 / 10:18:33 / cg" + (UISubSpecification + name: 'infoBarSubSpec' + layout: (LayoutFrame 0 0.0 -24 1 0 1.0 0 1.0) + majorKey: ToolApplicationModel + minorKey: windowSpecForInfoBar + ) + ) + + ) + ) ! ! !ImageEditor class methodsFor:'menu specs'! @@ -2070,21 +2072,21 @@ label: '-' ) (MenuItem - enabled: hasColormapAndColorSelected + enabled: hasColormapAndSingleColorSelected label: 'Cut Color' itemValue: cutColorFromColormap translateLabel: true isVisible: false ) (MenuItem - enabled: hasColorSelectedHolder + enabled: hasSingleColorSelectedHolder label: 'Copy Color' itemValue: copyColorFromColormap translateLabel: true shortcutKey: Copy ) (MenuItem - enabled: hasColormapAndColorSelected + enabled: hasColormapAndSingleColorSelected label: 'Pick and Paste Color...' itemValue: pickAndPasteColor translateLabel: true @@ -2099,7 +2101,7 @@ label: '-' ) (MenuItem - enabled: hasColormapAndColorSelected + enabled: hasColormapAndSingleColorSelected label: 'Edit Color...' itemValue: editSelectedColor translateLabel: true @@ -2123,10 +2125,16 @@ translateLabel: true ) (MenuItem + enabled: hasColormapAndColorSelected + label: 'Color Shift' + itemValue: makeSelectedColorShifted + translateLabel: true + ) + (MenuItem label: '-' ) (MenuItem - enabled: hasColorSelectedHolder + enabled: hasSingleColorSelectedHolder label: 'Inspect Color' itemValue: inspectColor translateLabel: true @@ -3726,7 +3734,7 @@ ! hasColorSelectedHolder - ^ [ self selectedColorIndexOrNil notNil ] + ^ [ self selectedColors value notEmptyOrNil "self selectedColorIndexOrNil notNil" ] "Created: / 04-07-2010 / 10:12:22 / cg" ! @@ -3744,12 +3752,24 @@ "Modified: / 04-07-2010 / 10:13:13 / cg" ! +hasColormapAndSingleColorSelected + ^ [ self hasColormapHolder value and:[self hasSingleColorSelectedHolder value]] + + "Modified: / 04-07-2010 / 10:13:13 / cg" +! + hasColormapHolder ^ [self hasColormap] "Created: / 04-07-2010 / 10:13:05 / cg" ! +hasSingleColorSelectedHolder + ^ [ self selectedColors value size == 1 "self selectedColorIndexOrNil notNil" ] + + "Created: / 04-07-2010 / 10:12:22 / cg" +! + imageHasImageSequence |img| @@ -3898,6 +3918,18 @@ "Created: / 04-07-2010 / 10:19:34 / cg" ! +selectedColors + "returns a valueHolder for the current set of selected colors." + + |holder| + + (holder := builder bindingAt:#selectedColors) isNil ifTrue:[ + builder aspectAt:#selectedColors put:(holder := nil asValue). + holder onChangeSend:#selectedColorsChanged to:self. + ]. + ^ holder +! + selectionOfColor "returns a valueHolder for the current selection of the edit color. Here, an AspectAdaptor which accesses selectedColorIndex is returned." @@ -4006,6 +4038,22 @@ "Modified: / 18-01-2012 / 13:58:38 / cg" ! +selectedColorsChanged + |colorIndices| + + (colorIndices := self selectedColors value) isEmptyOrNil ifTrue:[ + self selectionOfColor value:nil + ] ifFalse:[ + colorIndices size == 1 ifTrue:[ + "/ as single color selected + self selectionOfColor value:colorIndices first + ] ifFalse:[ + "/ multipl selected + self selectionOfColor value:nil + ]. + ]. +! + update:something with:aParameter from:changedObject |clrIndex img imagePreView clr changedColor| @@ -4090,7 +4138,7 @@ ] ifFalse:[ clrIndex := self listOfColors indexOf:aParameter. ]. - self selectionOfColor value:clrIndex. + self selectedColors value:{clrIndex}. "/ selectionOfColor value:clrIndex. ^ self. ]. ^ self. @@ -4266,7 +4314,7 @@ self updateImage. self updateImagePreView. - self selectionOfColor value:oldSel. + self selectedColors value:{oldSel}. imageEditView selectedColorIndex:oldSel. imageEditView selectedColor:(self listOfColors at:oldSel). ] @@ -4569,7 +4617,7 @@ mouseKeyColorMode := 1 asValue. mouseKeyColorMode onChangeEvaluate: [ imageEditView mouseKeyColorMode:mouseKeyColorMode value. - self selectionOfColor value: (self listOfColors indexOf:imageEditView selectedColor). + self selectedColors value:{ self listOfColors indexOf:imageEditView selectedColor }. ] ]. @@ -4614,6 +4662,38 @@ ! sortBlockForColors + ^ self sortBlockForColorsByHLS. +"/ ^ self sortBlockForColorsByRGB +! + +sortBlockForColorsByHLS + ^ [:a :b | + |h1 h2 s1 s2 l1 l2| + + h1 := a hue ? 0. + h2 := b hue ? 0. + (h1 between: h2-30 and:h2+30) ifTrue:[ + l1 := a light. + l2 := b light. + l1 = l2 ifTrue:[ + a saturation < b saturation + ] ifFalse:[ + l1 < l2 + ]. +"/ s1 := a saturation. +"/ s2 := b saturation. +"/ s1 = s2 ifTrue:[ +"/ a light < b light +"/ ] ifFalse:[ +"/ s1 < s2 +"/ ] + ] ifFalse:[ + h1 < h2 + ] + ] +! + +sortBlockForColorsByRGB ^ [:a :b | a redByte == b redByte ifTrue:[ a greenByte == b greenByte ifTrue:[ @@ -4808,8 +4888,7 @@ ]. drawingColormap add:newColor. self listOfColors contents:drawingColormap. - self selectionOfColor value:(drawingColormap size). - + self selectedColors value:{drawingColormap size}. "/ self warn:'Image has no colormap.\Change colorMap mode first.' withCRs. ^ self ]. @@ -4859,7 +4938,7 @@ listOfColors size > (oldCListSize + 1) ifTrue:[ listOfColors removeLast ]. - self selectionOfColor value:(listOfColors size). + self selectedColors value:{listOfColors size}. self updateLabelsAndHistory. ] @@ -4985,6 +5064,140 @@ ]. ! +changeHLSOfColors:colorsToShift + "interactive Hue/Light/Saturation editing" + + |bindings hueShift lightValue saturationValue originalColormap firstChange acceptChannel + shiftAction avgColorHolder avgColor shiftedColor shiftProcess readySema + originalPixels p previewImage previewImageHolder originalPreviewColormap originalPreviewPixels + anyChange | + + "/ compute the averageColor in the background (while asking user) + avgColorHolder := nil asValue. + previewImageHolder := nil asValue. + + readySema := Semaphore new. + [ + |image red green blue| + + image := imageEditView image. + originalColormap := image colorMap copy. + originalPixels := image bits. + red := (colorsToShift collect:[:clr | clr red]) average. + green := (colorsToShift collect:[:clr | clr green]) average. + blue := (colorsToShift collect:[:clr | clr blue]) average. + avgColor := Color red:red green:green blue:blue. + avgColorHolder value:avgColor. + + previewImage := self image magnifiedPreservingRatioTo:100@100. + previewImageHolder value: previewImage. + originalPreviewColormap := previewImage colorMap copy. + originalPreviewPixels := previewImage bits. + + readySema signal. + ] forkAt:7. + + acceptChannel := TriggerValue new. + + firstChange := true. + anyChange := false. + + shiftedColor := [:clr :hShift :lFactor :sFactor | + Color + hue:((clr hue) ? 0 + hShift) + light:((clr light * lFactor / 100) min:100) + saturation:((clr saturation * sFactor / 100) min:100)]. + + shiftAction := + [ + |hShift lFactor sFactor| + + acceptChannel value:true. + + firstChange ifTrue:[ + imageEditView makeUndo. + firstChange := false. + anyChange := true. + ]. + readySema notNil ifTrue:[readySema wait. readySema := nil]. + + hShift := hueShift value. + lFactor := lightValue value. + sFactor := saturationValue value. + + avgColorHolder value:(shiftedColor value:avgColor value:hShift value:lFactor value:sFactor). + + previewImage + colorMap:originalPreviewColormap copy; + bits:originalPreviewPixels copy; + release; + colorMapProcessing:[:clr | + (colorsToShift includes:clr) ifTrue:[ + shiftedColor value:clr value:hShift value:lFactor value:sFactor. + ] ifFalse:[ + clr + ] + ]. + previewImageHolder value:nil; value:previewImage. + + shiftProcess notNil ifTrue:[ + shiftProcess terminate. + shiftProcess waitUntilTerminated. + shiftProcess := nil. + ]. + + shiftProcess := + [ + [ + imageEditView image + colorMap:originalColormap copy; + bits:originalPixels copy; + release; + colorMapProcessing:[:clr | + (colorsToShift includes:clr) ifTrue:[ + shiftedColor value:clr value:hShift value:lFactor value:sFactor. + ] ifFalse:[ + clr + ] + ]. + self updateImage. + self updateInfoLabel. + self updateImagePreView. + ] ensure:[ shiftProcess := nil ]. + ] forkAt:7. + ]. + + bindings := IdentityDictionary new. + bindings at:#hueShiftAmount put:(hueShift := 0 asValue). + hueShift onChangeEvaluate:shiftAction. + + bindings at:#lightAmount put:(lightValue := 100 asValue). + lightValue onChangeEvaluate:shiftAction. + + bindings at:#saturationAmount put:(saturationValue := 100 asValue). + saturationValue onChangeEvaluate:shiftAction. + + bindings at:#acceptChannel put:acceptChannel. + bindings at:#hlsColor put:avgColorHolder. + bindings at:#previewImageHolder put:previewImageHolder. + + (self openDialogInterface:#changeHLSDialogSpec withBindings:bindings) + ifFalse:[ + anyChange ifTrue:[ + imageEditView undo + ] + ]. + + (p := shiftProcess) notNil ifTrue:[ + p waitUntilTerminated. + ]. + + anyChange ifTrue:[ + self updateImage. + self updateImagePreView. + ]. +! + clearColormapEntry0AndMaskedPixels "ensure that there is a colorMap entry with 0/0/0 at position 0 and then clear all masked pixels (to pixelValue 0). @@ -5543,15 +5756,27 @@ ! makeSelectedColorBrighter - self processSelectedColorWith:[:clr | clr lightened] + self processSelectedColorsWith:[:clr | clr lightened] ! makeSelectedColorDarker - self processSelectedColorWith:[:clr | clr darkened] + self processSelectedColorsWith:[:clr | clr darkened] ! makeSelectedColorGray - self processSelectedColorWith:[:clr | Color brightness:(clr brightness)] + self processSelectedColorsWith:[:clr | Color brightness:(clr brightness)] +! + +makeSelectedColorShifted + |cMap colors| + + cMap := self image colorMap. + self hasMask ifTrue:[ + colors := self selectedColors value collect:[:idx | cMap at:idx-1]. + ] ifFalse:[ + colors := self selectedColors value collect:[:idx | cMap at:idx]. + ]. + self changeHLSOfColors:colors. ! makeSlightlyBrighter @@ -5711,13 +5936,21 @@ ! processSelectedColorWith:aBlock - "undoable color processing: the selected color will be replaced by the - value of aBlock" - - |img cMap modifiedColormap oldColor newImage selectedColorIndex oldSelection newColor| - - selectedColorIndex := self selectedColorIndexOrNil. - selectedColorIndex isNil ifTrue:[^ self]. + "undoable color processing: + the selected color will be replaced by the value of aBlock" + + self processSelectedColorsWith:aBlock. +! + +processSelectedColorsWith:aBlock + "undoable color processing: + the selected colors will be replaced by the value of aBlock + (which gets a color vector and must return a color vector)" + + |img cMap modifiedColormap oldColors newImage selectedColorIndices newColors| + + selectedColorIndices := self selectedColors value. + selectedColorIndices isEmptyOrNil ifTrue:[^ self]. img := self image. cMap := img colorMap. @@ -5725,14 +5958,19 @@ self warn:(resources stringWithCRs:'Image has no colormap.\Please change the colorMap mode first.'). ^ self ]. - - oldColor := cMap at:selectedColorIndex. + self hasMask ifTrue:[ + oldColors := selectedColorIndices collect:[:idx | cMap at:idx-1]. + ] ifFalse:[ + oldColors := selectedColorIndices collect:[:idx | cMap at:idx]. + ]. imageEditView makeUndo. modifiedColormap := cMap asNewArray. - newColor := aBlock value:oldColor. - modifiedColormap at:selectedColorIndex put:newColor. + newColors := oldColors collect:aBlock. + selectedColorIndices with:newColors do:[:idx :newColor | + modifiedColormap at:idx put:newColor + ]. newImage := img species new width:img width @@ -5744,15 +5982,10 @@ newImage fileName:img fileName. newImage mask:(img mask copy). - oldSelection := self selectionOfColor value. - (imageEditView image:newImage) notNil ifTrue:[ self fetchImageData. ]. - self selectionOfColor value:oldSelection. - - "Created: / 12.3.1999 / 00:20:28 / cg" - "Modified: / 16.3.1999 / 21:57:26 / cg" + self selectedColors value:selectedColorIndices. ! reduceNumberOfColors @@ -5809,19 +6042,11 @@ ]. self withExecuteCursorDo:[ - image := self image. - "/ usedColors := image usedColorsMax:4096. - imageEditView makeUndo. - - newImage := image copy. - newImage photometric == #palette ifTrue:[ - newImage colorMap:(OrderedCollection new). - ]. - - image - colorsFromX:0 y:0 toX:(image width-1) y:(image height-1) - do:[:x :y :clr | - |r g b nr ng nb newClr| + |reduceColor| + + reduceColor := + [:clr | + |r g b nr ng nb| r := clr redByte. g := clr greenByte. @@ -5830,15 +6055,23 @@ ng := (g roundTo:rndG) min:255. nb := (b roundTo:rndB) min:255. - newClr := Color redByte:nr greenByte:ng blueByte:nb. - newImage photometric == #palette ifTrue:[ - (newImage colorMap includes:newClr) ifFalse:[ - newImage colorMap add:newClr - ]. + Color redByte:nr greenByte:ng blueByte:nb. + ]. + + image := self image. + "/ usedColors := image usedColorsMax:4096. + imageEditView makeUndo. + + newImage := image copy. + newImage photometric == #palette ifTrue:[ + newImage colorMap:(image colorMap collect:reduceColor). + ] ifFalse:[ + image + colorsFromX:0 y:0 toX:(image width-1) y:(image height-1) + do:[:x :y :clr | + newImage colorAtX:x y:y put:(reduceColor value:clr) ]. - newImage colorAtX:x y:y put:newClr - ]. - + ]. imageEditView image:newImage. imageEditView setModified. self updateImage. @@ -5886,7 +6119,7 @@ ]. ]. ]. - self selectionOfColor value:idx. + self selectedColors value:{idx}. "Modified: / 02-07-2010 / 12:06:07 / cg" ! @@ -5932,7 +6165,7 @@ sortColorMap "calculates a new color map for the image, sorting colors" - self sortColorMapWith:self sortBlockForColors + self sortColorMapWith:self sortBlockForColorsByRGB ! sortColorMapWith:sortBlock