Permalink
Browse files

first commit

  • Loading branch information...
0 parents commit b452aa0568f82f041ea777888ebf30980ee97682 @mattgemmell mattgemmell committed Jul 5, 2010
@@ -0,0 +1,31 @@
+//
+// MGImageUtilitiesAppDelegate.h
+// MGImageUtilities
+//
+// Created by Matt Gemmell on 04/07/2010.
+// Copyright Instinctive Code 2010.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface MGImageUtilitiesAppDelegate : NSObject <UIApplicationDelegate> {
+ UIWindow *window;
+ UIImageView *originalView;
+ UIImageView *resultView;
+ UISegmentedControl *methodControl;
+ UISwitch *tintSwitch;
+}
+
+@property (nonatomic, retain) IBOutlet UIWindow *window;
+@property (nonatomic, retain) IBOutlet UIImageView *originalView;
+@property (nonatomic, retain) IBOutlet UIImageView *resultView;
+@property (nonatomic, retain) IBOutlet UISegmentedControl *methodControl;
+@property (nonatomic, retain) IBOutlet UISwitch *tintSwitch;
+
+- (IBAction)methodChanged:(id)sender;
+- (IBAction)tintChanged:(id)sender;
+
+- (void)updateResult;
+
+@end
+
@@ -0,0 +1,88 @@
+//
+// MGImageUtilitiesAppDelegate.m
+// MGImageUtilities
+//
+// Created by Matt Gemmell on 04/07/2010.
+// Copyright Instinctive Code 2010.
+//
+
+#import "MGImageUtilitiesAppDelegate.h"
+#import "UIImage+ProportionalFill.h"
+#import "UIImage+Tint.h"
+
+@implementation MGImageUtilitiesAppDelegate
+
+
+@synthesize window;
+@synthesize originalView;
+@synthesize resultView;
+@synthesize methodControl;
+@synthesize tintSwitch;
+
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+ // Load a sample image for the demo.
+ originalView.image = [UIImage imageNamed:@"original.png"];
+ [self updateResult];
+
+ [window makeKeyAndVisible];
+
+ return YES;
+}
+
+
+- (void)dealloc
+{
+ [window release];
+
+ [super dealloc];
+}
+
+
+- (IBAction)methodChanged:(id)sender
+{
+ [self updateResult];
+}
+
+
+- (IBAction)tintChanged:(id)sender
+{
+ [self updateResult];
+}
+
+
+- (void)updateResult
+{
+ UIImage *oldImage = originalView.image;
+ UIImage *newImage;
+ CGSize newSize = resultView.frame.size;
+
+ // Resize the image using the user's chosen method.
+ switch (methodControl.selectedSegmentIndex) {
+ case 0:
+ newImage = [oldImage imageScaledToFitSize:newSize]; // uses MGImageResizeScale
+ break;
+ case 1:
+ newImage = [oldImage imageCroppedToFitSize:newSize]; // uses MGImageResizeCrop
+ break;
+ case 2:
+ newImage = [oldImage imageToFitSize:newSize method:MGImageResizeCropStart];
+ break;
+ case 3:
+ newImage = [oldImage imageToFitSize:newSize method:MGImageResizeCropEnd];
+ break;
+ default:
+ break;
+ }
+
+ // If appropriate, tint the resulting image.
+ if (tintSwitch.on) {
+ newImage = [newImage imageTintedWithColor:[UIColor redColor]];
+ }
+
+ resultView.image = newImage;
+}
+
+
+@end
@@ -0,0 +1,23 @@
+//
+// UIImage+ProportionalFill.h
+//
+// Created by Matt Gemmell on 20/08/2008.
+// Copyright 2008 Instinctive Code.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface UIImage (MGProportionalFill)
+
+typedef enum {
+ MGImageResizeCrop, // analogous to UIViewContentModeScaleAspectFill, i.e. "best fit" with no space around.
+ MGImageResizeCropStart,
+ MGImageResizeCropEnd,
+ MGImageResizeScale // analogous to UIViewContentModeScaleAspectFit, i.e. scale down to fit, leaving space around if necessary.
+} MGImageResizingMethod;
+
+- (UIImage *)imageToFitSize:(CGSize)size method:(MGImageResizingMethod)resizeMethod;
+- (UIImage *)imageCroppedToFitSize:(CGSize)size; // uses MGImageResizeCrop
+- (UIImage *)imageScaledToFitSize:(CGSize)size; // uses MGImageResizeScale
+
+@end
@@ -0,0 +1,109 @@
+//
+// UIImage+ProportionalFill.m
+//
+// Created by Matt Gemmell on 20/08/2008.
+// Copyright 2008 Instinctive Code.
+//
+
+#import "UIImage+ProportionalFill.h"
+
+
+@implementation UIImage (MGProportionalFill)
+
+
+- (UIImage *)imageToFitSize:(CGSize)fitSize method:(MGImageResizingMethod)resizeMethod
+{
+ float sourceWidth = [self size].width * self.scale;
+ float sourceHeight = [self size].height * self.scale;
+ float targetWidth = fitSize.width;
+ float targetHeight = fitSize.height;
+ BOOL cropping = !(resizeMethod == MGImageResizeScale);
+
+ // Calculate aspect ratios
+ float sourceRatio = sourceWidth / sourceHeight;
+ float targetRatio = targetWidth / targetHeight;
+
+ // Determine what side of the source image to use for proportional scaling
+ BOOL scaleWidth = (sourceRatio <= targetRatio);
+ // Deal with the case of just scaling proportionally to fit, without cropping
+ scaleWidth = (cropping) ? scaleWidth : !scaleWidth;
+
+ // Proportionally scale source image
+ float scalingFactor, scaledWidth, scaledHeight;
+ if (scaleWidth) {
+ scalingFactor = 1.0 / sourceRatio;
+ scaledWidth = targetWidth;
+ scaledHeight = round(targetWidth * scalingFactor);
+ } else {
+ scalingFactor = sourceRatio;
+ scaledWidth = round(targetHeight * scalingFactor);
+ scaledHeight = targetHeight;
+ }
+ float scaleFactor = scaledHeight / sourceHeight;
+
+ // Calculate compositing rectangles
+ CGRect sourceRect, destRect;
+ if (cropping) {
+ destRect = CGRectMake(0, 0, targetWidth, targetHeight);
+ float destX, destY;
+ if (resizeMethod == MGImageResizeCrop) {
+ // Crop center
+ destX = round((scaledWidth - targetWidth) / 2.0);
+ destY = round((scaledHeight - targetHeight) / 2.0);
+ } else if (resizeMethod == MGImageResizeCropStart) {
+ // Crop top or left (prefer top)
+ if (scaleWidth) {
+ // Crop top
+ destX = 0.0;
+ destY = 0.0;
+ } else {
+ // Crop left
+ destX = 0.0;
+ destY = round((scaledHeight - targetHeight) / 2.0);
+ }
+ } else if (resizeMethod == MGImageResizeCropEnd) {
+ // Crop bottom or right
+ if (scaleWidth) {
+ // Crop bottom
+ destX = round((scaledWidth - targetWidth) / 2.0);
+ destY = round(scaledHeight - targetHeight);
+ } else {
+ // Crop right
+ destX = round(scaledWidth - targetWidth);
+ destY = round((scaledHeight - targetHeight) / 2.0);
+ }
+ }
+ sourceRect = CGRectMake(destX / scaleFactor, destY / scaleFactor,
+ targetWidth / scaleFactor, targetHeight / scaleFactor);
+ } else {
+ sourceRect = CGRectMake(0, 0, sourceWidth, sourceHeight);
+ destRect = CGRectMake(0, 0, scaledWidth, scaledHeight);
+ }
+
+ // Create appropriately modified image.
+ UIImage *image;
+ UIGraphicsBeginImageContextWithOptions(destRect.size, NO, 0.0); // 0.0 for scale means "correct scale for device's main screen".
+ CGImageRef sourceImg = CGImageCreateWithImageInRect([self CGImage], sourceRect); // cropping happens here.
+ image = [UIImage imageWithCGImage:sourceImg scale:0.0 orientation:self.imageOrientation]; // create cropped UIImage.
+ [image drawInRect:destRect]; // the actual scaling happens here, and orientation is taken care of automatically.
+ CGImageRelease(sourceImg);
+ image = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+
+ return image;
+}
+
+
+- (UIImage *)imageCroppedToFitSize:(CGSize)fitSize
+{
+ return [self imageToFitSize:fitSize method:MGImageResizeCrop];
+}
+
+
+- (UIImage *)imageScaledToFitSize:(CGSize)fitSize
+{
+ return [self imageToFitSize:fitSize method:MGImageResizeScale];
+}
+
+
+@end
@@ -0,0 +1,15 @@
+//
+// UIImage+Tint.h
+//
+// Created by Matt Gemmell on 04/07/2010.
+// Copyright 2010 Instinctive Code.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface UIImage (MGTint)
+
+- (UIImage *)imageTintedWithColor:(UIColor *)color;
+- (UIImage *)imageTintedWithColor:(UIColor *)color fraction:(CGFloat)fraction;
+
+@end
@@ -0,0 +1,54 @@
+//
+// UIImage+Tint.m
+//
+// Created by Matt Gemmell on 04/07/2010.
+// Copyright 2010 Instinctive Code.
+//
+
+#import "UIImage+Tint.h"
+
+
+@implementation UIImage (MGTint)
+
+
+- (UIImage *)imageTintedWithColor:(UIColor *)color
+{
+ // This method is designed for use with template images, i.e. solid-coloured mask-like images.
+ return [self imageTintedWithColor:color fraction:0.0]; // default to a fully tinted mask of the image.
+}
+
+
+- (UIImage *)imageTintedWithColor:(UIColor *)color fraction:(CGFloat)fraction
+{
+ if (color) {
+ // Construct new image the same size as this one.
+ UIImage *image;
+ UIGraphicsBeginImageContextWithOptions([self size], NO, 0.0); // 0.0 for scale means "scale for device's main screen".
+ CGRect rect = CGRectZero;
+ rect.size = [self size];
+
+ // Composite tint color at its own opacity.
+ [color set];
+ UIRectFill(rect);
+
+ // Mask tint color-swatch to this image's opaque mask.
+ // We want behaviour like NSCompositeDestinationIn on Mac OS X.
+ [self drawInRect:rect blendMode:kCGBlendModeDestinationIn alpha:1.0];
+
+ // Finally, composite this image over the tinted mask at desired opacity.
+ if (fraction > 0.0) {
+ // We want behaviour like NSCompositeSourceOver on Mac OS X.
+ [self drawInRect:rect blendMode:kCGBlendModeSourceAtop alpha:fraction];
+ }
+ image = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+
+ return image;
+ }
+
+ return self;
+}
+
+
+
+@end
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleDisplayName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.instinctivecode.test.${PRODUCT_NAME:rfc1034identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>NSMainNibFile</key>
+ <string>MainWindow</string>
+</dict>
+</plist>
Oops, something went wrong.

0 comments on commit b452aa0

Please sign in to comment.