如何使用Swift将图像从iOS上传到Ruby / Rails服务器

时间:2021-07-24 21:21:25

I have a ruby/rails application that I want to accept an image upload in Base64 format inside of a JSON request payload. The basic app structure is as follows:

我有一个ruby / rails应用程序,我想在JSON请求有效负载内接受Base64格式的图像上传。基本的app结构如下:

import UIKit
import MapKit

class NewCafeDetailsTableViewController: UITableViewController, NSURLConnectionDataDelegate {

    @IBOutlet weak var submitButton: UIButton!
    @IBOutlet weak var mainImageCell: AddImageCell!
    var submitData: Dictionary<String, AnyObject>!

    override func viewDidLoad() {
        submitData = ["name": "Brian"]
        submitButton.addTarget(self, action: Selector("submit"), forControlEvents: UIControlEvents.TouchUpInside)
    }

    func submit() {
        // I\'ve tried to submit a dynamic image, but I switched it to a 
        // hard-coded 1x1 GIF just to get a grip on how to do this on 
        // the backend before attempting too much more
        submitData["thumbnail_data"] = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
        var error: NSError?

        var submitJSON: NSData!
        submitJSON = NSJSONSerialization.dataWithJSONObject(submitData, options: NSJSONWritingOptions.PrettyPrinted, error: &error)
        if (error == nil) {
            let submitJSONString = NSString(data: cafeJSON, encoding: NSUTF8StringEncoding)
            var url = NSURL(string: "http://localhost:3000/people.json")
            var request = NSMutableURLRequest(URL: url!)
            var requestData = submitJSONString?.dataUsingEncoding(NSUTF8StringEncoding)
            request.HTTPBody = requestData
            request.HTTPMethod = "POST"
            request.setValue("application/json", forHTTPHeaderField: "Content-type")
            request.setValue("application/json", forHTTPHeaderField: "Accept")
            request.timeoutInterval = 10

        }
    }

    func connection(connection: NSURLConnection, didReceiveResponse response: NSURLResponse) {
        var response = response as NSHTTPURLResponse

            if (response.statusCode >= 200 && response.statusCode <= 299) {
                self.navigationController?.popViewControllerAnimated(true)
                var alert = UIAlertView(title: "Success", message: "Cafe was successfully submitted. We'll review it in a few business days.", delegate: self, cancelButtonTitle: "Ok")
                alert.show()
            } else {
                var alert = UIAlertView(title: "Oops..", message: "It seems there was some kind of server error, please try again later", delegate: self, cancelButtonTitle: "Ok")
                alert.show()
            }


    }

    func connection(connection: NSURLConnection, didFailWithError error: NSError) {
        self.dismissViewControllerAnimated(true, completion: {
            var alert = UIAlertView(title: "Oops..", message: "It seems there was some kind of server error, please try again later", delegate: self, cancelButtonTitle: "Ok")
            alert.show()

        })
    }

}

In my Ruby code I have tried a variety of different paperclip options, which seems near broken. I also tried to decode the Base64 and save it myself with little to no success.

在我的Ruby代码中,我尝试了各种不同的回形针选项,这看起来差不多了。我也尝试解码Base64并自己保存,几乎没有成功。

Some of the things I tried:

我试过的一些事情:

data = Base64.decode64(params[:thumbnail_data])
File.open("test.jpg", "wb") do |f| f.write data end

data = Base64.decode64(params[:thumbnail_data].split(",")[-1])
File.open("test.jpg", "wb") do |f| f.write data end

It seems like no matter what I do, whenever I try to open the uploaded image preview says that the file has been corrupted. Could the problem be something to do with NSData endianness? or perhaps I'm not formatting the Base64 correctly? I've tried using a variety of gems as well.

似乎无论我做什么,每当我尝试打开上传的图像预览时都说文件已损坏。问题可能与NSData字节顺序有关吗?或者我可能没有正确格式化Base64?我也尝试过使用各种宝石。

2 个解决方案

#1


0  

You could set your thumbnail_data to just Base64 code as shown below and change the request HTTP body:

您可以将thumbnail_data设置为Base64代码,如下所示,并更改请求HTTP正文:

var submitData: Dictionary<String, AnyObject>!
submitData = ["name": "Brian"]
submitData["thumbnail_data"] = "R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"

let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: NSURL(string: "http://localhost:3000/people")!)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(submitData, options: [])
request.HTTPMethod = "POST"

let task = session.dataTaskWithRequest(request) {
    (data: NSData?, response: NSURLResponse?, error: NSError?) in
    //Handle server response
}
task.resume()

Specially if you want to upload an image directly from the device, in that case you should first create a representation and then encode it:

特别是如果您想直接从设备上传图像,在这种情况下,您应首先创建一个表示,然后对其进行编码:

let jpegRep = UIImageJPEGRepresentation(image!, 0.75)
let base64Image = jpegRep!.base64EncodedStringWithOptions([])

Where image is a UIImage object and 0.75 is image quality

其中图像是UIImage对象,0.75是图像质量

On the server side, if you're using paperclip gem, you should have something like this:

在服务器端,如果你使用的是paperclip gem,你应该有这样的东西:

image = StringIO.new(Base64.decode64(params[:thumbnail_data]))
Something.create(:image => image)

Hope this helps

希望这可以帮助

#2


0  

I had a similar problem and after few days of headaches came to solution:

我遇到了类似的问题,经过几天的头痛解决后:

just replace self.capturePhotoView.image with your image

只需将self.capturePhotoView.image替换为您的图像即可

if let capturePhotoImage = self.capturePhotoView.image {
    if let imageData = UIImagePNGRepresentation(capturePhotoImage) {
        let encodedImageData = imageData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
    }
}

and then decode it like this on your server side assuming you have paperclip on you Image model.

然后在您的服务器端解码它,假设您在图像模型上有回形针。

image = StringIO.new(Base64.decode64(params[:image].tr(' ', '+')))
image.class.class_eval { attr_accessor :original_filename, :content_type }
image.original_filename = SecureRandom.hex + '.png'
image.content_type = 'image/png'

create_image = Image.new(image: image)
create_image.save!

Hope this helps https://blog.kodius.io/2016/12/30/upload-image-from-swift-3-ios-app-to-rails-5-server/

希望这有助于https://blog.kodius.io/2016/12/30/upload-image-from-swift-3-ios-app-to-rails-5-server/

#1


0  

You could set your thumbnail_data to just Base64 code as shown below and change the request HTTP body:

您可以将thumbnail_data设置为Base64代码,如下所示,并更改请求HTTP正文:

var submitData: Dictionary<String, AnyObject>!
submitData = ["name": "Brian"]
submitData["thumbnail_data"] = "R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"

let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: NSURL(string: "http://localhost:3000/people")!)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(submitData, options: [])
request.HTTPMethod = "POST"

let task = session.dataTaskWithRequest(request) {
    (data: NSData?, response: NSURLResponse?, error: NSError?) in
    //Handle server response
}
task.resume()

Specially if you want to upload an image directly from the device, in that case you should first create a representation and then encode it:

特别是如果您想直接从设备上传图像,在这种情况下,您应首先创建一个表示,然后对其进行编码:

let jpegRep = UIImageJPEGRepresentation(image!, 0.75)
let base64Image = jpegRep!.base64EncodedStringWithOptions([])

Where image is a UIImage object and 0.75 is image quality

其中图像是UIImage对象,0.75是图像质量

On the server side, if you're using paperclip gem, you should have something like this:

在服务器端,如果你使用的是paperclip gem,你应该有这样的东西:

image = StringIO.new(Base64.decode64(params[:thumbnail_data]))
Something.create(:image => image)

Hope this helps

希望这可以帮助

#2


0  

I had a similar problem and after few days of headaches came to solution:

我遇到了类似的问题,经过几天的头痛解决后:

just replace self.capturePhotoView.image with your image

只需将self.capturePhotoView.image替换为您的图像即可

if let capturePhotoImage = self.capturePhotoView.image {
    if let imageData = UIImagePNGRepresentation(capturePhotoImage) {
        let encodedImageData = imageData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
    }
}

and then decode it like this on your server side assuming you have paperclip on you Image model.

然后在您的服务器端解码它,假设您在图像模型上有回形针。

image = StringIO.new(Base64.decode64(params[:image].tr(' ', '+')))
image.class.class_eval { attr_accessor :original_filename, :content_type }
image.original_filename = SecureRandom.hex + '.png'
image.content_type = 'image/png'

create_image = Image.new(image: image)
create_image.save!

Hope this helps https://blog.kodius.io/2016/12/30/upload-image-from-swift-3-ios-app-to-rails-5-server/

希望这有助于https://blog.kodius.io/2016/12/30/upload-image-from-swift-3-ios-app-to-rails-5-server/