Saya mencoba mengunggah file gambar ke Parse setelah mengambil foto langsung di ponsel. Tapi itu membuat pengecualian:
Menghentikan aplikasi karena pengecualian yang tidak tertangkap 'NSInvalidArgumentException', alasan: 'PFFile tidak boleh lebih besar dari 10485760 byte'
Ini kode saya:
Pada pengontrol tampilan pertama:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "getImage")
{
var svc = segue.destinationViewController as! ClothesDetail
svc.imagePassed = imageView.image
}
}
Dalam pengontrol tampilan yang mengunggah gambar:
let imageData = UIImagePNGRepresentation(imagePassed)
let imageFile = PFFile(name: "\(picName).png", data: imageData)
var userpic = PFObject(className:"UserPic")
userpic["picImage"] = imageFile`
Tapi saya masih perlu mengunggah foto itu ke Parse. Adakah cara untuk mengurangi ukuran atau resolusi gambar?
ios
swift
parse-platform
uiimage
elvislkm
sumber
sumber
Jawaban:
Ya, Anda dapat menggunakan
UIImageJPEGRepresentation
alih-alihUIImagePNGRepresentation
untuk mengurangi ukuran file gambar Anda. Anda bisa membuat ekstensi UIImage sebagai berikut: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) } }
edit / perbarui:
Xcode 10 Swift 4.2.0
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(_ jpegQuality: JPEGQuality) -> Data? { return jpegData(compressionQuality: jpegQuality.rawValue) } }
Pemakaian:
if let imageData = image.jpeg(.lowest) { print(imageData.count) }
sumber
UIImageJPEGRepresentation(yourImage, 1.0)
daripada hanya mengetik.jp
dan membiarkan xcode melengkapi metode tersebut secara otomatis untuk Anda. sama untuk penghitungan kompresi.whatever
.Jika Anda ingin membatasi ukuran gambar menjadi beberapa nilai konkret, Anda dapat melakukan hal berikut:
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 } }
sumber
if let data = bits.representation(using: .jpeg, properties: [.compressionFactor:compressingValue])
//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!)! }
sumber
Jus Fixing untuk Xcode 7, diuji pada 09/21/2015 dan berfungsi dengan baik:
Buat saja ekstensi
UIImage
sebagai berikut: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)! } }
Kemudian Anda bisa menggunakannya seperti ini:
let imageData = imagePassed.lowestQualityJPEGNSData
sumber
Swift 4 Binary Approach untuk mengompres gambar
Saya yakin sudah cukup terlambat untuk menjawab pertanyaan ini tetapi inilah solusi saya untuk pertanyaan yang dioptimalkan. Saya menggunakan pencarian Biner untuk menemukan nilai optimal. Jadi, misalnya, katakanlah dengan pendekatan pengurangan normal untuk mencapai 62% akan membutuhkan 38 percobaan kompresi, pendekatan * Pencarian biner ** akan mencapai solusi yang dibutuhkan dalam max log (100) = sekitar 7 percobaan.
Namun, juga ingin memberi tahu Anda bahwa
UIImageJPEGRepresentation
fungsi tersebut tidak berperilaku linier terutama jika jumlahnya mendekati 1. Berikut adalah screen grab di mana kita dapat melihat bahwa gambar berhenti mengompresi setelah nilai float> 0,995. Perilakunya tidak dapat diprediksi jadi lebih baik memiliki buffer delta yang akan menangani kasus seperti itu.Ini kodenya
extension UIImage { func resizeToApprox(sizeInMB: Double, deltaInMB: Double = 0.2) -> Data { let allowedSizeInBytes = Int(sizeInMB * 1024 * 1024) let deltaInBytes = Int(deltaInMB * 1024 * 1024) let fullResImage = UIImageJPEGRepresentation(self, 1.0) if (fullResImage?.count)! < Int(deltaInBytes + allowedSizeInBytes) { return fullResImage! } var i = 0 var left:CGFloat = 0.0, right: CGFloat = 1.0 var mid = (left + right) / 2.0 var newResImage = UIImageJPEGRepresentation(self, mid) while (true) { i += 1 if (i > 13) { print("Compression ran too many times ") // ideally max should be 7 times as log(base 2) 100 = 6.6 break } print("mid = \(mid)") if ((newResImage?.count)! < (allowedSizeInBytes - deltaInBytes)) { left = mid } else if ((newResImage?.count)! > (allowedSizeInBytes + deltaInBytes)) { right = mid } else { print("loop ran \(i) times") return newResImage! } mid = (left + right) / 2.0 newResImage = UIImageJPEGRepresentation(self, mid) } return UIImageJPEGRepresentation(self, 0.5)! } }
sumber
for i in 0...13
.Itu sangat sederhana dengan
UIImage
ekstensiextension UIImage { func resizeByByte(maxByte: Int, completion: @escaping (Data) -> Void) { var compressQuality: CGFloat = 1 var imageData = Data() var imageByte = UIImageJPEGRepresentation(self, 1)?.count while imageByte! > maxByte { imageData = UIImageJPEGRepresentation(self, compressQuality)! imageByte = UIImageJPEGRepresentation(self, compressQuality)?.count compressQuality -= 0.1 } if maxByte > imageByte! { completion(imageData) } else { completion(UIImageJPEGRepresentation(self, 1)!) } }
menggunakan
// max 300kb image.resizeByByte(maxByte: 300000) { (resizedData) in print("image size: \(resizedData.count)") }
sumber
Pembaruan Swift 4.2 . Saya membuat ekstensi ini untuk mengurangi ukuran gambar UII.
Di sini Anda memiliki dua metode, yang pertama mengambil persentase dan yang kedua mengurangi gambar menjadi 1MB.
Tentu saja Anda dapat mengubah metode kedua menjadi 1KB atau ukuran yang Anda inginkan.
import UIKit extension UIImage { func resized(withPercentage percentage: CGFloat) -> UIImage? { let canvasSize = CGSize(width: size.width * percentage, height: size.height * percentage) UIGraphicsBeginImageContextWithOptions(canvasSize, false, scale) defer { UIGraphicsEndImageContext() } draw(in: CGRect(origin: .zero, size: canvasSize)) return UIGraphicsGetImageFromCurrentImageContext() } func resizedTo1MB() -> UIImage? { guard let imageData = self.pngData() else { return nil } let megaByte = 1000.0 var resizingImage = self var imageSizeKB = Double(imageData.count) / megaByte // ! Or devide for 1024 if you need KB but not kB while imageSizeKB > megaByte { // ! Or use 1024 if you need KB but not kB guard let resizedImage = resizingImage.resized(withPercentage: 0.5), let imageData = resizedImage.pngData() else { return nil } resizingImage = resizedImage imageSizeKB = Double(imageData.count) / megaByte // ! Or devide for 1024 if you need KB but not kB } return resizingImage } }
sumber
Di Swift 5 sebagai jawaban @Thiago Arreguy:
extension UIImage { var highestQualityJPEGNSData: Data { return self.jpegData(compressionQuality: 1.0)! } var highQualityJPEGNSData: Data { return self.jpegData(compressionQuality: 0.75)!} var mediumQualityJPEGNSData: Data { return self.jpegData(compressionQuality: 0.5)! } var lowQualityJPEGNSData: Data { return self.jpegData(compressionQuality: 0.25)!} var lowestQualityJPEGNSData: Data { return self.jpegData(compressionQuality: 0.0)! } }
Dan Anda bisa menelepon seperti ini:
let imageData = imagePassed.lowestQualityJPEGNSData
sumber
Di Swift
func ResizeImageFromOriginalSize(targetSize: CGSize) -> UIImage { var actualHeight: Float = Float(self.size.height) var actualWidth: Float = Float(self.size.width) let maxHeight: Float = Float(targetSize.height) let maxWidth: Float = Float(targetSize.width) var imgRatio: Float = actualWidth / actualHeight let maxRatio: Float = maxWidth / maxHeight var 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 compressionQuality = 1.0 } } let rect = CGRect(x: 0.0, y: 0.0, width: CGFloat(actualWidth), height: CGFloat(actualHeight)) UIGraphicsBeginImageContextWithOptions(rect.size, false, CGFloat(compressionQuality)) self.draw(in: rect) let newImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return newImage! }
sumber
Penggunaan
func jpegData(compressionQuality: CGFloat) -> Data?
berfungsi dengan baik jika Anda tidak perlu mengompres ke ukuran tertentu. Namun, untuk gambar tertentu, saya merasa berguna untuk dapat mengompres di bawah ukuran file tertentu. Dalam hal itu,jpegData
tidak dapat diandalkan, dan pengompresan berulang-ulang pada gambar menghasilkan stagnan pada ukuran file (dan bisa sangat mahal). Sebagai gantinya, saya lebih suka mengurangi ukuran UIImage itu sendiri, lalu mengonversi ke jpegData dan memeriksa untuk melihat apakah ukuran yang diperkecil berada di bawah nilai yang saya pilih (dalam margin kesalahan yang saya tetapkan). Saya menyesuaikan pengali langkah kompresi berdasarkan rasio ukuran file saat ini dengan ukuran file yang diinginkan untuk mempercepat iterasi pertama yang paling mahal.Cepat 5
extension UIImage { func resized(withPercentage percentage: CGFloat, isOpaque: Bool = true) -> UIImage? { let canvas = CGSize(width: size.width * percentage, height: size.height * percentage) let format = imageRendererFormat format.opaque = isOpaque return UIGraphicsImageRenderer(size: canvas, format: format).image { _ in draw(in: CGRect(origin: .zero, size: canvas)) } } func compress(to kb: Int, allowedMargin: CGFloat = 0.2) -> Data { let bytes = kb * 1024 var compression: CGFloat = 1.0 let step: CGFloat = 0.05 var holderImage = self var complete = false while(!complete) { if let data = holderImage.jpegData(compressionQuality: 1.0) { let ratio = data.count / bytes if data.count < Int(CGFloat(bytes) * (1 + allowedMargin)) { complete = true return data } else { let multiplier:CGFloat = CGFloat((ratio / 5) + 1) compression -= (step * multiplier) } } guard let newImage = holderImage.resized(withPercentage: compression) else { break } holderImage = newImage } return Data() } }
Dan penggunaan:
let data = image.compress(to: 300)
resized
Ekstensi UIImage berasal dari: Bagaimana cara mengubah ukuran UIImage untuk mengurangi ukuran gambar unggahansumber
Cepat 3
@ leo-dabus jawaban direvisi untuk cepat 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) } }
sumber
Di Swift 4 saya membuat ekstensi ini yang akan menerima ukuran yang diharapkan dan mencoba mencapainya.
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) } }
Menggunakan
do { try UiImageView.image?.compressImage(100, completion: { (image, compressRatio) in print(image.size) imageData = UIImageJPEGRepresentation(image, compressRatio) base64data = imageData?.base64EncodedString() }) } catch { print("Error") }
sumber