Как улучшить резкость при изменении размера UIImage?

В моем приложении мне нужно загружать фотографии на сервер, поэтому перед этим я хочу изменить их размер и сжать до приемлемого размера. Я попытался изменить их размер двумя способами, и первый из них:

    // image is an instance of original UIImage that I want to resize
    let width : Int = 640
    let height : Int = 640
    let bitsPerComponent = CGImageGetBitsPerComponent(image.CGImage)
    let bytesPerRow = CGImageGetBytesPerRow(image.CGImage)
    let colorSpace = CGImageGetColorSpace(image.CGImage)
    let bitmapInfo = CGImageGetBitmapInfo(image.CGImage)

    let context = CGBitmapContextCreate(nil, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo)
    CGContextSetInterpolationQuality(context, kCGInterpolationHigh)
    CGContextDrawImage(context, CGRect(origin: CGPointZero, size: CGSize(width: CGFloat(width), height: CGFloat(height))), image.CGImage)

    image = UIImage(CGImage: CGBitmapContextCreateImage(context))

Другой способ:

image = RBResizeImage(image, targetSize: CGSizeMake(640, 640))

func RBResizeImage(image: UIImage?, targetSize: CGSize) -> UIImage? {
        if let image = image {
            let size = image.size

            let widthRatio  = targetSize.width  / image.size.width
            let heightRatio = targetSize.height / image.size.height

            // Figure out what our orientation is, and use that to form the rectangle
            var newSize: CGSize
            if(widthRatio > heightRatio) {
                newSize = CGSizeMake(size.width  heightRatio, size.height  heightRatio)
            } else {
                newSize = CGSizeMake(size.width  widthRatio,  size.height  widthRatio)
            }

            // This is the rect that we've calculated out and this is what is actually used below
            let rect = CGRectMake(0, 0, newSize.width, newSize.height)

            // Actually do the resizing to the rect using the ImageContext stuff
            UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
            image.drawInRect(rect)
            let newImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()

            return newImage
        } else {
            return nil
        }
    }

После этого я использую UIImageJPEGRepresentation сжать UIImage, но даже если compressionQuality 1, фотография по-прежнему размыта (это видно по краям объекта в основном, возможно, это не имеет большого значения, но фотография в три-пять раз больше той же фотографии из Instagram, например, но не имеет такой же резкости). Конечно, для 0.5 это еще хуже, а фотография все еще больше (в килобайтах), чем та же фотография из Instagram.

Фото из моего приложения. Качество сжатия - 1, края размыты, размер - 341 КБФото из моего приложения. Качество сжатия - 1, края размыты, размер - 341 КБ.

Фото из Instagram, края острые, а размер составляет 136 КБФото из Instagram, края острые, а размер составляет 136 КБ

РЕДАКТИРОВАТЬ:

Хорошо, но я немного запутался сейчас, я не уверен, что делать, чтобы сохранить соотношение сторон? Вот как я обрезаю изображение (scrollView имеет UIImageView, поэтому я могу перемещать и масштабировать изображение, и в конце я могу обрезать видимую часть scrollView, которая является sqare). Во всяком случае, изображение сверху изначально было 2048х2048, но оно все еще размытое.

 var scale  = 1/scrollView.zoomScale
 var visibleRect : CGRect = CGRect()

 visibleRect.origin.x = scrollView.contentOffset.x * scale
 visibleRect.origin.y = scrollView.contentOffset.y * scale
 visibleRect.size.width = scrollView.bounds.size.width * scale
 visibleRect.size.height = scrollView.bounds.size.height * scale
 image = crop(image!, rect: visibleRect)


func crop(srcImage : UIImage, rect : CGRect) -> UIImage? {
     var imageRef = CGImageCreateWithImageInRect(srcImage.CGImage, rect)
     var cropped = UIImage(CGImage: imageRef)

     return cropped
}

1 ответ

Данный код верен, но проблема в том, что вы не поддерживаете соотношение сторон изображения
как в вашем коде вы создаете новый прямоугольник как

let rect = CGRectMake(0, 0, newSize.width, newSize.height) 

если ваше заданное изображение имеет одинаковую высоту и ширину, оно даст плавное изменение размера изображения, но если высота и ширина отличаются, ваше изображение размыто. поэтому постарайтесь сохранить соотношение сторон
Ответить на редактирование вопроса:
сделать высоту или ширину кадрируемого изображения постоянной
Например, если вы сделаете ширину постоянной, используйте следующий код

 visibleRect.size.height = orignalImg.size.height *  visibleRect.size.width / orignalImg.size.width     

image = crop(image!, rect: visibleRect)
Другие вопросы по тегам