0

If this seems like a dupe, sorry. I'm trying to ask a very specific question, and not sure my searching has really led me to the right place. Anyway, here's the setup. Take a picture on the iPhone camera, turn it into base64 string data, shove it up the wire to a Node API, turn that into a file to shove onto S3. Pretty straight forward.

General disclaimers apply; I'd prefer to use a B64 string in JSON for simplicity and universality, and I'll withhold further comments on the silliness of form-encoded uploads :)

Here's my very simple Swift code to produce B64, turn it back into an image, and display it as a proof that the stuff works - at least in Apple land.

Note: "redButton" is one of the assets in my app. I switched to that for the sake of sending much smaller packets at the API for testing, but the results remain. Thanks.

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        // build data packet
        imagePicker.dismiss(animated: true, completion: nil)
        //let image:UIImage = (info[UIImagePickerControllerOriginalImage] as? UIImage)!
        let image:UIImage = UIImage(named: "redButton")!
        showAlert( title: "size", msg: String( describing: image.size ) )
        let data = UIImageJPEGRepresentation(image, 0.5)
        let b64 = data!.base64EncodedData()//.base64EncodedString()//options: Data.Base64EncodingOptions.lineLength64Characters)
        let b64String = b64.base64EncodedString()
        debugPrint( "len=" + String( describing: b64String.lengthOfBytes(using: String.Encoding.utf8)))
        let newDataString = Data.init(base64Encoded: b64String )
        let newData = Data.init(base64Encoded: newDataString! )
        let newImage = UIImage.init(data: newData!)
        tmpImage.image = newImage
}

That all works. I see the image in the little UIImage.

So at least fully in the Apple camp, the img->b64->img works.

However...

When I copy the actual resulting blob of b64-encoded string data, and manually paste it into the source attribute, marked up with the data stuff, it does NOT display the expected image, and in fact, just shows a broken image in the browser.

ie...

<html>
<body>
    <img src="data:image/jpg;base64,LzlqLzRBQVFTa1pKUmdBQkFRQUFTQUJJ (brevity)...">
</body>
</html>

So, am I doing something wrong in my proofing in the HTML page? Am I expecting the wrong results from what Apple calls base64 string data? Am I just plain missing something painfully obvious that my sleep-deprived brain is missing?

It eventually gets sent to the server in an HTTP POST call, per normal means, as a dictionary, turned into json via the json encoding stuff in newer Swift.

var params = ["image": [ "content_type": "image/jpg", "filename":"test.jpg", "file_data": b64String] ]

And for the sake of compeleteness, here's the Node code where I reconstitute this data into a binary bit, and from here I shove it up to the S3 system, and in every case, the file is not recognized as a proper JPG file.

var b64 = req.body.image.file_data;
var base64data = new Buffer(b64, 'base64'); // according to all the new-node version docs

I'm on the home stretch of a crunch-time product that we're shoving at investors next week, and apparently this is a critical feature to show off for that meeting.

Tell me I'm missing something painfully obvious, and that I'm stupid. I welcome it, please. It can't not be just something stupid, right?

Thanks!

ChrisH
  • 975
  • 12
  • 21
  • This might help you: https://stackoverflow.com/questions/695151/data-protocol-url-size-limitations – Cristik Mar 09 '18 at 13:12
  • The little file in question (redButton), for testing in the browser and for faster transfers, is about 11k in total after b64'ing. It's just a small button face for a corner-cancel button. :\ – ChrisH Mar 09 '18 at 13:25
  • Thank you, though. That helped clear up my concerns over the data size. – ChrisH Mar 09 '18 at 13:35

1 Answers1

1

Here:

let b64 = data!.base64EncodedData()
let b64String = b64.base64EncodedString()

you encode the given data twice. It should be just

let b64String = data!.base64EncodedString()

Your “in Apple land” test works because

let newDataString = Data.init(base64Encoded: b64String )
let newData = Data.init(base64Encoded: newDataString! )

also decodes the Base64 twice. That would now be just

let newData = Data(base64Encoded: b64String)
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • I'd had that originally, but I went full on verbose and multi-step as part of my proofing test. I'll chop it back and retry. Thanks. – ChrisH Mar 09 '18 at 13:26
  • omg. Yep... sleep-addled, dumb, totally missed it. Thank you for the fresh eyes. – ChrisH Mar 09 '18 at 13:33
  • (reply to post-edit comment) Yep, I finally went to bed at like 3am after thinking all day yesterday, "I'll handle the upload stuff later while I get this other stuff done." I now see that I was completely stuck in a loop in my head, apparently thinking, "nope, I need an existing data object, and THAT i can put out to a string", and second-tiering the whole damned thing, making a mess of it, and only digging deeper into my mistake. Thank you again! Fresh eyes, and clearer heads prevail :) – ChrisH Mar 09 '18 at 13:43