2013-07-26 73 views
14

Trong ứng dụng của tôi, người dùng chọn một hình ảnh hoặc chụp ảnh bằng UIImagePickerViewController. Khi hình ảnh đã được chọn, tôi muốn hiển thị hình thu nhỏ của nó trên một hình vuông UIImageView (90x90).Hình thu nhỏ hình vuông từ hình ảnh UIImagePickerViewController

Tôi đang sử dụng Apple's code để tạo hình thu nhỏ. Vấn đề là hình thu nhỏ không được bình phương, chức năng, sau khi đặt khóa kCGImageSourceThumbnailMaxPixelSize thành 90, dường như chỉ thay đổi kích thước chiều cao của hình ảnh và theo như tôi biết khóa kCGImageSourceThumbnailMaxPixelSize sẽ chịu trách nhiệm thiết lập chiều cao và chiều rộng của hình thu nhỏ.

Đây là một cái nhìn thoáng qua của mã của tôi:

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

    UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage]; 

    NSData *imageData = UIImageJPEGRepresentation (image, 0.5); 

    // My image view is 90x90 
    UIImage *thumbImage = MyCreateThumbnailImageFromData(imageData, 90); 

    [myImageView setImage:thumbImage]; 

    if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) { 

     UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil); 
    } 

    [picker dismissViewControllerAnimated:YES completion:nil]; 
} 

UIImage* MyCreateThumbnailImageFromData (NSData * data, int imageSize) { 

    CGImageRef  myThumbnailImage = NULL; 
    CGImageSourceRef myImageSource; 
    CFDictionaryRef myOptions = NULL; 
    CFStringRef  myKeys[3]; 
    CFTypeRef   myValues[3]; 
    CFNumberRef  thumbnailSize; 

    // Create an image source from NSData; no options. 
    myImageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, 
               NULL); 

    // Make sure the image source exists before continuing. 
    if (myImageSource == NULL){ 
     fprintf(stderr, "Image source is NULL."); 
     return NULL; 
    } 

    // Package the integer as a CFNumber object. Using CFTypes allows you 
    // to more easily create the options dictionary later. 
    thumbnailSize = CFNumberCreate(NULL, kCFNumberIntType, &imageSize); 

    // Set up the thumbnail options. 
    myKeys[0] = kCGImageSourceCreateThumbnailWithTransform; 
    myValues[0] = (CFTypeRef)kCFBooleanTrue; 
    myKeys[1] = kCGImageSourceCreateThumbnailFromImageIfAbsent; 
    myValues[1] = (CFTypeRef)kCFBooleanTrue; 
    myKeys[2] = kCGImageSourceThumbnailMaxPixelSize; 
    myValues[2] = thumbnailSize; 

    myOptions = CFDictionaryCreate(NULL, (const void **) myKeys, 
            (const void **) myValues, 2, 
            &kCFTypeDictionaryKeyCallBacks, 
            & kCFTypeDictionaryValueCallBacks); 

    // Create the thumbnail image using the specified options. 
    myThumbnailImage = CGImageSourceCreateThumbnailAtIndex(myImageSource, 
                  0, 
                  myOptions); 

    UIImage* scaled = [UIImage imageWithCGImage:myThumbnailImage]; 

    // Release the options dictionary and the image source 
    // when you no longer need them. 

    CFRelease(thumbnailSize); 
    CFRelease(myOptions); 
    CFRelease(myImageSource); 

    // Make sure the thumbnail image exists before continuing. 
    if (myThumbnailImage == NULL) { 
     fprintf(stderr, "Thumbnail image not created from image source."); 
     return NULL; 
    } 
    return scaled; 
} 

Và điều này như thế nào xem hình ảnh của tôi được khởi tạo:

myImageView = [[UIImageView alloc] init]; 
imageView.contentMode = UIViewContentModeScaleAspectFit; 

CGRect rect = imageView.frame; 
rect.size.height = 90; 
rect.size.width = 90; 

imageView.frame = rect; 
[imageView setUserInteractionEnabled:YES]; 

Nếu tôi không đặt imageView.contentMode = UIViewContentModeScaleAspectFit; hình thu nhỏ sẽ bị bóp méo, vì nó chỉ là một phiên bản hình ảnh gốc của tôi với chiều cao là 90 pixel.

Vì vậy, tại sao hình thu nhỏ của tôi không được bình phương?

+0

Note - một người sử dụng Meta không có kiến ​​thức của iOS sửa đi một số mã siêu tiện dụng từ câu trả lời của Clever dưới đây. nếu bạn thực sự lập trình và thực sự muốn có câu trả lời hữu ích và thực sự muốn sử dụng ý tưởng của Clever, bạn chỉ cần nhấp vào nút "đã chỉnh sửa" bên dưới, bạn sẽ thấy lịch sử và có thể cắt, dán và gửi tới cửa hàng ứng dụng:) – Fattie

+0

@JoeBlow Tôi không thấy bất kỳ mã bị xóa nào trong [edit history] (http://stackoverflow.com/posts/17884863/revisions) của câu trả lời của Clever Error. – cpburnz

+0

http://stackoverflow.com/posts/17884863/revisions rev "5" – Fattie

Trả lời

52

Điều dễ nhất cần làm là đặt contentMode trên hình ảnh của bạnView thành UIViewContentModeScaleAspectFill thay thế. Tuy nhiên, điều này có thể không lý tưởng vì nó sẽ giữ toàn bộ hình ảnh trong bộ nhớ.

Dưới đây là một số mã mà tôi sử dụng để thay đổi kích thước hình ảnh.

+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)size 
{ 
    UIGraphicsBeginImageContextWithOptions(size, NO, 0); 
    [image drawInRect:CGRectMake(0, 0, size.width, size.height)]; 
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();  
    UIGraphicsEndImageContext(); 
    return newImage; 
} 

Phiên bản này sẽ giữ cho hình ảnh bị méo nếu kích thước không giống với tỷ lệ khung hình như hình ảnh.

+ (UIImage *)imageWithImage:(UIImage *)image scaledToFillSize:(CGSize)size 
{ 
    CGFloat scale = MAX(size.width/image.size.width, size.height/image.size.height); 
    CGFloat width = image.size.width * scale; 
    CGFloat height = image.size.height * scale; 
    CGRect imageRect = CGRectMake((size.width - width)/2.0f, 
            (size.height - height)/2.0f, 
            width, 
            height); 

    UIGraphicsBeginImageContextWithOptions(size, NO, 0); 
    [image drawInRect:imageRect]; 
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();  
    UIGraphicsEndImageContext(); 
    return newImage; 
} 

Thông thường bạn muốn chỉ là đầu vuông của một hình ảnh (chứ không phải là trung tâm). Và bạn muốn hình ảnh cuối cùng có kích thước nhất định, hãy nói 128x128, như trong ví dụ bên dưới.

- (UIImage *)squareAndSmall // as a category (so, 'self' is the input image) 
{ 
    // fromCleverError's original 
    // http://stackoverflow.com/questions/17884555 
    CGSize finalsize = CGSizeMake(128,128); 

    CGFloat scale = MAX(
     finalsize.width/self.size.width, 
     finalsize.height/self.size.height); 
    CGFloat width = self.size.width * scale; 
    CGFloat height = self.size.height * scale; 

    CGRect rr = CGRectMake(0, 0, width, height); 

    UIGraphicsBeginImageContextWithOptions(finalsize, NO, 0); 
    [self drawInRect:rr]; 
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();  
    UIGraphicsEndImageContext(); 
    return newImage; 
} 
+0

Cách tiếp cận này bóp méo hình ảnh, tôi đã thử một cái gì đó như thế này. – douglasd3

+2

Tôi đã thêm một phiên bản không được làm méo hình ảnh. –

+0

Bây giờ nó không bị bóp méo, nhưng hình ảnh thu nhỏ không được bình phương, ý tôi là, nó là 90x90 nhưng hình ảnh không được thu nhỏ để lấp đầy hình vuông. – douglasd3

6

Đây là một liên kết mà bạn có thể tham khảo:

1) UIImage+Resize

2) UIImage+ProportionalFill

đây bạn có thể thay đổi kích thước xem và cũng thêm điền tỉ lệ sao cho tương ứng tỉ lệ và khác các chức năng như cắt, chia tỷ lệ, v.v.

Bạn có thể sử dụng phương thức -(UIImage*)resizedImageToSize:(CGSize*)size trong liên kết tham chiếu UIImage + Đổi kích thước ở trên để chỉnh sửa lại hình ảnh.

Hy vọng điều này sẽ giúp bạn.

Hãy cho tôi biết nếu bạn muốn được trợ giúp thêm.

+0

Liên kết thứ hai thực sự hữu ích! Tôi vẫn không biết vấn đề là gì, nhưng bây giờ đang làm việc, và nó sẽ giúp tôi tiết kiệm rất nhiều thời gian. Cảm ơn! – douglasd3

+1

@ douglasd3: Liên kết thứ hai thực sự hữu ích cho nhiều tính năng như cắt xén và Chia tỷ lệ. –

0

Một cách khác để làm điều này - chạy vào một vấn đề ngày khác và những người khác có thể có cùng một vấn đề khi sử dụng apple sample code đó là tốt nhất cho hình ảnh lớn.

Như đã đề cập trong câu trả lời được chấp nhận, điều này có vấn đề tải toàn bộ hình ảnh vào bộ nhớ và iOS có thể giết ứng dụng của bạn nếu nó quá lớn.CGImageSourceCreateThumbnailAtIndex trong mã ví dụ của Apple là hiệu quả hơn, tuy nhiên có một lỗi trong ví dụ. Tham số thứ 3 trong CFDictionaryCreate là "numValues" để sao chép. Cần phải được không 2.

myOptions = CFDictionaryCreate(NULL, (const void **) myKeys, 
           (const void **) myValues, 
           3, //Changed to 3 
           &kCFTypeDictionaryKeyCallBacks, 
           & kCFTypeDictionaryValueCallBacks); 
+1

ok, nhưng tôi đã thử phương pháp này so với câu trả lời chấp nhận bằng Quartz và câu trả lời được chấp nhận nhanh hơn 15 lần, đặc biệt nếu bạn đã có 'UIImage', vì bạn phải chuyển nó thành' CFData' để bạn có thể sử dụng 'CGImageSourceCreateThumbnailAtIndex' . Toàn bộ quá trình này chậm hơn 15 lần. – SpaceDog

3

Swift phiên bản 2.x của câu trả lời Clever Lỗi của trên:

// Define thumbnail size 
    let size = CGSize(width: 100, height: 100) 

    // Define rect for thumbnail 
    let scale = max(size.width/image.size.width, size.height/image.size.height) 
    let width = image.size.width * scale 
    let height = image.size.height * scale 
    let x = (size.width - width)/CGFloat(2) 
    let y = (size.height - height)/CGFloat(2) 
    let thumbnailRect = CGRectMake(x, y, width, height) 

    // Generate thumbnail from image 
    UIGraphicsBeginImageContextWithOptions(size, false, 0) 
    image.drawInRect(thumbnailRect) 
    let thumbnail = UIGraphicsGetImageFromCurrentImageContext() 
    UIGraphicsEndImageContext() 
+1

Đối với Swift 3, thay đổi việc gán thumbnailRect cho CGRect (x: x, y: y, width: width, height: height) –

Các vấn đề liên quan