0

Here are the steps my application is doing:

  1. User uploads an image (.PNG) file in the browser.
  2. Browser sends the raw image data to my server.
  3. The server then saves the file in my file system.

The problem is that my file system complains that the file is not a PNG file when I try to open it.

I'm trying to localize where the problem occurs without success. When I look at the file data using VIM it looks the same to me, with the same number of lines and the file contents both start with:

<89>PNG^M
 ^Z
 ^@^@^@^MIHDR^@^@^BD^@^@^@Î^H^B^@^@^@P6<8a><9a>^@^@^@^CsBIT^H^H^HÛáOà^  ^@^@_zTXtRaw profile type APP1^@^@^H<99>ãJOÍK-ÊLV((ÊOËÌIåR^@^Cc^S.   ^SK^SK£D^C^C^C^K^C^H04006^D<92>F@          
...             

However, the file sizes are different, with the file I'm writing from my server being larger. So obviously they are different in some way.

I tried doing diff file1 file2 in the command line and it just gives me binary files differ without showing me the difference... ?? Strange.

So I'm currently confused about how the files differ, and where in my code this difference gets introduced...

I feel I'm missing some crucial knowledge about how some things work here under the hood, and I would very much appreciate if someone smarter than me could help me out here.

Code

Client:

<input id="icon-button-file" type="file" onChange={handleChange} />
<label htmlFor="icon-button-file">
    <Button/>
</label>

 function handleChange(event: any) {
        if (!event.target.files[0]) return

        const file = event.target.files[0]
        const reader = new FileReader()

        reader.onload = function (e) {
            const instance = axios.create({
                baseURL: 'http://localhost:3000/',
                timeout: 5000,
                headers: { 'Content-Type': 'application/json' }
            })
            instance.post(
                'image',
                JSON.stringify({
                    imageData: e.target.result.toString()
                })
            ).then(result => {
                console.log(result)
            })
        }
        reader.readAsBinaryString(file)
}

Server:

app.post(`http://localhost:3000/image`, (req, res) => {
   fs.writeFile('img.png', req.body.imageData, (err) => {
      console.log(err)
   })
})

EDIT: I made it work by sending the image content to the server as a dataUrl instead, using reader.readAsDataUrl(). This encodes the image data as a Base64 string, which seems like a common practice. However, I'm still curious why sending the raw data doesn't work.

Alexmedkex
  • 427
  • 5
  • 13

2 Answers2

1

You can use Formidable to handle files in nodejs easily. Good to hear that you got it running already. I hope this helps to someone else. this covers some basics and yes another approach is to encode to Base64 and decode back to a file from the server side. cheers
var express = require('express'); var router = express.Router();

    var fs = require('fs');
    var formidable = require('formidable');
    /* GET home page. */
    router.get('/', function(req, res, next) {
      res.writeHead(200, {'Content-Type': 'text/html'});
      res.write('<form action="fileupload" method="post" enctype="multipart/form-data">');
      res.write('<input type="file" name="filetoupload"><br>');
      res.write('<input type="submit">');
      res.write('</form>');
      res.end()
    });
    router.post(`/fileupload`, (req, res) => {
      var form = new formidable.IncomingForm();
      form.parse(req, function (err, fields, files) {
        var oldpath = files.filetoupload.path;
        var newpath = './public/' + files.filetoupload.name;
        fs.rename(oldpath, newpath, function (err) {
          if (err) throw err;
          res.write('File uploaded and moved!');
          res.end();
        });
      });
    })
    module.exports = router;
Viroj Fernando
  • 461
  • 4
  • 8
0

Answering my own question.

The reason for the problem was that I was sending the image binary data over http which can corrupt the data.

See: https://stackoverflow.com/a/201510/6017605

Since base64 encodes it as text, it can safely be transmitted.

This also helped me understand the problem: https://www.jscape.com/blog/ftp-binary-and-ascii-transfer-types-and-the-case-of-corrupt-files

Alexmedkex
  • 427
  • 5
  • 13