我有一个iOS应用,该应用允许使用以下Swift功能将图像上传到Ubuntu服务器(带有Apache网络服务器):
private func uploadPhoto(image:UIImage) {
let imageData = image.jpegData(compressionQuality: 0.6)
if imageData == nil {
NSLog("Image Data is nil")
} else {
let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String
let url = URL(string: "https://example.com/myapi.php")!
var request = URLRequest(url: url)
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.httpMethod = "POST"
let boundary = NSUUID().uuidString
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let body = NSMutableData()
// Text Parameter: Action
body.append(NSString(format: "--%@\r\n", boundary).data(using: String.Encoding.utf8.rawValue)!)
body.append(NSString(format: "Content-Disposition: form-data; name=\"action\"\r\n\r\n").data(using: String.Encoding.utf8.rawValue)!)
body.append(NSString(format: "some_text_data\r\n").data(using: String.Encoding.utf8.rawValue)!)
// Text Parameter: Build Number
body.append(NSString(format: "--%@\r\n", boundary).data(using: String.Encoding.utf8.rawValue)!)
body.append(NSString(format: "Content-Disposition: form-data; name=\"build\"\r\n\r\n").data(using: String.Encoding.utf8.rawValue)!)
body.append(NSString(format: ("\(buildNumber ?? "99999")\r\n" as NSString)).data(using: String.Encoding.utf8.rawValue)!)
// File Parameter
body.append(NSString(format: "--%@\r\n", boundary).data(using: String.Encoding.utf8.rawValue)!)
body.append(NSString(format:"Content-Disposition: form-data; name=\"the_img\"; filename=\"image.jpg\"\r\n").data(using: String.Encoding.utf8.rawValue)!)
body.append(NSString(format: "Content-Type: application/octet-stream\r\n\r\n").data(using: String.Encoding.utf8.rawValue)!)
body.append(imageData!)
body.append(NSString(format: "\r\n--%@--\r\n", boundary).data(using: String.Encoding.utf8.rawValue)!)
request.httpBody = body as Data
let task = URLSession.shared.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
guard error == nil else {
return
}
guard let data = data else {
return
}
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
print(json)
}
} catch let error {
print(error.localizedDescription)
}
})
task.resume()
}
}
上载功能正常运行,并且图像已正确上载到服务器。但是,某些上传的图像(每100张图像中大约有1张)的缩略图(在macOS 10.15.6 Finder的快速预览中显示)上会带有绿线;似乎JPEG已损坏。请参见下面的示例屏幕截图:
但是图像本身似乎没有问题:
为什么会这样?如果将image.jpegData(compressionQuality:)
设置为1.0
(不压缩),则根本不会发生此问题。我的图像压缩不正确吗?
答案 0 :(得分:2)
您将需要遍历图像的整个流程,并查看此损坏发生的确切位置。
在您发布的内容中,您有一个UIImage
,它是图像的内存表示形式。您声称这张图片看起来不错。
下一步是使用image.jpegData(compressionQuality: 0.6)
将图像编码为标准格式JPEG。结果是可写入文件的数据,并且可以由支持打开JPEG图像的许多应用程序中的任何一个打开。我建议您尝试将其写入某个文件(Data
的写入选项为FileManager.default
),或者,也可以使用{{3}直接将其直接发送到计算机中, }。
如果此步骤产生损坏的图像,则iOS上的编码器存在问题,我希望不是这种情况。但是,如果是这样,请提交错误报告,并尝试使用其他压缩质量或其他格式(如果可能,请使用PNG)。
在这部分之后,您将原始JPEG数据注入到HTTP请求的主体中。没什么特别的。数据应按原样传送到服务器,并且在传输中造成损坏的机会太接近于零,以至于无法在一生中目睹损坏。因此,在这部分之后,您需要检查服务器上正在发生什么。
如果服务器上没有任何事件,那么下载JPEG所产生的数据应与发送给服务器的数据完全相同。您可以通过将数据imageData
与下载的数据进行比较来检查(只需使用try! Data(contentsOf: URL(string: "your URL here")!)
)。
如果数据不一样(我现在希望如此),则应分析服务器端发生的情况。发生这种损坏似乎很奇怪,但是可能存在一些不兼容的设置。有时,解决方案非常不直观;例如,您还需要在请求中发送mime类型。我认为您的情况应该是image/jpeg
。
同样从异常中我们看到我会怀疑“每行字节数”存在兼容性问题。有时出于性能原因,在每个“行”的末尾添加了额外的填充。如果不忽略填充,则将其带入下一行。在损坏的图像中,您可以看到第一行是正常的,而第二行以绿色异常开头。第三行将异常向前移动另一个相等的长度。不确定这些信息是否对您有任何帮助,但是在处理图形纹理(例如使用openGL)时,这是一个常见问题。
答案 1 :(得分:1)
我首先将哑剧类型从writeMM()
更改为image/jpeg
(正如Matic Oblak在他的详细回答中所建议的那样)。
因此,我自己在图片上传方面遇到了问题。