I have the following code which takes a HEX code somebody entered and transforms it into HSB:
NSString *cString = [[hexText.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString];
// String should be 6 or 8 characters
if ([cString length] < 6) NSLog(@"UH OH");
// strip 0X if it appears
if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2];
if ([cString length] != 6) NSLog(@"UH OH");
// Separate into r, g, b substrings
NSRange range;
range.location = 0;
range.length = 2;
NSString *rString = [cString substringWithRange:range];
range.location = 2;
NSString *gString = [cString substringWithRange:range];
range.location = 4;
NSString *bString = [cString substringW开发者_StackOverflow中文版ithRange:range];
// Scan values
unsigned int r, g, b;
[[NSScanner scannerWithString:rString] scanHexInt:&r];
[[NSScanner scannerWithString:gString] scanHexInt:&g];
[[NSScanner scannerWithString:bString] scanHexInt:&b];
float red = r / 255.0f;
float green = g / 255.0f;
float blue = b / 255.0f;
float colorArray[3];
colorArray[0] = red;
colorArray[1] = green;
colorArray[2] = blue;
int max;
int min;
min=0;
max=0;
for(int i=1; i<3; i++)
{
if(colorArray[i] > colorArray[max])
max=i;
if(colorArray[i] < colorArray[min])
min=i;
}
if(max==min)
{
h3=0;
s3=0;
b3=colorArray[0];
}
else
{
b3=colorArray[max];
s3=(colorArray[max]-colorArray[min])/(colorArray[max]);
if(max==0) // Red
h3 = (colorArray[1]-colorArray[2])/(colorArray[max]-colorArray[min])*60/360;
else if(max==1) // Green
h3 = (2.0 + (colorArray[2]-colorArray[0])/(colorArray[max]-colorArray[min]))*60/360;
else // Blue
h3 = (4.0 + (colorArray[0]-colorArray[1])/(colorArray[max]-colorArray[min]))*60/360;
}
I then have this code which does the opposite - transforms HSB into a hex code:
UIColor *forC = colourPreview.backgroundColor;
const CGFloat *c = CGColorGetComponents([forC CGColor]);
CGFloat r, g, b;
r = c[0];
g = c[1];
b = c[2];
if (r < 0.0f) r = 0.0f;
if (g < 0.0f) g = 0.0f;
if (b < 0.0f) b = 0.0f;
if (r > 1.0f) r = 1.0f;
if (g > 1.0f) g = 1.0f;
if (b > 1.0f) b = 1.0f;
hexWithoutHash = [NSString stringWithFormat:@"%02X%02X%02X",
(int)(r * 255), (int)(g * 255), (int)(b * 255)];
These should both give the same value, and most of the time it does. But sometimes I will type in a hex code such as 208DBC and it will return 1F8CBC. Any ideas? I think it's something to do with the second bit of code returning an inaccurate hex code, but not sure how to make this more accurate in this case?
Could be a floating-point precision issue. Using a float
or a double
does not store an exact value as using an int
or long
does. It stores the closest approximation of the exact value allowed by the IEEE-754 spec. The difference between the stored value and the exact value is generally very small, but it may be just big enough that when you convert back to an integer your value gets truncated to the next smaller integer. That is what is happening in your output (i.e. 0x1F = 0x20 - 1
, 0x8C = 0x8D - 1
).
The following code may illustrate the issue:
for (int redColor = 0; redColor < 256; redColor++) {
int originalRed = redColor;
float red = originalRed / 255.0f;
float redMultiplied = red * 255;
int newRed = (int)redMultiplied;
if (newRed != originalRed) {
NSLog(@"Value mismatch detected: origianlRed=%d, red=%f, redMultiplied=%f, newRed=%d",
originalRed, red, redMultiplied, newRed);
}
}
精彩评论