UIImagePickerViewController图像中的方形缩略图



在我的应用程序中,用户使用UIImagePickerViewController选择图像或拍照。选择图像后,我想在方形UIImageView(90x90)上显示其缩略图。

我正在使用苹果的代码创建缩略图。问题是缩略图没有平方,在将kCGImageSourceThumbnailMaxPixelSize键设置为90后,该函数似乎只调整图像的高度,据我所知,kCGImageSource thumbnail MaxPixelsize键应该负责设置缩略图的高度和宽度。

以下是我的代码:

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

我的图像视图就是这样实例化的:

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

如果我不设置imageView.contentMode = UIViewContentModeScaleAspectFit;,缩略图将失真,因为它只是我的原始图像的一个版本,高度为90像素。

那么,为什么我的缩略图不方正呢?

最简单的方法是将imageView上的contentMode设置为UIViewContentModeScaleAspectFill。然而,这可能并不理想,因为它会将整个图像保存在内存中。

下面是我用来调整图像大小的一些代码。

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

如果大小与图像的纵横比不同,此版本将防止图像失真。

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

通常,您只需要图像的顶部正方形(而不是中心)。您希望最终图像具有一定的大小,例如128x128,如下面的示例所示。

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

这里有一个可以参考的链接:

1) UIImage+调整大小

2) UIImage+比例填充

在这里,您可以调整视图的大小,也可以添加比例填充,以便按比例调整纵横比和其他功能,如裁剪、缩放等。

您可以在上面的参考链接UIImage+Resize下使用-(UIImage*)resizedImageToSize:(CGSize*)size方法来重新设置图像。

希望这对你有帮助。

如果你需要更多帮助,请告诉我。

上面Clever Error答案的Swift版本:更新为swift 4.1

func resizeImageToCenter(image: UIImage) -> UIImage {
    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 = CGRect.init(x: x, y: y, width: width, height: height)
    // Generate thumbnail from image
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    image.draw(in: thumbnailRect)
    let thumbnail = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return thumbnail!
}

另一种方法-前几天遇到了一个问题,其他人在使用最适合大图像的苹果示例代码时可能也会遇到同样的问题。

正如公认的答案中所提到的,这存在将整个图像加载到内存中的问题,如果应用程序太大,iOS可能会杀死它。苹果示例代码中的CGImageSourceCreateThumbnailAtIndex效率更高,但该示例中存在一个错误。CFDictionaryCreate中的第三个参数是要复制的"numValues"。需要3而不是2。

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

最新更新