最终效果图:
UIImage分类,Point2Color:
// // UIImage+Point2Color.h // 26_popOverCtrl // // Created by beyond on 14-8-31. // Copyright (c) 2014年 com.beyond. All rights reserved. // #import <UIKit/UIKit.h> @interface UIImage (Point2Color) // 传入 一个点坐标,返回图片上该点的颜色对象 - (UIColor *)colorFromPoint:(CGPoint)point; @end
// // UIImage+Point2Color.m // 26_popOverCtrl // // Created by beyond on 14-8-31. // Copyright (c) 2014年 com.beyond. All rights reserved. // 分类,传入一个point,获取该点的颜色 #import "UIImage+Point2Color.h" @implementation UIImage (Point2Color) // 传入 一个点坐标,返回图片上该点的颜色对象 // 将图片写入内存,再依据【点】中取颜色 - (UIColor *)colorFromPoint:(CGPoint)point { UIColor *color = nil; // 得到取色图片的引用 CGImageRef inImage = self.CGImage; // 调用自定义方法:从_imgView里面的image的引用,创建并返回对应的上下文 CGContextRef contexRef = [self ARGBBitmapContextFromImage:inImage]; // 如果创建该图片对应的上下文失败 if (contexRef == NULL){ NSLog(@"取色图片--创建对应的上下文失败~"); return nil; } // 准备将【取色图片】写入刚才创建出来的上下文 size_t w = CGImageGetWidth(inImage); size_t h = CGImageGetHeight(inImage); CGRect rect = {{0,0},{w,h}}; // 调试输出rect:--{{0, 0}, {225, 250}} // 将位图写入(渲染)已经创建好的 上下文工作空间 CGContextDrawImage(contexRef, rect, inImage); // 得到位图上下文 内存数据块的首地址,用指针记住,作为基地址 unsigned char* dataPoint = CGBitmapContextGetData (contexRef); NSLog(@"----首地址,指针%p",dataPoint); // ----首地址,指针0x8b3f000 if (dataPoint != NULL) { //offset 即:根据触摸点的xy,定位到位图内存空间中的一个特定像素 //4 的意思是每一个像素点,占4个字节 // w是每一行所有点的总数 // 根据所在行,所在列,算出在内存块中的偏移地址,然后乘以4,因为每一个点在内存中占四个字节 int offset = 4*((w*round(point.y))+round(point.x)); // alpha 为内存基地址+偏移地址 int alpha = dataPoint[offset]; // red 为内存基地址+偏移地址+1 其他类似 int red = dataPoint[offset+1]; int green = dataPoint[offset+2]; int blue = dataPoint[offset+3]; NSLog(@"偏移地址: %i colors: RGBA %i %i %i %i",offset,red,green,blue,alpha); // offset: 150908 colors: RGB A 255 0 254 255 // 根据RGBA 生成颜色对象 color = [UIColor colorWithRed:(red/255.0f) green:(green/255.0f) blue:(blue/255.0f) alpha:(alpha/255.0f)]; } // 操作完成后,释放上下文对象 CGContextRelease(contexRef); // 从内存中释放掉 加载到内存的图像数据 if (dataPoint) { free(dataPoint); } // 返回图片上该点对应的颜色 return color; } // 自定义方法2:通过_imgView里面的image的引用,创建并返回对应的上下文,即根据CGImageRef来创建一个ARGBBitmapContext - (CGContextRef)ARGBBitmapContextFromImage:(CGImageRef) inImage { // 要创建的上下文 CGContextRef context = NULL; // 色彩空间 CGColorSpaceRef colorSpace; // 位图数据在内存空间的首地址 void * bitmapData; // 每一行的字节数 int bitmapBytesPerRow; // 图片总的占的字节数 int bitmapByteCount; // 得到图片的宽度和高度,将要使用整个图片,创建上下文 size_t pixelsWide = CGImageGetWidth(inImage); size_t pixelsHigh = CGImageGetHeight(inImage); // 每一行占多少字节. 本取色图片中的每一个像素点占4个字节; // 红 绿 蓝 透明度 各占一个字节(8位 取值范围0~255) // 每一行的字节数,因为每一个像素点占4个字节(包含RGBA)(其中一个R就是一个字节,占8位,取值是2的8次方 0~255) bitmapBytesPerRow = (pixelsWide * 4); // 图片总的占的字节数 bitmapByteCount = (bitmapBytesPerRow * pixelsHigh); // 使用指定的 色彩空间(RGB) colorSpace = CGColorSpaceCreateDeviceRGB(); if (colorSpace == NULL) { fprintf(stderr, "创建并分配色彩空间 出错\n"); return NULL; } // 为取色图片数据 分配所有的内存空间 // 所有画到取色图片上下文的操作,都将被渲染到此内存空间 bitmapData = malloc( bitmapByteCount ); if (bitmapData == NULL) { fprintf (stderr, "内存空间分配失败~"); CGColorSpaceRelease( colorSpace ); return NULL; } // 创建位图上下文. 使用 pre-multiplied ARGB, ARGB中的每一个成员都占8个bit位,即一字节,一个像素共占4个字节 // 无论原取色图片的格式是什么(CMYK或Grayscale),都将通过CGBitmapContextCreate方法,转成指定的ARGB格式 context = CGBitmapContextCreate (bitmapData, pixelsWide, pixelsHigh, 8, // bits per component bitmapBytesPerRow, colorSpace, (CGBitmapInfo)kCGImageAlphaPremultipliedFirst); if (context == NULL) { free (bitmapData); fprintf (stderr, "位图上下文创建失败~"); } // 在返回上下文之前 必须记得释放 色彩空间 CGColorSpaceRelease( colorSpace ); return context; } @end
ColorPicker控制器及其代理
// // ColorPickerController.h // 26_popOverCtrl // // Created by beyond on 14-8-31. // Copyright (c) 2014年 com.beyond. All rights reserved. // #import <UIKit/UIKit.h> @protocol ColorPickerDelegate; @interface ColorPickerController : UIViewController // 成员:代理,到时个通知该代理,选择的颜色是啥~ @property (weak, nonatomic) id<ColorPickerDelegate> delegate; @end
// // ColorPickerController.m // 26_popOverCtrl // // Created by beyond on 14-8-31. // Copyright (c) 2014年 com.beyond. All rights reserved. // #import "ColorPickerController.h" // 分类 #import "UIImage+Point2Color.h" // 颜色选择完毕,通知代理 #import "ColorPickerDelegate.h" @interface ColorPickerController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @end @implementation ColorPickerController #pragma mark - 生命周期方法 - (void)viewDidLoad { [super viewDidLoad]; // 重要~~~指定 当前控制器在popover中显示的大小(跟 图片 一样) self.preferredContentSize = self.imageView.image.size; } // 触摸结束时,获取点击的坐标,调用UIImage分类方法,获取图片上该点的颜色 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { // 有人需要该点的颜色,才进行取色 if ([self.delegate respondsToSelector:@selector(colorPickerController:didSelectedColor:)]) { // 获得触摸点 UITouch *touch = [touches anyObject]; CGPoint point = [touch locationInView:touch.view]; // 获得颜色 UIColor *color = [self.imageView.image colorFromPoint:point]; // 告诉代理,该点对应的颜色 [self.delegate colorPickerController:self didSelectedColor:color]; } } @end
// // ColorPickerDelegate.h // 26_popOverCtrl // // Created by beyond on 14-8-31. // Copyright (c) 2014年 com.beyond. All rights reserved. // 颜色选择控制器的代理,当它解码出用户点击处的颜色时,通知代理 #import <Foundation/Foundation.h> @class ColorPickerController; @protocol ColorPickerDelegate <NSObject> @optional - (void)colorPickerController:(ColorPickerController *)ctrl didSelectedColor:(UIColor *)color; @end
主控制器
// // BeyondViewController.m // 26_popOverCtrl // // Created by beyond on 14-8-31. // Copyright (c) 2014年 com.beyond. All rights reserved. // 00000000 // 99999999 #import "BeyondViewController.h" // 点击左边Item,弹出Nana控制器 #import "NanaViewController.h" // 点击中间的按钮,弹出颜色选择控制器 #import "ColorPickerController.h" // 代理方法 #import "ColorPickerDelegate.h" @interface BeyondViewController ()<ColorPickerDelegate> - (IBAction)menuClick:(UIBarButtonItem *)sender; - (IBAction)colorButtonClick:(UIButton *)sender; // UIPopoverController 不能是局部变量,必须是成员变量 @property (nonatomic, strong) UIPopoverController *menuPopover; // UIPopoverController 不能是局部变量,必须是成员变量 @property (nonatomic, strong) UIPopoverController *colorPopover; @end @implementation BeyondViewController #pragma mark - 懒加载 getter方法 - (UIPopoverController *)menuPopover { if (_menuPopover == nil) { // 1.创建内容控制器 NanaViewController *nana = [[NanaViewController alloc] init]; UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:nana]; // 2.创建popover self.menuPopover = [[UIPopoverController alloc] initWithContentViewController:nav]; } // 返回popOver return _menuPopover; } - (UIPopoverController *)colorPopover { if (_colorPopover == nil) { // 1.创建内容控制器 ColorPickerController *cpvc = [[ColorPickerController alloc] init]; cpvc.delegate = self; // 2.创建popover self.colorPopover = [[UIPopoverController alloc] initWithContentViewController:cpvc]; // 重要~~~点击popOver之外的阴影,使点击事件可以穿透... // self.colorPopover.passthroughViews = @[self.colorButton]; } return _colorPopover; } #pragma mark - 颜色选择控制器的代理方法 - (void)colorPickerController:(ColorPickerController *)cpvc didSelectedColor:(UIColor *)color { self.view.backgroundColor = color; } #pragma mark - 监听按钮点击 /** * 点击菜单,在指定位置,弹出popOver */ - (IBAction)menuClick:(UIBarButtonItem *)sender { // 显示到哪个位置 [self.menuPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; } /** * 点击了颜色按钮,在指定位置,弹出popOver */ - (IBAction)colorButtonClick:(UIButton *)sender { [self.colorPopover presentPopoverFromRect:sender.bounds inView:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; } @end
原文地址:http://blog.csdn.net/pre_eminent/article/details/38962959