[iPhone][Tutorial #1] UIImage resize하기

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을 제공한다.

그림 3 by you.

#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의 함수를 개선한 것이다.

Donwload Sample Code

# Revision History
v1.0.0 2009.08.13 Initial version.

  • GNU

    uad81uae08ud574uc11c googleuc744 uba87uc2dcuac04uc5d0 ub4a4uc9c0ub294ub370 ub3c4uc800ud788 ubabbucc3euc544uc11c uc774ub807uac8c uc9c8ubb38ub4dcub824uc694…nud639uc2dc uc544uc2dcuba74 uaf2d ub2f5ubcc0 uc880 ubd80ud0c1ub4dcub9b4uaed8uc694niPhoneuc5d0uc11c uc0acuc9c4uc744 ucc0duc73cuba74 thumbnailub4e4uc774 uc0dduc131ub418uc796uc544uc694…nuc0dduc131ub41c thumbnailuc744 PCub85c uc62euae38 uc218ub294 uc5c6ub098uc694?nuc774uac8c Bitmapuac19uc740ub370 ub9deub098uc694?

  • GNU

    uad81uae08ud574uc11c googleuc744 uba87uc2dcuac04uc5d0 ub4a4uc9c0ub294ub370 ub3c4uc800ud788 ubabbucc3euc544uc11c uc774ub807uac8c uc9c8ubb38ub4dcub824uc694…nud639uc2dc uc544uc2dcuba74 uaf2d ub2f5ubcc0 uc880 ubd80ud0c1ub4dcub9b4uaed8uc694niPhoneuc5d0uc11c uc0acuc9c4uc744 ucc0duc73cuba74 thumbnailub4e4uc774 uc0dduc131ub418uc796uc544uc694…nuc0dduc131ub41c thumbnailuc744 PCub85c uc62euae38 uc218ub294 uc5c6ub098uc694?nuc774uac8c Bitmapuac19uc740ub370 ub9deub098uc694?

  • GNU

    uad81uae08ud574uc11c googleuc744 uba87uc2dcuac04uc5d0 ub4a4uc9c0ub294ub370 ub3c4uc800ud788 ubabbucc3euc544uc11c uc774ub807uac8c uc9c8ubb38ub4dcub824uc694…nud639uc2dc uc544uc2dcuba74 uaf2d ub2f5ubcc0 uc880 ubd80ud0c1ub4dcub9b4uaed8uc694niPhoneuc5d0uc11c uc0acuc9c4uc744 ucc0duc73cuba74 thumbnailub4e4uc774 uc0dduc131ub418uc796uc544uc694…nuc0dduc131ub41c thumbnailuc744 PCub85c uc62euae38 uc218ub294 uc5c6ub098uc694?nuc774uac8c Bitmapuac19uc740ub370 ub9deub098uc694?

  • GNU

    uad81uae08ud574uc11c googleuc744 uba87uc2dcuac04uc5d0 ub4a4uc9c0ub294ub370 ub3c4uc800ud788 ubabbucc3euc544uc11c uc774ub807uac8c uc9c8ubb38ub4dcub824uc694…nud639uc2dc uc544uc2dcuba74 uaf2d ub2f5ubcc0 uc880 ubd80ud0c1ub4dcub9b4uaed8uc694niPhoneuc5d0uc11c uc0acuc9c4uc744 ucc0duc73cuba74 thumbnailub4e4uc774 uc0dduc131ub418uc796uc544uc694…nuc0dduc131ub41c thumbnailuc744 PCub85c uc62euae38 uc218ub294 uc5c6ub098uc694?nuc774uac8c Bitmapuac19uc740ub370 ub9deub098uc694?

  • GNU

    uad81uae08ud574uc11c googleuc744 uba87uc2dcuac04uc5d0 ub4a4uc9c0ub294ub370 ub3c4uc800ud788 ubabbucc3euc544uc11c uc774ub807uac8c uc9c8ubb38ub4dcub824uc694…nud639uc2dc uc544uc2dcuba74 uaf2d ub2f5ubcc0 uc880 ubd80ud0c1ub4dcub9b4uaed8uc694niPhoneuc5d0uc11c uc0acuc9c4uc744 ucc0duc73cuba74 thumbnailub4e4uc774 uc0dduc131ub418uc796uc544uc694…nuc0dduc131ub41c thumbnailuc744 PCub85c uc62euae38 uc218ub294 uc5c6ub098uc694?nuc774uac8c Bitmapuac19uc740ub370 ub9deub098uc694?

  • GNU

    uad81uae08ud574uc11c googleuc744 uba87uc2dcuac04uc5d0 ub4a4uc9c0ub294ub370 ub3c4uc800ud788 ubabbucc3euc544uc11c uc774ub807uac8c uc9c8ubb38ub4dcub824uc694…nud639uc2dc uc544uc2dcuba74 uaf2d ub2f5ubcc0 uc880 ubd80ud0c1ub4dcub9b4uaed8uc694niPhoneuc5d0uc11c uc0acuc9c4uc744 ucc0duc73cuba74 thumbnailub4e4uc774 uc0dduc131ub418uc796uc544uc694…nuc0dduc131ub41c thumbnailuc744 PCub85c uc62euae38 uc218ub294 uc5c6ub098uc694?nuc774uac8c Bitmapuac19uc740ub370 ub9deub098uc694?

  • GNU

    uad81uae08ud574uc11c googleuc744 uba87uc2dcuac04uc5d0 ub4a4uc9c0ub294ub370 ub3c4uc800ud788 ubabbucc3euc544uc11c uc774ub807uac8c uc9c8ubb38ub4dcub824uc694…nud639uc2dc uc544uc2dcuba74 uaf2d ub2f5ubcc0 uc880 ubd80ud0c1ub4dcub9b4uaed8uc694niPhoneuc5d0uc11c uc0acuc9c4uc744 ucc0duc73cuba74 thumbnailub4e4uc774 uc0dduc131ub418uc796uc544uc694…nuc0dduc131ub41c thumbnailuc744 PCub85c uc62euae38 uc218ub294 uc5c6ub098uc694?nuc774uac8c Bitmapuac19uc740ub370 ub9deub098uc694?

  • GNU

    uad81uae08ud574uc11c googleuc744 uba87uc2dcuac04uc5d0 ub4a4uc9c0ub294ub370 ub3c4uc800ud788 ubabbucc3euc544uc11c uc774ub807uac8c uc9c8ubb38ub4dcub824uc694…nud639uc2dc uc544uc2dcuba74 uaf2d ub2f5ubcc0 uc880 ubd80ud0c1ub4dcub9b4uaed8uc694niPhoneuc5d0uc11c uc0acuc9c4uc744 ucc0duc73cuba74 thumbnailub4e4uc774 uc0dduc131ub418uc796uc544uc694…nuc0dduc131ub41c thumbnailuc744 PCub85c uc62euae38 uc218ub294 uc5c6ub098uc694?nuc774uac8c Bitmapuac19uc740ub370 ub9deub098uc694?

  • GNU

    궁금해서 google을 몇시간에 뒤지는데 도저히 못찾아서 이렇게 질문드려요…
    혹시 아시면 꼭 답변 좀 부탁드릴께요
    iPhone에서 사진을 찍으면 thumbnail들이 생성되잖아요…
    생성된 thumbnail을 PC로 옮길 수는 없나요?
    이게 Bitmap같은데 맞나요?

  • Hghggman

    안녕하세요.. 글 잘 읽었습니다. 한가지 궁금한 점이 있는데요.. 제가 1번 방법을 사용해서 UIImage의 사이즈를 변경하고 텍스쳐 맵핑을 했는데요.. 원본이랑 색이 다르게 나오네요.. 이거 왜그런지 알려주실수 있나요??

  • http://alones.kr Gidae Yeo

    안녕하세요~ 답변이 좀 늦었네요..
    음. 혹시 resized된 image를 처리하는 view의 크기가 resized size와 같은 가요?

  • http://twitter.com/y8k YoonBong Kim

    우히히 유용히 잘 사용했슴돠~

  • deVbug

    제가 제작 중인 오픈소스 프로그램에 넣으려고 합니다.
    #2 소스코드의 라이센스가 어떻게 되는지 궁금합니다.