[iPhone][Tutorial #1] UIImage resize하기
Aug 13
iphone_tutorial apple, Bitmap, dev tutorial, iphone, iphone dev, iphone dev tutorial, iPod, resize, resizing, UIImage, 아이폰, 아이폰 개발, 아이폰 튜토리얼, 애플 213 Comments
iPone Dev Tutorial을 시작해보려고 한다. 여러 앱들에 흩어져 있는 code snippet들도 정리하고 고견들도 듣기 위해서이다.
iPhone Dev 관련 포스트와 Tutorial의 차이는 코드가 제공 여부로 보면 좋겠다.
첫 번째 Tutorial은 UIImage를 resizing하는 것이다.
Resizing 없이 UIImageView에 content mode를 UIViewContentModeScaleAspectFit으로 설정하고 UIImageView.image에 UIImage를 줘버리면 끝나겠지만, thumbnail image를 제대로 resize해서 메모리 측면에서 효율적인 코딩을 해보자 (Core Data의 faulting에도 Original Image와 Resized Thumbnail Image를 이용하면 더 의미가 있을 것이다.).
이 Tutorial에서는 두 가지 방법을 제공할 것이다.
첫 번째는 UIGraphicsBeginImageContext()과 UIGraphicsGetImageFromCurrentImageContext() 을 이용하는 방법이고, 두 번째는 Using CGContextDrawImage(), CGBitmapContextCreateImage()과 UIImage imageWithCGImage을 이용하는 방법이다.
이 Tutorial에서는 아래 Screen shot과 같이 Image Picker로 앨범에서 사진을 하나 선택하고 이 것을 위 두 가지 방식으로 resizing해서 thumbnail image를 보여주는 Sample App을 제공한다.

#1 . UIGraphicsBeginImageContext()과 UIGraphicsGetImageFromCurrentImageContext() 이용 방법
UIGraphicsBeginImageContext()는 아래 설명과 같이 주어진 size로 GC (Graphics Context)를 만드는 것이다.
UIGraphicsBeginImageContext
Creates a bitmap-based graphics context and makes it the current context.void UIGraphicsBeginImageContext(CGSize size);
Parameters
size
The size of the new bitmap context. This represents the size of the image returned by the UIGraphicsGetImageFromCurrentImageContext function.
UIGraphicsGetImageFromCurrentImageContext 는 아래 설명과 같이 현재 CG에 있는 contents의 image (UIImage)를 반환해준다.
UIGraphicsGetImageFromCurrentImageContext
Returns an image based on the contents of the current bitmap-based graphics context.UIImage* UIGraphicsGetImageFromCurrentImageContext(void);
Return Value
An autoreleased image object containing the contents of the current bitmap graphics context.
위 두 함수의 설명만으로 resizing은 간단히 다음과 같이 이루어질 수 있다.
1. UIGraphicsBeginImageContext 를 이용해서 resizing할 rect 크기의 CG를 만든다.
2. Original Image (UIImage)를 UIImage::drawInRect:를 이용해서 축소된 CG에 그린다.
3. UIGraphicsGetImageFromCurrentImageContext를 이용해서 현재 CG의 UIImage를 가지고 온다.
그래서 origianl UIImage를 rect에 맞게 resizing 해주는 함수는 다음과 같이 만들어질 수 있다.
-(UIImage*)resizedImage1:(UIImage*)inImage inRect:(CGRect)thumbRect {
// Creates a bitmap-based graphics context and makes it the current context.
UIGraphicsBeginImageContext(thumbRect.size);
[inImage drawInRect:thumbRect];
return UIGraphicsGetImageFromCurrentImageContext();
}
# 2. Using CGContextDrawImage(), CGBitmapContextCreateImage()과 UIImage imageWithCGImage을 이용한 방법
이 방법도 첫 번째 방법과 비슷하나 다른 점은 resized Bitmap을 만들고 그 Bitmap에 image를 그리고, 그 Bitmap을 이용해서 UIImage를 만드는 것이다.
즉, 다음과 같은 절차를 가진다. 역시 bitmap이 들어가니 코드가 너저분해진다.
1. CGBitmapContextCreate()을 이용해서 resized된 bitmap을 만든다. 이때, rowbytes를 Original Image가 가로냐 세로냐에 따라 맞춰줘야 한다.
2. CGContextDrawImage()로 bitmap에 UIImge를 그린다.
3. CGBitmapContextCreateImage()으로 위 bitmap의 CGImageRef를 만든다.
4. 위 CGImageRef로 UIImage::imageWithCGImage로 UIImage를 만든다.
그래서 resizing 함수는 다음과 같다.
-(UIImage*)resizedImage2:(UIImage*)inImage inRect:(CGRect)thumbRect {
CGImageRef imageRef = [inImage CGImage];
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef);
// There's a wierdness with kCGImageAlphaNone and CGBitmapContextCreate
// see Supported Pixel Formats in the Quartz 2D Programming Guide
// Creating a Bitmap Graphics Context section
// only RGB 8 bit images with alpha of kCGImageAlphaNoneSkipFirst, kCGImageAlphaNoneSkipLast, kCGImageAlphaPremultipliedFirst,
// and kCGImageAlphaPremultipliedLast, with a few other oddball image kinds are supported
// The images on input here are likely to be png or jpeg files
if (alphaInfo == kCGImageAlphaNone)
alphaInfo = kCGImageAlphaNoneSkipLast;
// Build a bitmap context that's the size of the thumbRect
CGFloat bytesPerRow;
if( thumbRect.size.width > thumbRect.size.height ) {
bytesPerRow = 4 * thumbRect.size.width;
} else {
bytesPerRow = 4 * thumbRect.size.height;
}
CGContextRef bitmap = CGBitmapContextCreate(
NULL,
thumbRect.size.width, // width
thumbRect.size.height, // height
8, //CGImageGetBitsPerComponent(imageRef), // really needs to always be 8
bytesPerRow, //4 * thumbRect.size.width, // rowbytes
CGImageGetColorSpace(imageRef),
alphaInfo
);
// Draw into the context, this scales the image
CGContextDrawImage(bitmap, thumbRect, imageRef);
// Get an image from the context and a UIImage
CGImageRef ref = CGBitmapContextCreateImage(bitmap);
UIImage* result = [UIImage imageWithCGImage:ref];
CGContextRelease(bitmap); // ok if NULL
CGImageRelease(ref);
return result;
}
# 3. 가로/세로 이미지 고려하기
DIYPuzzle을 만들 때 삽질 좀 했었지만, 가로가 더 길거나 세로가 더 긴 이미지를 resizing 시에도 고려해주어야 한다. 가로가 길면 width로 resizing ratio를 세로가 길면 height로 resizing ratio를 만들어줘야할 것이다.
그래서 아래와 같이 이미지의 width/height를 체크 해서 thumbnail image의 rect를 만들어서 resizing 함수를 불러야 한다.
// Create a thumbnail image
// resizedImage1View의 크기에 맞추어서 ori image을 resize한다.
CGFloat ratio = 0;
if( oriImage.size.width > oriImage.size.height ) {
// 가로가 더 길면
// resizedImage1View.frame은 57 * 57 이다.
ratio = resizedImage1View.frame.size.width / oriImage.size.width;
} else {
// 세로가 더 길면
ratio = resizedImage1View.frame.size.width / oriImage.size.height;
}
// image의 가로 세로가 다르기 때문에 ori image에 ratio를 적용해서 rect만들기
CGRect rect = CGRectMake(0, 0, ratio*oriImage.size.width, ratio*oriImage.size.height);
Ref1. PhotoLocations 첫 번째 방법이 사용된 sample code이다.
Ref2. Resize Image High Quality alones로 위 두 함수를 댓글을 달기도 했다. bitmap을 이용한 방법은 PhoneyDev의 함수를 개선한 것이다.
