Checking HTML5 drag and drop file type

13,961

Solution 1

You can get the file types in Gecko and webkit supported browsers using file object.

var files =e.dataTransfer.files||e.target.files; // File list

The file object returns Name,Type and size. you can get last modified date too.

var mimeType= files[0].type; //mime type of file list first entry

Solution 2

Testing the type of a file in JavaScript is a bit of work, but new versions of the browsers now have the FileReader object that allows you to do that.

There is an incomplete reference to my implementation which reads the buffer as uint8 bytes and then checks to see whether the input is a valid JPEG, GIF, PNG. Obviously, it will be enhanced with time. For a more complete version, look for the editor.js file in the editor plugin of the snapwebsites project. https://sourceforge.net/p/snapcpp/code/ci/master/tree/snapwebsites/plugins/editor/

// The buffer is expected to be an ArrayBuffer() as read with a FileReader
_buffer2mime: function(buffer)
{
    buf = Uint8Array(buffer);
    if(buf[0] == 0xFF
    && buf[1] == 0xD8
    && buf[2] == 0xFF
    && buf[3] == 0xE0
    && buf[4] == 0x00
    && buf[5] == 0x10
    && buf[6] == 0x4A  // J
    && buf[7] == 0x46  // F
    && buf[8] == 0x49  // I
    && buf[9] == 0x46) // F
    {
        return "image/jpeg";
    }
    if(buf[0] == 0x89
    && buf[1] == 0x50  // P
    && buf[2] == 0x4E  // N
    && buf[3] == 0x47  // G
    && buf[4] == 0x0D  // \r
    && buf[5] == 0x0A) // \n
    {
        return "image/png";
    }
    if(buf[0] == 0x47  // G
    && buf[1] == 0x49  // I
    && buf[2] == 0x46  // F
    && buf[3] == 0x38  // 8
    && buf[4] == 0x39  // 9
    && buf[5] == 0x61) // a
    {
        return "image/gif";
    }

    // unknown
    return "";
},

_droppedImageAssign: function(e){
    var img,id;
    img = new Image();
    img.src = e.target.result;
    ++this._uniqueId;
    id="snap-editor-image-"+this._uniqueId;
    jQuery(img).hide().attr("id",id).appendTo(e.target.snapEditorElement);
    jQuery("#"+id).show();
},

_droppedImage: function(e){
    var mime, r, a, blob;

    mime = snapwebsites.EditorInstance._buffer2mime(e.target.result);
    if(mime.substr(0, 6) == "image/")
    {
        r = new FileReader;
        r.snapEditorElement = e.target.snapEditorElement;
        r.onload = snapwebsites.EditorInstance._droppedImageAssign;
        a = [];
        a.push(e.target.snapEditorFile);
        blob = new Blob(a, {type: mime}); // <- FORCE THE REAL MIME TYPE
        r.readAsDataURL(blob);
    }
},

jQuery("#some-object")
        .on("drop",function(e){
            // always prevent the default dropping mechanism
            // we handle the file manually all the way
            e.preventDefault();
            e.stopPropagation();

            // anything transferred on widget that accepts files?
            if(e.originalEvent.dataTransfer
            && e.originalEvent.dataTransfer.files.length)
            {
                accept_images = jQuery(this).hasClass("image");
                accept_files = jQuery(this).hasClass("attachment");
                if(accept_images || accept_files)
                {
                    for(i = 0; i < e.originalEvent.dataTransfer.files.length; ++i)
                    {
                        // read the image so we can make sure it is indeed an
                        // image and ignore any other type of files
                        r = new FileReader;
                        r.snapEditorElement = this;
                        r.snapEditorFile = e.originalEvent.dataTransfer.files[i];
                        r.onload = snapwebsites.EditorInstance._droppedImage;
                        // Get the first 64 bytes of the file to check the magic code
                        r.readAsArrayBuffer(r.snapEditorFile.slice(0, 64));
                    }
                }
            }

            return false;
        })

Solution 3

I don't think you can rely on the browser to give you the MIME type. It'd be much simpler if you checked the filename extension. :)

If you really want to check the file type, read the payload using DataTransfer.getData() and check the leading bytes (PNG, GIF89, JFIF or something).

Share:
13,961

Related videos on Youtube

Mikko Ohtamaa
Author by

Mikko Ohtamaa

Building Trading Strategy, a decentralised algorithmic trading protocol

Updated on June 04, 2022

Comments

  • Mikko Ohtamaa
    Mikko Ohtamaa almost 2 years

    I'd like to change drop zone background color to green or red depending on whether the contained drag over payload contains supported file types (JPEG).

    • Do Gecko and Webkit support determining the file type of drag and drop files?

    • How one can extract the file type in these two browsers?

    I have found event.dataTransfer.types API, but for Firefox it seems to be populated with application/x-moz-file and thus I think I am doing something wrong.

    • robertc
      robertc over 12 years
      Should work in Gecko, WebKit restricts access to the data transfer object on drag over. What code do you have at the moment?
  • jayarjo
    jayarjo over 11 years
    Why || e.target.files fallback? Does it take into account some unexpected case or something?
  • Alexis Wilke
    Alexis Wilke about 10 years
    So you really think that the filename extension is a more trustworthy indication of the file type??? Checking the data is the only real way to make sure. The file magic as it's called.
  • Alexis Wilke
    Alexis Wilke about 10 years
    Note that this MIME type is generated using the file extension (i.e. the .gif or .jpeg at the end of the filename.) This is definitively not going to be the real type of the file in all cases. Many people will put .jpg when they save a PNG or BMP file... because they know .jpg means "image".
  • Chris Janssen
    Chris Janssen almost 8 years
    @AlexisWilke, I think your case is an extreme corner case. Most people when saving a file dont type the extension (or it is hidden) in windows. But more importantly, I doubt most programs have fallback detection to figure out the filetype from the data itself when the extension doesnt match. E.g. adding .jpg at the end of a png file and trying to open it in photoshop (the #1 photo editor) leads to photoshop throwing an error that it is an invlaid jpg. If you have extension detection, and the user changes it to the wrong one, then that is their issue, not yours. Crap in, Crap out.
  • Alexis Wilke
    Alexis Wilke almost 8 years
    @ChrisJanssen at the same time, we are talking about files that will be sent by person A to server B which then serves that same file to person C...
  • Chris Janssen
    Chris Janssen almost 8 years
    And why is the filetype changing along that path? Every OS uses the filetype to determine what a file is and what the appropriate program to open it with, it doesn't parse the beginning data to make that decision, it trusts that the filetype wasn't changed. In most cases it warns the user not to change a filetype as it may stop functioning. Why not just keep it simple and check the filetype?
  • Loenix
    Loenix over 7 years
    I am trying to do that with a dragenter event in the last version of Firefox but files is null...