Wednesday, January 23, 2013

Multiple images uploading (with file size reduced) + MVC4, JQuery mobile, XMLHttpRequest, HTML5 File Api

I had to work with a project that had the functionality of multiple image files uploading. The specialty of the functionality was it had the ability of uploading larger images with reduced file sizes apart from uploading the original files. I thought of sharing the basic functionality of size reduced files-uploading.

Technologies used : MVC4, JQuery mobile, XMLHttpRequest, HTML5 File Api

MVC4 View

@{
    ViewBag.Title = "File Upload";
}

<div>
    <input type="file" accept="image/*" name="fileToUpload[]" id="fileToUpload" style='visibility: hidden;'
        name="img" onchange="fileSelected();" />
    <input type="button" value="Choose image"  onclick="javascript:document.getElementById('fileToUpload').click();">
    <ul data-role="listview" id="uploadfilelist" data-inset="true" data-split-theme="d"
        data-split-icon="delete">
    </ul>
</div>
<div>
    <ul data-role="listview" data-inset="true">
        <li data-role="fieldcontain">
            <input type="button" onclick="uploadFiles();" value="Upload [max. 5 files]" />
        </li>
    </ul>
</div>

There were several javascript functions I have written to fulfill the requirement. 

  • fileSelected - this function is used to show preview of the selected file. Also I have written some validations such as only image types are allowed, maximum file size is 10MB, no.of files that can be uploaded at once cannot be higher than 5. Remember that your browser should be supported HTML5 File Api.
  • uploadFiles - loop through filequeue and popping up the file and the list-element.
  • resizeAndUpload - this function does the size reducing before uploading. At the moment I have used the MAX Height as 600 and MAX Width as 800. I have use the canvas element and redraw the original image with the max height, width dimensions.  XMLHttpRequest object is used to send the data(canvas element can be converted to base64string with the use of toDataURL("image/jpeg")) to server.

javascript code


<script type="text/javascript">

    var filequeue = new Array();

    function fileSelected() {

        try {

            if (window.File && window.FileReader && window.FileList && window.Blob) {
                
                var selectedfile;

                var files = document.getElementById('fileToUpload').files;
                if (filequeue.length > 4) {
                    alert('Maximum number of allowable file uploads has been exceeded!!');
                } else {

                    selectedfile = files[0];

                    if (!selectedfile.type.match('image.*')) {
                        alert('Only image files are allowed');
                    } else if (selectedfile.size > 10485760) {
                        alert('Maximum file size exceeds');
                    }

                    if (selectedfile.type.match('image.*') && selectedfile.size < 10485760) {

                        var reader = new FileReader();

                        reader.onload = (function(theFile) {
                            return function(e) {

                                var li = document.createElement("li");
                                li.setAttribute("data-icon", "delete");

                                var newlink = document.createElement('a');

                                var img = document.createElement("img");
                                img.setAttribute("src", e.target.result);
                                img.setAttribute("height", "80");
                                img.setAttribute("width", "80");
                                newlink.appendChild(img);

                                var h3 = document.createElement("h3");
                                var h3Text = document.createTextNode(theFile.name);
                                h3.appendChild(h3Text);
                                newlink.appendChild(h3);

                                li.appendChild(newlink);

                                document.getElementById("uploadfilelist").appendChild(li);

                                $("#uploadfilelist").listview("refresh");

                                filequeue.push({ file: theFile, lisetElement: li });

                            };
                        })(selectedfile);

                        reader.readAsDataURL(selectedfile);

                    }

                }
                
            }else {
                alert("html5 file api is not compatible with this browser!");
            }

            $("#fileToUpload").val("");

        } catch (err) {
            alert("Exception " + err);
        }
    }


    function uploadFiles() {

        try {

            if (filequeue != null && filequeue.length != 0) {
                
                while (filequeue.length > 0) {

                    var item = filequeue.pop();
                    var file = item.file;
                    var li = item.lisetElement;
                    resizeAndUpload(file, li);

                }
            }

        } catch (err) {
            alert("Exception " + err);
        }

    }

    function resizeAndUpload(file, li) {

        try {

            if (window.File && window.FileReader && window.FileList && window.Blob) {

                var uploadurl = '@Url.Action("UploadSizeReducedFiles", "FileUpload")';

                var reader = new FileReader();
                reader.onloadend = function(evt) {

                    if (evt.target.readyState == FileReader.DONE) {

                        var tempImg = new Image();

                        tempImg.onload = function() {

                            var MAX_WIDTH = 800;
                            var MAX_HEIGHT = 600;
                            
                            var tempWidth = tempImg.width;
                            var tempHeight = tempImg.height;

                            if (tempWidth > tempHeight) {
                                if (tempWidth > MAX_WIDTH) {
                                    tempHeight *= MAX_WIDTH / tempWidth;
                                    tempWidth = MAX_WIDTH;
                                }
                            } else {
                                if (tempHeight > MAX_HEIGHT) {
                                    tempWidth *= MAX_HEIGHT / tempHeight;
                                    tempHeight = MAX_HEIGHT;
                                }
                            }

                            var canvas = document.createElement('canvas');
                            canvas.setAttribute("height", tempHeight);
                            canvas.setAttribute("width", tempWidth);
                            var context = canvas.getContext("2d");
                            context.drawImage(tempImg, 0, 0, tempWidth, tempHeight);

                            var xhr = new XMLHttpRequest();
                            xhr.open("POST", uploadurl);
                            xhr.setRequestHeader("Content-type", "application/json; charset=utf-8");
                            xhr.setRequestHeader("X-File-Name", file.name);
                            var data = 'image=' + canvas.toDataURL("image/jpeg");
                            xhr.send(data);

                            xhr.onreadystatechange = function() {

                                var containtext;

                                if (xhr.readyState != 4) {
                                    return;
                                }

                                else if (xhr.readyState == 4) {

                                    if (xhr.status == 500) {

                                        containtext = $(li).find("h3").text();
                                        $(li).find("h3").text(containtext + " upload error");
                                        $(li).find("h3").css("color", "#FF0000");

                                    }
                                    else if (xhr.status == 200) {

                                        containtext = $(li).find("h3").text();
                                        $(li).find("h3").text(containtext + " upload complete");

                                    }

                                }

                            };

                        };
                        tempImg.src = reader.result;

                    };

                };
                reader.readAsDataURL(file);

            } else {
                alert("html5 file api is not compatible with this browser!");
            }

        }
        catch(err) {
            alert("Exception " + err);
        }
    }

</script>

FileUpload Controller

This method handles the file saving to the server-side folder which is Uploads in my scenario, the status of the uploaded file will be displayed in the file uploading list.

[AcceptVerbs(HttpVerbs.Post)]
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public JsonResult UploadSizeReducedFiles()
{
    string fileName = null;
    string uploadedFilePath = null;

    try
    {

        fileName = Request.Headers["X-File-Name"];

        var directoryPath = Server.MapPath("~/Uploads/");

        if (!Directory.Exists(directoryPath))
        {
            Directory.CreateDirectory(directoryPath);
        }
                
        var stream = new StreamReader(Request.InputStream);
        var image = stream.ReadToEnd();

        image = image.Substring("image=data:image/jpeg;base64,".Length);
        var buffer = Convert.FromBase64String(image);

        uploadedFilePath = string.Format("{0}{1}", directoryPath, fileName);

        System.IO.File.WriteAllBytes(uploadedFilePath, buffer);

        return Json(fileName + " completed", JsonRequestBehavior.AllowGet);
    }
    catch (Exception e)
    {
        if (System.IO.File.Exists(uploadedFilePath))
        {
            if (uploadedFilePath != null) System.IO.File.Delete(uploadedFilePath);
        }

        Response.StatusCode = 500;
        return Json(fileName + " fail", JsonRequestBehavior.AllowGet);
    }
}

For functions like size reduce file uploading along with original file uploading, remove selected files before uploading, file uploading progress indicator please contact me via email.


Monday, January 7, 2013

Finding the location of a running process under Windows XP

I came across find in a location of a running process under Windows XP. It was not just as easy as Windows 7. Because in Windows 7, we can use TaskManager -> Processes -> Select a process & right click -> Open File Location to find the exact place of the running process.

But in Windows XP, you can achieve it by using command prompt and type one of the following command

Information about all Processes
WMIC /OUTPUT:C:\ProcessList.txt PROCESS get Caption, Commandline, Processid

Information about one process
WMIC /OUTPUT:"C:\ProcessList.txt" process where "caption='EMTC-Demo.exe'" get Caption,Commandline,Processid

hint: EMTC-Demo.exe is the process name