這一篇,簡單講一講模仿Sip Color App拾取圖片上某點的顏色值,并實現像Sip Color那樣,在屏幕上隨機生成幾個圓點視圖,圓點視圖顯示它所在點的顏色,可以點擊放大某個圓點視圖,也可以觸摸和移動某個圓點的效果。
從圖片上拾取顏色是Sip Color的最核心的功能之一,也是后面實現從攝像頭捕獲顏色等操作的基礎。
首先,我們用到的最重要的一個創建位圖上下文的方法:
/**
* @param data 指向要渲染的繪制內存的地址。這個內存塊的大小至少是(bytesPerRow*height)個字節
* @param width bitmap的寬度,單位為像素
* @param height bitmap的高度,單位為像素
* @param bitsPerComponent 內存中像素的每個組件的位數.例如,對于32位像素格式和RGB顏色空間,你應該將這個值設為8.
* @param bytesPerRow bitmap的每一行在內存所占的比特數
* @param space bitmap上下文使用的顏色空間
* @param bitmapInfo 指定bitmap是否包含alpha通道,像素中alpha通道的相對位置,像素組件是整形還是浮點型等信息的字符串。
*/
CGContextRef CGBitmapContextCreate(void *data,
size_t width,
size_t height,
size_t bitsPerComponent,
size_t bytesPerRow,
CGColorSpaceRef colorspace,
CGBitmapInfo bitmapInfo);
我們創建一個UIImage+Color分類來實現獲取圖片上某點的顏色值:
- (UIColor *)yl_colorAtPoint:(CGPoint)point
{
if(!CGRectContainsPoint(CGRectMake(0, 0, self.size.width, self.size.height), point)){
return nil;
}
NSInteger pointX = trunc(point.x);//截斷取整,不四舍五入
NSInteger pointY = trunc(point.y);
CGImageRef cgImage = self.CGImage;
CGFloat width = self.size.width;
CGFloat height = self.size.height;
//創建色彩標準
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
int bytesPerPixel = 4;
int bytesPerRow = bytesPerPixel * 1;
NSUInteger bitsPerComponent = 8;
unsigned char pixelData[4] = {0, 0, 0, 0};
CGContextRef context = CGBitmapContextCreate(pixelData,
1,
1,
bitsPerComponent,
bytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedLast|kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextSetBlendMode(context, kCGBlendModeCopy);
CGContextTranslateCTM(context, -pointX, pointY - height);
CGContextDrawImage(context, CGRectMake(0.f, 0.f, width, height), cgImage);
CGContextRelease(context);
CGFloat red = (CGFloat)pixelData[0] / 255.f;
CGFloat green = (CGFloat)pixelData[1] / 255.f;
CGFloat blue = (CGFloat)pixelData[2] / 255.f;
CGFloat alpha = (CGFloat)pixelData[3] / 255.f;
return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
}
然后,定義展示顏色點的圓形視圖
定義一個圓形視圖YLColorDotView,在視圖控制器中實現以下方法,在點擊圓點時對當前圓點進行放大,并記錄當前圓點,在手指移動時保持圓點放大的同時圓點跟著手指一起移動并且實時顯示當前觸摸點的顏色。觸摸結束,將當前拖動的圓點重置為正常大小并放在當前觸摸結束的位置上。
#pragma mark---touch action move dots
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
if(_imageView.hidden){
return;
}
BOOL touchOnDot = NO;
for(UITouch *touch in touches.allObjects){
if([touch.view isKindOfClass:[YLColorDotView class]]){
_currentDragDotView = (YLColorDotView *)(touch.view);
[_currentDragDotView showBigDotAnimated:YES];
touchOnDot = YES;
break;
}
}
if(!touchOnDot && _currentDragDotView){
_currentDragDotView = nil;
}
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
if(_imageView.hidden){
return;
}
UITouch *touch = touches.anyObject;
CGPoint location = [touch locationInView:self.view];
if(_currentDragDotView){
_currentDragDotView.backgroundColor = [self.imageView.image yl_colorAtPoint:location];
_currentDragDotView.center = location;
}
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
if(_imageView.hidden){
return;
}
if(_currentDragDotView){
[_currentDragDotView resetAnimated:YES];
}
}
最后,生成隨機點并把圓點放到這些隨機點上
通過隨機函數,在屏幕范圍內生成隨機的x,y值來確定隨機點,然后加一個動畫,把這些點移動到這些點。(為了防止重復創建,這里記錄了之前創建的圓點,如果圓點已存在,則修改圓點的顏色并將圓點從當前位置移動到新的隨機位置處。如果圓點是新創建的,則從屏幕中心點移動到隨機位置處。這樣的效果會比從屏幕左上角移動到隨機位置處的效果要好很多。)
- (void)generateDots
{
NSInteger maxWidth = CGRectGetWidth(self.view.bounds) - minDotSize;
NSInteger maxHeight = CGRectGetHeight(self.view.bounds) - minDotSize;
NSMutableArray *centerPoints = [NSMutableArray arrayWithCapacity:_maxDotCount];
for(NSInteger i = 0; i < _maxDotCount; i++){
CGFloat x = minDotSize * 0.5 + arc4random() % maxWidth + 1;
CGFloat y = minDotSize * 0.5 + arc4random() % maxHeight + 1;
CGPoint center = CGPointMake(x, y);
[centerPoints addObject:[NSValue valueWithCGPoint:center]];
YLColorDotView *dotView = nil;
UIColor *color = [_imageView.image yl_colorAtPoint:center];
if(i < _dotViews.count){
dotView = _dotViews[i];
}else{
dotView = [[YLColorDotView alloc]init];
//move from the view's center
dotView.center = self.view.center;
[self.view addSubview:dotView];
[_dotViews addObject:dotView];
}
//set color
dotView.backgroundColor = color;
}
[UIView animateWithDuration:0.5f delay:0.f options:UIViewAnimationOptionBeginFromCurrentState animations:^{
//move to the point
for(NSInteger i = 0; i < _maxDotCount; i++){
UIView *dotView = _dotViews[i];
dotView.center = [centerPoints[i]CGPointValue];
}
} completion:^(BOOL finished) {
}];
[self.view layoutIfNeeded];
}
最后,給大家看看效果圖:
sip-color