本文从【增强】模块入手介绍一下界面设计和功能实现。所有功能都已实现,部分功能有待改善,我会在以后时间中步步改善。目前效果也很棒。有兴趣的可以在文章最后提供的下载链接中下载并运行。模拟器最好使用iphone6模拟器【增强】功能包含如下功能
1.亮度
2.对比度
3.色温
4.饱和度
5.高光
6.暗部
7.智能补光
涉及开发技巧
效果bar的实现
UISlider的使用
GPUImage的使用
一、自定义bar
点击一个效果按钮时,该按钮变为高亮状态,而前面的按钮自动恢复到正常状态
代码实现
#import@class FWEffectBar, FWEffectBarItem;@protocol FWEffectBarDelegate - (void)effectBar:(FWEffectBar *)bar didSelectItemAtIndex:(NSInteger)index;@end@interface FWEffectBar : UIScrollView@property (nonatomic, assign) id delegate;@property (nonatomic, copy) NSArray *items;@property (nonatomic, weak) FWEffectBarItem *selectedItem;@property UIEdgeInsets contentEdgeInsets;/** * Sets the height of tab bar. */- (void)setHeight:(CGFloat)height;/** * Returns the minimum height of tab bar's items. */- (CGFloat)minimumContentHeight;@end
//// FWEffectBar.m// FWMeituApp//// Created by ForrestWoo on 15-9-23.// Copyright (c) 2015年 ForrestWoo co,.ltd. All rights reserved.//#import "FWEffectBar.h"#import "FWEffectBarItem.h"@interface FWEffectBar ()@property (nonatomic) CGFloat itemWidth;@end@implementation FWEffectBar- (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { } return self;}- (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { } return self;}- (id)init { return [self initWithFrame:CGRectZero];}- (void)layoutSubviews { CGSize frameSize = self.frame.size; CGFloat minimumContentHeight = [self minimumContentHeight]; [self setItemWidth:roundf((frameSize.width - [self contentEdgeInsets].left - [self contentEdgeInsets].right) / [[self items] count])]; NSInteger index = 0; // Layout items for (FWEffectBarItem *item in [self items]) { CGFloat itemHeight = [item itemHeight]; if (!itemHeight) { itemHeight = frameSize.height; } [item setFrame:CGRectMake(self.contentEdgeInsets.left + (index * self.itemWidth), roundf(frameSize.height - itemHeight) - self.contentEdgeInsets.top, self.itemWidth, itemHeight - self.contentEdgeInsets.bottom)]; [item setNeedsDisplay]; index++; }}#pragma mark - Configuration- (void)setItemWidth:(CGFloat)itemWidth { if (itemWidth > 0) { _itemWidth = itemWidth; }}- (void)setItems:(NSArray *)items { for (FWEffectBarItem *item in _items) { [item removeFromSuperview]; } _items = [items copy]; for (FWEffectBarItem *item in _items) { [item addTarget:self action:@selector(tabBarItemWasSelected:) forControlEvents:UIControlEventTouchDown]; [self addSubview:item]; }}- (void)setHeight:(CGFloat)height { [self setFrame:CGRectMake(CGRectGetMinX(self.frame), CGRectGetMinY(self.frame), CGRectGetWidth(self.frame), height)];}- (CGFloat)minimumContentHeight { CGFloat minimumTabBarContentHeight = CGRectGetHeight([self frame]); for (FWEffectBarItem *item in [self items]) { CGFloat itemHeight = [item itemHeight]; if (itemHeight && (itemHeight < minimumTabBarContentHeight)) { minimumTabBarContentHeight = itemHeight; } } return minimumTabBarContentHeight;}#pragma mark - Item selection- (void)tabBarItemWasSelected:(id)sender { [self setSelectedItem:sender]; if ([[self delegate] respondsToSelector:@selector(effectBar:didSelectItemAtIndex:)]) { NSInteger index = [self.items indexOfObject:self.selectedItem]; [[self delegate] effectBar:self didSelectItemAtIndex:index]; }}- (void)setSelectedItem:(FWEffectBarItem *)selectedItem { if (selectedItem == _selectedItem) { return; } [_selectedItem setSelected:NO]; _selectedItem = selectedItem; [_selectedItem setSelected:YES];}@end
我定义了一个FWEffectBarDelegate的协议,当点击bar中按钮时,将触发- (void)effectBar:(FWEffectBar *)bar didSelectItemAtIndex:(NSInteger)index,我们可以在FWEffectBar的代理中实现当我们点击按钮时要做的事情。
items属性是该bar所包含的所有子项(FWEffectBarItem)。
FWEffectBarItem是包含在bar中的按钮,图像文字竖着排列,当点击它时将呈现高亮状态。
//// FWEffectBarItem.h// FWMeituApp//// Created by ForrestWoo on 15-9-23.// Copyright (c) 2015年 ForrestWoo co,.ltd. All rights reserved.//#import@interface FWEffectBarItem : UIControl/** * itemHeight is an optional property. When set it is used instead of tabBar's height. */@property CGFloat itemHeight;#pragma mark - Title configuration/** * The title displayed by the tab bar item. */@property (nonatomic, copy) NSString *title;/** * The offset for the rectangle around the tab bar item's title. */@property (nonatomic) UIOffset titlePositionAdjustment;/** * For title's text attributes see * https://developer.apple.com/library/ios/documentation/uikit/reference/NSString_UIKit_Additions/Reference/Reference.html *//** * The title attributes dictionary used for tab bar item's unselected state. */@property (copy) NSDictionary *unselectedTitleAttributes;/** * The title attributes dictionary used for tab bar item's selected state. */@property (copy) NSDictionary *selectedTitleAttributes;#pragma mark - Image configuration/** * The offset for the rectangle around the tab bar item's image. */@property (nonatomic) UIOffset imagePositionAdjustment;/** * The image used for tab bar item's selected state. */- (UIImage *)finishedSelectedImage;/** * The image used for tab bar item's unselected state. */- (UIImage *)finishedUnselectedImage;/** * Sets the tab bar item's selected and unselected images. */- (void)setFinishedSelectedImage:(UIImage *)selectedImage withFinishedUnselectedImage:(UIImage *)unselectedImage;#pragma mark - Background configuration/** * The background image used for tab bar item's selected state. */- (UIImage *)backgroundSelectedImage;/** * The background image used for tab bar item's unselected state. */- (UIImage *)backgroundUnselectedImage;/** * Sets the tab bar item's selected and unselected background images. */- (void)setBackgroundSelectedImage:(UIImage *)selectedImage withUnselectedImage:(UIImage *)unselectedImage;@end
//// FWEffectBarItem.m// FWMeituApp//// Created by ForrestWoo on 15-9-23.// Copyright (c) 2015年 ForrestWoo co,.ltd. All rights reserved.//#import "FWEffectBarItem.h"@interface FWEffectBarItem (){ NSString *_title; UIOffset _imagePositionAdjustment; NSDictionary *_unselectedTitleAttributes; NSDictionary *_selectedTitleAttributes;}@property UIImage *unselectedBackgroundImage;@property UIImage *selectedBackgroundImage;@property UIImage *unselectedImage;@property UIImage *selectedImage;@end@implementation FWEffectBarItem- (id)initWithFrame:(CGRect)frame{ if (self = [super initWithFrame:frame]) { [self commonInitialization]; } return self;}- (id)initWithCoder:(NSCoder *)aDecoder{ if (self = [super initWithCoder:aDecoder]) { [self commonInitialization]; } return self;}- (id)init{ return [self initWithFrame:CGRectZero];}- (void)commonInitialization { // Setup defaults [self setBackgroundColor:[UIColor clearColor]]; _title = @""; _titlePositionAdjustment = UIOffsetZero; if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) { _unselectedTitleAttributes = @{ NSFontAttributeName: [UIFont systemFontOfSize:12], NSForegroundColorAttributeName: [UIColor whiteColor], }; } else {#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 _unselectedTitleAttributes = @{ UITextAttributeFont: [UIFont systemFontOfSize:12], UITextAttributeTextColor: [UIColor blackColor], };#endif } _selectedTitleAttributes = [_unselectedTitleAttributes copy];}- (void)drawRect:(CGRect)rect{ CGSize frameSize = self.frame.size; CGSize imageSize = CGSizeZero; CGSize titleSize = CGSizeZero; NSDictionary *titleAttributes = nil; UIImage *backgroundImage = nil; UIImage *image = nil; CGFloat imageStartingY = 0.0f; if ([self isSelected]) { image = [self selectedImage]; backgroundImage = [self selectedBackgroundImage]; titleAttributes = [self selectedTitleAttributes]; if (!titleAttributes) { titleAttributes = [self unselectedTitleAttributes]; } } else { image = [self unselectedImage]; backgroundImage = [self unselectedBackgroundImage]; titleAttributes = [self unselectedTitleAttributes]; } imageSize = [image size]; CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); [backgroundImage drawInRect:self.bounds]; // Draw image and title if (![_title length]) { [image drawInRect:CGRectMake(roundf(frameSize.width / 2 - imageSize.width / 2) + _imagePositionAdjustment.horizontal, roundf(frameSize.height / 2 - imageSize.height / 2) + _imagePositionAdjustment.vertical, imageSize.width, imageSize.height)]; } else { if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) { CGSize ts = CGSizeMake(frameSize.width, 20); titleSize = [_title boundingRectWithSize:ts options:NSStringDrawingUsesLineFragmentOrigin attributes:titleAttributes context:nil].size; imageStartingY = roundf((frameSize.height - imageSize.height - titleSize.height) / 2); CGRect frame = CGRectMake(roundf(frameSize.width / 2 - imageSize.width / 2) + _imagePositionAdjustment.horizontal, imageStartingY + _imagePositionAdjustment.vertical, imageSize.width, imageSize.height); [image drawInRect:frame];// NSLog(@"image frame:%@,%f,%f", NSStringFromCGRect(CGRectMake(roundf(frameSize.width / 2 - imageSize.width / 2) +// _imagePositionAdjustment.horizontal,// imageStartingY + _imagePositionAdjustment.vertical,// imageSize.width, imageSize.height)),imageStartingY,_imagePositionAdjustment.vertical); CGContextSetFillColorWithColor(context, [titleAttributes[NSForegroundColorAttributeName] CGColor]); CGRect frame1 = CGRectMake(roundf(frameSize.width / 2 - titleSize.width / 2) + _titlePositionAdjustment.horizontal, imageStartingY + imageSize.height + _titlePositionAdjustment.vertical, titleSize.width, titleSize.height);// NSLog(@"text frame:%@", NSStringFromCGRect(frame1));// NSLog(@"self frame:%@", NSStringFromCGRect(rect)); [_title drawInRect:frame1 withAttributes:titleAttributes]; } else {#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 titleSize = [_title sizeWithFont:titleAttributes[UITextAttributeFont] constrainedToSize:CGSizeMake(frameSize.width, 20)]; UIOffset titleShadowOffset = [titleAttributes[UITextAttributeTextShadowOffset] UIOffsetValue]; imageStartingY = roundf((frameSize.height - imageSize.height - titleSize.height) / 2); [image drawInRect:CGRectMake(roundf(frameSize.width / 2 - imageSize.width / 2) + _imagePositionAdjustment.horizontal, imageStartingY + _imagePositionAdjustment.vertical, imageSize.width, imageSize.height)]; CGContextSetFillColorWithColor(context, [titleAttributes[UITextAttributeTextColor] CGColor]); UIColor *shadowColor = titleAttributes[UITextAttributeTextShadowColor]; if (shadowColor) { CGContextSetShadowWithColor(context, CGSizeMake(titleShadowOffset.horizontal, titleShadowOffset.vertical), 1.0, [shadowColor CGColor]); } [_title drawInRect:CGRectMake(roundf(frameSize.width / 2 - titleSize.width / 2) + _titlePositionAdjustment.horizontal, imageStartingY + imageSize.height + _titlePositionAdjustment.vertical, titleSize.width, titleSize.height) withFont:titleAttributes[UITextAttributeFont] lineBreakMode:NSLineBreakByTruncatingTail];#endif } } CGContextRestoreGState(context);}- (UIImage *)finishedSelectedImage{ return [self selectedImage];}- (UIImage *)finishedUnselectedImage{ return [self unselectedImage];}- (void)setFinishedSelectedImage:(UIImage *)selectedImage withFinishedUnselectedImage:(UIImage *)unselectedImage{ if (selectedImage && (selectedImage != [self selectedImage])) { [self setSelectedImage:selectedImage]; } if (unselectedImage && (unselectedImage != [self unselectedImage])) { [self setUnselectedImage:unselectedImage]; }}- (UIImage *)backgroundSelectedImage { return [self selectedBackgroundImage];}- (UIImage *)backgroundUnselectedImage { return [self unselectedBackgroundImage];}- (void)setBackgroundSelectedImage:(UIImage *)selectedImage withUnselectedImage:(UIImage *)unselectedImage { if (selectedImage && (selectedImage != [self selectedBackgroundImage])) { [self setSelectedBackgroundImage:selectedImage]; } if (unselectedImage && (unselectedImage != [self unselectedBackgroundImage])) { [self setUnselectedBackgroundImage:unselectedImage]; }}@end
- (void)setFinishedSelectedImage:(UIImage *)selectedImage withFinishedUnselectedImage:(UIImage *)unselectedImage方法用来设置FWEffectBarItem的被选中和未选中时的图片
title属性用来设置FWEffectBarItem的文字。
二、UISlider的使用
UIView *subview = [[UIView alloc] initWithFrame:CGRectMake(0, HEIGHT - 115 - 40, WIDTH, 40)]; subview.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5]; [self.view addSubview:subview]; self.slider = [[FWSlider alloc] initWithFrame:CGRectZero]; self.slider.minimumValue = -100; self.slider.maximumValue = 100; self.slider.value = 0; self.slider.frame = CGRectMake(WIDTH / 2 - 100, 10, 200, 20); [self.slider addTarget:self action:@selector(updateValue:) forControlEvents:UIControlEventTouchUpInside]; [self.slider addTarget:self action:@selector(updateTipView:) forControlEvents:UIControlEventValueChanged]; [self.slider setThumbImage:[UIImage imageNamed:@"icon_slider_thumb"] forState:UIControlStateNormal]; [subview addSubview:self.slider];
setThumbImage用来设置滑块,该slider没有完全实现,当我们滑动的时候,没有显示当前值,有待改善
四、FWBeautyProcessType枚举的定义
typedef NS_ENUM(NSInteger, FWBeautyProcessType){ //智能优化 FWBeautyProcessTypeAutoBeauty, //编辑 FWBeautyProcessTypeEdit, //增强 FWBeautyProcessTypeColorList, //特效 FWBeautyProcessTypeFilter, //边框 FWBeautyProcessTypeBolder, //魔幻笔 FWBeautyProcessTypeMagicPen, //马赛克 FWBeautyProcessTypeMosaic, //文字 FWBeautyProcessTypeText, //背景虚化 FWBeautyProcessTypeBlur};
该枚举定义了【美化图片】下的所有功能模块,用于识别到底是哪种模块,不同模块相应的界面是不同的,请看下面代码
- (void)setupImageView{ if (self.type == FWBeautyProcessTypeAutoBeauty || self.type == FWBeautyProcessTypeColorList || self.type == FWBeautyProcessTypeEdit) { //105 = 设备高 - 关闭按钮高度 - 3段间距:30 - bar高度:55 - 的结果 self.imageView.frame = CGRectMake(0, 0, WIDTH, HEIGHT - 115); } self.imageView.contentMode = UIViewContentModeScaleAspectFit; [self.view addSubview:self.imageView];}//配置单选项卡- (void)setupBar{ self.styleBar = [[FWEffectBar alloc] init]; NSDictionary *autoDict = nil; if (self.type == FWBeautyProcessTypeAutoBeauty || self.type == FWBeautyProcessTypeColorList) { self.styleBar.frame = CGRectMake(0,HEIGHT - 105, WIDTH, 55); if (self.type == FWBeautyProcessTypeAutoBeauty ) autoDict = [[FWCommonTools getPlistDictionaryForButton] objectForKey:@"AutoBeauty"]; else autoDict = [[FWCommonTools getPlistDictionaryForButton] objectForKey:@"ColorValue"]; } else if (self.type == FWBeautyProcessTypeEdit) { self.styleBar.frame = CGRectMake(100, HEIGHT - 55, 160, 55); autoDict = [[FWCommonTools getPlistDictionaryForButton] objectForKey:@"Edit"]; } NSArray *normalImageArr = [autoDict objectForKey:@"normalImages"]; NSArray *hightlightedImageArr = [autoDict objectForKey:@"HighlightedImages"]; NSArray *textArr = [autoDict objectForKey:@"Texts"]; NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:0]; for (int i = 0; i < [textArr count]; i++) { FWEffectBarItem *item = [[FWEffectBarItem alloc] initWithFrame:CGRectZero]; [item setFinishedSelectedImage:[UIImage imageNamed:[hightlightedImageArr objectAtIndex:i]] withFinishedUnselectedImage:[UIImage imageNamed:[normalImageArr objectAtIndex:i]] ]; item.title = [textArr objectAtIndex:i]; [arr addObject:item]; } self.styleBar.items = arr; self.styleBar.delegate = self; [self.styleBar setSelectedItem:[self.styleBar.items objectAtIndex:0]]; [self.view addSubview:self.styleBar]; [self effectBar:self.styleBar didSelectItemAtIndex:0];}- (void)setupSliderForColorList{ UIView *subview = [[UIView alloc] initWithFrame:CGRectMake(0, HEIGHT - 115 - 40, WIDTH, 40)]; subview.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5]; [self.view addSubview:subview]; self.slider = [[FWSlider alloc] initWithFrame:CGRectZero]; self.slider.minimumValue = -100; self.slider.maximumValue = 100; self.slider.value = 0; self.slider.frame = CGRectMake(WIDTH / 2 - 100, 10, 200, 20); [self.slider addTarget:self action:@selector(updateValue:) forControlEvents:UIControlEventTouchUpInside]; [self.slider addTarget:self action:@selector(updateTipView:) forControlEvents:UIControlEventValueChanged]; [self.slider setThumbImage:[UIImage imageNamed:@"icon_slider_thumb"] forState:UIControlStateNormal]; [subview addSubview:self.slider]; self.slider.tipView.currentValueLabel.text = [NSString stringWithFormat:@"%f",self.slider.value];}
不同页面的方法
- (void)displayAutoBeautyPage{ [self setupImageView]; [self setupBar];}- (void)displayColorListPage{ [self setupImageView]; [self setupBar]; [self setupSliderForColorList];}- (void)displayEditPage{ [self setupImageView]; [self setupBar]; [self setupButtons];}
if ([text isEqualToString:@"智能优化"]) { FWFunctionViewController *vc = [[FWFunctionViewController alloc] initWithImage:self.image type:FWBeautyProcessTypeAutoBeauty]; [self presentViewController:vc animated:YES completion:^{ }]; [vc displayAutoBeautyPage]; } else if ([text isEqualToString:@"增强"]) { FWFunctionViewController *vc = [[FWFunctionViewController alloc] initWithImage:self.image type:FWBeautyProcessTypeColorList]; [self presentViewController:vc animated:YES completion:^{ }]; [vc displayColorListPage]; } else if ([text isEqualToString:@"编辑"]) { FWFunctionViewController *vc = [[FWFunctionViewController alloc] initWithImage:self.image type:FWBeautyProcessTypeEdit]; [self presentViewController:vc animated:YES completion:^{ }]; [vc displayEditPage]; // CGRect frame1 = CGRectMake(87.5, 550, 200, 20); // [vc setupSliderWithFrame:frame1]; }e
五、功能实现
1.亮度的实现
+ (UIImage *)changeValueForBrightnessFilter:(float)value image:(UIImage *)image;{ GPUImageBrightnessFilter *filter = [[GPUImageBrightnessFilter alloc] init]; filter.brightness = value; [filter forceProcessingAtSize:image.size]; GPUImagePicture *pic = [[GPUImagePicture alloc] initWithImage:image]; [pic addTarget:filter]; [pic processImage]; [filter useNextFrameForImageCapture]; return [filter imageFromCurrentFramebuffer];}
该功能使用了GPUImage库中的GPUImageBrightnessFilter滤镜,具体介绍请参考
2.对比度的实现
GPUImageContrastFilter *filter = [[GPUImageContrastFilter alloc] init]; filter.contrast = value; [filter forceProcessingAtSize:image.size]; GPUImagePicture *pic = [[GPUImagePicture alloc] initWithImage:image]; [pic addTarget:filter]; [pic processImage]; [filter useNextFrameForImageCapture]; return [filter imageFromCurrentFramebuffer];
该功能使用了GPUImage库中的GPUImageContrastFilter滤镜,具体介绍请参考
3.色温的实现
+ (UIImage *)changeValueForWhiteBalanceFilter:(float)value image:(UIImage *)image{ GPUImageWhiteBalanceFilter *filter = [[GPUImageWhiteBalanceFilter alloc] init]; filter.temperature = value; filter.tint = 0.0; [filter forceProcessingAtSize:image.size]; GPUImagePicture *pic = [[GPUImagePicture alloc] initWithImage:image]; [pic addTarget:filter]; [pic processImage]; [filter useNextFrameForImageCapture]; return [filter imageFromCurrentFramebuffer];}
该功能使用了GPUImage库中的GPUImageWhiteBalanceFilter滤镜。
4.饱和度的实现
+ (UIImage *)changeValueForSaturationFilter:(float)value image:(UIImage *)image;{ GPUImageSaturationFilter *filter = [[GPUImageSaturationFilter alloc] init]; filter.saturation = value; [filter forceProcessingAtSize:image.size]; GPUImagePicture *pic = [[GPUImagePicture alloc] initWithImage:image]; [pic addTarget:filter]; [pic processImage]; [filter useNextFrameForImageCapture]; return [filter imageFromCurrentFramebuffer];}
该功能使用了GPUImage库中的GPUImageSaturationFilter滤镜。
5.高光和暗部的实现
+ (UIImage *)changeValueForHightlightFilter:(float)value image:(UIImage *)image;{ GPUImageHighlightShadowFilter *filter = [[GPUImageHighlightShadowFilter alloc] init]; filter.highlights = value; filter.shadows = 0.0; [filter forceProcessingAtSize:image.size]; GPUImagePicture *pic = [[GPUImagePicture alloc] initWithImage:image]; [pic addTarget:filter]; [pic processImage]; [filter useNextFrameForImageCapture]; return [filter imageFromCurrentFramebuffer];}
+ (UIImage *)changeValueForLowlightFilter:(float)value image:(UIImage *)image{ GPUImageHighlightShadowFilter *filter = [[GPUImageHighlightShadowFilter alloc] init]; filter.highlights = 1.0; filter.shadows = value; [filter forceProcessingAtSize:image.size]; GPUImagePicture *pic = [[GPUImagePicture alloc] initWithImage:image]; [pic addTarget:filter]; [pic processImage]; [filter useNextFrameForImageCapture]; return [filter imageFromCurrentFramebuffer];}
该功能使用了GPUImage库中的GPUImageHighlightShadowFilter滤镜。
6.智能补光的实现
+ (UIImage *)changeValueForExposureFilter:(float)value image:(UIImage *)image{ GPUImageExposureFilter *filter = [[GPUImageExposureFilter alloc] init]; filter.exposure = value; [filter forceProcessingAtSize:image.size]; GPUImagePicture *pic = [[GPUImagePicture alloc] initWithImage:image]; [pic addTarget:filter]; [pic processImage]; [filter useNextFrameForImageCapture]; return [filter imageFromCurrentFramebuffer];}
该功能使用了GPUImage库中的GPUImageExposureFilter滤镜。
我将会在以后的时间里添加几篇介绍GPUImage库中的剩余滤镜,慢慢来学习opengl es.加油,我的宝贝~上下眼皮开始打架了,睡觉喽!咦,最后附几张效果图吧
原图 亮度较暗 对比度较高
色温较冷 饱和度较高 高光
智能补光