PoinではGPUImageというライブラリを使っていたのですが、Poin 1.5.0リリースのタイミングでライブラリのバージョンを0.1.2に上げたら、見事にバグりました。1.5.1で修正されます。
そんなわけで、トリムとリサイズをGPUImageなしで書き直したメモ。
イメージのリサイズ
リサイズのロジックは非常に単純で、UIGraphicsGetCurrentContextを作ってイメージを書くだけです。新しく作成されるイメージのorientationはUIImageOrientationUpになります。
下記はUIImageのカテゴリとして作成することを想定しています。
- (UIImage*) btk_ImageResized : (CGSize)size
{
if(CGSizeEqualToSize(self.size, size) && self.imageOrientation == UIImageOrientationUp){
// No need to resize nor convert orientation
return self;
}
UIGraphicsBeginImageContext(size);
@try {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
[self drawInRect:CGRectMake(0, 0, size.width, size.height)];
return UIGraphicsGetImageFromCurrentImageContext();
}
@finally {
UIGraphicsEndImageContext();
}
}
イメージのトリム
イメージトリムを行う場合は、CGImageCreateWithImageInRectを使うのが一番効率が良いと思います。ただ、この場合にはOrientationは元の画像と変わらないので、逆に切取り領域を変換する必要があります。
- (UIImage*) btk_ImageClipped : (CGRect)rect
{
// Convert rect to match orientation
rect = CGRectApplyAffineTransform(rect, self.btk_TransformForOrientation);
CGImageRef cgImage;
@try {
cgImage = CGImageCreateWithImageInRect(self.CGImage, rect);
return [UIImage imageWithCGImage:cgImage
scale:self.scale
orientation:self.imageOrientation];
}
@finally {
CGImageRelease(cgImage);
}
}
- (CGAffineTransform)btk_TransformForOrientation
{
CGAffineTransform t = CGAffineTransformIdentity;
CGSize visibleImageSize = self.size;
CGSize originalImageSize = self.size;
switch (self.imageOrientation) {
case UIImageOrientationLeft: // 90 deg CCW
case UIImageOrientationLeftMirrored:
case UIImageOrientationRight: // 90 deg CW
case UIImageOrientationRightMirrored:
originalImageSize = CGSizeMake(visibleImageSize.height, visibleImageSize.width);
break;
default:
originalImageSize = visibleImageSize;
}
t = CGAffineTransformTranslate(t, originalImageSize.width / 2, originalImageSize.height / 2);
switch (self.imageOrientation) {
case UIImageOrientationDownMirrored:
t = CGAffineTransformScale(t, -1, 1);
case UIImageOrientationDown: // 180 deg rotation
t = CGAffineTransformRotate(t, M_PI);
break;
case UIImageOrientationLeftMirrored:
t = CGAffineTransformScale(t, -1, 1);
case UIImageOrientationLeft: // 90 deg CCW
t = CGAffineTransformRotate(t, M_PI/2);
break;
case UIImageOrientationRightMirrored:
t = CGAffineTransformScale(t, -1, 1);
case UIImageOrientationRight: // 90 deg CW
t = CGAffineTransformRotate(t, -M_PI/2);
break;
case UIImageOrientationUpMirrored:
t = CGAffineTransformScale(t, -1, 1);
case UIImageOrientationUp:
default:
break;
}
t = CGAffineTransformTranslate(t, -visibleImageSize.width / 2, -visibleImageSize.height / 2);
return t;
}
非同期化
画像処理は重いのでバックグランドで行うことが望ましいです。
このような場合、メインのロジックは同期で書いておき、下記のように非同期化すると使い回しが楽になります。
- (void) btk_ImageResized : (CGSize)size
complete : (void (^)(UIImage *image))complete
{
if(!complete){
return;
}
if(![NSThread isMainThread]){
complete([self btk_ImageResized:size]);
return;
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImage *filteredImage = [self btk_ImageResized:size];
dispatch_async(dispatch_get_main_queue(), ^
{
complete(filteredImage);
});
});
}