diff options
author | siqi <me@siqi.fr> | 2013-07-15 20:07:03 +0200 |
---|---|---|
committer | siqi <me@siqi.fr> | 2013-07-15 20:07:03 +0200 |
commit | 71a80c52d73607384851da708735e4a48079fc62 (patch) | |
tree | ac28cc510663a7c245225c5818d1a5c36aa0364c | |
parent | 9d639f6b2f88aafa2c94a73a31b57ddd4122f436 (diff) |
UIImage categories used for load optimisation
Change-Id: Icf31e42c9be1fb749da912a2b3c79822f16a49e5
16 files changed, 660 insertions, 68 deletions
diff --git a/ios/iosremote/ic_launcher.png b/ios/iosremote/ic_launcher.png Binary files differindex 508d9475f98c..d39ebd1115c3 100644 --- a/ios/iosremote/ic_launcher.png +++ b/ios/iosremote/ic_launcher.png diff --git a/ios/iosremote/ic_launcher@2x.png b/ios/iosremote/ic_launcher@2x.png Binary files differindex 6febfad1df0b..333330893e51 100644 --- a/ios/iosremote/ic_launcher@2x.png +++ b/ios/iosremote/ic_launcher@2x.png diff --git a/ios/iosremote/iosremote.xcodeproj/project.pbxproj b/ios/iosremote/iosremote.xcodeproj/project.pbxproj index 539a83fbe94a..bba51b007537 100644 --- a/ios/iosremote/iosremote.xcodeproj/project.pbxproj +++ b/ios/iosremote/iosremote.xcodeproj/project.pbxproj @@ -11,6 +11,9 @@ 5711026D1794127E007D343B /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 571102691794127E007D343B /* README.md */; }; 5711026E1794127E007D343B /* release_notes.md in Resources */ = {isa = PBXBuildFile; fileRef = 5711026A1794127E007D343B /* release_notes.md */; }; 571102701794128E007D343B /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5711026F1794128E007D343B /* libz.dylib */; }; + 5711027B17946186007D343B /* UIImage+Alpha.m in Sources */ = {isa = PBXBuildFile; fileRef = 5711027617946185007D343B /* UIImage+Alpha.m */; }; + 5711027C17946186007D343B /* UIImage+Resize.m in Sources */ = {isa = PBXBuildFile; fileRef = 5711027817946186007D343B /* UIImage+Resize.m */; }; + 5711027D17946186007D343B /* UIImage+RoundedCorner.m in Sources */ = {isa = PBXBuildFile; fileRef = 5711027A17946186007D343B /* UIImage+RoundedCorner.m */; }; 571BFAD1178AADA200EF1BDB /* more_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 571BFAD0178AADA200EF1BDB /* more_icon.png */; }; 571D4807178B2F080063D93B /* timer_clear_btn.png in Resources */ = {isa = PBXBuildFile; fileRef = 571D4805178B2F080063D93B /* timer_clear_btn.png */; }; 571D4808178B2F080063D93B /* timer_start_btn.png in Resources */ = {isa = PBXBuildFile; fileRef = 571D4806178B2F080063D93B /* timer_start_btn.png */; }; @@ -65,6 +68,12 @@ 5711026A1794127E007D343B /* release_notes.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = release_notes.md; sourceTree = "<group>"; }; 5711026B1794127E007D343B /* TestFlight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestFlight.h; sourceTree = "<group>"; }; 5711026F1794128E007D343B /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; + 5711027517946185007D343B /* UIImage+Alpha.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Alpha.h"; sourceTree = "<group>"; }; + 5711027617946185007D343B /* UIImage+Alpha.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Alpha.m"; sourceTree = "<group>"; }; + 5711027717946186007D343B /* UIImage+Resize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Resize.h"; sourceTree = "<group>"; }; + 5711027817946186007D343B /* UIImage+Resize.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Resize.m"; sourceTree = "<group>"; }; + 5711027917946186007D343B /* UIImage+RoundedCorner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+RoundedCorner.h"; sourceTree = "<group>"; }; + 5711027A17946186007D343B /* UIImage+RoundedCorner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+RoundedCorner.m"; sourceTree = "<group>"; }; 571BFAD0178AADA200EF1BDB /* more_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = more_icon.png; path = iosremote/more_icon.png; sourceTree = "<group>"; }; 571D4805178B2F080063D93B /* timer_clear_btn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = timer_clear_btn.png; path = iosremote/timer_clear_btn.png; sourceTree = "<group>"; }; 571D4806178B2F080063D93B /* timer_start_btn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = timer_start_btn.png; path = iosremote/timer_start_btn.png; sourceTree = "<group>"; }; @@ -165,6 +174,19 @@ path = TestFlightSDK1.2.6; sourceTree = "<group>"; }; + 5711027417946185007D343B /* UIImage-categories */ = { + isa = PBXGroup; + children = ( + 5711027517946185007D343B /* UIImage+Alpha.h */, + 5711027617946185007D343B /* UIImage+Alpha.m */, + 5711027717946186007D343B /* UIImage+Resize.h */, + 5711027817946186007D343B /* UIImage+Resize.m */, + 5711027917946186007D343B /* UIImage+RoundedCorner.h */, + 5711027A17946186007D343B /* UIImage+RoundedCorner.m */, + ); + path = "UIImage-categories"; + sourceTree = "<group>"; + }; 571BFAD2178AB7BA00EF1BDB /* slideShow */ = { isa = PBXGroup; children = ( @@ -277,6 +299,7 @@ 57C6E3F9175E06E800E8BC5F /* Supporting Files */ = { isa = PBXGroup; children = ( + 5711027417946185007D343B /* UIImage-categories */, 57701736178AC83E00B99793 /* SWRevealViewController */, 57B152971764703500EECC67 /* Base64.h */, 57B152981764703500EECC67 /* Base64.m */, @@ -428,6 +451,9 @@ 57701742178B0A6900B99793 /* slideShowSwipeInList.m in Sources */, 57DC700F178E03330050FC58 /* touchPointer_vc.m in Sources */, 57DC7012178E16A40050FC58 /* UIViewTransitionCategory.m in Sources */, + 5711027B17946186007D343B /* UIImage+Alpha.m in Sources */, + 5711027C17946186007D343B /* UIImage+Resize.m in Sources */, + 5711027D17946186007D343B /* UIImage+RoundedCorner.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -497,7 +523,8 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_IDENTITY = "iPhone Distribution"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; COPY_PHASE_STRIP = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_ABOUT_RETURN_TYPE = YES; @@ -505,6 +532,8 @@ GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 6.1; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; + PROVISIONING_PROFILE = ""; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; @@ -517,7 +546,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "iosremote/iosremote-Prefix.pch"; INFOPLIST_FILE = "iosremote/iosremote-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 5.1; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "\"$(SRCROOT)/../../../../../../Downloads/TestFlightSDK1.2.6\"", @@ -535,7 +564,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "iosremote/iosremote-Prefix.pch"; INFOPLIST_FILE = "iosremote/iosremote-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 5.1; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "\"$(SRCROOT)/../../../../../../Downloads/TestFlightSDK1.2.6\"", diff --git a/ios/iosremote/iosremote.xcodeproj/xcuserdata/siqi.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist b/ios/iosremote/iosremote.xcodeproj/xcuserdata/siqi.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist index f488c43b9e92..42f3f3f54564 100644 --- a/ios/iosremote/iosremote.xcodeproj/xcuserdata/siqi.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist +++ b/ios/iosremote/iosremote.xcodeproj/xcuserdata/siqi.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist @@ -29,5 +29,18 @@ landmarkName = "-tableView:cellForRowAtIndexPath:" landmarkType = "5"> </FileBreakpoint> + <FileBreakpoint + shouldBeEnabled = "No" + ignoreCount = "0" + continueAfterRunningActions = "No" + filePath = "iosremote/Communication/Client.m" + timestampString = "395603811.784147" + startingColumnNumber = "9223372036854775807" + endingColumnNumber = "9223372036854775807" + startingLineNumber = "122" + endingLineNumber = "122" + landmarkName = "-streamOpenWithIp:withPortNumber:" + landmarkType = "5"> + </FileBreakpoint> </FileBreakpoints> </Bucket> diff --git a/ios/iosremote/iosremote/Communication/Client.m b/ios/iosremote/iosremote/Communication/Client.m index 1bdedf251def..441698688cf0 100644 --- a/ios/iosremote/iosremote/Communication/Client.m +++ b/ios/iosremote/iosremote/Communication/Client.m @@ -203,8 +203,12 @@ int count = 0; } } // NSLog(@"Command:%@", str); - NSArray *commands = [str componentsSeparatedByString:@"\n"]; - [self.receiver parse:commands]; + + backgroundQueue = dispatch_queue_create("com.libreoffice.iosremote", DISPATCH_QUEUE_CONCURRENT); + dispatch_async(backgroundQueue, ^(void) { + NSArray *commands = [str componentsSeparatedByString:@"\n"]; + [self.receiver parse:commands]; + }); data = nil; str = nil; } break; @@ -222,15 +226,16 @@ int count = 0; return; [self stopConnectionTimeoutTimer]; // NSLog(@"stream status i:%u o:%u", self.inputStream.streamStatus, self.outputStream.streamStatus); - if ([self.inputStream streamStatus] != NSStreamStatusClosed && [self.inputStream streamStatus] != NSStreamStatusError) { + if ([self.inputStream streamStatus] != NSStreamStatusClosed) { // NSLog(@"ci"); [self.inputStream close]; - } + } else + [self.inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; - if ([self.outputStream streamStatus] != NSStreamStatusClosed && [self.outputStream streamStatus] != NSStreamStatusError) { -// NSLog(@"co"); + if ([self.outputStream streamStatus] != NSStreamStatusClosed) { [self.outputStream close]; - } + } else + [self.outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; self.inputStream = nil; self.outputStream = nil; self.connected = NO; @@ -238,7 +243,7 @@ int count = 0; - (void) connect { - [self startConnectionTimeoutTimerwithInterval:3.0]; + [self startConnectionTimeoutTimerwithInterval:5.0]; backgroundQueue = dispatch_queue_create("com.libreoffice.iosremote", NULL); dispatch_async(backgroundQueue, ^(void) { [self streamOpenWithIp:self.server.serverAddress withPortNumber:self.mPort]; diff --git a/ios/iosremote/iosremote/Communication/SlideShow.m b/ios/iosremote/iosremote/Communication/SlideShow.m index 8f890b84df5a..8552311aa9ee 100644 --- a/ios/iosremote/iosremote/Communication/SlideShow.m +++ b/ios/iosremote/iosremote/Communication/SlideShow.m @@ -10,6 +10,7 @@ #import "SlideShow.h" #import "Base64.h" #import "slideShow_vc.h" +#import "UIImage+Resize.h" #import <dispatch/dispatch.h> @interface SlideShow() @@ -41,7 +42,7 @@ NSLock *dictLock; _size = 0; _currentSlide = 0; - backgroundQueue = dispatch_queue_create("org.libreoffice.iosremote.bgqueue", NULL); + backgroundQueue = dispatch_queue_create("org.libreoffice.iosremote.bgqueue", DISPATCH_QUEUE_CONCURRENT); NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; /** @@ -69,6 +70,7 @@ NSLock *dictLock; if ([view isKindOfClass:[UIImageView class]]){ UIImage *image = [self.imagesDictionary objectForKey:[self.loadBuffer objectForKey:tag]]; if (image) { + image = [image resizedImage:view.frame.size interpolationQuality:kCGInterpolationDefault]; dispatch_async(dispatch_get_main_queue(), ^{ [(UIImageView *)view setImage:image]; }); @@ -88,6 +90,7 @@ NSLock *dictLock; UIImage *image = [self.imagesDictionary objectForKey:[self.loadBuffer objectForKey:tag]]; if (image){ UIImageView *imageView = (UIImageView *)[view viewWithTag:1]; + image = [image resizedImage:imageView.frame.size interpolationQuality:kCGInterpolationDefault]; dispatch_async(dispatch_get_main_queue(), ^{ [imageView setImage:image]; }); diff --git a/ios/iosremote/iosremote/UIImage+Resize.m b/ios/iosremote/iosremote/UIImage+Resize.m new file mode 100644 index 000000000000..beed2360f31a --- /dev/null +++ b/ios/iosremote/iosremote/UIImage+Resize.m @@ -0,0 +1,186 @@ +// UIImage+Resize.m +// Created by Trevor Harmon on 8/5/09. +// Free for personal or commercial use, with or without modification. +// No warranty is expressed or implied. + +#import "UIImage+Resize.h" + +// Private helper methods +@interface UIImage () +- (UIImage *)resizedImage:(CGSize)newSize + transform:(CGAffineTransform)transform + drawTransposed:(BOOL)transpose + interpolationQuality:(CGInterpolationQuality)quality; +- (CGAffineTransform)transformForOrientation:(CGSize)newSize; +@end + +@implementation UIImage (Resize) + +// Returns a copy of this image that is cropped to the given bounds. +// The bounds will be adjusted using CGRectIntegral. +// This method ignores the image's imageOrientation setting. +- (UIImage *)croppedImage:(CGRect)bounds { + CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], bounds); + UIImage *croppedImage = [UIImage imageWithCGImage:imageRef]; + CGImageRelease(imageRef); + return croppedImage; +} + +// Returns a copy of this image that is squared to the thumbnail size. +// If transparentBorder is non-zero, a transparent border of the given size will be added around the edges of the thumbnail. (Adding a transparent border of at least one pixel in size has the side-effect of antialiasing the edges of the image when rotating it using Core Animation.) +- (UIImage *)thumbnailImage:(NSInteger)thumbnailSize + transparentBorder:(NSUInteger)borderSize + cornerRadius:(NSUInteger)cornerRadius + interpolationQuality:(CGInterpolationQuality)quality { + UIImage *resizedImage = [self resizedImageWithContentMode:UIViewContentModeScaleAspectFill + bounds:CGSizeMake(thumbnailSize, thumbnailSize) + interpolationQuality:quality]; + + // Crop out any part of the image that's larger than the thumbnail size + // The cropped rect must be centered on the resized image + // Round the origin points so that the size isn't altered when CGRectIntegral is later invoked + CGRect cropRect = CGRectMake(round((resizedImage.size.width - thumbnailSize) / 2), + round((resizedImage.size.height - thumbnailSize) / 2), + thumbnailSize, + thumbnailSize); + UIImage *croppedImage = [resizedImage croppedImage:cropRect]; + + UIImage *transparentBorderImage = borderSize ? [croppedImage transparentBorderImage:borderSize] : croppedImage; + + return [transparentBorderImage roundedCornerImage:cornerRadius borderSize:borderSize]; +} + +// Returns a rescaled copy of the image, taking into account its orientation +// The image will be scaled disproportionately if necessary to fit the bounds specified by the parameter +- (UIImage *)resizedImage:(CGSize)newSize interpolationQuality:(CGInterpolationQuality)quality { + BOOL drawTransposed; + + switch (self.imageOrientation) { + case UIImageOrientationLeft: + case UIImageOrientationLeftMirrored: + case UIImageOrientationRight: + case UIImageOrientationRightMirrored: + drawTransposed = YES; + break; + + default: + drawTransposed = NO; + } + + return [self resizedImage:newSize + transform:[self transformForOrientation:newSize] + drawTransposed:drawTransposed + interpolationQuality:quality]; +} + +// Resizes the image according to the given content mode, taking into account the image's orientation +- (UIImage *)resizedImageWithContentMode:(UIViewContentMode)contentMode + bounds:(CGSize)bounds + interpolationQuality:(CGInterpolationQuality)quality { + CGFloat horizontalRatio = bounds.width / self.size.width; + CGFloat verticalRatio = bounds.height / self.size.height; + CGFloat ratio; + + switch (contentMode) { + case UIViewContentModeScaleAspectFill: + ratio = MAX(horizontalRatio, verticalRatio); + break; + + case UIViewContentModeScaleAspectFit: + ratio = MIN(horizontalRatio, verticalRatio); + break; + + default: + [NSException raise:NSInvalidArgumentException format:@"Unsupported content mode: %d", contentMode]; + } + + CGSize newSize = CGSizeMake(self.size.width * ratio, self.size.height * ratio); + + return [self resizedImage:newSize interpolationQuality:quality]; +} + +#pragma mark - +#pragma mark Private helper methods + +// Returns a copy of the image that has been transformed using the given affine transform and scaled to the new size +// The new image's orientation will be UIImageOrientationUp, regardless of the current image's orientation +// If the new size is not integral, it will be rounded up +- (UIImage *)resizedImage:(CGSize)newSize + transform:(CGAffineTransform)transform + drawTransposed:(BOOL)transpose + interpolationQuality:(CGInterpolationQuality)quality { + CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height)); + CGRect transposedRect = CGRectMake(0, 0, newRect.size.height, newRect.size.width); + CGImageRef imageRef = self.CGImage; + + // Build a context that's the same dimensions as the new size + CGContextRef bitmap = CGBitmapContextCreate(NULL, + newRect.size.width, + newRect.size.height, + CGImageGetBitsPerComponent(imageRef), + 0, + CGImageGetColorSpace(imageRef), + CGImageGetBitmapInfo(imageRef)); + + // Rotate and/or flip the image if required by its orientation + CGContextConcatCTM(bitmap, transform); + + // Set the quality level to use when rescaling + CGContextSetInterpolationQuality(bitmap, quality); + + // Draw into the context; this scales the image + CGContextDrawImage(bitmap, transpose ? transposedRect : newRect, imageRef); + + // Get the resized image from the context and a UIImage + CGImageRef newImageRef = CGBitmapContextCreateImage(bitmap); + UIImage *newImage = [UIImage imageWithCGImage:newImageRef]; + + // Clean up + CGContextRelease(bitmap); + CGImageRelease(newImageRef); + + return newImage; +} + +// Returns an affine transform that takes into account the image orientation when drawing a scaled image +- (CGAffineTransform)transformForOrientation:(CGSize)newSize { + CGAffineTransform transform = CGAffineTransformIdentity; + + switch (self.imageOrientation) { + case UIImageOrientationDown: // EXIF = 3 + case UIImageOrientationDownMirrored: // EXIF = 4 + transform = CGAffineTransformTranslate(transform, newSize.width, newSize.height); + transform = CGAffineTransformRotate(transform, M_PI); + break; + + case UIImageOrientationLeft: // EXIF = 6 + case UIImageOrientationLeftMirrored: // EXIF = 5 + transform = CGAffineTransformTranslate(transform, newSize.width, 0); + transform = CGAffineTransformRotate(transform, M_PI_2); + break; + + case UIImageOrientationRight: // EXIF = 8 + case UIImageOrientationRightMirrored: // EXIF = 7 + transform = CGAffineTransformTranslate(transform, 0, newSize.height); + transform = CGAffineTransformRotate(transform, -M_PI_2); + break; + } + + switch (self.imageOrientation) { + case UIImageOrientationUpMirrored: // EXIF = 2 + case UIImageOrientationDownMirrored: // EXIF = 4 + transform = CGAffineTransformTranslate(transform, newSize.width, 0); + transform = CGAffineTransformScale(transform, -1, 1); + break; + + case UIImageOrientationLeftMirrored: // EXIF = 5 + case UIImageOrientationRightMirrored: // EXIF = 7 + transform = CGAffineTransformTranslate(transform, newSize.height, 0); + transform = CGAffineTransformScale(transform, -1, 1); + break; + } + + return transform; +} + +@end
\ No newline at end of file diff --git a/ios/iosremote/iosremote/UIImage-categories/UIImage+Alpha.h b/ios/iosremote/iosremote/UIImage-categories/UIImage+Alpha.h new file mode 100644 index 000000000000..370d978eb171 --- /dev/null +++ b/ios/iosremote/iosremote/UIImage-categories/UIImage+Alpha.h @@ -0,0 +1,11 @@ +// UIImage+Alpha.h +// Created by Trevor Harmon on 9/20/09. +// Free for personal or commercial use, with or without modification. +// No warranty is expressed or implied. + +// Helper methods for adding an alpha layer to an image +@interface UIImage (Alpha) +- (BOOL)hasAlpha; +- (UIImage *)imageWithAlpha; +- (UIImage *)transparentBorderImage:(NSUInteger)borderSize; +@end diff --git a/ios/iosremote/iosremote/UIImage-categories/UIImage+Alpha.m b/ios/iosremote/iosremote/UIImage-categories/UIImage+Alpha.m new file mode 100644 index 000000000000..d73106214508 --- /dev/null +++ b/ios/iosremote/iosremote/UIImage-categories/UIImage+Alpha.m @@ -0,0 +1,127 @@ +// UIImage+Alpha.m +// Created by Trevor Harmon on 9/20/09. +// Free for personal or commercial use, with or without modification. +// No warranty is expressed or implied. + +#import "UIImage+Alpha.h" + +// Private helper methods +@interface UIImage () +- (CGImageRef)newBorderMask:(NSUInteger)borderSize size:(CGSize)size; +@end + +@implementation UIImage (Alpha) + +// Returns true if the image has an alpha layer +- (BOOL)hasAlpha { + CGImageAlphaInfo alpha = CGImageGetAlphaInfo(self.CGImage); + return (alpha == kCGImageAlphaFirst || + alpha == kCGImageAlphaLast || + alpha == kCGImageAlphaPremultipliedFirst || + alpha == kCGImageAlphaPremultipliedLast); +} + +// Returns a copy of the given image, adding an alpha channel if it doesn't already have one +- (UIImage *)imageWithAlpha { + if ([self hasAlpha]) { + return self; + } + + CGImageRef imageRef = self.CGImage; + size_t width = CGImageGetWidth(imageRef); + size_t height = CGImageGetHeight(imageRef); + + // The bitsPerComponent and bitmapInfo values are hard-coded to prevent an "unsupported parameter combination" error + CGContextRef offscreenContext = CGBitmapContextCreate(NULL, + width, + height, + 8, + 0, + CGImageGetColorSpace(imageRef), + kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst); + + // Draw the image into the context and retrieve the new image, which will now have an alpha layer + CGContextDrawImage(offscreenContext, CGRectMake(0, 0, width, height), imageRef); + CGImageRef imageRefWithAlpha = CGBitmapContextCreateImage(offscreenContext); + UIImage *imageWithAlpha = [UIImage imageWithCGImage:imageRefWithAlpha]; + + // Clean up + CGContextRelease(offscreenContext); + CGImageRelease(imageRefWithAlpha); + + return imageWithAlpha; +} + +// Returns a copy of the image with a transparent border of the given size added around its edges. +// If the image has no alpha layer, one will be added to it. +- (UIImage *)transparentBorderImage:(NSUInteger)borderSize { + // If the image does not have an alpha layer, add one + UIImage *image = [self imageWithAlpha]; + + CGRect newRect = CGRectMake(0, 0, image.size.width + borderSize * 2, image.size.height + borderSize * 2); + + // Build a context that's the same dimensions as the new size + CGContextRef bitmap = CGBitmapContextCreate(NULL, + newRect.size.width, + newRect.size.height, + CGImageGetBitsPerComponent(self.CGImage), + 0, + CGImageGetColorSpace(self.CGImage), + CGImageGetBitmapInfo(self.CGImage)); + + // Draw the image in the center of the context, leaving a gap around the edges + CGRect imageLocation = CGRectMake(borderSize, borderSize, image.size.width, image.size.height); + CGContextDrawImage(bitmap, imageLocation, self.CGImage); + CGImageRef borderImageRef = CGBitmapContextCreateImage(bitmap); + + // Create a mask to make the border transparent, and combine it with the image + CGImageRef maskImageRef = [self newBorderMask:borderSize size:newRect.size]; + CGImageRef transparentBorderImageRef = CGImageCreateWithMask(borderImageRef, maskImageRef); + UIImage *transparentBorderImage = [UIImage imageWithCGImage:transparentBorderImageRef]; + + // Clean up + CGContextRelease(bitmap); + CGImageRelease(borderImageRef); + CGImageRelease(maskImageRef); + CGImageRelease(transparentBorderImageRef); + + return transparentBorderImage; +} + +#pragma mark - +#pragma mark Private helper methods + +// Creates a mask that makes the outer edges transparent and everything else opaque +// The size must include the entire mask (opaque part + transparent border) +// The caller is responsible for releasing the returned reference by calling CGImageRelease +- (CGImageRef)newBorderMask:(NSUInteger)borderSize size:(CGSize)size { + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); + + // Build a context that's the same dimensions as the new size + CGContextRef maskContext = CGBitmapContextCreate(NULL, + size.width, + size.height, + 8, // 8-bit grayscale + 0, + colorSpace, + kCGBitmapByteOrderDefault | kCGImageAlphaNone); + + // Start with a mask that's entirely transparent + CGContextSetFillColorWithColor(maskContext, [UIColor blackColor].CGColor); + CGContextFillRect(maskContext, CGRectMake(0, 0, size.width, size.height)); + + // Make the inner part (within the border) opaque + CGContextSetFillColorWithColor(maskContext, [UIColor whiteColor].CGColor); + CGContextFillRect(maskContext, CGRectMake(borderSize, borderSize, size.width - borderSize * 2, size.height - borderSize * 2)); + + // Get an image of the context + CGImageRef maskImageRef = CGBitmapContextCreateImage(maskContext); + + // Clean up + CGContextRelease(maskContext); + CGColorSpaceRelease(colorSpace); + + return maskImageRef; +} + +@end diff --git a/ios/iosremote/iosremote/UIImage-categories/UIImage+Resize.h b/ios/iosremote/iosremote/UIImage-categories/UIImage+Resize.h new file mode 100644 index 000000000000..f143381e9c31 --- /dev/null +++ b/ios/iosremote/iosremote/UIImage-categories/UIImage+Resize.h @@ -0,0 +1,18 @@ +// UIImage+Resize.h +// Created by Trevor Harmon on 8/5/09. +// Free for personal or commercial use, with or without modification. +// No warranty is expressed or implied. + +// Extends the UIImage class to support resizing/cropping +@interface UIImage (Resize) +- (UIImage *)croppedImage:(CGRect)bounds; +- (UIImage *)thumbnailImage:(NSInteger)thumbnailSize + transparentBorder:(NSUInteger)borderSize + cornerRadius:(NSUInteger)cornerRadius + interpolationQuality:(CGInterpolationQuality)quality; +- (UIImage *)resizedImage:(CGSize)newSize + interpolationQuality:(CGInterpolationQuality)quality; +- (UIImage *)resizedImageWithContentMode:(UIViewContentMode)contentMode + bounds:(CGSize)bounds + interpolationQuality:(CGInterpolationQuality)quality; +@end diff --git a/ios/iosremote/iosremote/UIImage-categories/UIImage+Resize.m b/ios/iosremote/iosremote/UIImage-categories/UIImage+Resize.m new file mode 100644 index 000000000000..129561067938 --- /dev/null +++ b/ios/iosremote/iosremote/UIImage-categories/UIImage+Resize.m @@ -0,0 +1,188 @@ +// UIImage+Resize.m +// Created by Trevor Harmon on 8/5/09. +// Free for personal or commercial use, with or without modification. +// No warranty is expressed or implied. + +#import "UIImage+Resize.h" +#import "UIImage+RoundedCorner.h" +#import "UIImage+Alpha.h" + +// Private helper methods +@interface UIImage () +- (UIImage *)resizedImage:(CGSize)newSize + transform:(CGAffineTransform)transform + drawTransposed:(BOOL)transpose + interpolationQuality:(CGInterpolationQuality)quality; +- (CGAffineTransform)transformForOrientation:(CGSize)newSize; +@end + +@implementation UIImage (Resize) + +// Returns a copy of this image that is cropped to the given bounds. +// The bounds will be adjusted using CGRectIntegral. +// This method ignores the image's imageOrientation setting. +- (UIImage *)croppedImage:(CGRect)bounds { + CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], bounds); + UIImage *croppedImage = [UIImage imageWithCGImage:imageRef]; + CGImageRelease(imageRef); + return croppedImage; +} + +// Returns a copy of this image that is squared to the thumbnail size. +// If transparentBorder is non-zero, a transparent border of the given size will be added around the edges of the thumbnail. (Adding a transparent border of at least one pixel in size has the side-effect of antialiasing the edges of the image when rotating it using Core Animation.) +- (UIImage *)thumbnailImage:(NSInteger)thumbnailSize + transparentBorder:(NSUInteger)borderSize + cornerRadius:(NSUInteger)cornerRadius + interpolationQuality:(CGInterpolationQuality)quality { + UIImage *resizedImage = [self resizedImageWithContentMode:UIViewContentModeScaleAspectFill + bounds:CGSizeMake(thumbnailSize, thumbnailSize) + interpolationQuality:quality]; + + // Crop out any part of the image that's larger than the thumbnail size + // The cropped rect must be centered on the resized image + // Round the origin points so that the size isn't altered when CGRectIntegral is later invoked + CGRect cropRect = CGRectMake(round((resizedImage.size.width - thumbnailSize) / 2), + round((resizedImage.size.height - thumbnailSize) / 2), + thumbnailSize, + thumbnailSize); + UIImage *croppedImage = [resizedImage croppedImage:cropRect]; + + UIImage *transparentBorderImage = borderSize ? [croppedImage transparentBorderImage:borderSize] : croppedImage; + + return [transparentBorderImage roundedCornerImage:cornerRadius borderSize:borderSize]; +} + +// Returns a rescaled copy of the image, taking into account its orientation +// The image will be scaled disproportionately if necessary to fit the bounds specified by the parameter +- (UIImage *)resizedImage:(CGSize)newSize interpolationQuality:(CGInterpolationQuality)quality { + BOOL drawTransposed; + + switch (self.imageOrientation) { + case UIImageOrientationLeft: + case UIImageOrientationLeftMirrored: + case UIImageOrientationRight: + case UIImageOrientationRightMirrored: + drawTransposed = YES; + break; + + default: + drawTransposed = NO; + } + + return [self resizedImage:newSize + transform:[self transformForOrientation:newSize] + drawTransposed:drawTransposed + interpolationQuality:quality]; +} + +// Resizes the image according to the given content mode, taking into account the image's orientation +- (UIImage *)resizedImageWithContentMode:(UIViewContentMode)contentMode + bounds:(CGSize)bounds + interpolationQuality:(CGInterpolationQuality)quality { + CGFloat horizontalRatio = bounds.width / self.size.width; + CGFloat verticalRatio = bounds.height / self.size.height; + CGFloat ratio; + + switch (contentMode) { + case UIViewContentModeScaleAspectFill: + ratio = MAX(horizontalRatio, verticalRatio); + break; + + case UIViewContentModeScaleAspectFit: + ratio = MIN(horizontalRatio, verticalRatio); + break; + + default: + [NSException raise:NSInvalidArgumentException format:@"Unsupported content mode: %d", contentMode]; + } + + CGSize newSize = CGSizeMake(self.size.width * ratio, self.size.height * ratio); + + return [self resizedImage:newSize interpolationQuality:quality]; +} + +#pragma mark - +#pragma mark Private helper methods + +// Returns a copy of the image that has been transformed using the given affine transform and scaled to the new size +// The new image's orientation will be UIImageOrientationUp, regardless of the current image's orientation +// If the new size is not integral, it will be rounded up +- (UIImage *)resizedImage:(CGSize)newSize + transform:(CGAffineTransform)transform + drawTransposed:(BOOL)transpose + interpolationQuality:(CGInterpolationQuality)quality { + CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height)); + CGRect transposedRect = CGRectMake(0, 0, newRect.size.height, newRect.size.width); + CGImageRef imageRef = self.CGImage; + + // Build a context that's the same dimensions as the new size + CGContextRef bitmap = CGBitmapContextCreate(NULL, + newRect.size.width, + newRect.size.height, + CGImageGetBitsPerComponent(imageRef), + 0, + CGImageGetColorSpace(imageRef), + CGImageGetBitmapInfo(imageRef)); + + // Rotate and/or flip the image if required by its orientation + CGContextConcatCTM(bitmap, transform); + + // Set the quality level to use when rescaling + CGContextSetInterpolationQuality(bitmap, quality); + + // Draw into the context; this scales the image + CGContextDrawImage(bitmap, transpose ? transposedRect : newRect, imageRef); + + // Get the resized image from the context and a UIImage + CGImageRef newImageRef = CGBitmapContextCreateImage(bitmap); + UIImage *newImage = [UIImage imageWithCGImage:newImageRef]; + + // Clean up + CGContextRelease(bitmap); + CGImageRelease(newImageRef); + + return newImage; +} + +// Returns an affine transform that takes into account the image orientation when drawing a scaled image +- (CGAffineTransform)transformForOrientation:(CGSize)newSize { + CGAffineTransform transform = CGAffineTransformIdentity; + + switch (self.imageOrientation) { + case UIImageOrientationDown: // EXIF = 3 + case UIImageOrientationDownMirrored: // EXIF = 4 + transform = CGAffineTransformTranslate(transform, newSize.width, newSize.height); + transform = CGAffineTransformRotate(transform, M_PI); + break; + + case UIImageOrientationLeft: // EXIF = 6 + case UIImageOrientationLeftMirrored: // EXIF = 5 + transform = CGAffineTransformTranslate(transform, newSize.width, 0); + transform = CGAffineTransformRotate(transform, M_PI_2); + break; + + case UIImageOrientationRight: // EXIF = 8 + case UIImageOrientationRightMirrored: // EXIF = 7 + transform = CGAffineTransformTranslate(transform, 0, newSize.height); + transform = CGAffineTransformRotate(transform, -M_PI_2); + break; + } + + switch (self.imageOrientation) { + case UIImageOrientationUpMirrored: // EXIF = 2 + case UIImageOrientationDownMirrored: // EXIF = 4 + transform = CGAffineTransformTranslate(transform, newSize.width, 0); + transform = CGAffineTransformScale(transform, -1, 1); + break; + + case UIImageOrientationLeftMirrored: // EXIF = 5 + case UIImageOrientationRightMirrored: // EXIF = 7 + transform = CGAffineTransformTranslate(transform, newSize.height, 0); + transform = CGAffineTransformScale(transform, -1, 1); + break; + } + + return transform; +} + +@end diff --git a/ios/iosremote/iosremote/UIImage-categories/UIImage+RoundedCorner.h b/ios/iosremote/iosremote/UIImage-categories/UIImage+RoundedCorner.h new file mode 100644 index 000000000000..630ebb38fec8 --- /dev/null +++ b/ios/iosremote/iosremote/UIImage-categories/UIImage+RoundedCorner.h @@ -0,0 +1,9 @@ +// UIImage+RoundedCorner.h +// Created by Trevor Harmon on 9/20/09. +// Free for personal or commercial use, with or without modification. +// No warranty is expressed or implied. + +// Extends the UIImage class to support making rounded corners +@interface UIImage (RoundedCorner) +- (UIImage *)roundedCornerImage:(NSInteger)cornerSize borderSize:(NSInteger)borderSize; +@end diff --git a/ios/iosremote/iosremote/UIImage-categories/UIImage+RoundedCorner.m b/ios/iosremote/iosremote/UIImage-categories/UIImage+RoundedCorner.m new file mode 100644 index 000000000000..696754029b28 --- /dev/null +++ b/ios/iosremote/iosremote/UIImage-categories/UIImage+RoundedCorner.m @@ -0,0 +1,58 @@ +// UIImage+RoundedCorner.m +// Created by Trevor Harmon on 9/20/09. +// Free for personal or commercial use, with or without modification. +// No warranty is expressed or implied. + +#import "UIImage+RoundedCorner.h" +#import "UIImage+Alpha.h" + +// Private helper methods +@interface UIImage () +- (void)addRoundedRectToPath:(CGRect)rect context:(CGContextRef)context ovalWidth:(CGFloat)ovalWidth ovalHeight:(CGFloat)ovalHeight; +@end + +@implementation UIImage (RoundedCorner) + +// Creates a copy of this image with rounded corners +// If borderSize is non-zero, a transparent border of the given size will also be added +// Original author: Björn Sållarp. Used with permission. See: http://blog.sallarp.com/iphone-uiimage-round-corners/ +- (UIImage *)roundedCornerImage:(NSInteger)cornerSize borderSize:(NSInteger)borderSize { + // If the image does not have an alpha layer, add one + UIImage *image = [self imageWithAlpha]; + + // Build a context that's the same dimensions as the new size + CGContextRef context = CGBitmapContextCreate(NULL, + image.size.width, + image.size.height, + CGImageGetBitsPerComponent(image.CGImage), + 0, + CGImageGetColorSpace(image.CGImage), + CGImageGetBitmapInfo(image.CGImage)); + + // Create a clipping path with rounded corners + CGContextBeginPath(context); + [self addRoundedRectToPath:CGRectMake(borderSize, borderSize, image.size.width - borderSize * 2, image.size.height - borderSize * 2) + context:context + ovalWidth:cornerSize + ovalHeight:cornerSize]; + CGContextClosePath(context); + CGContextClip(context); + + // Draw the image to the context; the clipping path will make anything outside the rounded rect transparent + CGContextDrawImage(context, CGRectMake(0, 0, image.size.width, image.size.height), image.CGImage); + + // Create a CGImage from the context + CGImageRef clippedImage = CGBitmapContextCreateImage(context); + CGContextRelease(context); + + // Create a UIImage from the CGImage + UIImage *roundedImage = [UIImage imageWithCGImage:clippedImage]; + CGImageRelease(clippedImage); + + return roundedImage; +} + +#pragma mark - +#pragma mark Private helper methods + +@end diff --git a/ios/iosremote/iosremote/en.lproj/iPhone_autoSize.storyboard b/ios/iosremote/iosremote/en.lproj/iPhone_autoSize.storyboard index 9e5f891861d5..c43204c72c29 100644 --- a/ios/iosremote/iosremote/en.lproj/iPhone_autoSize.storyboard +++ b/ios/iosremote/iosremote/en.lproj/iPhone_autoSize.storyboard @@ -427,49 +427,6 @@ </objects> <point key="canvasLocation" x="2290" y="1807"/> </scene> - <!--Touch Pointer vc--> - <scene sceneID="lb3-jJ-4Di"> - <objects> - <viewController id="hES-Cx-oSf" customClass="touchPointer_vc" sceneMemberID="viewController"> - <view key="view" contentMode="scaleToFill" id="5Hd-U9-nNh"> - <rect key="frame" x="0.0" y="20" width="320" height="548"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> - <subviews> - <view contentMode="scaleToFill" id="mRz-Gd-KLu"> - <rect key="frame" x="-20" y="-20" width="360" height="588"/> - <subviews> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="wNe-aT-xcf"> - <rect key="frame" x="73" y="493" width="214" height="44"/> - <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/> - <state key="normal" title="Back"> - <color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/> - <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/> - </state> - <state key="highlighted"> - <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/> - </state> - <connections> - <action selector="dismissModal:" destination="hES-Cx-oSf" eventType="touchUpInside" id="tXy-a7-aOT"/> - </connections> - </button> - <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" verticalCompressionResistancePriority="1000" id="yBi-pu-DQa"> - <rect key="frame" x="20" y="129" width="320" height="242"/> - <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> - </imageView> - </subviews> - <color key="backgroundColor" cocoaTouchSystemColor="scrollViewTexturedBackgroundColor"/> - </view> - </subviews> - <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> - </view> - <connections> - <outlet property="imageView" destination="yBi-pu-DQa" id="XE8-h0-pu0"/> - </connections> - </viewController> - <placeholder placeholderIdentifier="IBFirstResponder" id="gog-t4-scM" userLabel="First Responder" sceneMemberID="firstResponder"/> - </objects> - <point key="canvasLocation" x="2807" y="1752"/> - </scene> <!--Slide Show Preview Table vc--> <scene sceneID="Tvi-bD-vMC"> <objects> @@ -627,7 +584,6 @@ <class className="slideShowPreviewTable_vc" superclassName="UITableViewController"> <source key="sourceIdentifier" type="project" relativePath="./Classes/slideShowPreviewTable_vc.h"/> <relationships> - <relationship kind="action" name="startPresentationAction:"/> <relationship kind="outlet" name="optionsTable" candidateClass="UITableView"/> </relationships> </class> @@ -659,13 +615,6 @@ <relationship kind="outlet" name="touchPointerScrollView" candidateClass="UIScrollView"/> </relationships> </class> - <class className="touchPointer_vc" superclassName="UIViewController"> - <source key="sourceIdentifier" type="project" relativePath="./Classes/touchPointer_vc.h"/> - <relationships> - <relationship kind="action" name="dismissModal:"/> - <relationship kind="outlet" name="imageView" candidateClass="UIImageView"/> - </relationships> - </class> </classes> <simulatedMetricsContainer key="defaultSimulatedMetrics"> <simulatedStatusBarMetrics key="statusBar"/> diff --git a/ios/iosremote/iosremote/iosremote-Info.plist b/ios/iosremote/iosremote/iosremote-Info.plist index 578325c61939..59dcb6f765e9 100644 --- a/ios/iosremote/iosremote/iosremote-Info.plist +++ b/ios/iosremote/iosremote/iosremote-Info.plist @@ -17,8 +17,6 @@ <string>ic_launcher.png</string> <string>ic_launcher@2x.png</string> </array> - <key>UIPrerenderedIcon</key> - <true/> </dict> </dict> <key>CFBundleIdentifier</key> @@ -39,8 +37,6 @@ <true/> <key>UIMainStoryboardFile</key> <string>iPhone_autoSize</string> - <key>UIPrerenderedIcon</key> - <true/> <key>UIRequiredDeviceCapabilities</key> <array> <string>armv7</string> diff --git a/ios/iosremote/iosremote/newServer_vc.m b/ios/iosremote/iosremote/newServer_vc.m index acd887ed21cf..65a384645998 100644 --- a/ios/iosremote/iosremote/newServer_vc.m +++ b/ios/iosremote/iosremote/newServer_vc.m @@ -185,7 +185,7 @@ EditableTableViewCell *cell = nil; NSString *text = nil; NSString *placeholder = nil; - UIKeyboardType keyboardType; + UIKeyboardType keyboardType = UIKeyboardTypeDefault; // Pick the editable cell and the values for its textField // |