Как улучшить резкость при изменении размера 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 КБФотография из моего app, качество сжатия - 1, края размытые, размер - 341 КБ.

Фотография из Instagram, края резкие, размер 136 КБФотография из Instagram, края резкие, и размер 136 КБ

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

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

 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
}

person Marko    schedule 22.04.2015    source источник
comment
stackoverflow.com/questions/28809355/   -  person user4261201    schedule 22.04.2015
comment
Я тоже только что пробовал, но получаю тот же результат. Фотография сверху снова составляет 341 КБ, и каждый пиксель остается прежним.   -  person Marko    schedule 22.04.2015


Ответы (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)
person Rizwan Shaikh    schedule 22.04.2015
comment
На самом деле я так и делаю, просто не писал эту часть кода. Я всегда сначала обрезаю изображение до квадрата, поэтому, если у меня есть изображение 3264x2448, я обрезаю его до 2448x2448 перед изменением размера до 640x640. - person Marko; 22.04.2015
comment
существует та же проблема соотношения сторон, что и у вашего изображения размером 3264 * 2448 соотношение сторон 1,33, и когда вы кадрируете его до 2448 * 2448, его соотношение сторон становится 1 - person Rizwan Shaikh; 22.04.2015
comment
просто откройте эту ссылку и посмотрите фотографии, чтобы понять, чего не хватает en.wikipedia.org/ wiki / Cropping_ (изображение) - person Rizwan Shaikh; 22.04.2015
comment
Хорошо, спасибо, но теперь я не знаю, что делать, чтобы это исправить? Я отредактировал свой вопрос, чтобы вы могли видеть, что происходит, перед изменением размера. - person Marko; 22.04.2015