Problem with comparing 2 colors

I get my first color by creating it with:
set colorA to (current application's NSColor's colorWithCalibratedRed:0.299992 green:0.30457 blue:0.30457 alpha:1)
and the second color from an attributed string:
set colorB to theFont's valueForKey:"NSColor"
They both have the same value in log panel:
(*NSCalibratedRGBColorSpace 0.299992 0.30457 0.30457 1*)

But when I compare them using colorA's isEqual:colorB the result is false.
Is this an issue with Applescript’s inherent approximation on large numbers?
Or something else?

I suspect so. The Cocoa way is to use CGColorEqualToColor(), but that requires CGColors, which you can’t use from ASObjC.

Yes. Even if the NSColor class has a CGColor property, it appears to be unusable.
Thank you Shane.

Have a great day!

If you have sufficient desire, you can probably run any C code from AppleScript via do shell script.

I remember playing with it in the past.

Here’s one thread on the subject:

This method is the easiest, in my view:

do shell script "cc /path/to/your/test.c ; ~/a.out"

It does work, for example, for this simple sample from years ago I’ve just tried:

#include <stdio.h>

int arc4random_uniform(int);

int main(void)    
{
  printf("%i\n", arc4random_uniform(10000000));
return 0;
}

I don’t know if it’s worth the trouble or if it’s suitable for your particular need at all.

Hi Leo,

Thanks for the suggestion buy it’s a bit too complex for my needs.
My solution is to compare rgba values, rounded to 6 decimals.

This code and my Mac mini M1 (macOS 13.6) returns true.
My MacBook Air M2 (macOS 14.6) returns true, too.
Which is your os and machine?

use AppleScript
use framework “Foundation”
use framework “AppKit”
use scripting additions

set colA to current application’s NSColor’s colorWithCalibratedRed:0.299992 green:0.30457 blue:0.30457 alpha:1
set colB to current application’s NSColor’s colorWithCalibratedRed:0.299992 green:0.30457 blue:0.30457 alpha:1

set colRes to colA’s isEqual:colB
→ true

Hi Piyo,
I think you read my post a little too quickly.

:wink:

Oh, I might have a mistake.
I’ll go to bed to sleep enough.

Post again. It reads RTF format information, converts it to a dictionary in list, and processes color matching with AppleScript. It is a function that is actually used in various AppleScripts, such as extracting color values from each RGB channel, extracting general color trends as color domains.

Using such AppleScript routines, we believe that we can make comparisons with numbers and characters.

http://piyocast.com/as/archives/1278

Hi Takaaki,

Your script is more or less what I’m doing: I’m using color values to compare them.
Here is the handler I’m using to retrieve color values:

on getColorValues:colRange inText:colText
	set theFont to colText's fontAttributesInRange:colRange
	set theColor to theFont's valueForKey:"NSColor"
	if theColor = missing value then return {}
	set theRed to round ((theColor's redComponent()) * 1000000) rounding down
	set theGreen to round ((theColor's greenComponent()) * 1000000) rounding down
	set theBlue to round ((theColor's blueComponent()) * 1000000) rounding down
	set theAlpha to theColor's alphaComponent()
	set theSpace to theColor's colorSpace()
	return {theRed, theGreen, theBlue, theAlpha, theSpace}
end getColorValues:inText:

And the following is to get the attribute runs, given an attributed string:

-- get attribute runs
set textStorage to (current application's NSTextStorage's alloc()'s initWithAttributedString:attString)
set attRuns to textStorage's attributeRuns()

@ionah what if you just compare the colors’ descriptions as strings:

set colorA to (current application's NSColor's colorWithCalibratedRed:0.299992 green:0.30457 blue:0.30457 alpha:1)
set colorB to theFont's valueForKey:"NSColor"
colorA's |description|()'s isEqualToString:(colorB's |description|())
1 Like

Excellent suggestion, Shane!

I think RTF is a kind of a subset of Microsoft Word document.

Microsoft Word coloring function is…

スクリーンショット 2024-08-13 10.03.26

Like this.

I can’t imagine a use case where RTF ≈ Word Document needs to deal with very subtle color differences.

@ionah
I played with your code, and both examples return boolean true with method:isEqual

use framework "Foundation"
use framework "AppKit"
use scripting additions

set theColor1 to current application's NSColor's redColor()
log theColor1's |description|() as string

set attrDict1 to current application's NSDictionary's dictionaryWithObject:theColor1 forKey:"NSForegroundColorAttributeName"
set attrString to current application's NSAttributedString's alloc()'s initWithString:"hello" attributes:attrDict1
set theColor2_2 to (attrString's attributesAtIndex:0 effectiveRange:(current application's NSMakeRange(0, 1)))'s valueForKey:"NSForegroundColorAttributeName"

set theColor2 to current application's NSColor's colorWithSRGBRed:1 green:0 blue:0 alpha:1
log (theColor1's isEqual:theColor2)
log (theColor1's isEqual:theColor2_2)

set theColor3 to (current application's NSColor's colorWithCalibratedRed:1 green:0 blue:0 alpha:1)
log theColor3's |description|() as string

set attrDict2 to current application's NSDictionary's dictionaryWithObject:theColor3 forKey:"NSForegroundColorAttributeName"
set attrString to current application's NSAttributedString's alloc()'s initWithString:"hello" attributes:attrDict2
set theColor4 to (attrString's attributesAtIndex:0 effectiveRange:(current application's NSMakeRange(0, 1)))'s valueForKey:"NSForegroundColorAttributeName"
log (theColor3's isEqual:theColor4)

Hi, @Fredrik71

Yes, with this kind of colors…

The colors I use come from several client documents, generated on PC by a database manager.
RGB values in those documents are up to 12 digits when I load them using AppleScriptObjC.

The problem here is that if we look for the color value in the result or log pane, it will return values rounded to 6 digits.
The only way to get the complete value is to ask for individual components like in this example:

use framework "Foundation"

set theRed to (current application's NSColor's colorWithCalibratedRed:0.654987321987 green:0 blue:0 alpha:1)

log theRed's redComponent()
log theRed
return theRed

So: if you are in a hurry, use the color description; otherwise, take the time to extract the value of each component…

:wink:

I wonder if using debugDescription() instead will make a difference?

If I’m correct CGFloat could be float or double. So I took @leo_r info and convert it to NSNumber

use framework "Foundation"
use framework "AppKit"
use scripting additions

set theColor1 to (current application's NSColor's colorWithCalibratedRed:0.123456789123 green:0 blue:0 alpha:1)
log theColor1's |description|() as string
log theColor1's |debugDescription|() as string
set theNumber1 to current application's NSNumber's numberWithDouble:(theColor1's redComponent())
log theNumber1's |debugDescription|() as string

set attrDict2 to current application's NSDictionary's dictionaryWithObject:theColor1 forKey:"NSForegroundColorAttributeName"
set attrString to current application's NSAttributedString's alloc()'s initWithString:"hello" attributes:attrDict2
set theColor2 to (attrString's attributesAtIndex:0 effectiveRange:(current application's NSMakeRange(0, 1)))'s valueForKey:"NSForegroundColorAttributeName"
set theNumber2 to current application's NSNumber's numberWithDouble:(theColor2's redComponent())
log theNumber2's |debugDescription|() as string
log theColor2's |description|() as string
log theColor2's |debugDescription|() as string
-- 6 digits
log (theColor1's isEqual:theColor2)
-- 12 digits
log (theNumber1's isEqual:theNumber2)