将图像大小压缩到 1.5 MB,同时发送到多部分 ios swift
Posted
技术标签:
【中文标题】将图像大小压缩到 1.5 MB,同时发送到多部分 ios swift【英文标题】:Compress image size to 1.5 MB while sending to multipart ios swift 【发布时间】:2019-11-21 08:22:42 【问题描述】:我正在上传大小小于 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。 【参考方案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
【讨论】:
以上是关于将图像大小压缩到 1.5 MB,同时发送到多部分 ios swift的主要内容,如果未能解决你的问题,请参考以下文章