Fuse Day, Dec 2012–Getting our hands dirty with WinRT

The fuse day tradition @ Tikal is basically a day and half where you get to put your hands in the mud with the technology of your choice. More like and advanced hello world, which you don’t get to do in the everyday life.

[repository: https://github.com/manishma/windows-8-javascript-application]

Objective: create a Win8 application which allows the following:

  • - Take a picture snapshot from the web cam
  • - Save the picture locally
  • - Browse the picture and apply a canvas on the selected image for custom drawing.
  • - Save the result as an image
  • </ul>

    For the most of us (we are experienced .Net developers with JavaScript skills), developing on Windows 8 was a very first experience but pretty exciting and really fun part, although working on a virtual machine had its share of hardware problems (application hanged, camera worked only in Igor’s laptop).

    We decided to write the whole application using WinJS and it’s really amazing that writing some pieces of code in HTML + JavaScript can actually result in a very nice windows 8 application! Still, not clear whether there is a browser behind or does all HTML controls are rendered to WinRT equivalent? While WinRT has it’s dedicated controls like the List control, most of HTML functionality that we used worked out of the box in our application.

    Things went relatively straight forward as the documentation in MSDN and in the internet were relatively enough detailed and good intelligence support in Visual Studio 2012 gave the final kick. We also used the Windows 8 SDK samples which supplied a lot of samples as a starting point and I strongly recommend using it whenever you want to search for something. Much like the android SDK it is very detailed and has a lot of samples.

    The particularity of WinJS is a strong use of asynchronous events that can be controlled with the use of the promise-deferred module.

    We also figured out from the beginning that if we want to use a C# DLL with business logic to integrate into the JavaScript project we had to create Windows Runtime Component project and then add it as a reference into the JavaScript project. Then use it as a normal JavaScript reference as the intelisence will immediately recognize it. Some pointers: all the classes need to be sealed and if we want to debug it, we need to debug either the C# code or the JavaScript code using the project configuration – but not both in the same time.

    clip_image002

     

    Application Structure

    We first started with a navigation model: much like HTML when we link between different pages and have a history/back/forward buttons. I cant realy say that the navigation worked out of the box and in the middle of the development we decided to break the navigation model from a multi-page structure to a single page application (SPA). The reason is to have the context state available for all the controls and to get the “navigation” finally working.

    MVC – Views are defined by an HTML page coupled with a JavaScript file. The convention is to place the html file into the html directory and the JavaScript file into the js directory. The HTML is clean and should have any JavaScript in it.

    We than need to “bind” them together: from the HTML page we call

    <script src="/js/collage.js"></script>

    And from the JavaScript page we call

    var page = WinJS.UI.Pages.define("/collage.html", {
    
    init: function (element, options) {
    
    },
    
    ready: function (element, options) {
    
    onLoad();
    
    }
    
    });
    
    

    Because we used a single navigation model we did not have to include every time the themes and base scripts in the HTML page:

    <link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
    
    <script src="//Microsoft.WinJS.1.0/js/base.js"></script>
    
    <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
    
    
    
    <link href="/css/default.css" rel="stylesheet" />
    
    <script src="/js/default.js"></script>
    
    

    Some Code

    while most of the things where trivial we had a very hard time converting a canvas content into an image file (look in the repository for the code)

    Here is the code for opening a file from the file picker (taken from the SDK samples)

    function pickPhoto() {
    
    // Verify that we are currently not snapped, or that we can unsnap to open the picker
    
    var currentState = Windows.UI.ViewManagement.ApplicationView.value;
    
    if (currentState === Windows.UI.ViewManagement.ApplicationViewState.snapped &&
    
    !Windows.UI.ViewManagement.ApplicationView.tryUnsnap()) {
    
    // Fail silently if we can't unsnap
    
    return;
    
    }
    
    // Clean output in case of repeat usage
    
    cleanOutput();
    
    var openpicker = new Windows.Storage.Pickers.FileOpenPicker();
    
    openpicker.fileTypeFilter.replaceAll([".jpg", ".png", ".bmp", ".gif", ".tif"]);
    
    openpicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.picturesLibrary;
    
    openpicker.pickSingleFileAsync().done(function (file) {
    
    loadImage(file);
    
    });
    
    }
    
    var loadImage = function(file) {
    
    if (file) {
    
    file.getThumbnailAsync(thumbnailMode, requestedSize, thumbnailOptions).done(function(thumbnail) {
    
    if (thumbnail) {
    
    outputResult(file, thumbnail, Windows.Storage.FileProperties.ThumbnailMode.singleItem, requestedSize);
    
    } else if (isFastSelected) {
    
    WinJS.log && WinJS.log(SdkSample.errors.noExif, "sample", "status");
    
    } else {
    
    WinJS.log && WinJS.log(SdkSample.errors.noThumbnail, "sample", "status");
    
    }
    
    }, function(error) {
    
    WinJS.log && WinJS.log(SdkSample.errors.fail, "sample", "status");
    
    });
    
    } else {
    
    WinJS.log && WinJS.log(SdkSample.errors.cancel, "sample", "status");
    
    }
    
    };
    
    function outputResult(item, thumbnailImage, thumbnailMode, requestedSize) {
    
    document.getElementById("picture-thumb-modeName").innerText = thumbnailMode;
    
    document.getElementById("picture-thumb-fileName").innerText = "File used: " + item.name;
    
    document.getElementById("picture-thumb-requestedSize").innerText = "Requested size: " + requestedSize;
    
    document.getElementById("picture-thumb-returnedSize").innerText = "Returned size: " + thumbnailImage.originalWidth + "x" + thumbnailImage.originalHeight;
    
    var can = document.getElementById('paintCanvas');
    
    var ctx = can.getContext('2d');
    
    var img = new Image();
    
    img.onload = function () {
    
    ctx.drawImage(img, (canvasSize - img.width) / 2, (canvasSize - img.height) / 2);
    
    thumbnailImage.close();
    
    }
    
    img.src = URL.createObjectURL(thumbnailImage, { oneTimeOnly: true });
    
    }
    
    

    And here is the code for taking a photo

    function startCamera() {
    
    var livePreview = document.getElementById("live-preview");
    
    mediaCapture = new Capture.MediaCapture();
    
    mediaCapture.initializeAsync().then(function () {
    
    livePreview.src = URL.createObjectURL(mediaCapture);
    
    livePreview.play();
    
    });
    
    }
    
    var picturesLib = Storage.KnownFolders.picturesLibrary;
    
    picturesLib.createFolderAsync("Winstagram", Storage.CreationCollisionOption.openIfExists)
    
    .then(function (folder) {
    
    pics = folder;
    
    });
    
    function takePhoto() {
    
    if (takePhotoBlock) {
    
    console.log('take photo is disabled');
    
    return;
    
    }
    
    takePhotoBlock = true;
    
    pics.createFileAsync((new Date()).getTime()+".jpg", Storage.CreationCollisionOption.generateUniqueName)
    
    .then(function (file) {
    
    var photoProperties = Windows.Media.MediaProperties.ImageEncodingProperties.createJpeg();
    
    mediaCapture.capturePhotoToStorageFileAsync(photoProperties, file).then(function () {
    
    console.log("Image saved on disk on: " + file.path);
    
    takePhotoBlock = false; // not needed, because the page will be rendered again.
    
    WinJS.Navigation.navigate("/collage.html", { file: file });
    
    });
    
    mediaCapture.onfailed = function (e) {
    
    takePhotoBlock = false;
    
    console.log(e);
    
    };
    
    });
    
    }
    
    

    clip_image003

    clip_image005

    Most important thing: It was fun and easy to get started with, unlike many languages and frameworks out there that state so but don’t deliver. Still, the API needs to be learned and understood, and after building our app we still believe that we only understand 80% of the code – which is a good thing for 1 day “getting to know WinRT” thingy.

    [repository: https://github.com/manishma/windows-8-javascript-application]

Thank you for your interest!

We will contact you as soon as possible.

Send us a message

Oops, something went wrong
Please try again or contact us by email at info@tikalk.com