我正在尝试将UIView
背景颜色设置为UIImage左边缘颜色的颜色。我认为这将在UIView
上设置背景颜色以非常接近地匹配图像背景。
我尝试了平均颜色,有时效果不好 - 我的UIView
的颜色通常是几个阴影或错误的阴影,所有颜色都是图像的背景颜色。因此,我认为查看UIImage
的左边缘应该能够合理准确地表示UIImage
的背景颜色。
进行一些搜索并查看SO问题 - 我发现了一些代码,它完全符合我的需要。但它是OS X而不是iOS的代码。
- (NSColor*)findEdgeColor:(NSImage*)image imageColors:(NSCountedSet**)colors
{
NSBitmapImageRep *imageRep = [[image representations] lastObject];
if ( ![imageRep isKindOfClass:[NSBitmapImageRep class]] ) // sanity check
return nil;
NSInteger pixelsWide = [imageRep pixelsWide];
NSInteger pixelsHigh = [imageRep pixelsHigh];
NSCountedSet *imageColors = [[NSCountedSet alloc] initWithCapacity:pixelsWide * pixelsHigh];
NSCountedSet *leftEdgeColors = [[NSCountedSet alloc] initWithCapacity:pixelsHigh];
for ( NSUInteger x = 0; x < pixelsWide; x++ )
{
for ( NSUInteger y = 0; y < pixelsHigh; y++ )
{
NSColor *color = [imageRep colorAtX:x y:y];
if ( x == 0 )
{
[leftEdgeColors addObject:color];
}
[imageColors addObject:color];
}
}
*colors = imageColors;
NSEnumerator *enumerator = [leftEdgeColors objectEnumerator];
NSColor *curColor = nil;
NSMutableArray *sortedColors = [NSMutableArray arrayWithCapacity:[leftEdgeColors count]];
while ( (curColor = [enumerator nextObject]) != nil )
{
NSUInteger colorCount = [leftEdgeColors countForObject:curColor];
NSInteger randomColorsThreshold = (NSInteger)(pixelsHigh * kColorThresholdMinimumPercentage);
if ( colorCount <= randomColorsThreshold ) // prevent using random colors, threshold based on input image height
continue;
PCCountedColor *container = [[PCCountedColor alloc] initWithColor:curColor count:colorCount];
[sortedColors addObject:container];
}
[sortedColors sortUsingSelector:@selector(compare:)];
PCCountedColor *proposedEdgeColor = nil;
if ( [sortedColors count] > 0 )
{
proposedEdgeColor = [sortedColors objectAtIndex:0];
if ( [proposedEdgeColor.color pc_isBlackOrWhite] ) // want to choose color over black/white so we keep looking
{
for ( NSInteger i = 1; i < [sortedColors count]; i++ )
{
PCCountedColor *nextProposedColor = [sortedColors objectAtIndex:i];
if (((double)nextProposedColor.count / (double)proposedEdgeColor.count) > .3 ) // make sure the second choice color is 30% as common as the first choice
{
if ( ![nextProposedColor.color pc_isBlackOrWhite] )
{
proposedEdgeColor = nextProposedColor;
break;
}
}
else
{
// reached color threshold less than 40% of the original proposed edge color so bail
break;
}
}
}
}
return proposedEdgeColor.color;
}
有谁知道我怎么能为iOS做同样的事情?
答案 0 :(得分:1)
正如在https://github.com/lukaswelte/ColorArt
中所做的那样您可以通过以下方式执行此操作:
- (UIColor*)_findEdgeColor:(UIImage*)image imageColors:(NSArray**)colors {
CGImageRef imageRep = image.CGImage;
NSUInteger pixelRange = 32;
NSUInteger scale = 256 / pixelRange;
NSUInteger rawImageColors[pixelRange][pixelRange][pixelRange];
NSUInteger rawEdgeColors[pixelRange][pixelRange][pixelRange];
// Should probably just switch to calloc, but this doesn't show up in instruments
// So I guess it's fine
for(NSUInteger b = 0; b < pixelRange; b++) {
for(NSUInteger g = 0; g < pixelRange; g++) {
for(NSUInteger r = 0; r < pixelRange; r++) {
rawImageColors[r][g][b] = 0;
rawEdgeColors[r][g][b] = 0;
}
}
}
NSInteger width = CGImageGetWidth(imageRep);// [imageRep pixelsWide];
NSInteger height = CGImageGetHeight(imageRep); //[imageRep pixelsHigh];
CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
CGContextRef bmContext = CGBitmapContextCreate(NULL, width, height, 8, 4 * width, cs, kCGImageAlphaNoneSkipLast);
CGContextDrawImage(bmContext, (CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size.width = width, .size.height = height}, image.CGImage);
CGColorSpaceRelease(cs);
const RGBAPixel* pixels = (const RGBAPixel*)CGBitmapContextGetData(bmContext);
for (NSUInteger y = 0; y < height; y++)
{
for (NSUInteger x = 0; x < width; x++)
{
const NSUInteger index = x + y * width;
RGBAPixel pixel = pixels[index];
Byte r = pixel.red / scale;
Byte g = pixel.green / scale;
Byte b = pixel.blue / scale;
rawImageColors[r][g][b] = rawImageColors[r][g][b] + 1;
if(0 == x) {
rawEdgeColors[r][g][b] = rawEdgeColors[r][g][b] + 1;
}
}
}
CGContextRelease(bmContext);
NSMutableArray* imageColors = [NSMutableArray array];
NSMutableArray* edgeColors = [NSMutableArray array];
for(NSUInteger b = 0; b < pixelRange; b++) {
for(NSUInteger g = 0; g < pixelRange; g++) {
for(NSUInteger r = 0; r < pixelRange; r++) {
NSUInteger count = rawImageColors[r][g][b];
if(count > _randomColorThreshold) {
UIColor* color = [UIColor colorWithRed:r / (CGFloat)pixelRange green:g / (CGFloat)pixelRange blue:b / (CGFloat)pixelRange alpha:1];
PCCountedColor* countedColor = [[PCCountedColor alloc] initWithColor:color count:count];
[imageColors addObject:countedColor];
}
count = rawEdgeColors[r][g][b];
if(count > _randomColorThreshold) {
UIColor* color = [UIColor colorWithRed:r / (CGFloat)pixelRange green:g / (CGFloat)pixelRange blue:b / (CGFloat)pixelRange alpha:1];
PCCountedColor* countedColor = [[PCCountedColor alloc] initWithColor:color count:count];
[edgeColors addObject:countedColor];
}
}
}
}
*colors = imageColors;
NSMutableArray* sortedColors = edgeColors;
[sortedColors sortUsingSelector:@selector(compare:)];
PCCountedColor *proposedEdgeColor = nil;
if ( [sortedColors count] > 0 )
{
proposedEdgeColor = [sortedColors objectAtIndex:0];
if ( [proposedEdgeColor.color pc_isBlackOrWhite] ) // want to choose color over black/white so we keep looking
{
for ( NSInteger i = 1; i < [sortedColors count]; i++ )
{
PCCountedColor *nextProposedColor = [sortedColors objectAtIndex:i];
if (((double)nextProposedColor.count / (double)proposedEdgeColor.count) > .4 ) // make sure the second choice color is 40% as common as the first choice
{
if ( ![nextProposedColor.color pc_isBlackOrWhite] )
{
proposedEdgeColor = nextProposedColor;
break;
}
}
else
{
// reached color threshold less than 40% of the original proposed edge color so bail
break;
}
}
}
}
return proposedEdgeColor.color;
}
如果你只想要左边缘,你可以通过简单地排除其他边缘的for循环来实现这一点。