发送到多部分时将图像大小压缩到 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
}
我正在上传大小小于 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
}