Read Binary Data from blob to display Image React Native
Asked Answered
C

1

2

here's the flow of what I have to do:

  1. take image with image picker for react native and get the image data in base64 (sourceData)
ImagePicker.showImagePicker(imagePickerOptions, (response) => {
    const sourceData = { uri: 'data:image/jpeg;base64,' + response.data };
});
  1. Post the sourceData.uri to a server running locally on my machine:
const data = new FormData();
data.append('receipt', {
    uri: sourceData.uri,
    type: 'image/jpeg',
    name: 'receipt'
});

const response = await fetch(SERVER_POST_ROUTE, {
    method: 'POST',
    headers: {
        'Accept': 'application/json',
        'Content-Type': 'multipart/form-data',
    },
    body: data
});

The sourceData.uri looks like this:

'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAASABIAAD/4QBYRXhpZgAATU0AKgAAAAgAAgESAAMAAAABAAEAAIdpAAQAAAABAAAAJgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAABLKADAAQAAAABAAAA4QAAAAD/7QA4UGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAAA4QklNBCUAAAAAABDUHYzZjwCyBOmACZjs+EJ+/8AAEQgA4QEsAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/bAEMABgYGBgYGCgYGCg4KCgoOEg4ODg4SFxISEhISFxwXFxcXFxccHBwcHBwcHCIiIiIiIicnJycnLCwsLCwsLCwsLP/bAEMBBwcHCwoLEwoKEy4fGh8uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u<…>'
  1. That's the server POST route (shortened)
router.post('/:id/receipts', (req, res) => {
  const id = req.params.id
  const expense = expenses.find((expense) => expense.id === id)

  if (expense) {
    const receipt = req.files.receipt as UploadedFile
    const receiptId = `${id}-${expense.receipts.length}`
    receipt.mv(`${process.cwd()}/receipts/${receiptId}`, (err) => {

      expense.receipts.push({
        url: `/receipts/${receiptId}`
      })
      res.status(200).send(expense)

    })

  } else {
    res.status(404)
  }
})
  1. That's what the server gets when I console.log(receipt)
{ name: 'receipt',
  data:
   <Buffer ff d8 ff e0 00 10 4a 46 49 46 00 01 01 00 00 48 00 48 00 00 ff e1 00 58 45 78 69 66 00 00 4d 4d 00 2a 00 00 00 08 00 02 01 12 00 03 00 00 00 01 00 01 ... >,
  encoding: '7bit',
  truncated: false,
  mimetype: 'image/jpeg',
  md5: SOME_MD5_STRING,
  mv: [Function: mv] }
  1. As you see, the server moves the file to a local location receipt.mv(`${process.cwd()}/receipts/${receiptId}`)

6. MY PROBLEM: I need to access this location and turn what I get back into an image

What I am doing right now: - Use fetch to get what is at that location and extract the blob

const response = await fetch(FILE_LOCAL_URL);
const blob = await response.blob();
  • And that's what I get when I console.log(blob)
{ _data: 
   { size: 23296,
     offset: 0,
     blobId: 'F8F693CD-6FBB-41C8-95E3-E54EB2A82F63',
     type: 'application/octet-stream',
     name: '5b996064dfd5b783915112f5-3' } }

Now: I can't figure out how to turn this binary file into an base64 string to add to the uri of the image. That's what I tried, but obviously it does not work:

<Image 
    source={{ uri: 'data:image/jpeg;base64,' + blob._data }}
    style={{height: 120, width: 80}}/>

Any help is truly appreciated. Thanks

Carbonado answered 3/11, 2019 at 10:16 Comment(1)
for fetch file you can use github.com/joltup/rn-fetch-blob. fetch don't properly work for fetch fileSilvery
C
5

Actually I solved it: to read the blob ideally you should use readAsArrayBuffer but it is not implemented in react native (read also https://forums.expo.io/t/blob-object-how-can-i-access-the-blobs-raw-data-as-an-arraybuffer/9717). But you can use readAsDataURL What I was looking for is stored in reader.result.

const response = await fetch(URL_OF_BINARY_DATA_FILE);
const blob = await response.blob();
var reader = new FileReader();
reader.onload = () => {
   console.log(reader.result);  
}
reader.readAsDataURL(blob);
Carbonado answered 5/11, 2019 at 9:18 Comment(1)
This only works on expo projects and not pure RN projects. The RN fetch does not send blob data over the RN bridge so you can't read it from the JS side.Parotitis

© 2022 - 2024 — McMap. All rights reserved.