首页 文章

UIImage:调整大小,然后裁剪

提问于
浏览
186

我现在一直在抨击这一个人几天,即使我不断地感觉到我在启示的边缘,我根本无法实现我的目标 .

我认为,在我的设计的概念阶段提前,从iPhone的相机或库中获取图像,使用相当于UIImageView的 Aspect Fill 选项的功能将其缩小到指定高度将是一件小事 . (完全在代码中),然后 crop off 任何不适合传递的CGRect的东西 .

从相机或图书馆获取原始图像非常简单 . 我很震惊其他两个步骤的难度 .

附图显示了我想要实现的目标 . 有人请你好好握住我的手吗?到目前为止我发现的每个代码示例似乎都会破坏图像,颠倒过来,看起来像废话,画出界限,或者其他方法都不能正常工作 .

16 回答

  • 2

    Swift版本:

    static func imageWithImage(image:UIImage, newSize:CGSize) ->UIImage {
        UIGraphicsBeginImageContextWithOptions(newSize, true, UIScreen.mainScreen().scale);
        image.drawInRect(CGRectMake(0, 0, newSize.width, newSize.height))
    
        let newImage = UIGraphicsGetImageFromCurrentImageContext();
    
        UIGraphicsEndImageContext();
        return newImage
    }
    
  • 0

    这是Jane Sales在Swift中的回答版本 . 干杯!

    public func resizeImage(image: UIImage, size: CGSize) -> UIImage? {
        var returnImage: UIImage?
    
        var scaleFactor: CGFloat = 1.0
        var scaledWidth = size.width
        var scaledHeight = size.height
        var thumbnailPoint = CGPointMake(0, 0)
    
        if !CGSizeEqualToSize(image.size, size) {
            let widthFactor = size.width / image.size.width
            let heightFactor = size.height / image.size.height
    
            if widthFactor > heightFactor {
                scaleFactor = widthFactor
            } else {
                scaleFactor = heightFactor
            }
    
            scaledWidth = image.size.width * scaleFactor
            scaledHeight = image.size.height * scaleFactor
    
            if widthFactor > heightFactor {
                thumbnailPoint.y = (size.height - scaledHeight) * 0.5
            } else if widthFactor < heightFactor {
                thumbnailPoint.x = (size.width - scaledWidth) * 0.5
            }
        }
    
        UIGraphicsBeginImageContextWithOptions(size, true, 0)
    
        var thumbnailRect = CGRectZero
        thumbnailRect.origin = thumbnailPoint
        thumbnailRect.size.width = scaledWidth
        thumbnailRect.size.height = scaledHeight
    
        image.drawInRect(thumbnailRect)
        returnImage = UIGraphicsGetImageFromCurrentImageContext()
    
        UIGraphicsEndImageContext()
    
        return returnImage
    }
    
  • 1

    干得好 . 这个很完美;-)

    编辑:见下面的评论 - “不适用于某些图像,失败:CGContextSetInterpolationQuality:无效的上下文0x0错误”

    // Resizes the image according to the given content mode, taking into account the image's orientation
    - (UIImage *)resizedImageWithContentMode:(UIViewContentMode)contentMode imageToScale:(UIImage*)imageToScale bounds:(CGSize)bounds interpolationQuality:(CGInterpolationQuality)quality {
        //Get the size we want to scale it to
        CGFloat horizontalRatio = bounds.width / imageToScale.size.width;
        CGFloat verticalRatio = bounds.height / imageToScale.size.height;
        CGFloat ratio;
    
        switch (contentMode) {
            case UIViewContentModeScaleAspectFill:
                ratio = MAX(horizontalRatio, verticalRatio);
                break;
    
            case UIViewContentModeScaleAspectFit:
                ratio = MIN(horizontalRatio, verticalRatio);
                break;
    
            default:
                [NSException raise:NSInvalidArgumentException format:@"Unsupported content mode: %d", contentMode];
        }
    
        //...and here it is
        CGSize newSize = CGSizeMake(imageToScale.size.width * ratio, imageToScale.size.height * ratio);
    
    
        //start scaling it
        CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
        CGImageRef imageRef = imageToScale.CGImage;
        CGContextRef bitmap = CGBitmapContextCreate(NULL,
                                                    newRect.size.width,
                                                    newRect.size.height,
                                                    CGImageGetBitsPerComponent(imageRef),
                                                    0,
                                                    CGImageGetColorSpace(imageRef),
                                                    CGImageGetBitmapInfo(imageRef));
    
        CGContextSetInterpolationQuality(bitmap, quality);
    
        // Draw into the context; this scales the image
        CGContextDrawImage(bitmap, newRect, imageRef);
    
        // Get the resized image from the context and a UIImage
        CGImageRef newImageRef = CGBitmapContextCreateImage(bitmap);
        UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
    
        // Clean up
        CGContextRelease(bitmap);
        CGImageRelease(newImageRef);
    
        return newImage;
    }
    
  • 1
    - (UIImage*)imageScale:(CGFloat)scaleFactor cropForSize:(CGSize)targetSize
    {
        targetSize = !targetSize.width?self.size:targetSize;
        UIGraphicsBeginImageContext(targetSize); // this will crop
    
        CGRect thumbnailRect = CGRectZero;
    
        thumbnailRect.size.width  = targetSize.width*scaleFactor;
        thumbnailRect.size.height = targetSize.height*scaleFactor;
        CGFloat xOffset = (targetSize.width- thumbnailRect.size.width)/2;
        CGFloat yOffset = (targetSize.height- thumbnailRect.size.height)/2;
        thumbnailRect.origin = CGPointMake(xOffset,yOffset);
    
        [self drawInRect:thumbnailRect];
    
        UIImage *newImage  = UIGraphicsGetImageFromCurrentImageContext();
    
        if(newImage == nil)
        {
            NSLog(@"could not scale image");
        }
    
        UIGraphicsEndImageContext();
    
        return newImage;
    }
    

    下面的工作示例:左图像 - (原始图像);右图像,刻度为x2

    enter image description here

    如果要缩放图像但保留其帧(比例),请按以下方式调用方法:

    [yourImage imageScale:2.0f cropForSize:CGSizeZero];
    
  • 15

    我发现由Evgenii Kanvets发布的Swift 3并没有统一缩放图像 .

    这是我的Swift 4版本的功能,不会压缩图像:

    static func resizedCroppedImage(image: UIImage, newSize:CGSize) -> UIImage? {
    
        // This function returns a newImage, based on image
        // - image is scaled uniformaly to fit into a rect of size newSize
        // - if the newSize rect is of a different aspect ratio from the source image
        //     the new image is cropped to be in the center of the source image
        //     (the excess source image is removed)
    
        var ratio: CGFloat = 0
        var delta: CGFloat = 0
        var drawRect = CGRect()
    
        if newSize.width > newSize.height {
    
            ratio = newSize.width / image.size.width
            delta = (ratio * image.size.height) - newSize.height
            drawRect = CGRect(x: 0, y: -delta / 2, width: newSize.width, height: newSize.height + delta)
    
        } else {
    
            ratio = newSize.height / image.size.height
            delta = (ratio * image.size.width) - newSize.width
            drawRect = CGRect(x: -delta / 2, y: 0, width: newSize.width + delta, height: newSize.height)
    
        }
    
        UIGraphicsBeginImageContextWithOptions(newSize, true, 0.0)
        image.draw(in: drawRect)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
    
        return newImage
    }
    
  • 77

    我需要同样的东西 - 在我的情况下,选择适合缩放的尺寸,然后裁剪每一端以使其余部分适合宽度 . (我在横向工作,所以可能没有注意到肖像模式中的任何缺陷 . )这是我的代码 - 它是UIImage的一个类似的一部分 . 我的代码中的目标大小始终设置为设备的全屏大小 .

    @implementation UIImage (Extras)
    
    #pragma mark -
    #pragma mark Scale and crop image
    
    - (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize
    {
        UIImage *sourceImage = self;
        UIImage *newImage = nil;    
        CGSize imageSize = sourceImage.size;
        CGFloat width = imageSize.width;
        CGFloat height = imageSize.height;
        CGFloat targetWidth = targetSize.width;
        CGFloat targetHeight = targetSize.height;
        CGFloat scaleFactor = 0.0;
        CGFloat scaledWidth = targetWidth;
        CGFloat scaledHeight = targetHeight;
        CGPoint thumbnailPoint = CGPointMake(0.0,0.0);
    
        if (CGSizeEqualToSize(imageSize, targetSize) == NO) 
        {
            CGFloat widthFactor = targetWidth / width;
            CGFloat heightFactor = targetHeight / height;
    
            if (widthFactor > heightFactor) 
            {
                scaleFactor = widthFactor; // scale to fit height
            }
            else
            {
                scaleFactor = heightFactor; // scale to fit width
            }
    
            scaledWidth  = width * scaleFactor;
            scaledHeight = height * scaleFactor;
    
            // center the image
            if (widthFactor > heightFactor)
            {
                thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; 
            }
            else
            {
                if (widthFactor < heightFactor)
                {
                    thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
                }
            }
        }   
    
        UIGraphicsBeginImageContext(targetSize); // this will crop
    
        CGRect thumbnailRect = CGRectZero;
        thumbnailRect.origin = thumbnailPoint;
        thumbnailRect.size.width  = scaledWidth;
        thumbnailRect.size.height = scaledHeight;
    
        [sourceImage drawInRect:thumbnailRect];
    
        newImage = UIGraphicsGetImageFromCurrentImageContext();
    
        if(newImage == nil)
        {
            NSLog(@"could not scale image");
        }
    
        //pop the context to get back to the default
        UIGraphicsEndImageContext();
    
        return newImage;
    }
    
  • 2

    这个问题似乎已经得到了解决,但在我寻求一个我可以更容易理解的解决方案(并用Swift编写)中,我到达了这个(也发布到:How to crop the UIImage?


    我希望能够根据宽高比从区域进行裁剪,并根据外部边界范围缩放到大小 . 这是我的变化:

    import AVFoundation
    import ImageIO
    
    class Image {
    
        class func crop(image:UIImage, crop source:CGRect, aspect:CGSize, outputExtent:CGSize) -> UIImage {
    
            let sourceRect = AVMakeRectWithAspectRatioInsideRect(aspect, source)
            let targetRect = AVMakeRectWithAspectRatioInsideRect(aspect, CGRect(origin: CGPointZero, size: outputExtent))
    
            let opaque = true, deviceScale:CGFloat = 0.0 // use scale of device's main screen
            UIGraphicsBeginImageContextWithOptions(targetRect.size, opaque, deviceScale)
    
            let scale = max(
                targetRect.size.width / sourceRect.size.width,
                targetRect.size.height / sourceRect.size.height)
    
            let drawRect = CGRect(origin: -sourceRect.origin * scale, size: image.size * scale)
            image.drawInRect(drawRect)
    
            let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
    
            return scaledImage
        }
    }
    

    我发现有一些令人困惑的事情,即裁剪和调整大小的单独问题 . 使用传递给drawInRect的rect的原点处理裁剪,并且缩放由size部分处理 . 在我的情况下,我需要将源上裁剪矩形的大小与相同宽高比的输出矩相关联 . 然后输出/输入比例因子,这需要应用于drawRect(传递给drawInRect) .

    需要注意的是,这种方法有效地假设您绘制的图像大于图像上下文 . 我没有对此进行测试,但我认为您可以使用此代码来处理裁剪/缩放,但明确将scale参数定义为上述缩放参数 . 默认情况下,UIKit根据屏幕分辨率应用乘数 .

    最后,应该注意的是,这种UIKit方法比CoreGraphics / Quartz和Core Image方法更高级,并且似乎处理图像方向问题 . 值得一提的是,它非常快,仅次于ImageIO,根据这篇文章:http://nshipster.com/image-resizing/

  • 0
    scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0,0.0,ScreenWidth,ScreenHeigth)];
        [scrollView setBackgroundColor:[UIColor blackColor]];
        [scrollView setDelegate:self];
        [scrollView setShowsHorizontalScrollIndicator:NO];
        [scrollView setShowsVerticalScrollIndicator:NO];
        [scrollView setMaximumZoomScale:2.0];
        image=[image scaleToSize:CGSizeMake(ScreenWidth, ScreenHeigth)];
        imageView = [[UIImageView alloc] initWithImage:image];
        UIImageView* imageViewBk = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"background.png"]];
        [self.view addSubview:imageViewBk];
        CGRect rect;
        rect.origin.x=0;
        rect.origin.y=0;
        rect.size.width = image.size.width;
        rect.size.height = image.size.height;
    
        [imageView setFrame:rect];
    
        [scrollView setContentSize:[imageView frame].size];
        [scrollView setMinimumZoomScale:[scrollView frame].size.width / [imageView frame].size.width];
        [scrollView setZoomScale:[scrollView minimumZoomScale]];
        [scrollView addSubview:imageView];
    
        [[self view] addSubview:scrollView];
    

    然后你可以通过这个屏幕拍摄你的图像

    float zoomScale = 1.0 / [scrollView zoomScale];
    CGRect rect;
    rect.origin.x = [scrollView contentOffset].x * zoomScale;
    rect.origin.y = [scrollView contentOffset].y * zoomScale;
    rect.size.width = [scrollView bounds].size.width * zoomScale;
    rect.size.height = [scrollView bounds].size.height * zoomScale;
    
    CGImageRef cr = CGImageCreateWithImageInRect([[imageView image] CGImage], rect);
    
    UIImage *cropped = [UIImage imageWithCGImage:cr];
    
    CGImageRelease(cr);
    
  • 2

    有一些很好的代码与调整其他几个操作的图像大小有关 . 当我试图想象你如何调整图像大小时,我来到了这个... http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way/

  • 0

    我修改了Brad Larson的代码 . 它会在给定的rect中填充图像 .

    -(UIImage*) scaleAndCropToSize:(CGSize)newSize;
    {
        float ratio = self.size.width / self.size.height;
    
        UIGraphicsBeginImageContext(newSize);
    
        if (ratio > 1) {
            CGFloat newWidth = ratio * newSize.width;
            CGFloat newHeight = newSize.height;
            CGFloat leftMargin = (newWidth - newHeight) / 2;
            [self drawInRect:CGRectMake(-leftMargin, 0, newWidth, newHeight)];
        }
        else {
            CGFloat newWidth = newSize.width;
            CGFloat newHeight = newSize.height / ratio;
            CGFloat topMargin = (newHeight - newWidth) / 2;
            [self drawInRect:CGRectMake(0, -topMargin, newSize.width, newSize.height/ratio)];
        }
    
        UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        return newImage;
    }
    
  • 7

    我转换了Sam Wirch's guide to swift并且它对我很有用,尽管有解决方法 .

    func resizedCroppedImage(image: UIImage, newSize:CGSize) -> UIImage {
        var ratio: CGFloat = 0
        var delta: CGFloat = 0
        var offset = CGPointZero
        if image.size.width > image.size.height {
            ratio = newSize.width / image.size.width
            delta = (ratio * image.size.width) - (ratio * image.size.height)
            offset = CGPointMake(delta / 2, 0)
        } else {
            ratio = newSize.width / image.size.height
            delta = (ratio * image.size.height) - (ratio * image.size.width)
            offset = CGPointMake(0, delta / 2)
        }
        let clipRect = CGRectMake(-offset.x, -offset.y, (ratio * image.size.width) + delta, (ratio * image.size.height) + delta)
        UIGraphicsBeginImageContextWithOptions(newSize, true, 0.0)
        UIRectClip(clipRect)
        image.drawInRect(clipRect)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
    

    如果有人想要客观的c版本,那就在他的网站上 .

  • 6

    accepted answer on how to resize and then crop UIImage (Aspect Fill)的Xamarin.iOS版本如下

    public static UIImage ScaleAndCropImage(UIImage sourceImage, SizeF targetSize)
        {
            var imageSize = sourceImage.Size;
            UIImage newImage = null;
            var width = imageSize.Width;
            var height = imageSize.Height;
            var targetWidth = targetSize.Width;
            var targetHeight = targetSize.Height;
            var scaleFactor = 0.0f;
            var scaledWidth = targetWidth;
            var scaledHeight = targetHeight;
            var thumbnailPoint = PointF.Empty;
            if (imageSize != targetSize)
            {
                var widthFactor = targetWidth / width;
                var heightFactor = targetHeight / height;
                if (widthFactor > heightFactor)
                {
                    scaleFactor = widthFactor;// scale to fit height
                }
                else
                {
                    scaleFactor = heightFactor;// scale to fit width
                }
                scaledWidth = width * scaleFactor;
                scaledHeight = height * scaleFactor;
                // center the image
                if (widthFactor > heightFactor)
                {
                    thumbnailPoint.Y = (targetHeight - scaledHeight) * 0.5f;
                }
                else
                {
                    if (widthFactor < heightFactor)
                    {
                        thumbnailPoint.X = (targetWidth - scaledWidth) * 0.5f;
                    }
                }
            }
            UIGraphics.BeginImageContextWithOptions(targetSize, false, 0.0f);
            var thumbnailRect = new RectangleF(thumbnailPoint, new SizeF(scaledWidth, scaledHeight));
            sourceImage.Draw(thumbnailRect);
            newImage = UIGraphics.GetImageFromCurrentImageContext();
            if (newImage == null)
            {
                Console.WriteLine("could not scale image");
            }
            //pop the context to get back to the default
            UIGraphics.EndImageContext();
    
            return newImage;
        }
    
  • 0

    较旧的帖子包含调整UIImage大小的方法的代码 . 相关部分如下:

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

    就裁剪而言,我相信如果你改变方法使用不同的缩放大小而不是上下文,你的结果图像应该被剪裁到上下文的边界 .

  • 18
    + (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)targetSize {
        //If scaleFactor is not touched, no scaling will occur      
        CGFloat scaleFactor = 1.0;
    
        //Deciding which factor to use to scale the image (factor = targetSize / imageSize)
        if (image.size.width > targetSize.width || image.size.height > targetSize.height)
            if (!((scaleFactor = (targetSize.width / image.size.width)) > (targetSize.height / image.size.height))) //scale to fit width, or
                scaleFactor = targetSize.height / image.size.height; // scale to fit heigth.
    
        UIGraphicsBeginImageContext(targetSize); 
    
        //Creating the rect where the scaled image is drawn in
        CGRect rect = CGRectMake((targetSize.width - image.size.width * scaleFactor) / 2,
                                 (targetSize.height -  image.size.height * scaleFactor) / 2,
                                 image.size.width * scaleFactor, image.size.height * scaleFactor);
    
        //Draw the image into the rect
        [image drawInRect:rect];
    
        //Saving the image, ending image context
        UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        return scaledImage;
    }
    

    我提出这个 . 她不是美女吗? ;)

  • 245

    以下简单代码对我有用 .

    [imageView setContentMode:UIViewContentModeScaleAspectFill];
    [imageView setClipsToBounds:YES];
    
  • 1

    这是William T.发布的Sam Wirch's guide to swift的Swift 3版本

    extension UIImage {
    
        static func resizedCroppedImage(image: UIImage, newSize:CGSize) -> UIImage? {
            var ratio: CGFloat = 0
            var delta: CGFloat = 0
            var offset = CGPoint.zero
    
            if image.size.width > image.size.height {
                ratio = newSize.width / image.size.width
                delta = (ratio * image.size.width) - (ratio * image.size.height)
                offset = CGPoint(x: delta / 2, y: 0)
            } else {
                ratio = newSize.width / image.size.height
                delta = (ratio * image.size.height) - (ratio * image.size.width)
                offset = CGPoint(x: 0, y: delta / 2)
            }
    
            let clipRect = CGRect(x: -offset.x, y: -offset.y, width: (ratio * image.size.width) + delta, height: (ratio * image.size.height) + delta)
            UIGraphicsBeginImageContextWithOptions(newSize, true, 0.0)
            UIRectClip(clipRect)
            image.draw(in: clipRect)
            let newImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
    
            return newImage
        }
    
    }
    

相关问题