最終效果圖:
UIImage分類,Point2Color:<喎?/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPjwvcD4KPHA+PHByZSBjbGFzcz0="brush:java;">//
// UIImage+Point2Color.h
// 26_popOverCtrl
//
// Created by beyond on 14-8-31.
// Copyright (c) 2014年 com.beyond. All rights reserved.
//
#import
// // 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@protocol ColorPickerDelegate; @interface ColorPickerController : UIViewController // 成員:代理,到時個通知該代理,選擇的顏色是啥~ @property (weak, nonatomic) id 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@class ColorPickerController; @protocol ColorPickerDelegate @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 ()- (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