Share via


Get Automatic Pictures from Device and Upload to Web Server


Scope

In this article, we'll see how to develop a Windows Phone app capable of automatically taking photos through the device's camera, uploading them on a web server through which they can be seen from a browser. In other words, we'll develop a sort of network camera / webcam that could be run from a smartphone or tablet to monitor a certain place from elsewhere. We'll use Visual Basic .NET for the app part, while the server-side coding will be done in PHP, as we've done in a previous article about geolocalization (refer to Geolocalize a device and store coordinates on Webserver for further information).

Prerequisites

To use the code presented in the article, you'll need:

  • Windows 8.1
  • Visual Studio with Windows Phone 8.1 SDK
  • A local or hosted web server, with Apache with PHP support enabled. Alternatively, the web server part could be written in ASP/ASP.NET.

Configuring each one of the above prerequisites goes beyond the scope of the article, so i will not address this point, assuming that everything was previously successfully configured and running. If you need a brief reference on how to install an Apache plus PHP/MySQL server, you could refer to my article Quickly installing LAMP server on Debian or Ubuntu Linux

Introduction

In this article i'll present a simple method to implement a sort of smartphone/tablet base webcam, useful to set-up scenarios that can be evolved into surveillance application, and the like. A growing attention to the Iot application field bring us to be increasingly concerned and aware of the possibilities of inter-connectivity of our daily use devices, and i think the present could be a nice (though really basic) exercise in that direction.

What we will do here is to use a Windows device as an automatic camera, to take pictures as data stream every predetermined seconds, to send them remotely to a PHP script that will consolidate them as a file on the remote webserver, making it available to be seen while standing at any place that allows Internet connections.
Let's start from the server part, in order to do some initial assumptions that will make clearer the app development.

Server-side scripts

As we've previously stated, we'll use PHP (and an Apache webserver) to setup a simple script capable of receiving a file, which will be sent through POST method, to store it and thus making it subsequently accessible to further HTTP requests, such as a browser navigation. The script is the most simple possible: it consist in the reception of a POST content (namely, "file" parameter), proceeding then in opening an arbitrary file (which i've named "test.jpg"), writing in it what was sent in binary mode. Let's see it:

<?php
   $content = $_POST['file'];
   $sfile   = fopen("test.jpg", 'wb');   // 'wb' parameter means "write binary"
   fwrite($sfile, $content); 
   fclose($sfile);
?>

Pretty self explanatory with minimum PHP knowledge.
Next, we will prepare another page, which I've named "index.html": a plain HTML file in which our "test.jpg" will be shown.

<title>Network Camera</title>
<!-- Omissis: styles will be present in the full code -->
<h1>Network Camera</h1>
<div id="imgwrapper">
   <img src="test.jpg">
</div>

To sum up this part of our project, we are speaking here about having a web server equipped by two simple scripts. The first one will be exploited by our Windows Phone app, and it will receive and file remotely the data stream sent by the app itself, while the second one is simply a viewer for those data, encapsulating the sent data (i.e., a photo) in an IMG tag, to allow users to see it. Now we can implement our app to complete the work.

Automatic camera app for Windows Phone

In this section, we will develop our Windows Phone app, which will consist of the following:

  • Automatic camera shooting
  • Automatic photo upload (i.e. submitting the photo to our upload.php page)

We will make use of Windows.Media.MediaProperties namespace to access our device's camera capabilities.
First, open Visual Studio and select from Visual Basic template menĂ¹ the Store Apps / Blank App (Windows Phone) template. It will create for us a simple layout based on a single page, namely MainPage.xaml, on which we will apply the needed controls and business logic.

Let's see what elements we will include in our XAML

First we have a CaptureElement, i.e. a control in which we will render the camera preview, in order to observe what will be acquired as image. A TextBox named txtRemUP will contain the remote address of our upload.php (useful in case our app must communicate with different hosts, instead of hardcoding un URI). A ToggleButton will allow us to start and stop image acquisition, and last we have a couple of TextBlock for log purposes (date and time of the last shoot and upload), and a Canvas that will show us the last picture taken.

App prerequisites

Since our application must require the use of hardware device and network communications, we must set the app's Capabilities and Requirements accordingly.
Thus, we must double-click on Package.appxmanifest file (which was created by Visual Studio), accessing both the Capabilities and Requirements tabs, setting the camera and network flag as follows:

Camera initialization

Code-side, the first thing to do is to initialize our camera when the app starts, setting the CaptureElement Source property accordingly. Please note almost all the events that will be presented will be asynchronous. Let's start with the OnNavigatedTo event, which defines the moment in which a certain Page will be shown.

Protected Overrides Async Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
    cam = New Windows.Media.Capture.MediaCapture
    Await cam.InitializeAsync()
    mCanvas.Source = cam
    Await cam.StartPreviewAsync()
End Sub

I've declared a MediaCapture variable, cam, as visible to the entire scope. Here we'll use the method InitializeAsync on it, to initialize our camera, binding the MediaCapture variable as the source of our CaptureElement control. A further call to the StartPreviewAsync method will result in a graphical rendering of the camera acquisition on the control.

On the Toggled event of our ToggleButton, we will control a Timer launch or its disposition, depending on the ToggleButton status.

If toggler.IsOn  Then
    t = New System.Threading.Timer(AddressOf Shoot, Nothing, TimeSpan.Zero, New TimeSpan(0, 0, 10))
    t.Change(30000, Threading.Timeout.Infinite)
Else
    If Not (t Is Nothing) Then t.Dispose()
End If

If the ToggleButton is active, we will create a new instance of a t Timer, using 30 seconds as its interval. For each interval, a call to the subroutine Shoot will be made. In that sub we will control the picture acquisition, plus its uploading.

Photo capturing

The Shoot subroutine is as follows:

Public Async Sub Shoot(sender  As Object)
        Dim imgFormat  As ImageEncodingProperties = ImageEncodingProperties.CreateJpeg()
        stream = New Streams.InMemoryRandomAccessStream
 
        Await cam.CapturePhotoToStreamAsync(imgFormat, stream)
        Await stream.FlushAsync
        stream.Seek(0)
 
        Await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, AddressOf SetCanvas)
        Await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, AddressOf MarshalToggler)
End Sub

In it, we define a RandomAccessStream that will be initialized by calling the method CapturePhotoToStreamAsync (from the MediaCapture variable). Simply as that, the calling to that method will access the camera to take a shoot, proceeding in copy the image to a stream. At the end of our routine, you can see two Dispatchers towards two subroutines, the latter being simply a check on the ToggleButton status. The first one, though, calls upon the SetCanvas routine, which will be used to save the image to our Canvas, but - more importantly - to upload it on our webserver, through a POST towards our upload.php URI.

Private Async Sub SetCanvas()
        tmpLab.Text = DateTime.Now.ToString
        Dim b As New BitmapImage()
        Await b.SetSourceAsync(stream)
        pCanvas.Source = b
 
        Dim io As Stream = stream.AsStreamForRead
        Dim buf(io.Length)  As Byte
        io.Position = 0
        Await io.ReadAsync(buf, 0, io.Length)
 
        Dim httpClient  As New HttpClient
        Dim form = New MultipartFormDataContent
        form.Add(New ByteArrayContent(buf, 0, buf.Length), "file")
        Dim response = Await httpClient.PostAsync(txtRemUP.Text, form)
 
        response.EnsureSuccessStatusCode()
        httpClient.Dispose()
        Dim sd As String = response.Content.ReadAsStringAsync().Result
        lastSent.Text = Date.Now.ToString
End Sub

Apart from the TextBlocks used for logging purposes, what this routine will do is as follows:

  • Creation of a BitmapImage object: through the method SetSourceAsync, a new Bitmap is made from our RandomAccessStream, using it as the Source of our Canvas, in order to show the last taken picture.
  • Creation of a simple Stream to access to a Byte array from our original RandomAccessStream (our image). That will be needer to upload correctly our data
  • Creation of a MultipartFormDataContent (i.e. a "simulated" HTTP form, with the web awaited variable, which we've named "file" when we've created our upload.php page)
  • Physical upload of our image

The complete MainPage code-behind will be as follows:

Imports System.Net.Http
Imports Windows.Storage
Imports Windows.Media.MediaProperties
 
Public NotInheritable Class MainPage
    Inherits Page
 
    Dim t As System.Threading.Timer
    Dim cam As Windows.Media.Capture.MediaCapture
    Dim stream As Streams.InMemoryRandomAccessStream
 
    Protected Overrides Async Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
        cam = New Windows.Media.Capture.MediaCapture
        Await cam.InitializeAsync()
        mCanvas.Source = cam
        Await cam.StartPreviewAsync()
    End Sub
 
    Private Async Sub SetCanvas()
        tmpLab.Text = DateTime.Now.ToString
        Dim b As New BitmapImage()
        Await b.SetSourceAsync(stream)
        pCanvas.Source = b
 
        Dim io As Stream = stream.AsStreamForRead
        Dim buf(io.Length)  As Byte
        io.Position = 0
        Await io.ReadAsync(buf, 0, io.Length)
 
        Dim httpClient  As New HttpClient
        Dim form = New MultipartFormDataContent
        form.Add(New ByteArrayContent(buf, 0, buf.Length), "file")
        Dim response = Await httpClient.PostAsync(txtRemUP.Text, form)
 
        response.EnsureSuccessStatusCode()
        httpClient.Dispose()
        Dim sd As String = response.Content.ReadAsStringAsync().Result
        lastSent.Text = Date.Now.ToString
    End Sub
 
    Private Sub MarshalToggler()
        If toggler.IsOn  Then
            t = New System.Threading.Timer(AddressOf Shoot, Nothing, TimeSpan.Zero, New TimeSpan(0, 0, 10))
            t.Change(30000, Threading.Timeout.Infinite)
        Else
            If Not (t Is Nothing) Then t.Dispose()
        End If
    End Sub
 
    Public Async Sub Shoot(sender  As Object)
        Dim imgFormat  As ImageEncodingProperties = ImageEncodingProperties.CreateJpeg()
        stream = New Streams.InMemoryRandomAccessStream
 
        Await cam.CapturePhotoToStreamAsync(imgFormat, stream)
        Await stream.FlushAsync
        stream.Seek(0)
 
        Await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, AddressOf SetCanvas)
        Await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, AddressOf MarshalToggler)
    End Sub
 
    Private Sub toggler_Toggled(sender  As Object, e As RoutedEventArgs)
        MarshalToggler()
    End Sub
End Class

Upon the completion of those steps, our "test.jpg" file will be uploaded and ready to be viewed by knowing the remote URI and being able to access it from any device.
Let's see an example of the execution of the project.

An overall test

A simple test will consist in setting up the webserver and the device, launch the Windows Phone app awaiting it to take and upload photos, checking for them later through a browser, visiting the HTML page we've created before:

  

Source Code

The complete source  code used in the present article can be downloaded at: https://code.msdn.microsoft.com/Get-Automatic-Pictures-3b3875dd

Bibliography

Other Languages

The present article is available in the following localizations: