iOSDev, UIImage, 이미지 자르기에서 고려할 점. (Crop images)


이 글을 쓰게 된 이유를 적어 본다.

경우는 2가지가 있는데…

100개의 이모티콘을 프로그램에 적용할 시

경우1)
100개의 png 파일을 만들 수 있다.

경우2)
또는 1개 큰 타일 png(10×10)를 만들 수 있다.
(경우2의 적용과 더블어 XML 파서를 없앤 것으로 2초 가까이 성능향상이 있었다.)

여기서 문제점만 얘기를 하면,

경우1) 100개의 png

100개의 이미지는 file open을 100번 해야 한다. 이모티콘이 많아지면 더 문제로 느끼게 될 것이다.

경우2) 1개의 png

1개의 압축된 png 파일에서 100개의 이미지를 조각조각을 가지고 와서 화면에 뿌려줘야 한다.
이때 내가 profiling 하면서 체험 한 것은 CPU도 최대로 먹고, 시간이 오래 걸린다.
이유는 명확하지 못하나
우선 inflate(반대는 deflate) 에서 많은 시간을 잡아먹으므로 압축과 관련 있어 보인다.
압축풀기 혹은 이미지 색 인덱스, 파레트(palette)에서 많은 시간을 잡아 먹는 듯 싶다.

예를들어 파레트를 추측해 보면,
1개의 이미지파일에서 다양한 색의 인덱스 부분을 메타정보에 가지고 있을 것 같다.
이것을 이용해서 조각난 부분의 색을 표현하고 하는데 시간이 오래걸리는 것이다.
증상은 이모티콘 입력창이 느리게 뜬다. 미리 이미지를 조각내서 메모리에 들고 있었어도
결국 화면에 보여지는 부분에서 내부적으로 많은 일을 하다가 이모티콘 창이 늦게 뜬다.

결론,

우선 해결 하고 이글을 쓰게 되었는데…
해결은 큰 이미지를 우선 inflate을 먼저 한다.
방법은 아래 링크에 설명이 되있다.

출처 : Does CGContextDrawImage decompress PNG on the fly?

CGImageRef Inflate(CGImageRef compressedImage)
{
size_t width = CGImageGetWidth(compressedImage);
size_t height = CGImageGetHeight(compressedImage);

CGContextRef context = CGBitmapContextCreate(
NULL,
width,
height,
CGImageGetBitsPerComponent(compressedImage),
CGImageGetBytesPerRow(compressedImage),
CGImageGetColorSpace(compressedImage),
CGImageGetBitmapInfo(compressedImage)
);

CGContextDrawImage(context, CGRectMake(0, 0, width, height), compressedImage);
CGImageRef result = CGBitmapContextCreateImage(context);
CFRelease(context);
return result;
}

1) 큰이미지 inflate 시간

큰 이미지를 inflate 하는 시간은 그리 오래 걸리지 않았다.

2) 100개의 UIImage 화면에 뿌리는 시간 (이모티콘 입력창 보이는 시간)

이후 이미지를 100개 쪼개서 UIImage 에 넣어 두고
나중에 이 UIImage를 화면에 뿌려보니 빠르게 뜨는것을 볼 수 있었다.


다음은 이미지 자르는 것 찾은 것에 대한 정리이다.

출처 : Problem in cropping the UIImage using CGContext?

[예제 1]

- (UIImage*)imageByCropping:(UIImage *)originalImage toRect:(CGRect)rect {
CGImageRef graphicOriginalImage = [originalImage.image CGImage];
UIGraphicsBeginImageContext(originalImage.image.size);

CGContextRef ctx = UIGraphicsGetCurrentContext();
CGBitmapContextCreateImage(graphicOriginalImage);

CGContextTranslateCTM(ctx, 0, image.size.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextDrawImage(ctx, rect, graphicOriginalImage);

croppedImage = UIGraphicsGetImageFromCurrentImageContext();

return croppedImage;
}

[예제 2]

- (UIImage *)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)rect
 {
CGImageRef imageRef = CGImageCreateWithImageInRect([imageToCrop CGImage], rect);

UIImage *cropped = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);


 return cropped;

}

출처: Code Sample: Crop an image using the iPhone SDK

[예제 3]

- (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)rect
{
//create a context to do our clipping in
UIGraphicsBeginImageContext(rect.size);
CGContextRef currentContext = UIGraphicsGetCurrentContext();

//create a rect with the size we want to crop the image to
//the X and Y here are zero so we start at the beginning of our
//newly created context
CGRect clippedRect = CGRectMake(0, 0, rect.size.width, rect.size.height);
CGContextClipToRect( currentContext, clippedRect);

//create a rect equivalent to the full size of the image
//offset the rect by the X and Y we want to start the crop
//from in order to cut off anything before them
CGRect drawRect = CGRectMake(rect.origin.x * -1,
rect.origin.y * -1,
imageToCrop.size.width,
imageToCrop.size.height);

//draw the image to our clipped context using our offset rect
CGContextDrawImage(currentContext, drawRect, imageToCrop.CGImage);

//pull the image from our cropped context
UIImage *cropped = UIGraphicsGetImageFromCurrentImageContext();

//pop the context to get back to the default
UIGraphicsEndImageContext();

//Note: this is autoreleased
return cropped;
}

Advertisements

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중