Search code examples
applescriptactioncolor-pickerapplescript-objc

How to copy color with Color Picker Apple Script?


I need to improve this Apple Script: https://gist.github.com/mariocesar/b15cddd184481f25390e0a6e5cff2d40

# Open the color picker
on convertRGBColorToHexValue(theRGBValues)
    set theHexList to {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}
    set theHexValue to ""
    repeat with a from 1 to count of theRGBValues
        set theCurrentRGBValue to (item a of theRGBValues) div 256
        if theCurrentRGBValue is 256 then set theCurrentRGBValue to 255
        set theFirstItem to item ((theCurrentRGBValue div 16) + 1) of theHexList
        set theSecondItem to item (((theCurrentRGBValue / 16 mod 1) * 16) + 1) of theHexList
        set theHexValue to (theHexValue & theFirstItem & theSecondItem) as string
    end repeat
    return ("#" & theHexValue) as string
end convertRGBColorToHexValue

set theRGBValues to (choose color default color {255, 255, 255})
set hexValue to (convertRGBColorToHexValue(theRGBValues))

set the clipboard to hexValue as text

Currently, this script copies in the clipboard the color hexa value, AFTER clicking manually on "OK" button of the Color Picker window.

I would like to copy the color in the clipboard as soon as I click on it, to avoid clicking on "OK" button.

I tried to use click button "OK" without success.

enter image description here


Solution

  • interesting question. I found a great answer using lots of Applescript-ObjC from Applescript Guru Shane Stanley external link to MacScripter.net

    I tried a little bit around and adapted (mainly copied...) his handler. The solution:

    use scripting additions
    use framework "Foundation"
    use framework "AppKit"
    
    property theRGBValues : missing value
    
    -- check we are running in foreground
    -- when starting from Script Editor, please use CTRL-CMD-R !
    if not (current application's NSThread's isMainThread()) as boolean then
        display alert "This script must be run from the main thread." buttons {"Cancel"} as critical
        error number -128
    end if
    
    set my theRGBValues to missing value -- start off empty
    -- get color panel
    set thePicker to current application's NSColorPanel's sharedColorPanel()
    current application's NSColorPanel's setPickerMode:(current application's NSWheelModeColorPanel)
    -- get the action called by the eye-dropper button; hackish...
    set theViews to thePicker's contentView()'s subviews()
    repeat with aView in theViews
        if aView's |class|() is current application's NSButton then
            set theAction to aView's action()
            exit repeat
        end if
    end repeat
    -- set what happens when you click
    thePicker's setTarget:me -- message will be sent to this script
    thePicker's setAction:"colorPicked:" -- message will call handler of this name
    -- show the panel
    thePicker's orderFront:me
    -- click the eye-dropper
    aView's setState:(current application's NSOnState)
    thePicker's performSelector:theAction
    
    repeat -- loop until the user clicks
        if theRGBValues is not missing value then exit repeat
        delay 0.05
    end repeat
    
    set hexValue to (convertRGBColorToHexValue(theRGBValues))
    
    set the clipboard to hexValue as text
    
    (*****************************************
    ************* Handlers *********************
    ******************************************)
    
    -- gets called when you click
    on colorPicked:sender
        -- get the color
        set theColor to sender's |color|()
        -- convert to correct colorspace
        set newColor to theColor's colorUsingColorSpace:(current application's NSColorSpace's deviceRGBColorSpace())
        -- get components
        set theRed to newColor's redComponent()
        set theBlue to newColor's blueComponent()
        set theGreen to newColor's greenComponent()
        -- close panel
        sender's orderOut:me
        -- set property
        set my theRGBValues to {theRed * 255 as integer, theGreen * 255 as integer, theBlue * 255 as integer}
    end colorPicked:
    
    on convertRGBColorToHexValue(givenRGBValues)
        set theHexList to {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}
        set theHexValue to ""
        repeat with anRGBValue in givenRGBValues
            set theFirstItem to item ((anRGBValue div 16) + 1) of theHexList
            set theSecondItem to item (((anRGBValue / 16 mod 1) * 16) + 1) of theHexList
            set theHexValue to (theHexValue & theFirstItem & theSecondItem) as string
        end repeat
        return ("#" & theHexValue) as string
    end convertRGBColorToHexValue
    

    I changed the convertRGBColorToHexValue handler to work with the data returned by the color picker.

    Have fun! Michael / Hamburg