iDev: UIImage and UIImage View

When we use images in our application then we face different type of scenarios while handling the image. Before we go into the scenarios / situations of image handling in Application, let us understand the concept of UIImage and UIImageView.

Concept of UIImage and UIImageView (container)

UIImage – Bitmap with different formats Ex png and jpeg. Recommended format is png.UIImageView – This is an iOS Widget that acts like a container for holding the image. To hold the image, UIImageView is required.

When UIImage is shown in UIImageView, there is a property (Content Mode) of UIImageView, that render the Image in UIImageView. We mostly use three types of Content Mode property. These are:

  • Scale To Fill
  • Aspect Fit
  • Aspect Fill

How these Content Mode render the image we can see by following examples

  • UIImage of size (100×150)
  • UIImageView of size (200×200)

Different Content modes for placing Image in ImageView

1. Scale To Fill

In this case, content is scaled to fill in ImageView with distorted or same aspect ratio. If the image aspect ratio is different than that of container then final image ratio when fitted in the container will be different and hence the image is finally distorted.

(Aspect Ratio is Width / Height)

InnovationM Image Handling in iOS

2. Aspect Fit

In this case, content is scaled to fit in ImageView (container) without changing the aspect ratio of image . Remainder is transparent.

InnovationM Image Handling in iOS

3. Aspect Fill Without Clipping

In this case, image is scaled to fill in ImageView. Aspect ratio of image is not changed.

InnovationM Image Handling in iOS

4. Aspect Fill With Clipping

In this case, content is scaled to fill in ImageView the same way it happen in the above case but then finally image is cropped to the exact size of the ImageView size.

InnovationM Image Handling in iOS

Calculating new width and height with maintaining aspect ratio

Image original width = 100 and height = 150
Container width  = 200 and height = 200

x-ratio = Container width / Image original width = 200/100 = 2.0
y-ratio =  Container height / Image original height = 200/ 150 =  1.33

Selected ratio = min (x-ratio, y-ratio) = 1.33

Final Image width = Image original width * Selected Ratio = 100 * 1.33 = 133
Final Image height = Image original height * Selected Ratio = 150 * 1.33 = 200

Final Image width x height = 133 x 200 (Original width x height of image was 100 x 150)

Showing Images coming from Server (Different Scenarios)

We can use Aspect Fit mode for all the scenarios. It will serve in every scenario if you don’t want to distort image.

Scenario 1
Image width is lesser than Container width.
Image height is lesser than Container height

Image width = 100 and height = 150
UIImageView width = 200 and height = 200

Final Image width = 133  and height = 200 (Refer the calculations above)
Image is scaled up to fit the container.

InnovationM Image Handling in iOS

Scenario 2 
Image width is greater than Container width.
Image height is lesser than Container height

Image width = 100 and height = 150
UIImageView width = 80 and height = 200

Final Image width = 80 and height = 122
Image is scaled down to fit the container.

InnovationM Image Handling in iOS

Scenario 3
Image width is lesser than Container width.
Image height is greater than Container height.

Image width = 100 and height = 150
UIImageView width = 200 and height = 120

Final width = 80  and height = 120
Image is scaled down to fit the container.
InnovationM Image Handling in iOS

Scenario 4
Image width is greater than Container width.
Image height is greater than Container height.

Image width = 100 and height = 150
UIImageView width = 80 and height = 100

Final width = 66  and height = 100
Image is scaled down to fit the container.

InnovationM Image Handling in iOS

Scenario 5 (Same Aspect Ratio of Image and ImageView)
Image width is greater than Container width.
Image height is greater than Container height.

Image width = 100 and height = 150
UIImageView width = 80 and height = 120

Final width = 80 and height = 120
Image is scaled down to fit the container.

InnovationM Image Handling in iOS

Scenario 6 (Same Aspect Ratio of Image and ImageView)
Image width is lesser than Container width.
Image height is lesser than Container height.

Image width = 100 and height = 150
UIImageView width = 120 and height = 180

Final width = 120 and height = 180
Image is scaled up to fit the container.

InnovationM Image Handling in iOS

How we change the image size and compress image file size-

Uploading Images to the Server (Different Scenarios)

Many times we have to upload images in an application from device (iPhone, iPad) to the server. It could be a photo clicked from the camera or there was an old image that we choose and upload from the application.

Before uploading we can do two things with the image:

1. Change the width and height of original image.
2. Compress the image to be of smaller file size.

Let us understand them.

1. Change the width and height of original image.

To resize the image, we have to configure the drawing environment for rendering into a bitmap.

1# UIGraphicsBeginImageContextWithOptions()  method is used to create the bitmap-based graphics context.

This method takes two parameters:

  1. Size of image (changed size) and
  2. Scale factor of device as parameter.

Scale factor for Normal Display = 1.0
Scale factor for Retina Display = 2.0

2# – (void) drawInRect:(CGRect)rect; method is used to draw the image in target rectangle.

3# UIGraphicsGetImageFromCurrentImageContext()  method is used to get the resized image from drawing environment.

4# UIGraphicsEndImageContext() method is used to clean up the bitmap drawing environment and remove the graphics context from the top of the context stack.

Example :

Original source Image  Size = (2448, 3264)
Original source image file size = 3.8 MB

After resizing image to size (1024,768):
Resized source Image  Size = (1024,768)
Resized source image file size = 2.0 MB

Code Example:

2. Compress the image to be of smaller file size.

We can compress the image file size by following method.

UIImageJPEGRepresentation() This method takes two parameter

  1. UIImage object.
  2. Compress ratio (It can be between 0.0 and 1.0)

This method will return NSData representation of image after compressing.

Example :

Original source Image  Size = (2448, 3264)
Original source image file size = 3.8 MB

After compressing image file  size by 0.5:
Resized source Image  Size = (2448, 3264)
Resized source image file size = 534 KB

Code Example:

Depending upon your requirement whether to reduce the size (width and height in pixels) OR reduce the file size OR Both, you may apply the above.

Original Source: Click Here

iDev: UIImage Orientaion Code

// method for swipe
static CGRect swapWidthAndHeight(CGRect rect)
{
CGFloat swap = rect.size.width;

rect.size.width = rect.size.height;
rect.size.height = swap;

return rect;
}

#pragma mark – rotateImage captured

-(UIImage*)rotateImageOrien:(UIImageOrientation)orient andImage:(UIImage *)img
{
CGRect bnds = CGRectZero;
UIImage* copy = nil;
CGContextRef ctxt = nil;
CGImageRef imag = img.CGImage;
CGRect rect = CGRectZero;
CGAffineTransform tran = CGAffineTransformIdentity;

rect.size.width = CGImageGetWidth(imag);
rect.size.height = CGImageGetHeight(imag);

bnds = rect;

switch (orient)
{
case UIImageOrientationUp:
// would get you an exact copy of the original
//assert(false);
return nil;

case UIImageOrientationUpMirrored:
tran = CGAffineTransformMakeTranslation(rect.size.width, 0.0);
tran = CGAffineTransformScale(tran, -1.0, 1.0);
break;

case UIImageOrientationDown:
tran = CGAffineTransformMakeTranslation(rect.size.width,
rect.size.height);
tran = CGAffineTransformRotate(tran, M_PI);
break;

case UIImageOrientationDownMirrored:
tran = CGAffineTransformMakeTranslation(0.0, rect.size.height);
tran = CGAffineTransformScale(tran, 1.0, -1.0);
break;

case UIImageOrientationLeft:
bnds = swapWidthAndHeight(bnds);
tran = CGAffineTransformMakeTranslation(0.0, rect.size.width);
tran = CGAffineTransformRotate(tran, 3.0 * M_PI / 2.0);
break;

case UIImageOrientationLeftMirrored:
bnds = swapWidthAndHeight(bnds);
tran = CGAffineTransformMakeTranslation(rect.size.height,
rect.size.width);
tran = CGAffineTransformScale(tran, -1.0, 1.0);
tran = CGAffineTransformRotate(tran, 3.0 * M_PI / 2.0);
break;

case UIImageOrientationRight:
bnds = swapWidthAndHeight(bnds);
tran = CGAffineTransformMakeTranslation(rect.size.height, 0.0);
tran = CGAffineTransformRotate(tran, M_PI / 2.0);
break;

case UIImageOrientationRightMirrored:
bnds = swapWidthAndHeight(bnds);
tran = CGAffineTransformMakeScale(-1.0, 1.0);
tran = CGAffineTransformRotate(tran, M_PI / 2.0);
break;

default:
// orientation value supplied is invalid
assert(false);
return nil;
}

UIGraphicsBeginImageContext(bnds.size);
ctxt = UIGraphicsGetCurrentContext();

switch (orient)
{
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
CGContextScaleCTM(ctxt, -1.0, 1.0);
CGContextTranslateCTM(ctxt, -rect.size.height, 0.0);
break;

default:
CGContextScaleCTM(ctxt, 1.0, -1.0);
CGContextTranslateCTM(ctxt, 0.0, -rect.size.height);
break;
}

CGContextConcatCTM(ctxt, tran);
CGContextDrawImage(UIGraphicsGetCurrentContext(), rect, imag);

copy = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

return copy;
}

iDev: Saving and Getting Image from NSDocumentDirectory (get image from URL)

Look the Code”

//Getting the image from URL

-(void)savedPhotoInDocDir:(NSString *) imageURL{

NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageURL]];

NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];

//TimeStamp getting random number
int randomNumber = [self getRandomNumber:9 to:9999999999];

//Creating Time stamp for specific name of save Image

NSString * timeStampValue = [NSString stringWithFormat:@”%ld”, (long)[[NSDate date] timeIntervalSince1970]];

[self setImagePath:[documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:@”savePhoto%@%d.png”,timeStampValue,randomNumber]]];

BOOL isDone =[fileManager createFileAtPath:imagePath contents:imageData attributes:nil];

if(isDone==TRUE){
NSLog(@”Saved Image Document Directory”); }
else {
NSLog(@”Not Save”);
}
}

//Generating Random number

-(int)getRandomNumber:(int)from to:(int)to {

return (int)from + arc4random() % (to-from+1);
}

// getting the image

– (UIImage*)getImage_FromName :(NSString *)imageName {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,     NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *getImagePath = [documentsDirectory stringByAppendingPathComponent:imageName];
UIImage *img = [UIImage imageWithContentsOfFile:getImagePath];
return img;
}

Keep Coding …

UIButton : How to create a UIButton Programmatically

Sample Code:

// Set a method for this

-(void) addButtonWithFrame :(CGRect ) btnFrame  andName: (NSString *) titleName

{

UIButton *addButton = [UIButton buttonWithType: UIButtonTypeCustom];

// (Value = 0) means NO Button Style.

/* iOS Library provide more Types of UIButton , like

  1. UIButtonTypeRoundedRect (Value = 1), Means a Rounded-Rectangle Style
  2. UIButtonTypeDetailDisclosure (Value = 2), Means a Details Disclosure Button
  3. UIButtonTypeInfoLight (Value = 3), Means an Information button with light background
  4. UIButtonTypeInfoDark (Value = 4), Means an Information Button with dark background
  5. UIButtonTypeContactAdd (Value = 5), Means a contact add button.

You can choose any one of them. */

//Set Button Frame

addButton.frame = btnFrame;

//Set Tag

addButton.tag = cnt; //cnt = 0,1,2…..so on.

// Set Title

[addButton setTitle : titleName forState: UIControlSateNormal];

//If you want to user touch and title highlighted, changes the state like :

// [addButton setTitle : titleName forState: UIControlStateHighlighted];

//Set Title Color

[addButton setTitileColor: [UIColor darkGrayColor] forState: UIControlStateNormal];

//Set Font

addButton.titleLabel.font = [UIFont fontWithName: @ “FontName” size:14 ];

or

addButton.titleLabel.font = [UIFont systemFontOfSize:14];

//Set Image

[addButton setImage:[UIImage imageNamed:@ “ImageName_Normal”] forState: UIControlStateNormal];

[addButton setImage:[UIImage imageNamed:@ “ImageName_Highlighted”] forState: UIControlStateHighlighted];

// Set Background Image

[addButton setBackgroundImage:[UIImage imageNamed:@ “ImageNormal.png”] forState: UIControlStateNormal];// highlighted

[addButton setBackgroundImage:[UIImage imageNamed:@ “ImageHighlighted.png”] forState: UIControlStateHighlighted];

// Set your custom Image, means add a ImageView on Button

UIImageView *myImageView = [[UIImageView alloc] initWithFrame: CGRectMake( 0,0, btnFrame.frame.size.width, btnFrame.frame.size.height)];

myImageView.image = [UIImage imageNamed: @ “Image.png”];

[addButton addSubview: myImageView];

[myImageView release];

// Other way to set Image highlighted and normal with Strechable Image

UIImage *normalImage = [UIImage imageNamed:@ “normalImage.png”];

UIImage *strechableNormalImage = [normalImage stretchableImageWithLeftCapWidth: 14 topCapHeight: 0];

[addButton setBackgroundImage: strechableNormalImage forState: UIControlStateNormal];

UIImage *highlightedImage = [UIImage imageNamed:@ “highlightedImage.png”];

UIImage *strechableHighlightedImage = [highlightedImage  stretchableImageWithLeftCapWidth: 14 topCapHeight: 0];

[addButton setBackgroundImage: strechableHighlightedImage forState: UIControlStateHighlighted];

//Set Line Break Mode

addButton.titleLabel.lineBreakMode = UILineBreakModeTrailTruncation;

// Set Border Layer border Width and Color

// First you import and add QuartzCore Framework

addButton.layer.borderWidth = 2.0f;

addButton.layer.borderColor = [UIColor blackColor].cgcolor;

// setRadius Corner

addButton.layer.radiusCorner = 9.0f;

// Set Action on Button

[addButton addTarget: self  action:@selector(clickOnButtons:) forControlEvents: UIControlEventTouchUpInside];

// Add to SubView  

[self.view addSubview: addButton];

}

//Calling Method

[self addButtonWithFrame:CGRectMake(20,20,120,30) andName:@ “Close”];

Or

CGRect rect;

rect = CGRectMake (20,20,120,30);

NSString *btnName = @ “Close”;

[self addButtonWithFrame:rect andName:btnName];

UINavigationBar: How to customize Navigation Bar

By customization we can change look and feel of Navigation Bar. Below is sample code which demonstrates how to customize Navigation Bar.

We can achieve this by using Categories in Objective-C:
Code Sample:

/*********************************************************/

@interface UINavigationBar (CustomNavBarImage)

– (void) setNavBackgroundImage:(UIImage*)bgImage;

– (void) removeNavBackgroundImage ;

@end

/************************************************************/

//.m file (Implementaion file)

#import “UINavigationBar+CustomNavBarImage.h”

@implementation UINavigationBar (CustomNavBarImage)

– (void) setNavBackgroundImage:(UIImage*)bgImage

{

if (bgImage == NULL)

return;

UIImageView *myImageView= [[UIImageView alloc] initWithImage:bgImage];

myImageView.frame = CGRectMake(0,0,320,44);

[self addSubview:myImageView];

[myImageView release];

// If you want to add some buttons and title go through that

//[myImageView release];

UIButton *addButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];//UIButtonTypeCustom

addButton .frame = CGRectMake(10, 0, 100, 44);

[addButton setTitle:@”Add” forState:UIControlStateNormal];

[addButton addTarget:self action:@selector(clickOnAddButton:) forControlEvents:UIControlEventTouchUpInside];

//Font size of title

addButton.titleLabel.font = [UIFont boldSystemFontOfSize:14];

[myImageView addSubview:addButton];

myImageView.userInteractionEnable = YES;

}

– (void) removeNavBackgroundImage

{

NSArray *subviewsArray = [self subviews];

for (int i=0; i<[subviewsArray count]; i++)

{

if ([[subviewsArray objectAtIndex:i]  isMemberOfClass:[UIImageView class]])

{

[[subviewsArray objectAtIndex:i] removeFromSuperview];

}

}

}

@end

// Calling

// Set Navigation Bar Image

[[self.navigationController navigationBar] performSelectorInBackground:@selector(setNavBackgroundImage:) withObject:bgImage];

// Remove Image

[[self.navigationController navigationBar] performSelector:@selector(removeNavBackgroundImage) withObject:nil];

// Second Simple Way : (Without Categories)

// Set  first this : self.NavigationController.navigationBarHidden = YES;

-(void) setCustomNavBar

{

UIImageView *myImage = [[UIImageView alloc] initWithFrame:CGRectMake (0,0,320,44)];

// set your background image name like NavBarImage.png

myImage.image = [UIImage imageNamed:@”yourBGImage”];

myImage.backgroundColor = [UIColor clearColor];

[self.view addSubview: myImage];

UIButton *addButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];//UIButtonTypeCustom

addButton .frame = CGRectMake(10, 0, 100, 44);

[addButton setTitle:@”Add” forState:UIControlStateNormal];

[addButton addTarget:self action:@selector(clickOnAddButton:) forControlEvents:UIControlEventTouchUpInside];

//Font size of title

addButton.titleLabel.font = [UIFont boldSystemFontOfSize:14];

[myImage addSubview:addButton];

myImage.userInteractionEnable = YES;

}

//Called this function on viewdidload or loadView or viewWillAppear (according to your preference).

[self performSelector:@selector(setCustomNavBar)];

Other Methods are :

 

Until iOS 5 came out, we used drawRect override in AppDelegate to customize UINavigationBar.
Now iOS 5 give us some new method for styling (and old doesn’t work).
How to build app that will work on iOS 4 and iOS 5 with stylized UINavigationBar?
You must to do both!
In AppDelegate use this code:

@implementation UINavigationBar (UINavigationBarCategory)
– (void)drawRect:(CGRect)rect {
UIImage *img = [UIImage imageNamed:@”navbar.png”];
[img drawInRect:rect];
}
@end

and in

viewDidLoad method for iOS5 and above (in your view implementation):

if ([self.navigationController.navigationBar respondsToSelector:@selector( setBackgroundImage:forBarMetrics:)]){
[self.navigationController.navigationBar setBackgroundImage:[UIImage  imageNamed:@”navbar.png”] forBarMetrics:UIBarMetricsDefault];
}

If you see, here we are asking if navbar will respondToSelector to avoid crash on iOS4!
If you use this for iOS5:

if([[UINavigationBar appearance] respondsToSelector:@selector( setBackgroundImage:forBarMetrics:)]){
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@”navbar_bg.png”] forBarMetrics:UIBarMetricsDefault];
}


Your app will not work on iOS4 because can’t found [UINavigationBar appearance].
But, if you want to target only iOS5 this snippet will work for whole app. You can put it just in didFinishLaunchingWithOptions method in AppDelegate:

[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@”navbar_bg.png”] forBarMetrics:UIBarMetricsDefault];

Set the image using method setBackgroundImage:forBarMetrics. (ios 5 and above)

[[UINavigationBarappearance] setBackgroundImage: portrait

forBarMetrics:UIBarMetricsDefault];

[[UINavigationBarappearance] setBackgroundImage: landscape

forBarMetrics:UIBarMetricsLandscapePhone];

Create resizable images

UIImage *portrait = [[UIImageimageNamed:@”image1″]

resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];

UIImage *landscape = [[UIImage imageNamed:@”image2″]

resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0,0)];

Set the attributes of Naviagtion Bar (to set the title font, color, shadow offset)

[[UINavigationBarappearance] setTitleTextAttributes:

[NSDictionarydictionaryWithObjectsAndKeys:

[UIColorcolorWithRed:255.0/255.0green:255.0/255.0blue:255.0/255.0alpha:1.0],

UITextAttributeTextColor,

[UIColorcolorWithRed:0.0green:0.0blue:0.0alpha:0.8],

UITextAttributeTextShadowColor,

[NSValuevalueWithUIOffset:UIOffsetMake(0, -1)],

UITextAttributeTextShadowOffset,

[UIFontfontWithName:@”Arial-Bold”size:0.0],

UITextAttributeFont,

nil]];

Similary, we can set the background image of UISegmentedControl and UITabBar, UIBarButtonItem etc.

UIImageView: Show Images from URL,Resources Folder, and Document Directory

Use the following functions to get Image from Web URL or Main Bundle (Resource Folder) or Document Directory

// From URL

-(UIImage *) getImageFromURL : (NSString *) urlString

{

NSURL *pathURL = [NSURL URLWithString: urlString];

NSData *imageData = [NSData dataWithContentOfURL:pathURL];

UIImage *getImage = [[UIImage alloc]initWithData:imageData];

return getImage;

}

// From Bundle

-(UIImage *) getImageFromResources_FileName: (NSString *)file_Name andFileType: (NSString *) file_Extension

{

NSString *filePath = [[NSBundle mainBundle] pathForResource : file_Name ofType: file_Extension];

UIImage *getImage = [UIImage imageWithContentsOfFile:filePath];

return getImage;

}

// From Document Directory (NSDocumentDirectory)

-(UIImage *) getImageFromDocumentDirectory_ImageName:(NSString *) imageName

{

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDirectory = [paths objectAtIndex:0];
NSString *destPath = [docDirectory stringByAppendingPathComponent:imageName];//image.png
NSURL *url = [NSURL fileURLWithPath:destPath];
UIImage *getImage= [manager imageWithURL:url];

if (getImage)
{

UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:@”Image” message:@”Found” delegate:nil cancelButtonTitle:@”OK” otherButtonTitles:nil];
[alertView show];

}
else
{

getImage = [UIImage imageNamed:@”defaultImage.png”];
UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:@”Image” message:@”Not Found” delegate:nil
cancelButtonTitle:@”OK” otherButtonTitles:nil];
[alertView show];

}

return getImage;

}

Procedure:

#define FROM_RESOURCES 1

#define FROM_WEB_URL 2

#define FROM_DOC_DIR 3

/*******************************************Calling **************************************************/

UIImageView *showImage = [[UIImageView alloc] initWithFrame:CGRectMake(20,20,250,250)];

//Calling from Resources Folder

if(FROM_RESOURCES)

{

showImage.image = [self getImageFromResources_FileName:@”Niketan” andFileType:@”png/jpg”];

}

else if (FROM_WEB_URL)

//Calling from URL

{

showImage.image = [self getImageFromURL : @”your url”];

// @”http://www.yourweb.com/pictures/niketan.png&#8221;;

}

else

//Calling From Document Directory

{

showImage.image = [self getImageFromDocumentDirectory_ImageName: @”Vinay.png”];

}

[self.view addSubview: showImage];