7

I’m using Expo’s image picker and I’m getting this output:

Object {
  "cancelled": false,
  "height": 468,
  "uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540jbaek7023%252Fstylee/ImagePicker/9a12f0a3-9260-416c-98a6-51911c91ddf4.jpg",
  "width": 468,
}

I could render my image, but I just realized that the URL is the phone’s local URI.

I’m using Redux-Thunk and Axios to send HTTP POST request:

export const sendPost = ( imageUri, title, content ) => async dispatch => {
  let response = await axios.post(`${ROOT_URL}/rest-auth/registration/`, {
    image, <<<<- I can't put image uri here :( it's LOCAL path
    title,
    content
  })

  if(response.data) {
    dispatch({ type: POST_CREATE_SUCCESS, payload: response.data.token })
  } else {
    dispatch({ type: POST_CREATE_FAIL })
  }
}

UPDATE I changed a request call

let headers = { 'Authorization': `JWT ${token}`};
  if(hType==1) {
    headers = { 'Authorization': `JWT ${token}`};
  } else if (hType==2) {
    headers = { 'Authorization': `Bearer ${token}`};
  }

let imageData = new FormData();
imageData.append('file', { uri: image });
let response = await axios.post(`${ROOT_URL}/clothes/create/`, {
    image: imageData,
    text, bigType, onlyMe ...
  }, {headers});

!! sorry for the complication but image variable name; image is uri for the image. I didn't want to change the name of original variable name

and on server, it's printing

'image': {'_parts': [['file', {'uri': 'file:///data/user/0/host.exp.exponent
    /cache/ExperienceData/%2540jbaek7023%252Fstylee/
    ImagePicker/78f7526a-1dfa-4fc9-b4d7-2362964ab10d.jpg'}]]}

I found that gzip compression is a way to send image data. Does it help?

merry-go-round
  • 4,533
  • 10
  • 54
  • 102
  • This answer may help you https://stackoverflow.com/a/34972537/3514603 – Radovan Kuka Oct 26 '17 at 10:30
  • I'm looking into it. But I think React has better option than vanila js – merry-go-round Oct 26 '17 at 10:43
  • 1
    React is just a UI library. Nothing more and nothing less. And you want to work with XHR. You can use [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) for uploading image if your backend support this format at that endpoint. – Radovan Kuka Oct 26 '17 at 11:28
  • @RadovanKuka I think I have to follow your case. Could you post an answer for me? – merry-go-round Nov 02 '17 at 15:06
  • What answer do you mean? I suggested FormData as was suggested also by others or you can convert that image to Base64 as was answered in linked question. – Radovan Kuka Nov 03 '17 at 07:48

3 Answers3

4

It has to be a local URI, there's no issues with that, how else are you going to point to the image.

Now to upload the image you should first wrap it inside of FormData:

// add this just above the axios request
let img = new FormData();
img.append('file', { uri: imageUri });

Then inside of your axios request body add:

image: img,

EDIT: This question in it's current form is unanswerable.

I'm using the same Expo’s image picker with React-native in one of my projects as OP and everything works just fine, there's no issues with FormData.

After having talked with OP in a stackoverflow chat, couple of days ago, and stripping the request down to just an image, the server started throwing encoding errors:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 168: invalid start byte

So the issue is with OP's Django backend not being setup correctly in parsing the image, and not with the sending of the image itself - which makes the question unanswerable.

linasmnew
  • 3,907
  • 2
  • 20
  • 33
  • Wow. I hope this works. Let me test it on my computer before I accept it. – merry-go-round Oct 26 '17 at 10:44
  • Thanks for your intrest but I'm working on UI part before I send a request. I will test it in 24 hours (hopefully) – merry-go-round Oct 27 '17 at 11:14
  • 'image': {'_parts': [['file', {'uri': 'file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540jbaek7023%252Fstylee/ImagePicker/78f7526a-1dfa-4fc9-b4d7-2362964ab10d.jpg'}]]} – merry-go-round Nov 02 '17 at 09:16
  • Hi! I'm getting this output on console. I think it's pointing to the image correctly but it's not sending an actual image. – merry-go-round Nov 02 '17 at 09:17
  • The image in { uri: image } has to be just the 'uri' portion not the whole image object like you console.log'ed – linasmnew Nov 02 '17 at 09:52
  • sorry for the complication but image is image 'uri'. I didn't want to change the name of original variable name – merry-go-round Nov 02 '17 at 09:54
  • You might be missing some headers I'm not familiar with axios so I dont know how helpful it is, but the above definately works when using with fetch, try adding this header: 'content-type': 'multipart/form-data' and on server side you need to have some image processor like Multer that will process the image and add it to req.file – linasmnew Nov 02 '17 at 10:31
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/158062/discussion-between-linas-mickevicius-and-john-baek). – linasmnew Nov 02 '17 at 10:48
  • I just included header on the question. Thanks for asking – merry-go-round Nov 02 '17 at 11:12
  • I could get current logged in user from header. Header seems ok to me. But I think the way to send an image is not correct :( – merry-go-round Nov 02 '17 at 11:13
  • 1
    I understand that the request is working, problem is with type, add 'content-type': 'multipart/form-data' – linasmnew Nov 02 '17 at 11:45
  • I think something is wrong with header. let headers = { 'Authorization': `JWT ${token}`, 'content-type': 'multipart/form-data'}; It's giving me 400 error. I'm working on this. – merry-go-round Nov 02 '17 at 11:55
  • I think I need to imageData.append(text), imageData.append(bigType) rather than putting imageData as a param – merry-go-round Nov 02 '17 at 12:04
  • I think converting image into base64 format will be the best answer. Because it works. Thanks for your input. I appreciate it – merry-go-round Nov 09 '17 at 15:33
  • Honestly a lifesaver. I have been revolving around this and finally got an actual solution. Many thanks to you sir/madam – Reznov Sep 29 '22 at 17:42
4

Another option is to convert your image to base64 and send the string. Downsize is that usually the base64 strings has a bigger size than the image itself.

Something like this:

function readImage(url, callback) {   
    var request = new XMLHttpRequest();
    request.onload = function() {
       var file = new FileReader();
       file.onloadend = function() {
          callback(file.result);
       }
       file.readAsDataURL(request.response);
    };   
    request.open('GET', url);   
    request.responseType = 'blob';              
    request.send(); 
}
Abhishek Ghosh
  • 2,593
  • 3
  • 27
  • 60
sebastianf182
  • 9,844
  • 3
  • 34
  • 66
2

you cant use react-native-fetch-blob .....

import RNFetchBlob from " react-native-fetch-blob"
  PostRequest(PATH){
      RNFetchBlob.fetch('POST', "[URL]", {

            "x-session-id": "SESSION_ID", //or Custom headers
            'Content-Type': 'multipart/form-data',

        }, [

                { name: 'image', filename: 'vid.jpeg', data: RNFetchBlob.wrap(PATH) },
                // custom content type

            ]).then((res) => {
                console.log(res)

            })
            .catch((err) => {
                console.log(err)
                // error handling ..
            })
        }
  }

for reference react-native-fetch-blob

Rajat Gupta
  • 1,864
  • 1
  • 9
  • 17