【问题标题】:Compress image size to 1.5 MB while sending to multipart ios swift将图像大小压缩到 1.5 MB,同时发送到多部分 ios swift
【发布时间】:2024-01-14 02:31:01
【问题描述】:

我正在上传大小小于 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")

},

【问题讨论】:

  • 你想调整图像数据的大小..??
  • Yes to 1.5 MB n less ....我得到 2122 字节,但我仍然得到图像大小不应超过 1.5 MB :(
  • @RanuDhurandhar 你用过 UIImage 的“UIImageJPEGRepresentation”功能吗?或者您必须将您的 compressionQuality: 0 更改为 compressionQuality: 0.5
  • 我想将大小压缩为 1.5 MB。

标签: ios swift uiimage multipartform-data


【解决方案1】:

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

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


【讨论】:

    【解决方案2】:

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

    Step1:使用 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)"
    }
    

    Step2:图片压缩

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

    }

    【讨论】:

    • 我会试试这个
    • 您可以使用compressionQuality 参数管理所需的压缩大小。
    【解决方案3】:

    答案:

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

    【讨论】:

      【解决方案4】:

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

      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
      }
      

      【讨论】:

        【解决方案5】:

        这个解决方案适合我

        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
            }
        

        【讨论】:

          最近更新 更多