527 lines
17 KiB
Objective-C

//
// CLResizeTool.m
//
// Created by sho yakushiji on 2013/12/12.
// Copyright (c) 2013年 CALACULU. All rights reserved.
//
#import "CLResizeTool.h"
static NSString* const kCLResizeToolPresetSizes = @"presetSizes";
static NSString* const kCLResizeToolLimitSize = @"limitSize";
static NSString* const kCLResizeToolHorizontalIconName = @"horizontalIconAssetsName";
static NSString* const kCLResizeToolVerticalIconName = @"verticalIconAssetsName";
static NSString* const kCLResizeToolChainOnIconName = @"chainOnIconAssetsName";
static NSString* const kCLResizeToolChainOffIconName = @"chainOffIconAssetsName";
@interface _CLResizePanel : UIView
<UITextFieldDelegate>
- (id)initWithFrame:(CGRect)frame originalSize:(CGSize)size tool:(CLResizeTool*)tool;
- (void)setImageWidth:(CGFloat)width;
- (void)setImageHeight:(CGFloat)height;
- (void)setLimitSize:(CGFloat)limit;
- (CGSize)imageSize;
@end
@implementation CLResizeTool
{
UIImage *_originalImage;
UIView *_menuContainer;
CLToolbarMenuItem *_switchBtn;
UIScrollView *_menuScroll;
_CLResizePanel *_resizePanel;
}
+ (NSArray*)subtools
{
return nil;
}
+ (NSString*)defaultTitle
{
return [CLImageEditorTheme localizedString:@"CLResizeTool_DefaultTitle" withDefault:@"Resize"];
}
+ (BOOL)isAvailable
{
return ([UIDevice iosVersion] >= 5.0);
}
+ (CGFloat)defaultDockedNumber
{
return 5.5;
}
#pragma mark- optional info
+ (NSArray*)defaultPresetSizes
{
return @[@240, @320, @480, @640, @800, @960, @1024, @2048];
}
+ (NSNumber*)defaultLimitSize
{
return @3200;
}
+ (NSDictionary*)optionalInfo
{
return @{
kCLResizeToolPresetSizes:[self defaultPresetSizes],
kCLResizeToolLimitSize:[self defaultLimitSize],
kCLResizeToolHorizontalIconName:@"",
kCLResizeToolVerticalIconName:@"",
kCLResizeToolChainOnIconName:@"",
kCLResizeToolChainOffIconName:@"",
};
}
#pragma mark- implementation
- (void)setup
{
_originalImage = self.editor.imageView.image;
[self.editor fixZoomScaleWithAnimated:YES];
_menuContainer = [[UIView alloc] initWithFrame:self.editor.menuView.frame];
_menuContainer.backgroundColor = self.editor.menuView.backgroundColor;
[self.editor.view addSubview:_menuContainer];
_menuScroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, _menuContainer.width - 70, _menuContainer.height)];
_menuScroll.backgroundColor = [UIColor clearColor];
_menuScroll.showsHorizontalScrollIndicator = NO;
_menuScroll.clipsToBounds = NO;
[_menuContainer addSubview:_menuScroll];
UIView *btnPanel = [[UIView alloc] initWithFrame:CGRectMake(_menuScroll.right, 0, 70, _menuContainer.height)];
btnPanel.backgroundColor = [_menuContainer.backgroundColor colorWithAlphaComponent:0.97];
[_menuContainer addSubview:btnPanel];
_switchBtn = [CLImageEditorTheme menuItemWithFrame:CGRectMake(0, 0, 70, btnPanel.height) target:self action:@selector(pushedSwitchBtn:) toolInfo:nil];
_switchBtn.tag = 0;
_switchBtn.iconImage = [self imageForKey:kCLResizeToolHorizontalIconName defaultImageName:@"btn_width.png"];
[btnPanel addSubview:_switchBtn];
NSNumber *limit = self.toolInfo.optionalInfo[kCLResizeToolLimitSize];
if(limit==nil){ limit = [self.class defaultLimitSize]; }
_resizePanel = [[_CLResizePanel alloc] initWithFrame:self.editor.imageView.superview.frame originalSize:_originalImage.size tool:self];
_resizePanel.backgroundColor = [[CLImageEditorTheme toolbarColor] colorWithAlphaComponent:0.4];
[_resizePanel setLimitSize:limit.floatValue];
[self.editor.view addSubview:_resizePanel];
[self setResizeMenu];
_menuContainer.transform = CGAffineTransformMakeTranslation(0, self.editor.view.height-_menuScroll.top);
[UIView animateWithDuration:kCLImageToolAnimationDuration
animations:^{
self->_menuContainer.transform = CGAffineTransformIdentity;
}];
}
- (void)cleanup
{
[self.editor resetZoomScaleWithAnimated:YES];
[_resizePanel endEditing:YES];
[_resizePanel removeFromSuperview];
[UIView animateWithDuration:kCLImageToolAnimationDuration
animations:^{
self->_menuContainer.transform = CGAffineTransformMakeTranslation(0, self.editor.view.height-self->_menuScroll.top);
}
completion:^(BOOL finished) {
[self->_menuContainer removeFromSuperview];
}];
}
- (void)executeWithCompletionBlock:(void (^)(UIImage *, NSError *, NSDictionary *))completionBlock
{
CGSize size = _resizePanel.imageSize;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if(size.width>0 && size.height>0){
UIImage *image = [self->_originalImage resize:size];
dispatch_async(dispatch_get_main_queue(), ^{
completionBlock(image, nil, nil);
});
}
else{
dispatch_async(dispatch_get_main_queue(), ^{
completionBlock(nil, nil, nil);
});
}
});
}
#pragma mark-
- (UIImage*)imageWithString:(NSString*)str
{
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
label.textAlignment = NSTextAlignmentCenter;
label.text = str;
label.font = [UIFont boldSystemFontOfSize:30];
label.minimumScaleFactor = 0.5;
label.backgroundColor = [[CLImageEditorTheme theme] toolbarTextColor];
label.textColor = [[CLImageEditorTheme theme] toolbarColor];
UIGraphicsBeginImageContextWithOptions(label.frame.size, NO, 0.0);
[label.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
- (void)setResizeMenu
{
CGFloat W = 70;
CGFloat H = _menuScroll.height;
CGFloat x = 0;
NSArray *sizes = self.toolInfo.optionalInfo[kCLResizeToolPresetSizes];
if(sizes==nil || ![sizes isKindOfClass:[NSArray class]] || sizes.count==0){
sizes = [[self class] defaultPresetSizes];
}
for(NSNumber *size in sizes){
CLToolbarMenuItem *view = [CLImageEditorTheme menuItemWithFrame:CGRectMake(x, 0, W, H) target:self action:@selector(tappedResizePanel:) toolInfo:nil];
view.userInfo = @{@"size":size};
view.iconImage = [self imageWithString:[NSString stringWithFormat:@"%@", size]];
[_menuScroll addSubview:view];
x += W;
}
_menuScroll.contentSize = CGSizeMake(MAX(x, _menuScroll.frame.size.width+1), 0);
}
- (void)pushedSwitchBtn:(UITapGestureRecognizer*)sender
{
if(_switchBtn.tag==0){
_switchBtn.tag = 1;
_switchBtn.iconImage = [self imageForKey:kCLResizeToolVerticalIconName defaultImageName:@"btn_height.png"];
}
else{
_switchBtn.tag = 0;
_switchBtn.iconImage = [self imageForKey:kCLResizeToolHorizontalIconName defaultImageName:@"btn_width.png"];
}
_switchBtn.alpha = 0.2;
[UIView animateWithDuration:kCLImageToolAnimationDuration
animations:^{
self->_switchBtn.alpha = 1;
}
];
}
- (void)tappedResizePanel:(UITapGestureRecognizer*)sender
{
UIView *view = sender.view;
NSNumber *size = view.userInfo[@"size"];
if(size){
if(_switchBtn.tag==0){
[_resizePanel setImageWidth:size.floatValue];
}
else{
[_resizePanel setImageHeight:size.floatValue];
}
}
view.alpha = 0.2;
[UIView animateWithDuration:kCLImageToolAnimationDuration
animations:^{
view.alpha = 1;
}
];
}
@end
@implementation _CLResizePanel
{
UIView *_infoPanel;
CGSize _originalSize;
CGFloat _limitSize;
UITextField *_fieldW;
UITextField *_fieldH;
UIButton *_chainBtn;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self){
_infoPanel = [[UIView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width*0.85, 180)];
_infoPanel.backgroundColor = [[CLImageEditorTheme toolbarColor] colorWithAlphaComponent:0.9];
_infoPanel.layer.cornerRadius = 5;
_infoPanel.center = CGPointMake(self.width/2, self.height/2);
_infoPanel.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin;
[self addSubview:_infoPanel];
[self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(viewDidTap:)]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyBoardWillChange:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyBoardWillChange:) name:UIKeyboardWillHideNotification object:nil];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (id)initWithFrame:(CGRect)frame originalSize:(CGSize)size tool:(CLResizeTool *)tool
{
self = [self initWithFrame:frame];
if(self){
_originalSize = size;
[self initInfoPanelWithTool:tool];
}
return self;
}
- (void)initInfoPanelWithTool:(CLResizeTool*)tool
{
UIFont *font = [CLImageEditorTheme toolbarTextFont];
CGFloat y = 0;
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, _infoPanel.width-20, 30)];
[label setTextColor:[CLImageEditorTheme toolbarTextColor]];
label.backgroundColor = [UIColor clearColor];
label.font = [font fontWithSize:17];
label.text = [CLImageEditorTheme localizedString:@"CLResizeTool_InfoPanelTextOriginalSize" withDefault:@"Original Image Size:"];
[_infoPanel addSubview:label];
y = label.bottom;
label = [[UILabel alloc] initWithFrame:CGRectMake(10, y, _infoPanel.width-20, 50)];
[label setTextColor:[CLImageEditorTheme toolbarTextColor]];
label.backgroundColor = [UIColor clearColor];
label.font = [font fontWithSize:30];
label.text = [NSString stringWithFormat:@"%ld x %ld", (long)_originalSize.width, (long)_originalSize.height];
label.textAlignment = NSTextAlignmentCenter;
[_infoPanel addSubview:label];
//y = label.bottom;
label = [[UILabel alloc] initWithFrame:CGRectMake(10, _infoPanel.height/2, _infoPanel.width-20, 30)];
[label setTextColor:[CLImageEditorTheme toolbarTextColor]];
label.backgroundColor = [UIColor clearColor];
label.font = [font fontWithSize:17];
label.text = [CLImageEditorTheme localizedString:@"CLResizeTool_InfoPanelTextNewSize" withDefault:@"New Image Size:"];
[_infoPanel addSubview:label];
y = label.bottom;
/*
label = [[UILabel alloc] initWithFrame:CGRectMake(10, y, _infoPanel.width-20, 50)];
label.backgroundColor = [UIColor clearColor];
label.font = [font fontWithSize:30];
label.text = @"x";
label.textAlignment = NSTextAlignmentCenter;
[_infoPanel addSubview:label];
*/
_chainBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_chainBtn.frame = CGRectMake(0, 0, 35, 35);
_chainBtn.center = CGPointMake(label.center.x, y + 25);
[_chainBtn setImage:[tool imageForKey:kCLResizeToolChainOffIconName defaultImageName:@"btn_chain_off.png"] forState:UIControlStateNormal];
[_chainBtn setImage:[tool imageForKey:kCLResizeToolChainOnIconName defaultImageName:@"btn_chain_on.png"] forState:UIControlStateSelected];
[_chainBtn addTarget:self action:@selector(chainBtnDidPush:) forControlEvents:UIControlEventTouchUpInside];
_chainBtn.selected = YES;
[_infoPanel addSubview:_chainBtn];
_fieldW = [[UITextField alloc] initWithFrame:CGRectMake(_chainBtn.left - 110, y+5, 100, 40)];
[_fieldW setTextColor:[CLImageEditorTheme toolbarTextColor]];
_fieldW.font = [font fontWithSize:30];
_fieldW.textAlignment = NSTextAlignmentCenter;
_fieldW.keyboardType = UIKeyboardTypeNumberPad;
_fieldW.layer.borderWidth = 1;
_fieldW.layer.borderColor = [[[CLImageEditorTheme theme] toolbarTextColor] CGColor];
_fieldW.text = [NSString stringWithFormat:@"%ld", (long)_originalSize.width];
_fieldW.delegate = self;
[_fieldW addTarget:self action:@selector(textFieldDidChanged:) forControlEvents:UIControlEventEditingChanged];
[_infoPanel addSubview:_fieldW];
_fieldH = [[UITextField alloc] initWithFrame:CGRectMake(_chainBtn.right + 10, y+5, 100, 40)];
[_fieldH setTextColor:[CLImageEditorTheme toolbarTextColor]];
_fieldH.font = [font fontWithSize:30];
_fieldH.textAlignment = NSTextAlignmentCenter;
_fieldH.keyboardType = UIKeyboardTypeNumberPad;
_fieldH.layer.borderWidth = 1;
_fieldH.layer.borderColor = _fieldW.layer.borderColor;
_fieldH.text = [NSString stringWithFormat:@"%ld", (long)_originalSize.height];
_fieldH.delegate = self;
[_fieldH addTarget:self action:@selector(textFieldDidChanged:) forControlEvents:UIControlEventEditingChanged];
[_infoPanel addSubview:_fieldH];
}
#pragma mark - gesture events
- (void)viewDidTap:(UITapGestureRecognizer*)sender
{
[self endEditing:YES];
}
- (void)chainBtnDidPush:(UIButton*)sender
{
sender.selected = !sender.selected;
CGFloat W = _fieldW.text.floatValue;
CGFloat H = _fieldH.text.floatValue;
if(W>H){
[self setImageWidth:W];
}
else{
[self setImageHeight:H];
}
}
#pragma mark - keyboard events
- (void)keyBoardWillChange:(NSNotification *)notificatioin
{
CGRect keyboardFrame = [[notificatioin.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
keyboardFrame = [self.superview convertRect:keyboardFrame fromView:self.window];
UIViewAnimationCurve animationCurve = [[notificatioin.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];
double duration = [[notificatioin.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:duration
delay:0
options:UIViewAnimationOptionBeginFromCurrentState | (animationCurve<<16)
animations:^{
CGFloat H = MIN(self.height, keyboardFrame.origin.y - self.top);
self->_infoPanel.center = CGPointMake(self->_infoPanel.center.x, H/2);
} completion:^(BOOL finished) {
}
];
}
#pragma mark- Size settings
- (void)setLimitSize:(CGFloat)limit
{
_limitSize = limit;
[self setImageWidth:_fieldW.text.floatValue];
}
- (void)setImageWidth:(CGFloat)width
{
width = MIN(width, _limitSize);
if(_chainBtn.selected){
if(width>0){
CGFloat height = MAX(1, width * _originalSize.height / _originalSize.width);
if(height>_limitSize){
[self setImageHeight:_limitSize];
}
else{
_fieldW.text = [NSString stringWithFormat:@"%ld", (long)width];
_fieldH.text = [NSString stringWithFormat:@"%ld", (long)height];
}
}
else{
_fieldH.text = @"";
}
}
else if(width>0){
_fieldW.text = [NSString stringWithFormat:@"%ld", (long)width];
}
}
- (void)setImageHeight:(CGFloat)height
{
height = MIN(height, _limitSize);
if(_chainBtn.selected){
if(height>0){
CGFloat width = MAX(1, height * _originalSize.width / _originalSize.height);
if(width>_limitSize){
[self setImageWidth:_limitSize];
}
else{
_fieldW.text = [NSString stringWithFormat:@"%ld", (long)width];
_fieldH.text = [NSString stringWithFormat:@"%ld", (long)height];
}
}
else{
_fieldW.text = @"";
}
}
else if(height>0){
_fieldH.text = [NSString stringWithFormat:@"%ld", (long)height];
}
}
- (void)textFieldDidChanged:(id)sender
{
if(sender==_fieldW){
[self setImageWidth:_fieldW.text.floatValue];
}
else if(sender==_fieldH){
[self setImageHeight:_fieldH.text.floatValue];
}
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if(textField==_fieldW || textField==_fieldH){
if((string != nil) && (![@"" isEqualToString:string])){
const char *c = [string cStringUsingEncoding:NSASCIIStringEncoding];
if(c[0]==0){ return YES; }
else if([textField.text length]>=4){ return NO; }
else {return [self isNumber:string]; }
}
}
return YES;
}
- (BOOL)isNumber:(NSString *)value
{
if(value == nil || [@"" isEqualToString:value]){ return NO; }
BOOL isNum = NO;
for(int i=0; i<[value length]; i++){
NSString *str = [[value substringFromIndex:i] substringToIndex:1];
const char *c = [str cStringUsingEncoding:NSASCIIStringEncoding];
isNum = ((c!=NULL)&&(c[0]>=0x30)&&(c[0]<=0x39));
if(_fieldW.text.length==0 && i==0 && (c!=NULL&&c[0]==0x30)){ isNum = NO; }
if(!isNum){ break; }
}
return isNum;
}
- (CGSize)imageSize
{
__block CGSize size = CGSizeZero;
safe_dispatch_sync_main(^{
size = CGSizeMake(self->_fieldW.text.floatValue, self->_fieldH.text.floatValue);
});
return size;
}
@end