JavaScript and HTML5: read a file and base64 encode it

jclose

Member
Jun 30, 2000
101
0
76
I am having some issues getting a chunk of code to work. Most of it works, but not the important parts. I am very new to JavaScript.

The short version of what I am trying to accomplish: read in a file from the user (a binary image file), and display to the browser window the base64 encoded result.

HTML5 file handling is from: http://www.html5rocks.com/en/tutorials/file/dndfiles/

Base64 Encoding code from: David Lindquist


My current code:
Code:
<script>
  function b64Enc(str) {
      /*
       * base64.js - Base64 encoding and decoding functions
       * See: http://developer.mozilla.org/en/docs/DOM:window.btoa
       *      http://developer.mozilla.org/en/docs/DOM:window.atob
       * Copyright (c) 2007, David Lindquist <david.lindquist@gmail.com>
       * Released under the MIT license
       *  [edited by me]
      */
 b64Enc()
      var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
      var encoded = [];
      var c = 0;
      while (c < str.length) {
          var b0 = str.charCodeAt(c++);
          var b1 = str.charCodeAt(c++);
          var b2 = str.charCodeAt(c++);
          var buf = (b0 << 16) + ((b1 || 0) << 8) + (b2 || 0);
          var i0 = (buf & (63 << 18)) >> 18;
          var i1 = (buf & (63 << 12)) >> 12;
          var i2 = isNaN(b1) ? 64 : (buf & (63 << 6)) >> 6;
          var i3 = isNaN(b2) ? 64 : (buf & 63);
          encoded[encoded.length] = chars.charAt(i0);
          encoded[encoded.length] = chars.charAt(i1);
          encoded[encoded.length] = chars.charAt(i2);
          encoded[encoded.length] = chars.charAt(i3);
      }
      alert ( "Done" ) ;   //OK, it got here...but no output.
      return encoded.join('');
  }
  
  function handleFileSelect(evt) {
    evt.stopPropagation();
    evt.preventDefault();
    var inputFiles = evt.dataTransfer.files; // Gets a FileList object - a list of File objects.
    var fReader = new FileReader () ;  
    var output = [];
    for (var i = 0, f; f = inputFiles[i]; i++) {
      if ( !f.type.match('image.*')) { continue; }    //Breaks out of current loop iteration, i.e. skip non-image files
      alert ( "Image file found!");
      
      fReader.onLoad = (
        function (aFile) {
          return function (e) { output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
                  f.size, ' bytes, last modified: ',
                  f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a',
                  '<br><br>' , b64Enc(e.target.result) , '<br><br>End File', '</li>');
          };
        }
      ) (f);
      
      fReader.readAsText(f);
    }
    document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
  }

  function handleDragOver(evt) {
    evt.stopPropagation();
    evt.preventDefault();
    evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
  }
  
  // Setup the dnd listeners.  [Slightly modified by JC]
  var dropZone = document.getElementById('filedrag');
  dropZone.addEventListener('dragover', handleDragOver, false);
  dropZone.addEventListener('drop', handleFileSelect, false);
</script>


Here is the sample code that I am using as my template.

Code:
//////////////////////
//  from http://www.html5rocks.com/en/tutorials/file/dndfiles/
//////////////////////
  function handleFileSelect(evt) {
    var files = evt.target.files; // FileList object

    // Loop through the FileList and render image files as thumbnails.
    for (var i = 0, f; f = files[i]; i++) {

      // Only process image files.
      if (!f.type.match('image.*')) {
        continue;
      }

      var reader = new FileReader();

      // Closure to capture the file information.
      reader.onload = (
          function(theFile) {
              return function(e) {
                // Render thumbnail.
                var span = document.createElement('span');
                span.innerHTML = ['<img class="thumb" src="', e.target.result,
                                  '" title="', escape(theFile.name), '"/>'].join('');
                document.getElementById('list').insertBefore(span, null);
              };
          }
      )(f);

      // Read in the image file as a data URL.
      reader.readAsDataURL(f);
    }
  }

  document.getElementById('files').addEventListener('change', handleFileSelect, false);

it is that inner-inner function that uses the 'e.target.result' that is confusing me a good bit. I am not quite grasping what the flow of calls and parameters is, and what the truly represents.

Thanks again,
J