2012-06-27 8 views
8

私はinstagramのようにiPhone上でいくつかの画像フィルタ機能を試してみたいです。 私はimagePickerControllerを使用してカメラロールから写真を取得します。私はimagePickerControllerによる画像の戻りがメモリを節約するために削減されたことを理解しています。元画像をUIImageに読み込むのは賢明ではありません。しかし、どうやってイメージを処理して元のピクセルとして元に戻すことができますか? 開発用デバイスとしてiPhone 4Sを使用しています。カメラロールで写真をスクエアカットする方法は?

カメラロール内の元の写真は、3264 * 2448

UIImagePickerControllerOriginalImageによる画像リターン* 1440 1920

UIImagePickerControllerEditedImageによる画像リターンは640 * 640

imageViewOld(UIImagePickerControllerCropRectを[使用でありますUIImagePickerControllerOriginalImageでイメージの戻り値をトリミングする)は、1280 * 1224

imageViewNew(ダブルサイズのUIImagePickerControll erCropRect [80,216,2560,2560] UIImagePickerControllerOriginalImageによる画像リターンをトリミングするために)私は同じ写真がInstagramのによって進行チェック1840 * 1224

は、私の質問がある* 1280 1280

です:

  1. なぜUIImagePickerControllerOriginalImageが「オリジナル」の写真を返さないのですか?なぜそれを1920 * 1440に減らしましたか?
  2. なぜUIImagePickerControllerEditedImageは1280 * 1280でイメージを返しませんか?
    UIImagePickerControllerCropRectは、1280 * 1280の四角でカットされていることを示していますか?

  3. オリジナルの写真を2448 * 2448イメージにするにはどうすればよいですか?

ありがとうございます。以下 は私のコードです:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info 
    { 

    NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType]; 
    if ([mediaType isEqualToString:@"public.image"]) 
    { 

    UIImage *imageEdited = [info objectForKey:UIImagePickerControllerEditedImage]; 
    UIImage *imagePicked = [info objectForKey:UIImagePickerControllerOriginalImage]; 

    CGRect cropRect; 
    cropRect = [[info valueForKey:@"UIImagePickerControllerCropRect"] CGRectValue]; 

    NSLog(@"Original width = %f height= %f ",imagePicked.size.width, imagePicked.size.height); 
    //Original width = 1440.000000 height= 1920.000000 

    NSLog(@"imageEdited width = %f height = %f",imageEdited.size.width, imageEdited.size.height); 
    //imageEdited width = 640.000000 height = 640.000000 

    NSLog(@"corpRect %f %f %f %f", cropRect.origin.x, cropRect.origin.y , cropRect.size.width, cropRect.size.height); 
    //corpRect 80.000000 216.000000 1280.000000 1280.000000 

    CGRect rectNew = CGRectMake(cropRect.origin.x, cropRect.origin.y , cropRect.size.width*2, cropRect.size.height*2); 

    CGRect rectOld = CGRectMake(cropRect.origin.x, cropRect.origin.y , cropRect.size.width, cropRect.size.height); 

    CGImageRef imageRefNew = CGImageCreateWithImageInRect([imagePicked CGImage], rectNew); 
    CGImageRef imageRefOld = CGImageCreateWithImageInRect([imagePicked CGImage], rectOld); 

    UIImageView *imageViewNew = [[UIImageView alloc] initWithImage:[UIImage imageWithCGImage:imageRefNew]]; 
    CGImageRelease(imageRefNew); 

    UIImageView *imageViewOld = [[UIImageView alloc] initWithImage:[UIImage imageWithCGImage:imageRefOld]]; 
    CGImageRelease(imageRefOld); 


    NSLog(@"imageViewNew width = %f height = %f",imageViewNew.image.size.width, imageViewNew.image.size.height); 
    //imageViewNew width = 1840.000000 height = 1224.000000 

    NSLog(@"imageViewOld width = %f height = %f",imageViewOld.image.size.width, imageViewOld.image.size.height); 
    //imageViewOld width = 1280.000000 height = 1224.000000 

    UIImageWriteToSavedPhotosAlbum(imageEdited, nil, nil, NULL); 

    UIImageWriteToSavedPhotosAlbum([imageViewNew.image imageRotatedByDegrees:90.0], nil, nil, NULL); 
    UIImageWriteToSavedPhotosAlbum([imageViewOld.image imageRotatedByDegrees:90.0], nil, nil, NULL); 


    //assign the image to an UIImage Control 
    self.imageV.contentMode = UIViewContentModeScaleAspectFit; 
    self.imageV.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.width); 
    self.imageV.image = imageEdited; 


    } 

    [self dismissModalViewControllerAnimated:YES]; 

} 

答えて

12

あなたはUIImagePickerControllerが時々640x640時々320×320(デバイス依存)縮小編集した画像を返します観察してきたように。

ご質問:

私は2448 * 2448の画像であることを、元の写真に正方形のカットをどのように行うことができますか?あなたが最初の情報の辞書のUIImagePickerControllerOriginalImageキーを使用して得られた元の画像から新しい画像を作成するためにUIImagePickerControllerCropRectを使用する必要があります。これを行うために

。 Quartz CoreメソッドCGImageCreateWithImageInRectを使用すると、渡された矩形で囲まれたピクセルのみを含む新しいイメージを作成できます。この場合は切り抜き線になります。これが正しく機能するためには、オリエンテーションを考慮する必要があります。次に、画像を必要なサイズに調整するだけで済みます。クロップレットは、カメラまたはフォトライブラリから出てくるものではなく、元のイメージが正しく配置された後のものであることに注意することが重要です。このため、Quartzメソッドを使用して新しい画像などを作成するときに、トリミング矩形を向きに合わせて変換する必要があるのはこのためです

私は上記のコードを取り上げて、クロップ矩形に基づいて元の画像から1280x1280の画像を作成しました。依然としていくつかのエッジケースがあります。つまり、未加工の四角形が負の値を持つことがあります(コードは四角形の四角形を前提としています)。

  1. 入力画像とサイズの向きを考慮してクロップ矩形を最初に変換します。これはtransformCGRectForUIImageOrientation関数です。NiftyBean
  2. 変換されたクロップ矩形にクロップされたイメージを作成します。
  3. イメージを希望のサイズに拡大縮小(および回転)します。つまり1280x1280です。
  4. 正しい縮尺と向きでCGImageからUIImageを作成します。ここで

変更で、あなたのコードです:UPDATE新しいコードが欠落している場合の世話をする必要があり、この下に追加されました。

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { 
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType]; 
if ([mediaType isEqualToString:@"public.image"]) 
{ 

    UIImage *imageEdited = [info objectForKey:UIImagePickerControllerEditedImage]; 
    UIImage *imagePicked = [info objectForKey:UIImagePickerControllerOriginalImage]; 

    CGRect cropRect; 
    cropRect = [[info valueForKey:@"UIImagePickerControllerCropRect"] CGRectValue]; 

    NSLog(@"Original width = %f height= %f ",imagePicked.size.width, imagePicked.size.height); 
    //Original width = 1440.000000 height= 1920.000000 

    NSLog(@"imageEdited width = %f height = %f",imageEdited.size.width, imageEdited.size.height); 
    //imageEdited width = 640.000000 height = 640.000000 

    NSLog(@"corpRect %@", NSStringFromCGRect(cropRect)); 
    //corpRect 80.000000 216.000000 1280.000000 1280.000000 

    CGSize finalSize = CGSizeMake(1280,1280); 
    CGImageRef imagePickedRef = imagePicked.CGImage; 

    CGRect transformedRect = transformCGRectForUIImageOrientation(cropRect, imagePicked.imageOrientation, imagePicked.size); 
    CGImageRef cropRectImage = CGImageCreateWithImageInRect(imagePickedRef, transformedRect); 
    CGColorSpaceRef colorspace = CGImageGetColorSpace(imagePickedRef); 
    CGContextRef context = CGBitmapContextCreate(NULL, 
               finalSize.width, 
               finalSize.height, 
               CGImageGetBitsPerComponent(imagePickedRef), 
               CGImageGetBytesPerRow(imagePickedRef), 
               colorspace, 
               CGImageGetAlphaInfo(imagePickedRef)); 
    CGContextSetInterpolationQuality(context, kCGInterpolationHigh); //Give the context a hint that we want high quality during the scale 
    CGContextDrawImage(context, CGRectMake(0, 0, finalSize.width, finalSize.height), cropRectImage); 
    CGImageRelease(cropRectImage); 

    CGImageRef instaImage = CGBitmapContextCreateImage(context); 
    CGContextRelease(context); 

    //assign the image to an UIImage Control 
    UIImage *image = [UIImage imageWithCGImage:instaImage scale:imagePicked.scale orientation:imagePicked.imageOrientation]; 
    self.imageView.contentMode = UIViewContentModeScaleAspectFit; 
    self.imageView.image = image; 
    CGImageRelease(instaImage); 

    UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil); 
} 

[self dismissModalViewControllerAnimated:YES]; 

}

CGRect transformCGRectForUIImageOrientation(CGRect source, UIImageOrientation orientation, CGSize imageSize) { 
switch (orientation) { 
    case UIImageOrientationLeft: { // EXIF #8 
     CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(imageSize.height, 0.0); 
     CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI_2); 
     return CGRectApplyAffineTransform(source, txCompound); 
    } 
    case UIImageOrientationDown: { // EXIF #3 
     CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height); 
     CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI); 
     return CGRectApplyAffineTransform(source, txCompound); 
    } 
    case UIImageOrientationRight: { // EXIF #6 
     CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(0.0, imageSize.width); 
     CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI + M_PI_2); 
     return CGRectApplyAffineTransform(source, txCompound); 
    } 
    case UIImageOrientationUp: // EXIF #1 - do nothing 
    default: // EXIF 2,4,5,7 - ignore 
     return source; 
} 
} 

UPDATE私は例残りの世話をする方法をいくつか作ってきました。 手順は基本的に同じで、いくつかの変更が加えられています。

  1. まず変更が正しく、
  2. を変換し、着信画像の向きを処理するためのコンテキストを拡張することで、2番目はあなたが UIImagePickerControllerから得ることができる非正方形の作物をサポートすることです。これらの場合、正方形の画像はあなたの選択した色で塗りつぶされた です。

新しいコード

// CropRect is assumed to be in UIImageOrientationUp, as it is delivered this way from the UIImagePickerController when using AllowsImageEditing is on. 
// The sourceImage can be in any orientation, the crop will be transformed to match 
// The output image bounds define the final size of the image, the image will be scaled to fit,(AspectFit) the bounds, the fill color will be 
// used for areas that are not covered by the scaled image. 
-(UIImage *)cropImage:(UIImage *)sourceImage cropRect:(CGRect)cropRect aspectFitBounds:(CGSize)finalImageSize fillColor:(UIColor *)fillColor { 

CGImageRef sourceImageRef = sourceImage.CGImage; 

//Since the crop rect is in UIImageOrientationUp we need to transform it to match the source image. 
CGAffineTransform rectTransform = [self transformSize:sourceImage.size orientation:sourceImage.imageOrientation]; 
CGRect transformedRect = CGRectApplyAffineTransform(cropRect, rectTransform); 

//Now we get just the region of the source image that we are interested in. 
CGImageRef cropRectImage = CGImageCreateWithImageInRect(sourceImageRef, transformedRect); 

//Figure out which dimension fits within our final size and calculate the aspect correct rect that will fit in our new bounds 
CGFloat horizontalRatio = finalImageSize.width/CGImageGetWidth(cropRectImage); 
CGFloat verticalRatio = finalImageSize.height/CGImageGetHeight(cropRectImage); 
CGFloat ratio = MIN(horizontalRatio, verticalRatio); //Aspect Fit 
CGSize aspectFitSize = CGSizeMake(CGImageGetWidth(cropRectImage) * ratio, CGImageGetHeight(cropRectImage) * ratio); 


CGContextRef context = CGBitmapContextCreate(NULL, 
              finalImageSize.width, 
              finalImageSize.height, 
              CGImageGetBitsPerComponent(cropRectImage), 
              0, 
              CGImageGetColorSpace(cropRectImage), 
              CGImageGetBitmapInfo(cropRectImage)); 

if (context == NULL) { 
    NSLog(@"NULL CONTEXT!"); 
} 

//Fill with our background color 
CGContextSetFillColorWithColor(context, fillColor.CGColor); 
CGContextFillRect(context, CGRectMake(0, 0, finalImageSize.width, finalImageSize.height)); 

//We need to rotate and transform the context based on the orientation of the source image. 
CGAffineTransform contextTransform = [self transformSize:finalImageSize orientation:sourceImage.imageOrientation]; 
CGContextConcatCTM(context, contextTransform); 

//Give the context a hint that we want high quality during the scale 
CGContextSetInterpolationQuality(context, kCGInterpolationHigh); 

//Draw our image centered vertically and horizontally in our context. 
CGContextDrawImage(context, CGRectMake((finalImageSize.width-aspectFitSize.width)/2, (finalImageSize.height-aspectFitSize.height)/2, aspectFitSize.width, aspectFitSize.height), cropRectImage); 

//Start cleaning up.. 
CGImageRelease(cropRectImage); 

CGImageRef finalImageRef = CGBitmapContextCreateImage(context); 
UIImage *finalImage = [UIImage imageWithCGImage:finalImageRef]; 

CGContextRelease(context); 
CGImageRelease(finalImageRef); 
return finalImage; 
} 

//Creates a transform that will correctly rotate and translate for the passed orientation. 
//Based on code from niftyBean.com 
- (CGAffineTransform) transformSize:(CGSize)imageSize orientation:(UIImageOrientation)orientation { 

CGAffineTransform transform = CGAffineTransformIdentity; 
switch (orientation) { 
    case UIImageOrientationLeft: { // EXIF #8 
     CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(imageSize.height, 0.0); 
     CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI_2); 
     transform = txCompound; 
     break; 
    } 
    case UIImageOrientationDown: { // EXIF #3 
     CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height); 
     CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI); 
     transform = txCompound; 
     break; 
    } 
    case UIImageOrientationRight: { // EXIF #6 
     CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(0.0, imageSize.width); 
     CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,-M_PI_2); 
     transform = txCompound; 
     break; 
    } 
    case UIImageOrientationUp: // EXIF #1 - do nothing 
    default: // EXIF 2,4,5,7 - ignore 
     break; 
} 
return transform; 

} 
+0

うん!それは動作します! UIImagePickerControllerが私にカメラロールのオリジナルイメージを与えない理由を教えてください。 – user1486413

+0

私はそれが何の裏にあるのかは分かりません。私はあなたがカメラで写真を撮るときに完全に解像度のバージョンを取得することを確かめました。フル解像度版を入手する必要がある場合は、 'UIImagePickerControllerReferenceURL'を' ALAssetLibrary'クラスと組み合わせて使用​​して取得することができると思います。このフレームワークを使用すると、元の画像にジオタグが付いているため、その場所にアクセスする権限がユーザーに求められます。 –

+0

また、回転をより安全に処理するコードを更新し、トリミング矩形が四角形でない場合でも正方形の画像を取得するように処理します。それが役に立てば幸い。 –

関連する問題