2015-04-19 14 views
43

Stavo cercando di caricare un file immagine su Parse dopo aver scattato una foto direttamente sul telefono. Ma viene generata un'eccezione:Come comprimere di ridurre la dimensione di un'immagine prima di caricarla in Parse come PFFile? (Swift)

terminazione app a causa di eccezione non identificata 'NSInvalidArgumentException', la ragione: 'PFFile non può essere maggiore di 10485760 byte'

Ecco il mio codice:

In primo vista del regolatore:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 
    if (segue.identifier == "getImage") 
    { 
     var svc = segue.destinationViewController as! ClothesDetail 
     svc.imagePassed = imageView.image 
    } 
} 

In controller della vista che carica immagine:

let imageData = UIImagePNGRepresentation(imagePassed) 
let imageFile = PFFile(name: "\(picName).png", data: imageData) 

var userpic = PFObject(className:"UserPic") 
userpic["picImage"] = imageFile` 

Ma devo ancora caricare quella foto su Parse. C'è un modo per ridurre le dimensioni o la risoluzione dell'immagine?

+0

ho provato l'ultima proposta di GBK e la fonte alla fine che se chiamo lasciare newData = UIImageJPEGRepresentation (UIImage (dati: i dati), 1) non è newData.count uguale a data.count ed è molto più grande con un factore di più di 2. Quale è per me davvero sorprendente! Comunque, grazie per il codice! – NicoD

risposta

116

Sì, è possibile utilizzare UIImageJPEGRepresentation anziché UIImagePNGRepresentation per ridurre le dimensioni del file di immagine. È sufficiente creare un'estensione UIImmagine come segue:

Xcode 8.2 • Swift 3.0.2

extension UIImage { 
    enum JPEGQuality: CGFloat { 
     case lowest = 0 
     case low  = 0.25 
     case medium = 0.5 
     case high = 0.75 
     case highest = 1 
    } 

    /// Returns the data for the specified image in JPEG format. 
    /// If the image object’s underlying image data has been purged, calling this function forces that data to be reloaded into memory. 
    /// - returns: A data object containing the JPEG data, or nil if there was a problem generating the data. This function may return nil if the image has no data or if the underlying CGImageRef contains data in an unsupported bitmap format. 
    func jpeg(_ quality: JPEGQuality) -> Data? { 
     return UIImageJPEGRepresentation(self, quality.rawValue) 
    } 
} 

Usage:

if let imageData = image.jpeg(.lowest) { 
    print(imageData.count) 
} 

+0

Uso del tipo non dichiarato UIImmagine. Questo è l'errore che ottengo – Umitk

+1

Stavo restituendo immagini con dimensioni di 22-25 MB, ora una frazione di quello. Grazie mille! Grande estensione! –

+0

Com'è diverso dall'utilizzo di UIImageJPEGRepresentation()? –

6

Jus di fissaggio per Xcode 7, testato su 2015/09/21 e lavorando bene:

Basta creare un'estensione UIImage come segue:

extension UIImage 
{ 
    var highestQualityJPEGNSData: NSData { return UIImageJPEGRepresentation(self, 1.0)! } 
    var highQualityJPEGNSData: NSData { return UIImageJPEGRepresentation(self, 0.75)!} 
    var mediumQualityJPEGNSData: NSData { return UIImageJPEGRepresentation(self, 0.5)! } 
    var lowQualityJPEGNSData: NSData  { return UIImageJPEGRepresentation(self, 0.25)!} 
    var lowestQualityJPEGNSData: NSData { return UIImageJPEGRepresentation(self, 0.0)! } 
} 

Quindi è possibile utilizzare in questo modo:

let imageData = imagePassed.lowestQualityJPEGNSData 
14

Se si desidera limitare il formato dell'immagine su un valore concreto u può fare come segue:

import UIKit 

extension UIImage { 
    // MARK: - UIImage+Resize 
    func compressTo(_ expectedSizeInMb:Int) -> UIImage? { 
     let sizeInBytes = expectedSizeInMb * 1024 * 1024 
     var needCompress:Bool = true 
     var imgData:Data? 
     var compressingValue:CGFloat = 1.0 
     while (needCompress && compressingValue > 0.0) { 
     if let data:Data = UIImageJPEGRepresentation(self, compressingValue) { 
      if data.count < sizeInBytes { 
       needCompress = false 
       imgData = data 
      } else { 
       compressingValue -= 0.1 
      } 
     } 
    } 

    if let data = imgData { 
     if (data.count < sizeInBytes) { 
      return UIImage(data: data) 
     } 
    } 
     return nil 
    } 
} 
+0

Questa è una soluzione più completa. –

+0

Perfetto, grazie! – MQLN

+0

swift 3.1 'se let data = bits.representation (utilizzando: .jpeg, proprietà: [.compressionFactor: compressingValue])' – Jacksonsox

4
//image compression 
func resizeImage(image: UIImage) -> UIImage { 
    var actualHeight: Float = Float(image.size.height) 
    var actualWidth: Float = Float(image.size.width) 
    let maxHeight: Float = 300.0 
    let maxWidth: Float = 400.0 
    var imgRatio: Float = actualWidth/actualHeight 
    let maxRatio: Float = maxWidth/maxHeight 
    let compressionQuality: Float = 0.5 
    //50 percent compression 

    if actualHeight > maxHeight || actualWidth > maxWidth { 
     if imgRatio < maxRatio { 
      //adjust width according to maxHeight 
      imgRatio = maxHeight/actualHeight 
      actualWidth = imgRatio * actualWidth 
      actualHeight = maxHeight 
     } 
     else if imgRatio > maxRatio { 
      //adjust height according to maxWidth 
      imgRatio = maxWidth/actualWidth 
      actualHeight = imgRatio * actualHeight 
      actualWidth = maxWidth 
     } 
     else { 
      actualHeight = maxHeight 
      actualWidth = maxWidth 
     } 
    } 

    let rect = CGRectMake(0.0, 0.0, CGFloat(actualWidth), CGFloat(actualHeight)) 
    UIGraphicsBeginImageContext(rect.size) 
    image.drawInRect(rect) 
    let img = UIGraphicsGetImageFromCurrentImageContext() 
    let imageData = UIImageJPEGRepresentation(img!,CGFloat(compressionQuality)) 
    UIGraphicsEndImageContext() 
    return UIImage(data: imageData!)! 
} 
0

Swift 3

@ risposta leo-dabus revisionata per swift 3

extension UIImage { 
    var uncompressedPNGData: Data?  { return UIImagePNGRepresentation(self)  } 
    var highestQualityJPEGNSData: Data? { return UIImageJPEGRepresentation(self, 1.0) } 
    var highQualityJPEGNSData: Data? { return UIImageJPEGRepresentation(self, 0.75) } 
    var mediumQualityJPEGNSData: Data? { return UIImageJPEGRepresentation(self, 0.5) } 
    var lowQualityJPEGNSData: Data?  { return UIImageJPEGRepresentation(self, 0.25) } 
    var lowestQualityJPEGNSData:Data? { return UIImageJPEGRepresentation(self, 0.0) } 
} 
2

Questo è molto semplice, con estensione UIImage

extension UIImage { 

func resizeByByte(maxByte: Int) { 

    var compressQuality: CGFloat = 1 
    var imageByte = UIImageJPEGRepresentation(self, 1)?.count 

    while imageByte! > maxByte { 

     imageByte = UIImageJPEGRepresentation(self, compressQuality)?.count 
     compressQuality -= 0.1 
    } 
} 

}

da usare

// max 300kb 
yourUIImage.resizeByByte(maxByte: 300000) 

Se si desidera controllare il byte di immagine

print("image size: \((UIImageJPEGRepresentation(yourUIImage, 1)?.count)!)") 
+0

molto lento e sincronizzato –

0

In Swift 4 I creato questa estensione che riceverà l'expecte taglia e prova a raggiungerlo.

extension UIImage { 

    enum CompressImageErrors: Error { 
     case invalidExSize 
     case sizeImpossibleToReach 
    } 
    func compressImage(_ expectedSizeKb: Int, completion : (UIImage,CGFloat) -> Void) throws { 

     let minimalCompressRate :CGFloat = 0.4 // min compressRate to be checked later 

     if expectedSizeKb == 0 { 
      throw CompressImageErrors.invalidExSize // if the size is equal to zero throws 
     } 

     let expectedSizeBytes = expectedSizeKb * 1024 
     let imageToBeHandled: UIImage = self 
     var actualHeight : CGFloat = self.size.height 
     var actualWidth : CGFloat = self.size.width 
     var maxHeight : CGFloat = 841 //A4 default size I'm thinking about a document 
     var maxWidth : CGFloat = 594 
     var imgRatio : CGFloat = actualWidth/actualHeight 
     let maxRatio : CGFloat = maxWidth/maxHeight 
     var compressionQuality : CGFloat = 1 
     var imageData:Data = UIImageJPEGRepresentation(imageToBeHandled, compressionQuality)! 
     while imageData.count > expectedSizeBytes { 

      if (actualHeight > maxHeight || actualWidth > maxWidth){ 
       if(imgRatio < maxRatio){ 
        imgRatio = maxHeight/actualHeight; 
        actualWidth = imgRatio * actualWidth; 
        actualHeight = maxHeight; 
       } 
       else if(imgRatio > maxRatio){ 
        imgRatio = maxWidth/actualWidth; 
        actualHeight = imgRatio * actualHeight; 
        actualWidth = maxWidth; 
       } 
       else{ 
        actualHeight = maxHeight; 
        actualWidth = maxWidth; 
        compressionQuality = 1; 
       } 
      } 
      let rect = CGRect(x: 0.0, y: 0.0, width: actualWidth, height: actualHeight) 
      UIGraphicsBeginImageContext(rect.size); 
      imageToBeHandled.draw(in: rect) 
      let img = UIGraphicsGetImageFromCurrentImageContext(); 
      UIGraphicsEndImageContext(); 
       if let imgData = UIImageJPEGRepresentation(img!, compressionQuality) { 
       if imgData.count > expectedSizeBytes { 
        if compressionQuality > minimalCompressRate { 
         compressionQuality -= 0.1 
        } else { 
         maxHeight = maxHeight * 0.9 
         maxWidth = maxWidth * 0.9 
        } 
       } 
       imageData = imgData 
      } 


     } 

     completion(UIImage(data: imageData)!, compressionQuality) 
    } 


} 

utilizzare

 do { 
      try UiImageView.image?.compressImage(100, completion: { (image, compressRatio) in 
       print(image.size) 
       imageData = UIImageJPEGRepresentation(image, compressRatio) 
       base64data = imageData?.base64EncodedString() 

      }) 
     } catch { 
       print("Error") 
     } 
Problemi correlati