将图像上传到服务器时出现绿线

时间:2020-09-22 03:07:25

标签: ios swift

我有一个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已损坏。请参见下面的示例屏幕截图:

screenshot of quick preview

但是图像本身似乎没有问题:

original photo

为什么会这样?如果将image.jpegData(compressionQuality:)设置为1.0(不压缩),则根本不会发生此问题。我的图像压缩不正确吗?

2 个答案:

答案 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在他的详细回答中所建议的那样)。 因此,我自己在图片上传方面遇到了问题。