2012-06-27 10 views
8

Tôi muốn thử một số tính năng lọc hình ảnh trên iPhone như instagram. Tôi sử dụng imagePickerController để lấy ảnh từ thư viện ảnh. Tôi hiểu rằng hình ảnh trở lại bởi imagePickerController đã được giảm xuống để tiết kiệm bộ nhớ. Và không nên tải hình ảnh gốc vào UIImage. Nhưng làm thế nào tôi có thể processe hình ảnh sau đó lưu nó trở lại như các điểm ảnh ban đầu? Tôi sử dụng iPhone 4S làm thiết bị phát triển của mình.Làm thế nào để thực hiện cắt vuông cho các bức ảnh trong cuộn camera?

Bức ảnh ban đầu trong thư viện ảnh là 3264 * 2448.

Sự trở lại hình ảnh bằng cách UIImagePickerControllerOriginalImage là 1920 * 1440

Sự trở lại hình ảnh bằng cách UIImagePickerControllerEditedImage là 640 * 640

imageViewOld (sử dụng UIImagePickerControllerCropRect [ 80,216,1280,1280] để cắt ảnh trở lại bằng UIImagePickerControllerOriginalImage) là 1280 * 1224

imageXemNew (sử dụng đôi kích thước UIImagePickerControll erCropRect [80,216,2560,2560] để cắt sự trở lại hình ảnh bằng cách UIImagePickerControllerOriginalImage) là 1840 * 1224.

tôi kiểm tra các bức ảnh cùng tiến hành bằng instagram là 1280 * 1280

Câu hỏi của tôi là:

  1. Tại sao UIImagePickerControllerOriginalImage không trả lại ảnh "Gốc"? Tại sao giảm nó xuống 1920 * 1440?
  2. Tại sao UIImagePickerControllerEditedImage không trả về hình ảnh 1280 * 1280? Khi
    UIImagePickerControllerCropRect cho thấy nó bị cắt bởi 1280 * 1280 hình vuông?

  3. Tôi làm cách nào để cắt hình vuông thành ảnh gốc thành hình ảnh 2448 * 2448?

Xin cảm ơn trước. Dưới đây là mã của tôi:

- (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]; 

} 

Trả lời

12

Như các bạn đã quan sát UIImagePickerController sẽ trả về một thu nhỏ lại hình ảnh đã chỉnh sửa đôi khi 640x640 đôi khi 320x320 (thiết bị phụ thuộc).

Câu hỏi của bạn:

Làm thế nào tôi có thể làm một cắt vuông tới ảnh gốc là một hình ảnh 2448 * 2448?

Để thực hiện việc này, trước tiên bạn cần sử dụng UIImagePickerControllerCropRect để tạo hình ảnh mới từ hình ảnh gốc thu được bằng cách sử dụng khóa UIImagePickerControllerOriginalImage của từ điển thông tin. Sử dụng phương pháp Quartz Core, CGImageCreateWithImageInRect bạn có thể tạo một hình ảnh mới chỉ chứa các điểm ảnh bị giới hạn bởi đường cong đã truyền; trong trường hợp này là cây trồng rect. Bạn sẽ cần phải đưa vào định hướng tài khoản để điều này hoạt động đúng. Sau đó, bạn chỉ cần quy mô hình ảnh theo kích thước mong muốn của bạn. Điều quan trọng cần lưu ý là crop rect có liên quan đến hình ảnh gốc khi nó được định hướng đúng, không phải khi nó xuất hiện từ thư viện ảnh hoặc thư viện ảnh. Đây là lý do tại sao chúng ta cần phải chuyển đổi crop rect để phù hợp với định hướng khi chúng ta bắt đầu sử dụng các phương thức Quartz để tạo ra các hình ảnh mới, v.v.

Tôi lấy mã của bạn ở trên và thiết lập mã để tạo hình ảnh 1280x1280 từ hình ảnh gốc dựa trên cây trồng trực tràng. Vẫn còn một số trường hợp cạnh ở đây, tức là có tính đến vụ cắt đôi có thể có giá trị âm, (mã giả định hình vuông cắt vuông góc) chưa được giải quyết.

  1. Đầu tiên chuyển đổi cắt trực tiếp để tính đến hướng của hình ảnh và kích thước đến. Chức năng này transformCGRectForUIImageOrientation là từ NiftyBean
  2. Tạo một hình ảnh được cắt thành trực tiếp cắt xén.
  3. Quy mô (và xoay) hình ảnh theo kích thước mong muốn. tức là 1280x1280.
  4. Tạo UIImage từ CGImage với quy mô và hướng chính xác.

Đây là mã của bạn với các thay đổi: CẬP NHẬT Mã mới đã được thêm vào bên dưới để đảm bảo các trường hợp bị thiếu.

- (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; 
} 
} 

CẬP NHẬT Tôi đã thực hiện một vài phương pháp mà sẽ chăm sóc phần còn lại của các trường hợp. Các bước cơ bản giống nhau, với một vài sửa đổi.

  1. sửa đổi đầu tiên là để chuyển đổi một cách chính xác và mở rộng bối cảnh để xử lý các định hướng của hình ảnh đến,
  2. và thứ hai là để hỗ trợ các loại cây trồng không vuông bạn có thể nhận được từ các UIImagePickerController. Trong những trường hợp này, hình vuông là được tô màu theo lựa chọn của bạn.

Mã New

// 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

Yeah! Nó hoạt động! Bạn có thể cho tôi biết tại sao UIImagePickerController không cho tôi hình ảnh gốc trong cuộn camera? – user1486413

+0

Tôi không chắc chắn lý do đằng sau nó là gì. Tôi đã quan sát thấy rằng bạn chắc chắn có được một phiên bản độ phân giải đầy đủ khi chụp ảnh bằng máy ảnh. Nếu bạn cần có phiên bản độ phân giải đầy đủ, tôi nghĩ bạn có thể sử dụng 'UIImagePickerControllerReferenceURL' kết hợp với các lớp' ALAssetLibrary' để lấy nó. Sử dụng khung này sẽ yêu cầu người dùng của bạn cho phép truy cập vị trí của họ, vì hình ảnh gốc sẽ được gắn thẻ địa lý. –

+0

Ngoài ra .. cập nhật mã để xử lý vòng quay an toàn hơn, và cũng xử lý việc nhận được một hình ảnh vuông ngay cả khi cây trồng rect không vuông. Hy vọng nó giúp. –