2015-04-19 7 views
43

Próbowałem przesłać plik obrazu do Parse po zrobieniu zdjęcia bezpośrednio na telefonie. Ale zgłasza wyjątek:Jak skompresować zmniejszyć rozmiar obrazu przed przesłaniem do Parse jako PFFile? (Swift)

Zakończenie aplikację spowodowane nieprzechwyconego wyjątku „NSInvalidArgumentException”, powód: „PFFile nie może być większa niż 10485760 bajtów”

Oto mój kod:

W pierwszym widok kontroler:

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

w widoku kontrolera, który przesyła obrazu:

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

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

Ale nadal muszę przesłać to zdjęcie do analizy. Czy istnieje sposób na zmniejszenie rozmiaru lub rozdzielczości obrazu?

+0

Próbowałem ostatnią propozycję GBK i czcionka na koniec, że jeśli zadzwonię niech newData = UIImageJPEGRepresentation (UIImage (dane: dane), 1) nie jest newData.count równa się data.count i jest naprawdę większa z faktorem większym niż 2. Co jest dla mnie naprawdę zaskakujące! W każdym razie, dzięki za kod! – NicoD

Odpowiedz

116

Tak można użyć UIImageJPEGRepresentation zamiast UIImagePNGRepresentation, aby zmniejszyć rozmiar pliku obrazu. Możesz po prostu utworzyć rozszerzenie UIImage w następujący sposób:

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) 
    } 
} 

Zastosowanie:

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

+0

Używanie niezadeklarowanego typu UIImage. To jest błąd, który dostaję: – Umitk

+1

Zwróciłem obrazy o rozmiarach 22-25MB, a teraz ułamek tego. Dziękuję bardzo! Świetne rozszerzenie! –

+0

Czym to się różni od używania UIImageJPEGRepresentation()? –

6

Jus Mocowanie do Xcode 7, testowany na 09/21/2015 i działa bez zarzutu:

Wystarczy utworzyć rozszerzenie UIImage następująco:

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)! } 
} 

Wtedy można go używać tak:

let imageData = imagePassed.lowestQualityJPEGNSData 
14

Jeśli chcesz ograniczyć rozmiar obrazu do jakiejś konkretnej wartości u można zrobić następująco:

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

To jest bardziej kompleksowe rozwiązanie. –

+0

Doskonale, dziękuję! – MQLN

+0

swift 3.1 'if let data = bits.representation (używając: .jpeg, properties: [.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

@ leo-dabus odpowiedź zmieniona na 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

To bardzo proste z rozszerzeniem 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 
    } 
} 

}

używać

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

Jeśli chcesz sprawdzić bajt obrazu

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

bardzo wolno i synchronizować –

0

W Swift 4 I stworzyłem to rozszerzenie, które otrzyma oczekiwane d rozmiar próbować go osiągnąć.

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) 
    } 


} 

korzystać

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

      }) 
     } catch { 
       print("Error") 
     } 
Powiązane problemy