Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: Image upload with JavaScript - File is damaged, corrupted or too large

I am using Spring Boot as backend server and I have a JavaScript frontend. For sending data between front- and backend I'm using the Axios library, which usually works pretty fine.

The Problem:
The image looks like this in the (Chrome) browser console: Console output It's a very very long alphanumeric string and that's what I send to the server with the following code:

static uploadFiles(files) {
    const data = new FormData();

    Object.keys(files).forEach(key => {
        data.append("files", new Blob([files[key]], { type: 'image/jpeg' }));
    });

    const url = API_URL + "uploadFiles";
    return axios.post(url, data, RestServices.getAuth({
        "Content-Type": "multipart/form-data;boundary=gc0p4Jq0M2Yt08jU534c0p"
    }));
}

I have no idea what the boundary thing does but it worked to receive a file in the backend tho...

On backend (spring) side I successfully receive an array of MultipartFiles:

@RequestMapping(value = "/uploadFiles", method = RequestMethod.POST)
@ResponseBody
public boolean uploadFiles(HttpServletRequest request, @RequestParam("files") MultipartFile[] files) throws IOException {
    String filePath = Thread.currentThread().getContextClassLoader().getResource("assets/images/").getFile();
    InputStream inputStream;
    OutputStream outputStream;
    for(MultipartFile file : files) {
        File newFile = new File(filePath + file.getOriginalFilename() + ".jpg");
        inputStream = file.getInputStream();

        if (!newFile.exists() && newFile.createNewFile()) {
            outputStream = new FileOutputStream(newFile);
            int read;
            byte[] bytes = new byte[1024];

            while ((read = inputStream.read(bytes)) != -1) {
                outputStream.write(bytes, 0, read);
            }
        }
        System.out.println(newFile.getAbsolutePath());
    }
    return true;
}

I've also tried it file.transferTo(newFile); instead of in- and outputstreams - which didn't work either.
After that I get the following output, which means that the image was saved successfully: /path/to/blob.jpg
If I check the path where the file was uploaded, there is a file named blob.jpg, but if I open it, the windows photo viewer has the following problem: Error in windows photo viewer I've opened the image before and after upload with notepad++:
Before upload: Image before upload (Byte Array) I think this is a byte array, but If I open the image after upload I get exactly the output of the browser. This means it didn't get converted to a byte array (correct me if I'm wrong) and I believe that's why it's a corrupt image...

My questions are:

  • What's the problem?
  • How can I fix it?

I really tried everything which crossed my mind but I ran out of ideas.

Thanks for your help! :-)


I've read following *related* questions (but they **don't** have an answer):
[Question1][5], [Question2][6], and **many** more...

like image 607
patwis Avatar asked Nov 16 '17 12:11

patwis


1 Answers

I've finally found an answer on my own!

I think the problem was that I used the e.target.result (which is used to show the image on the frontend) but insted I had to use the JS File object. The standard HTML 5 file input fields return those File objects (as I've read here).

The only thing I had to do now is to make a FormData object, append the File Object, set the FormData as Body and set the Content-Type header and that's it!

const data = new FormData();
data.append("files", fileObject);
return axios.post(url, data, {
    "Content-Type": "multipart/form-data"
});

Those JS File Objects are recognized from Java as Multipart files:

@RequestMapping(value = "/uploadFiles", method = RequestMethod.POST)
@ResponseBody
public boolean uploadFiles(HttpServletRequest request, @RequestParam("files") MultipartFile[] files) {

    boolean transferSuccessful = true;

    for (MultipartFile file : files) {
        String extension = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.'));

        String newFileName = genRandomName() + extension; //set unique name when saving on server
        File newFile;

        File imageFolder = new File(imageBasePath);
        //check if parent folders exist else create it
        if(imageFolder .exists() || imageFolder .mkdirs()) {
            while ((newFile = new File(imageFolder .getAbsolutePath() + "\\" + newFileName)).exists()) {
                newFileName = genRandomName(); //generate new name if file already exists
            }
            try {
                file.transferTo(newFile);
            } catch (IOException e) {
                e.printStackTrace();
                transferSuccessful = false;
            }
        } else {
            LOG.error("Could not create folder at " + imageFolder.getAbsolutePath());
            transferSuccessful = false;
        }
    }
    return transferSuccessful;
}

I hope this is helpful :)

like image 153
patwis Avatar answered Oct 23 '22 21:10

patwis