ecently, I was consulting on a Windows Mobile project where the client asked if it is possible to send images using SMS messaging. After searching high and low for a solution, I concluded that there is no easy way to do it unless you want to buy some fanciful third-party software. Basically, my client wanted to build a security system to alert security guards when someone who is under monitoring leaves the compound under surveillance. To do so, they would automate the process by sending a SMS message to the guards, with the image of the person attached. The image would be a small mug shot of that person, which is relatively small in size.
This article details the solution that I proposed and will hopefully be of use to readers who are comtemplating such implementations.
How It Works
Before you can build the application, you need to understand how to embed both text and image into an SMS message. As SMS messaging is inherently text-based, sending images (binary data) poses a challenge.
Basically, you need to “flatten” the binary data into a string of printable characters so that you can send them via SMS. Base64 encoding is well suited for this purpose; the only draw back is that it inflates your data size by about 33 percent. Hence, after encoding your binary data (image) into base64, you should optionally perform a compression to reduce the size of the data. However, do note that images (such as the .jpg format) normally do not compress well, and in some instances, the compressed data is actually much larger than the original data. Figure 1 summarizes the action you need to perform in order to send an image over SMS.
|Figure 1. Image Manipulation Lifecycle: First, flatten an image into base64 and then compress it.|
Note that you cannot simply convert a byte array into a string using the ASCII.GetString() method found in the System.Text.ASCIIEncoding class because it may return non-printable characters, which cannot be represented in an SMS message’s body.
For text data, you can optionlly compress it before sending (in order to reduce its size). Generally, if you’re sending a small amount of text, compression doesn’t help much?in fact, this usually increases data size. However, text data that contains a lot of repeating patterms generally compresses well.
One restriction with SMS messaging is the 160-character limit. If the message length exceeds 160 characters, the message will be split into multiple messages and sent separately, then assembled on the receiving end. Fortunately, all this takes place behind the scenes. What you need to know is that when you send a 1000-character SMS message, the recipient will get the 1000-character message.
The downside is that SMS messaging is charged based number of messages sent. And you will be charged seven SMS messages when you send a 1000-character message (1000/160). For this reason, this application works best if you have a unlimited SMS plan for your mobile phone.
Defining the Message Format
After the text and image are encoded, they need to be packaged properly so that they can be sent as an SMS message. In this application, the body of a SMS message can contain either text or an image (or both).
The preamble of the message’s body is prefixed by the <*> tag. Text content is enclosed within the
: Text only (compressed) ………
………: Text only (uncompressed)
………: Image only (compressed)
- <*>………: Image only (uncompressed)
……… ….: Text and Image compressed
……… ….: Text uncompressed and Image compressed
Creating the Application
Using Visual Studio 2005, create a new Windows Mobile 5.0 Pocket PC application and name it as SMS_Pictures. In the default Form1, populate it with the following controls shown in Figure 2 and 3.
Until .NET Compact Framework 3.5 is released, you have to rely on third-party components for compression. For compression using the .NET Compact Framework 2.0, I used the “ComponentOne Zip for Mobile Devices – Subscription – 2007v1” (check out their web site for pricing information). For this article, I used the available trial edition.
Once the “ComponentOne Zip for Mobile Devices” is downloaded and installed on your computer, add a reference to the C1.CF.C1Zip.2.dll library, which by default is located in C:Program FilesComponentOne Studio.NET 2.0in.
Switch to the code-behind of Form1 and import the following namespaces:
Imports System.IOImports Microsoft.WindowsMobile.PocketOutlookImports Microsoft.WindowsMobile.PocketOutlook.MessageInterceptionImports C1.C1Zip
Declare the following two member variables:
Public Class Form1 Private msgInterceptor As MessageInterceptor Private SMS_Message As New SmsMessage
Define the CompressString() and ExpandString() functions respectively to compress and expand a string (see Listing 1).
|Author’s Note: These two functions are taken from the sample code accompanying the “ComponentOne Zip for Mobile Devices.”|
First write the code to send messages. Double-click on the Select File button and code the following so that users can select a file to attach to the SMS (see Listing 2).
When a file has been selected, the ConvertFileContentToBase64() function is called so that it can convert the file content into base64 encoding. It is then compressed to potentially reduce its size and encoded back into base64 encoding again. A check is then made to see if there is a reduction in file size. If there is, the compressed base64 image is used, else the original base64 encoding of the image data is used instead.
The ConvertFileContentToBase64() function is defined as in Listing 3, and the DisplayStatus() subroutine is defined as follows:
Public Sub DisplayStatus(ByVal str As String) txtStatus.Text = str & vbCrLf & txtStatus.Text Application.DoEvents() End Sub
Next, double-click on the Send SMS menu item and code it like in Listing 4.
Here, you try to compress the text (if any) and see if there is a reduction in data size. As usual, if there is no reduction in size, you will use the original uncompressed text. Else, use the compressed text. After that, prompt the user to confirm sending the message. The message containing the text and image will then be sent.
When a picture SMS message is received, you need to intercept it and take the appropriate action to decode its content.
Code the following in the Form1_Load event:
Private Sub Form1_Load( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load msgInterceptor = _ New MessageInterceptor( _ InterceptionAction.NotifyAndDelete, _ True) '---set the filter for the message--- msgInterceptor.MessageCondition = _ New MessageCondition( _ MessageProperty.Body, _ MessagePropertyComparisonType.StartsWith, _ "<*>", True) '---set the event handler for the message interceptor--- AddHandler msgInterceptor.MessageReceived, _ AddressOf smsInterceptor_MessageReceived End Sub
Basically, you are intercepting all incoming SMS messages whose body begins with the <*> string. When messages are intercepted, the smsInterceptor_MessageReceived() subroutine is called, which is defined as shown in Listing 5.
When a message is intercepted, you first cast the message into a SmsMessage object so that you can retrieve the details of the message (such as the sender phone number, message content, etc). You then decode the body of the message and extract the text and image accordingly.
The two delegates and the two subroutines for displaying the text and image content are defined as follows:
Private Delegate Sub delDisplayText(ByVal str As String) Private Sub DisplayText(ByVal str As String) Try txtMessageReceived.Text = str Catch ex As Exception MsgBox(ex.ToString) End Try End Sub Private Delegate Sub delDisplayImage(ByVal img As Byte()) Private Sub DisplayImage(ByVal img As Byte()) Try Dim ms As MemoryStream = New MemoryStream(img) PictureBox1.Image = New Bitmap(ms) Catch ex As Exception MsgBox(ex.ToString) End Try End Sub
The ConvertBase64ToByteArray() function converts a base64 string into a byte array:
Private Function ConvertBase64ToByteArray( _ ByVal base64string As String) As Byte() Dim binaryData() As Byte Try binaryData = _ System.Convert.FromBase64String(base64string) Catch ex As Exception Console.WriteLine("Error decoding content") Return (Nothing) End Try Return binaryData End Function
Testing the Application
You can now test out the application and see how it works! Deploy the application onto a Windows Mobile 5.0 device (with a valid SIM card for sending and receiving SMS messages). Enter the recipient number and type in some text. To add an image to the message, click the Select File button and select a .jpg file. Click the Send SMS menu item to send the message. When prompted, click Yes to send the message. The recipient (also running the application) will now receive the message. Figure 4 outlines the steps just described.
|Author’s Note: The easiest way to test the application is to send a message to yourself.|
|Figure 4. Test It!: These are the steps for testing the application.|
Use with Some Consideration
The solution presented in this article shows one way of sending images using SMS. While theoretically you can send images of any size using this method, there is actually a limit to the size of the SMS message that you can send. Also, sending an image using this method uses a large number of SMS messages, which can be quite costly depending on your data plans. However, if your purpose is to send images to recipients quickly, this is a viable solution that you can adopt. Have fun?and let me know if you have an innovative use for this application.