Изменение размера изображения до определенного размера при сохранении пропорций, обрезайте изображение, если необходимо (iOS)

Я использую UIImagePickerController для выбора изображения из своего рулона камеры и изменения его размера перед загрузкой в ​​Parse.

Я хочу изменить размер изображения до определенного размера (допустим, 750x1000), сохраняя соотношение сторон исходного изображения. Если необходимо, я хочу обрезать изображение. Я также хочу, чтобы было легко иметь разные версии изображения (полный размер, размер эскиза). Сейчас я изменяю только высоту изображения. Как я могу достичь того, что я ищу?

Спасибо.

NewProductViewController.h

@interface NewProductViewController : UIViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate, UITextFieldDelegate>

@property (nonatomic, strong) UIImage *image;
@property (nonatomic, strong) UIImagePickerController *imagePicker;
@property (nonatomic, weak) IBOutlet UIImageView *imageView;

- (UIImage *)imageWithImage:(UIImage *)sourceImage scaledToHeight:(float) i_height;

@end

NewProductViewController.m

- (IBAction)addImage:(id)sender {
    self.imagePicker = [[UIImagePickerController alloc] init];
    self.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    self.imagePicker.delegate = self;
    self.imagePicker.allowsEditing = NO;

    [self presentViewController:self.imagePicker animated:NO completion:nil];
}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];

    if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
        // A photo was selected
        self.image = [info objectForKey:UIImagePickerControllerOriginalImage];
        if (self.imagePicker.sourceType == UIImagePickerControllerSourceTypeCamera) {
            // Save the image!
            UIImageWriteToSavedPhotosAlbum(self.image, nil, nil, nil);
        }
    }

    [self.imageView setImage:self.image];

    [self dismissViewControllerAnimated:YES completion:nil];
}
- (UIImage *)imageWithImage:(UIImage *)sourceImage scaledToHeight:(float) i_height {
    float oldHeight = sourceImage.size.height;
    float scaleFactor = i_height / oldHeight;

    float newWidth = sourceImage.size.width* scaleFactor;
    float newHeight = oldHeight * scaleFactor;

    UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
    [sourceImage drawInRect:CGRectMake(0, 0, newWidth, newHeight)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

- (IBAction)createProduct:(id)sender {
    PFObject *newProduct = [PFObject objectWithClassName:@"Product"];

    UIImage *newImage = [self imageWithImage:self.image scaledToHeight:1000.f];
    UIImage *thumbnailImage = [self imageWithImage:self.image scaledToHeight:410.f];

    NSData *imageData = UIImageJPEGRepresentation(newImage, 0.8f);
    NSData *thumbnailData = UIImageJPEGRepresentation(thumbnailImage, 0.8f);

    PFFile *imageFile = [PFFile fileWithName:@"image.jpg" data:imageData];
    PFFile *thumbnailFile = [PFFile fileWithName:@"thumbnail.jpg" data:thumbnailData];

    newProduct[@"imageFile"] = imageFile;
    newProduct[@"thumbnailFile"] = thumbnailFile;

    [newProduct setObject:[PFUser currentUser] forKey:@"user"];
}

Ответ 1

Попробуйте это, он пропорционально распределяет исходное изображение, а затем масштабирует его до необходимого размера:

- (UIImage *)imageWithImage:(UIImage *)sourceImage size:(CGSize)size {
    CGSize newSize = CGSizeZero;
    if ((sourceImage.size.width / size.width) < (sourceImage.size.height / size.height)) {
        newSize = CGSizeMake(sourceImage.size.width, size.height * (sourceImage.size.width / size.width));
    } else {
        newSize = CGSizeMake(size.width * (sourceImage.size.height / size.height), sourceImage.size.height);
    }

    CGRect cropRect = CGRectZero;
    cropRect.origin.x = (sourceImage.size.width - newSize.width) / 2.0f;
    cropRect.origin.y = (sourceImage.size.height - newSize.height) / 2.0f;
    cropRect.size = newSize;

    CGImageRef croppedImageRef = CGImageCreateWithImageInRect([sourceImage CGImage], cropRect);
    UIImage *croppedImage = [UIImage imageWithCGImage:croppedImageRef];
    CGImageRelease(croppedImageRef);

    UIGraphicsBeginImageContextWithOptions(CGSizeMake(size.width, size.height), NO, 0.0);
    [croppedImage drawInRect:CGRectMake(0.0f, 0.0f, size.width, size.height)];
    UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return scaledImage;
}

Ответ 2

Этот код может помочь вам:

UIImage *originalImage = [UIImage imageNamed:@"minions.png"];
CGSize destination = CGSizeMake(750, 1000);
UIGraphicsBeginImageContext(destination);
[originalImage drawInRect:CGRectMake(0,0,destination.width,destination.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView *new = [[UIImageView alloc] initWithFrame:CGRectMake(40, 40, 750, 1000)];
new.image = newImage;
[self.view addSubview:New];

Сообщите мне, если это сработает для вас:)

Ответ 3

При масштабировании до точной ширины или высоты вы можете потерять разрешение изображения. Поэтому мое решение заключается в обрезке в пропорции:

Swift 3

func cropImage(image: UIImage, to aspectRatio: CGFloat) -> UIImage {

    let imageAspectRatio = image.size.height/image.size.width

    var newSize = image.size

    if imageAspectRatio > aspectRatio {
        newSize.height = image.size.width * aspectRatio
    } else if imageAspectRatio < aspectRatio {
        newSize.width = image.size.height / aspectRatio
    } else {
        return image
    }

    let center = CGPoint(x: image.size.width/2, y: image.size.height/2)
    let origin = CGPoint(x: center.x - newSize.width/2, y: center.y - newSize.height/2)

    let cgCroppedImage = image.cgImage!.cropping(to: CGRect(origin: origin, size: CGSize(width: newSize.width, height: newSize.height)))!
    let croppedImage = UIImage(cgImage: cgCroppedImage, scale: image.scale, orientation: image.imageOrientation)

    return croppedImage
}

Ответ 4

Это простой метод, который я создал

    -(UIImage *)getRescaledImage:(UIImage *)image{
    int height = image.size.height;
    int width = image.size.width;
    int max = MOImageMaxHeightWidth;
    float divideFactor = 0;

    if(!(height > max) || !(width > max)){
        return image;
    }

    if(height > width){
        divideFactor = height/max;
    }else{
        divideFactor = width/max;
    }

    height = height/divideFactor;
    width = width/divideFactor;

    return [self imageWithImage:image scaledToSize:CGSizeMake(width, height)];
}


+ (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize {
    UIGraphicsBeginImageContext( newSize );
    [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

MOImageMaxHeightWidth - это постоянное значение float, которое вы можете указать для определения максимальной ширины/высоты. Соотношение сторон изображения будет сохранено. Переменная divideFactor позаботится об этом и сама объяснит.

Ответ 5

Я использовал ниже категории UIImage. Надеюсь, это тоже сработает для вас.

https://github.com/mbcharbonneau/UIImage-Categories

CGFloat scale = .5f;

CGFloat maxSize = 1632 * 1224;
CGFloat currentSize = croppedImage.size.width * croppedImage.size.height;

if ((currentSize / 2) > maxSize) {
    scale = maxSize / currentSize;
}

CGSize size = CGSizeMake(croppedImage.size.width * scale, croppedImage.size.height * scale);
__block UIImage *imageToSave = [croppedImage resizedImageWithContentMode:UIViewContentModeScaleAspectFill bounds:size interpolationQuality:kCGInterpolationLow];