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

Posted

技术标签:

【中文标题】上传图片到服务器时出现绿线【英文标题】:Green lines appeared when uploading an image to server 【发布时间】:2020-09-22 03:07:25 【问题描述】:

我有一个 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(无压缩),则根本不会发生此问题。我的图片压缩有误吗?

【问题讨论】:

我不明白。如果图像从 iOS 应用程序上传到 Ubuntu 服务器,您如何“在 macOS 10.15.6 Finder 的快速预览中”查看它们的缩略图? 我将图像从 Ubuntu 服务器下载到我的桌​​面 iMac。 【参考方案1】:

您需要检查图像的整个流程,看看到底发生了这种损坏。

根据您发布的内容,您有一个UIImage,它是图像的内存表示。您声称这张图片看起来不错。

下一步是使用image.jpegData(compressionQuality: 0.6) 将图像编码为标准格式的JPEG。结果是可写入文件的数据,并且可以由许多支持打开 JPEG 图像的应用程序中的任何一个打开。我建议您尝试将其写入某个文件(Data 具有使用FileManager.default 的写入选项),或者您可以快速尝试使用activity controller 直接将其发送到您的计算机。

如果此步骤产生损坏的图像,则 iOS 上的编码器存在问题,我希望不是这种情况。但如果是这样,请提交错误报告并尝试使用不同的压缩质量或不同的格式(如果可能,PNG)。

在这部分之后,您将原始 JPEG 数据注入到 HTTP 请求的正文中。它没有什么特别之处。数据应该按原样传送到服务器,并且在传输过程中发生损坏的机会太接近于零,以至于无法在一生中见证损坏。所以在这部分之后你需要检查服务器上发生了什么。

如果服务器上没有发生任何事情,那么下载您的 JPEG 应该会产生与您发送到服务器的数据完全相同的数据。您可以通过将您的数据imageData 与下载的数据进行比较来检查这一点(只需使用try! Data(contentsOf: URL(string: "your URL here")!))。

如果数据不一样(我现在预计会这样),您应该分析服务器端发生的情况。发生这种损坏似乎很奇怪,但可能存在一些不兼容的设置。有时解决方案非常不直观;例如,您还需要在请求中发送 mime 类型。我认为在你的情况下应该是image/jpeg

此外,从我们看到的异常情况来看,我怀疑“每行字节数”存在兼容性问题。有时出于性能原因,在每个“行”的末尾添加额外的填充。如果不忽略填充,则将其带到下一行。在您损坏的图像中,您可以看到第一行正常,而第二行以绿色异常开始。第三行将异常向前移动另一个相等的长度。不确定这些信息是否对您有任何帮助,但这是处理图形纹理时的常见问题,例如在使用 openGL 时。

【讨论】:

感谢您的详细回答。我想我应该马上开始我的调试之旅。似乎很难调试这个。 我对回答致以最深的敬意;虽然想指出第一行也不好 - 黄色“射线”从那里开始(从瓶子的顶部)。并且整个图像的颜色都混乱了。无论如何,所描述的确定错误的方法是我能想象到的最好的方法 @nrx 你是对的,谢谢。我确实看到还有多个其他异常;黄色,然后是一些蓝色和一些红色伪影。造成它们的原因真的超出了我的范围。但如果我不得不猜测,我会说这是压缩质量的一部分。由于压缩将块打包在一起,因此假设单个“像素”错误会影响整个区域是有意义的。我们甚至可以观察到两条绿线周围的一些伪影对称。但同样,这只是我的猜测。【参考方案2】:

我首先将 mime 类型从 application/octet-stream 更改为 image/jpeg(正如 Matic Oblak 在他的详细回答中所建议的那样)。 因此,我自己在上传图片时遇到了问题。

【讨论】:

以上是关于上传图片到服务器时出现绿线的主要内容,如果未能解决你的问题,请参考以下文章

上传到 Firebase 时出现图片方向问题

将多个图像上传到服务器时出现内存问题

本地图片上传服务器后不显示问题

求救!android部分手机上传照片到后台服务器为啥显示的图片是不全的,有缺失,缺失部分为黑色。

请求太重时出现 NodeJS CORS 错误(文件上传)

VB怎样上传图片到服务器