Fix the sd_colorAtPoint return wrong value on pre-multiplied CGImage
Should always un-multiplied the color to match CGColor/UIColor documentation
This commit is contained in:
parent
213be11357
commit
9efacfed97
|
@ -107,6 +107,7 @@ typedef NS_OPTIONS(NSUInteger, SDRectCorner) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Return the pixel color at specify position. The point is from the top-left to the bottom-right and 0-based. The returned the color is always be RGBA format. The image must be CG-based.
|
Return the pixel color at specify position. The point is from the top-left to the bottom-right and 0-based. The returned the color is always be RGBA format. The image must be CG-based.
|
||||||
|
@note The point's x/y will be converted into integer.
|
||||||
@note The point's x/y should not be smaller than 0, or greater than or equal to width/height.
|
@note The point's x/y should not be smaller than 0, or greater than or equal to width/height.
|
||||||
@note The overhead of object creation means this method is best suited for infrequent color sampling. For heavy image processing, grab the raw bitmap data and process yourself.
|
@note The overhead of object creation means this method is best suited for infrequent color sampling. For heavy image processing, grab the raw bitmap data and process yourself.
|
||||||
|
|
||||||
|
@ -117,6 +118,7 @@ typedef NS_OPTIONS(NSUInteger, SDRectCorner) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Return the pixel color array with specify rectangle. The rect is from the top-left to the bottom-right and 0-based. The returned the color is always be RGBA format. The image must be CG-based.
|
Return the pixel color array with specify rectangle. The rect is from the top-left to the bottom-right and 0-based. The returned the color is always be RGBA format. The image must be CG-based.
|
||||||
|
@note The rect's origin and size will be converted into integer.
|
||||||
@note The rect's width/height should not be smaller than or equal to 0. The minX/minY should not be smaller than 0. The maxX/maxY should not be greater than width/height. Attention this limit is different from `sd_colorAtPoint:` (point: (0, 0) like rect: (0, 0, 1, 1))
|
@note The rect's width/height should not be smaller than or equal to 0. The minX/minY should not be smaller than 0. The maxX/maxY should not be greater than width/height. Attention this limit is different from `sd_colorAtPoint:` (point: (0, 0) like rect: (0, 0, 1, 1))
|
||||||
@note The overhead of object creation means this method is best suited for infrequent color sampling. For heavy image processing, grab the raw bitmap data and process yourself.
|
@note The overhead of object creation means this method is best suited for infrequent color sampling. For heavy image processing, grab the raw bitmap data and process yourself.
|
||||||
|
|
||||||
|
|
|
@ -169,7 +169,32 @@ static inline UIColor * SDGetColorFromRGBA(Pixel_8888 pixel, CGBitmapInfo bitmap
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
switch (alphaInfo) {
|
switch (alphaInfo) {
|
||||||
case kCGImageAlphaPremultipliedFirst:
|
case kCGImageAlphaPremultipliedFirst: {
|
||||||
|
if (byteOrderNormal) {
|
||||||
|
// ARGB8888-premultiplied
|
||||||
|
a = pixel[0] / 255.0;
|
||||||
|
r = pixel[1] / 255.0;
|
||||||
|
g = pixel[2] / 255.0;
|
||||||
|
b = pixel[3] / 255.0;
|
||||||
|
if (a > 0) {
|
||||||
|
r /= a;
|
||||||
|
g /= a;
|
||||||
|
b /= a;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// BGRA8888-premultiplied
|
||||||
|
b = pixel[0] / 255.0;
|
||||||
|
g = pixel[1] / 255.0;
|
||||||
|
r = pixel[2] / 255.0;
|
||||||
|
a = pixel[3] / 255.0;
|
||||||
|
if (a > 0) {
|
||||||
|
r /= a;
|
||||||
|
g /= a;
|
||||||
|
b /= a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case kCGImageAlphaFirst: {
|
case kCGImageAlphaFirst: {
|
||||||
if (byteOrderNormal) {
|
if (byteOrderNormal) {
|
||||||
// ARGB8888
|
// ARGB8888
|
||||||
|
@ -186,7 +211,32 @@ static inline UIColor * SDGetColorFromRGBA(Pixel_8888 pixel, CGBitmapInfo bitmap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case kCGImageAlphaPremultipliedLast:
|
case kCGImageAlphaPremultipliedLast: {
|
||||||
|
if (byteOrderNormal) {
|
||||||
|
// RGBA8888-premultiplied
|
||||||
|
r = pixel[0] / 255.0;
|
||||||
|
g = pixel[1] / 255.0;
|
||||||
|
b = pixel[2] / 255.0;
|
||||||
|
a = pixel[3] / 255.0;
|
||||||
|
if (a > 0) {
|
||||||
|
r /= a;
|
||||||
|
g /= a;
|
||||||
|
b /= a;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// ABGR8888-premultiplied
|
||||||
|
a = pixel[0] / 255.0;
|
||||||
|
b = pixel[1] / 255.0;
|
||||||
|
g = pixel[2] / 255.0;
|
||||||
|
r = pixel[3] / 255.0;
|
||||||
|
if (a > 0) {
|
||||||
|
r /= a;
|
||||||
|
g /= a;
|
||||||
|
b /= a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case kCGImageAlphaLast: {
|
case kCGImageAlphaLast: {
|
||||||
if (byteOrderNormal) {
|
if (byteOrderNormal) {
|
||||||
// RGBA8888
|
// RGBA8888
|
||||||
|
@ -546,9 +596,11 @@ static inline CGImageRef _Nullable SDCreateCGImageFromCIImage(CIImage * _Nonnull
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check point
|
// Check point
|
||||||
CGFloat width = CGImageGetWidth(imageRef);
|
size_t width = CGImageGetWidth(imageRef);
|
||||||
CGFloat height = CGImageGetHeight(imageRef);
|
size_t height = CGImageGetHeight(imageRef);
|
||||||
if (point.x < 0 || point.y < 0 || point.x >= width || point.y >= height) {
|
size_t x = point.x;
|
||||||
|
size_t y = point.y;
|
||||||
|
if (x < 0 || y < 0 || x >= width || y >= height) {
|
||||||
CGImageRelease(imageRef);
|
CGImageRelease(imageRef);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
@ -570,7 +622,7 @@ static inline CGImageRef _Nullable SDCreateCGImageFromCIImage(CIImage * _Nonnull
|
||||||
size_t components = CGImageGetBitsPerPixel(imageRef) / CGImageGetBitsPerComponent(imageRef);
|
size_t components = CGImageGetBitsPerPixel(imageRef) / CGImageGetBitsPerComponent(imageRef);
|
||||||
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
|
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
|
||||||
|
|
||||||
CFRange range = CFRangeMake(bytesPerRow * point.y + components * point.x, components);
|
CFRange range = CFRangeMake(bytesPerRow * y + components * x, components);
|
||||||
if (CFDataGetLength(data) < range.location + range.length) {
|
if (CFDataGetLength(data) < range.location + range.length) {
|
||||||
CFRelease(data);
|
CFRelease(data);
|
||||||
CGImageRelease(imageRef);
|
CGImageRelease(imageRef);
|
||||||
|
@ -620,8 +672,8 @@ static inline CGImageRef _Nullable SDCreateCGImageFromCIImage(CIImage * _Nonnull
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check rect
|
// Check rect
|
||||||
CGFloat width = CGImageGetWidth(imageRef);
|
size_t width = CGImageGetWidth(imageRef);
|
||||||
CGFloat height = CGImageGetHeight(imageRef);
|
size_t height = CGImageGetHeight(imageRef);
|
||||||
if (CGRectGetWidth(rect) <= 0 || CGRectGetHeight(rect) <= 0 || CGRectGetMinX(rect) < 0 || CGRectGetMinY(rect) < 0 || CGRectGetMaxX(rect) > width || CGRectGetMaxY(rect) > height) {
|
if (CGRectGetWidth(rect) <= 0 || CGRectGetHeight(rect) <= 0 || CGRectGetMinX(rect) < 0 || CGRectGetMinY(rect) < 0 || CGRectGetMaxX(rect) > width || CGRectGetMaxY(rect) > height) {
|
||||||
CGImageRelease(imageRef);
|
CGImageRelease(imageRef);
|
||||||
return nil;
|
return nil;
|
||||||
|
|
Loading…
Reference in New Issue