Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at the New York ColdFusion User Group (Jan. 2010) with:

Showing Plupload Image Previews Using Base64-Encoded Data Urls

By Ben Nadel on

For the last few years, I've been using (and loving) Plupload as a means to perform rich, client-side file uploads in my AJAX-driven web applications. Typically, my workflow is such that I'll upload an image using Plupload, get back a JSON (JavaScript Object Notation) response from the server, and then render the image (or image thumbnail) in the browser. To augment the user's perception of the web app, however, I wanted to see if I could render a pre-uploaded version of the image using a data-url.


 
 
 

 
  
 
 
 

View this demo in my Plupload Image Preview project on GitHub.

To experiment with this concept, I downloaded the latest version of Plupload, which was v2.0.0 Beta at the time of this post. As it turns out, v2 has a whole bunch of stuff that I had never seen before. This includes utility classes for things like drop zones, images, and file readers. And, as luck would have it, the "File" and "Image" classes supplied by mOxie (Plupload authors) do exactly what I want; you can use the mOxie objects to read-in the client-side file objects and retrieve their data urls in base64-encoded format. These data urls can then be used to render client-side thumbnails before the image is even uploaded to the server.

To see this in action, I've created a completely paired-down Plupload demo that does nothing more than initialize the Plupload library and hook into the file-selection event. And, once the files have been selected, I am rendering them - immediately - on the client using base64-encoded data urls. I'm not even uploading the files to the server.

NOTE: View this post to see a full Plupload demo.

  • <!doctype html>
  • <html>
  • <head>
  • <meta charset="utf-8" />
  •  
  • <title>
  • Showing Plupload Image Previews Using Base64-Encoded Data Urls
  • </title>
  •  
  • <link rel="stylesheet" type="text/css" href="./assets/css/styles.css"></link>
  • </head>
  • <body>
  •  
  • <h1>
  • Showing Plupload Image Previews Using Base64-Encoded Data Urls
  • </h1>
  •  
  • <div id="uploader" class="uploader">
  •  
  • <a id="selectFiles" href="#">Select Files</a>
  •  
  • </div>
  •  
  • <ul class="uploads">
  • <!-- Will be populated dynamically with LI/IMG tags. -->
  • </ul>
  •  
  •  
  • <!-- Load and initialize scripts. -->
  • <script type="text/javascript" src="./assets/jquery/jquery-2.0.3.min.js"></script>
  • <script type="text/javascript" src="./assets/plupload/js/plupload.full.min.js"></script>
  • <script type="text/javascript">
  •  
  • (function( $, plupload ) {
  •  
  •  
  • // Find and cache the DOM elements we'll be using.
  • var dom = {
  • uploader: $( "#uploader" ),
  • uploads: $( "ul.uploads" )
  • };
  •  
  •  
  • // Instantiate the Plupload uploader.
  • var uploader = new plupload.Uploader({
  •  
  • // Try to load the HTML5 engine and then, if that's
  • // not supported, the Flash fallback engine.
  • runtimes: "html5,flash",
  •  
  • // The upload URL - for our demo, we'll just use a
  • // fake end-point (we're not actually uploading).
  • url: "./post.json",
  •  
  • // The ID of the drop-zone element.
  • drop_element: "uploader",
  •  
  • // To enable click-to-select-files, you can provide
  • // a browse button. We can use the same one as the
  • // drop zone.
  • browse_button: "selectFiles",
  •  
  • // For the Flash engine, we have to define the ID
  • // of the node into which Pluploader will inject the
  • // <OBJECT> tag for the flash movie.
  • container: "uploader",
  •  
  • // The URL for the SWF file for the Flash upload
  • // engine for browsers that don't support HTML5.
  • flash_swf_url: "./assets/plupload/js/Moxie.swf",
  •  
  • // Needed for the Flash environment to work.
  • urlstream_upload: true
  •  
  • });
  •  
  •  
  • // Set up the event handlers for the uploader.
  • // --
  • // NOTE: I have excluded a good number of events that are
  • // not relevant to the current demo.
  • uploader.bind( "PostInit", handlePluploadInit );
  • uploader.bind( "FilesAdded", handlePluploadFilesAdded );
  •  
  • // Initialize the uploader (it is only after the
  • // initialization is complete that we will know which
  • // runtime load: html5 vs. Flash).
  • uploader.init();
  •  
  •  
  • // ------------------------------------------ //
  • // ------------------------------------------ //
  •  
  •  
  • // I handle the init event. At this point, we will know
  • // which runtime has loaded, and whether or not drag-
  • // drop functionality is supported.
  • // --
  • // NOTE: For this build of Plupload, I had to switch from
  • // using the "Init" event to the "PostInit" in order for
  • // the "dragdrop" feature to be correct defined.
  • function handlePluploadInit( uploader, params ) {
  •  
  • console.log( "Initialization complete." );
  •  
  • console.log( "Drag-drop supported:", !! uploader.features.dragdrop );
  •  
  • }
  •  
  •  
  • // I handle the files-added event. This is different
  • // that the queue-changed event. At this point, we
  • // have an opportunity to reject files from the queue.
  • function handlePluploadFilesAdded( uploader, files ) {
  •  
  • console.log( "Files selected." );
  •  
  • // Show the client-side preview using the loaded File.
  • for ( var i = 0 ; i < files.length ; i++ ) {
  •  
  • showImagePreview( files[ i ] );
  •  
  • }
  •  
  • }
  •  
  •  
  • // I take the given File object (as presented by
  • // Plupoload), and show the client-side-only preview of
  • // the selected image object.
  • function showImagePreview( file ) {
  •  
  • var item = $( "<li></li>" ).prependTo( dom.uploads );
  • var image = $( new Image() ).appendTo( item );
  •  
  • // Create an instance of the mOxie Image object. This
  • // utility object provides several means of reading in
  • // and loading image data from various sources.
  • // --
  • // Wiki: https://github.com/moxiecode/moxie/wiki/Image
  • var preloader = new mOxie.Image();
  •  
  • // Define the onload BEFORE you execute the load()
  • // command as load() does not execute async.
  • preloader.onload = function() {
  •  
  • // This will scale the image (in memory) before it
  • // tries to render it. This just reduces the amount
  • // of Base64 data that needs to be rendered.
  • preloader.downsize( 300, 300 );
  •  
  • // Now that the image is preloaded, grab the Base64
  • // encoded data URL. This will show the image
  • // without making an Network request using the
  • // client-side file binary.
  • image.prop( "src", preloader.getAsDataURL() );
  •  
  • // NOTE: These previews "work" in the FLASH runtime.
  • // But, they look seriously junky-to-the-monkey.
  • // Looks like they are only using like 256 colors.
  •  
  • };
  •  
  • // Calling the .getSource() on the file will return an
  • // instance of mOxie.File, which is a unified file
  • // wrapper that can be used across the various runtimes.
  • // --
  • // Wiki: https://github.com/moxiecode/plupload/wiki/File
  • preloader.load( file.getSource() );
  •  
  • }
  •  
  •  
  • })( jQuery, plupload );
  •  
  • </script>
  •  
  • </body>
  • </html>

Most of the code in the demo is just there to setup the demo. The real meat of the code takes place in the showImagePreview() function. There, we use the Image object to read-in the underlying File source. Then, the Image object translates the source into a data url.

Pretty cool stuff! And, there is more stuff in the v2 build of Plupload that I'll be playing around with. Such an awesome library!



Looking For A New Job?

100% of job board revenue is donated to Kiva. Loans that change livesFind out more »

Reader Comments

Nice post. I am a bit Fran of plupload and This feature is very usefull. Does This work when Flash uploder is used or only html5 ?

Reply to this Comment

@Sabato,

I was able to get this to work with the Flash runtime; but, the image previews were of a lower quality than those produced in the HTML5 runtime.

Reply to this Comment

Hi,

Thanks for your post! It's not easy to find posts talking about plupload api!

Unfortunately I cant make this work with ie9... The onload event is not triggered, but the onerror one is. If I ouput the error I have this :

LOG: {"type":"error","target":{"uid":"uid_18jachmst5hunta1poq18hj1ge01o","ruid":"html4_18jachb2q193hko3198j17o616fg4","name":"Chrysanthemum.jpg","size":0,"width":0,"height":0,"type":"","meta":{},"onprogress":null,"onresize":null,"onembedded":null}}

Reply to this Comment

@Dip, @Nikhil,

I know that I was able to get it run in the Flash runtime on IE. But, I *may* have been using IE10 in my Virtual Machine - I don't remember offhand. I'll see if I can get some time to try it.

Reply to this Comment

I recently discovered plupload. It's very nice. However, when adding several images at the same time, the browser can freeze. This isn't an issue for me but my client seems to think "it's not right". I have been reading up on the .deferred() object in jQuery. But I'm not quite getting it.

Would it be possible to get some clues on how to execute the showImagePreview() function with a .deferred() object?

Thanks again!

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.