发送到多部分时将图像大小压缩到 1.5 MB ios swift

Compress image size to 1.5 MB while sending to multipart ios swift

我正在上传大小小于 1.5 MB 的图像(在 imagePickerController 中选择),然后将其保存到 Userdefault,但是当我尝试获取它时,它的大小会增加。因此,在将其上传到 Multipart 时,我再次尝试按如下方式对其进行压缩。它给了我“2122 字节”。没关系,因为它小于 1.5 MB。但主要问题是我无法上传它。

let compressData = UIImage(data:UserDefaultValues.imagep1! as Data)!.jpegData(compressionQuality: 0)

print("length:", UIImage(data:compressData!)!.jpegData(compressionQuality: 0)!)//2122 bytes

let compressData2 = UIImage(data:UserDefaultValues.imagep3! as Data)?.jpegData(compressionQuality: 0) 

print("length2:", UIImage(data:compressData2!)!.jpegData(compressionQuality: 0)!)//2122 bytes


multipartFormData: { multipartFormData in

                    multipartFormData.append(compressData!, withName: "image", fileName: "", mimeType: "image/png")
                    multipartFormData.append("\(storyid)".data(using: .utf8)! , withName: "story_id")
                    multipartFormData.append(compressData2!, withName: "series_image", fileName: "", mimeType: "image/png")
                    multipartFormData.append("\(seriesid)".data(using: .utf8)! , withName: "series_id")

},

Image Compression extension 可能会帮助您保持可发送图像大小一致。

Uploading multipartFormData

 Alamofire.upload(multipartFormData: { multipartFromData in
                    if !fileData.isEmpty {
                        multipartFromData.append(fileData, withName: "file", fileName: "\(UUID().uuidString).png", mimeType: "image/png")
                    }

                }, to:URL , method: .post, headers: headers, encodingCompletion: { result in
                    print(result)

                    switch result {
                    case .success(let upload, _, _):
                        upload.validate(statusCode: 200 ..< 300).responseString(completionHandler: { _ in
                         print("Upload success")
                        })
                    case .failure(let error):
                        print(error.localizedDescription)
                    }
                })


这是使用示例代码在服务器上上传图片的一些步骤

第 1 步:使用 URLSession 上传图片

    var croppedImage = UIImage()

    func imageUploadRequest(){
    let getUserData :UserDefaults = UserDefaults.standard
    let User_Id = getUserData.value(forKey: "userid")
    print("userid :\(String(describing: User_Id))!)")
    let myUrl = NSURL(string: "Enter API String Here");
    let request = NSMutableURLRequest(url:myUrl! as URL);
    request.httpMethod = "POST";
    let param = [
        "user_id"  : "\(User_Id!)",

    ]
    let boundary = generateBoundaryString()
    request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
    //Pass image in compressImage function
    let compressedImage = self.compressImage(image: croppedImage)
    //Convert It NSData To UIImage and also pass scale value for compression
    convertedImage = UIImage(data:compressedImage as Data,scale:1.0)!
    print("print Lates compress image size : \(convertedImage.size)")
    let imageData = UIImageJPEGRepresentation(convertedImage, 1)
    if(imageData==nil)  { return; }
    request.httpBody = createBodyWithParameters(parameters: param, filePathKey: "fileToUpload", imageDataKey: imageData! as NSData, boundary: boundary) as Data
    //Pass This converted Image To Server
    let task = URLSession.shared.dataTask(with: request as URLRequest) {
        data, response, error in
        if error != nil {
            print("error=\(String(describing: error))")
            return
        }
        // You can print out response object
        print("******* response = \(String(describing: response))")
        // Print out reponse body
        let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
        print("****** response data = \(responseString!)")
        //Show Alert after successfull uploaded
        DispatchQueue.main.async {
            //resolved view is not hiararchy issue.
            let createProfileVC = UIStoryboard(name: "Main", bundle:nil).instantiateViewController(withIdentifier: "CreateProfileViewController") as! CreateProfileViewController
            let appDelegate = (UIApplication.shared.delegate as! AppDelegate)
            appDelegate.window?.rootViewController = createProfileVC
        }
        do {
            let json = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary
            print(json)
            self.imageView.image = nil;
        }catch
        {
            print(error)
        }
      }
    task.resume()
  }

func createBodyWithParameters(parameters: [String: String]?, filePathKey: String?, imageDataKey: NSData, boundary: String) -> NSData {
    let body = NSMutableData();
    if parameters != nil {
        for (key, value) in parameters! {
            body.appendString(string: "--\(boundary)\r\n")
            body.appendString(string: "Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
            body.appendString(string: "\(value)\r\n")
        }
    }
    let filename = "profileImage"
    let mimetype = "image/jpg"
    body.appendString(string: "--\(boundary)\r\n")
    body.appendString(string: "Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename)\"\r\n")
    body.appendString(string: "Content-Type: \(mimetype)\r\n\r\n")
    body.append(imageDataKey as Data)
    body.appendString(string: "\r\n")

    body.appendString(string: "--\(boundary)--\r\n")

    return body
}

func generateBoundaryString() -> String {
    return "Boundary-\(NSUUID().uuidString)"
}

第二步:图片压缩

 //Need to convert NSData to UIImage
func compressImage(image:UIImage) -> NSData {
    // Reducing file size to a 10th

    var actualHeight : CGFloat = image.size.height
    var actualWidth : CGFloat = image.size.width
    var maxHeight : CGFloat = 1136.0
    var maxWidth : CGFloat = 640.0
    var imgRatio : CGFloat = actualWidth/actualHeight
    var maxRatio : CGFloat = maxWidth/maxHeight
    var compressionQuality : CGFloat = 0.5

    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;
            compressionQuality = 1;
        }
    }


    var rect = CGRect(x: 0.0, y:0.0 , width:actualWidth , height: actualHeight)

    UIGraphicsBeginImageContext(rect.size);
    image.draw(in: rect)
    var img = UIGraphicsGetImageFromCurrentImageContext();
    let imageData = UIImageJPEGRepresentation(img!, compressionQuality);
    UIGraphicsEndImageContext();

    return imageData as! NSData;
}

}

扩展 NSMutableData {

func appendString(string: String) {
    let data = string.data(using: String.Encoding.utf8, allowLossyConversion: true)
    append(data!)
}

}

答案:

func sendStorySeriesImage(seriesid: Int, storyid: Int){
    let sv = UIViewController.displaySpinner(onView: view)
    guard let compressData2 = (UIImage(data:UserDefaultValues.imagep1! as Data)!).jpegData(compressionQuality: 0.5) else {
        return
    }
    guard let compressData = (UIImage(data:UserDefaultValues.imagep1! as Data)!).jpegData(compressionQuality: 0.5) else {
        return
    }

let url = URL(string: Constants.wevlrBaseUrl + Constants.privateLink + Constants.createstoryseriesImage)!

Alamofire.upload(
    multipartFormData: { multipartFormData in

    multipartFormData.append("\(storyid)".data(using: .utf8)! , withName: "story_id")
    multipartFormData.append("\(seriesid)".data(using: .utf8)! , withName: "series_id")
    multipartFormData.append(compressData, withName: "image", fileName: "\(UUID().uuidString).jpg", mimeType: "image/jpg")
    multipartFormData.append(compressData2, withName: "series_image", fileName: "\(UUID().uuidString).jpg", mimeType: "image/jpg")

},
        to: url,
        method : .post,
        headers : Constants.headers,
        encodingCompletion: { encodingResult in
        switch encodingResult {
        case .success(let upload, _, _):

        upload.responseJSON { response in

            debugPrint(response)
            switch response.result {
            case .success(let data):
                UIViewController.removeSpinner(spinner: sv)
                let dict = response.result.value as! NSDictionary
                let statusCode = response.response?.statusCode

                if(statusCode == 201) {
                            UIViewController.removeSpinner(spinner: sv)
                            self.alert(title: "Success!", message: (dict["msg"] as? String)!)



               }else{
                            UIViewController.removeSpinner(spinner: sv)
                            self.alert(title: "Alert!", message: (dict["msg"] as? String)!)
                           }
            break
            case .failure(_):
             self.alert(title: "Alert!", message: "Something went wrong. Please try again.")
            break
            }

        }
        case .failure(_):
         self.alert(title: "Alert!", message: "Something went wrong. Please try again.")
        break
        }
    }
        )

}

您可以在多部分发送图像之前压缩图像。使用以下功能,您将获得压缩图像数据和完成时质量损失最小的图像。

extension UIImage {
func compressImageBelow(kb: Double, completion:(UIImage?, Data?) -> Void) {
    if let imageData = self.jpegData(compressionQuality: 0.5)
    {
      var resizingImage = self
      var imageSizeKB = Double(imageData.count) / 1000.0
      var imgFinalData: Data = imageData
      while imageSizeKB > kb {
            if let resizedImage = resizingImage.resized(withPercentage: 0.9),
                let imageData = resizedImage.jpegData(compressionQuality: 0.5) {
                resizingImage = resizedImage
                imageSizeKB = Double(imageData.count) / 1000.0 // ! Or devide for 1024 if you need KB but not kB
                imgFinalData = imageData
                print("There were \(imageData.count) bytes")
                let bcf = ByteCountFormatter()
                bcf.allowedUnits = [.useMB] // optional: restricts the units to MB only
                bcf.countStyle = .file
                let string = bcf.string(fromByteCount: Int64(imageData.count))
                print("formatted result: \(string)")
            }
        }
        completion(self, imgFinalData);
    }
    completion(nil, nil);
  }
}

用法:

image.compressImageBelow(kb: 1500.0, completion: { (compressedImage, imageData) in
  guard let imgData = imageData else {
    return
  }
  //Use compressedImage here or
  //Send img data in multiparts
}

这个解决方案对我有用

func resize(_ expectedSizeInMb:Int) -> Data? {
        guard let fileSize = self.jpegData(compressionQuality: 1) else {return nil}
        let Size = CGFloat(Double(fileSize.count)/1024/1024)
        // I am checking 5 MB size here you check as you want
        if Size > CGFloat(expectedSizeInMb) {
            let sizeInBytes: CGFloat = CGFloat(expectedSizeInMb * 1024 * 1024)
            let leastExpectedSize: CGFloat = (CGFloat(expectedSizeInMb) - 1) * 1024 * 1024
            var imgData:Data?
            var start: CGFloat = 0
            var end: CGFloat = 1
            var mid: CGFloat = (end+start)/2
            while true {
                imgData = self.jpegData(compressionQuality: CGFloat(mid))
                print("current image size \(CGFloat(imgData!.count)/(1024*1024))")
                print("1st \(start) 2nd \(mid) 3rd \(end)")
                if CGFloat(imgData?.count ?? 0) > sizeInBytes {
                    end = mid
                    mid = (start+end)/2
                } else if CGFloat(imgData?.count ?? 0) < sizeInBytes && CGFloat(imgData?.count ?? 0) < leastExpectedSize {
                    start = mid
                    mid = (start+end)/2
                } else {
                    print("returning")
                    return imgData
                }
            }
        }
        return fileSize
    }