Pridefy.com – Inspired by Love and created with Love
Inspired by the decision of the Supreme Court of the United States to declare same sex marriage a constitutional right and the celebratepride tool that Facebook launched on that same day, I decided to create an MMS ( Twilio powered) version of the same for those who (and I’m not sure why) do not have a Facebook account yet. Here are the steps I followed to make this happen; if you want to see the demo go to Pridefy.com
Step 1 – Change Opacity:
First I needed to find a way to change the opacity of the rainbow flag; a 50% seemed like the right choice here but I made this option part of the input for the method, just in case you want to play with this in the future. Check this article for some more details into this.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static Bitmap ChangeOpacity(Image img, float opacityvalue) | |
{ | |
Bitmap bmp = new Bitmap(img.Width, img.Height); | |
Graphics graphics = Graphics.FromImage(bmp); | |
ColorMatrix colormatrix = new ColorMatrix(); | |
colormatrix.Matrix33 = opacityvalue; | |
ImageAttributes imgAttribute = new ImageAttributes(); | |
imgAttribute.SetColorMatrix(colormatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); | |
graphics.DrawImage(img, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, imgAttribute); | |
graphics.Dispose(); | |
return bmp; | |
} |
I tried this method and got some results, but not quite what I wanted. See what I mean here:
Step 2 – Scale Image:I wanted like the rainbow flag to cover the whole image, So I tried making both images the same size and this is what I got:
This didn’t turn out like I wanted it. I needed to scale the image using ratios horizontally but needed to retain the same vertical height.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static Image ScaleImage(Image image, int maxWidth, int maxHeight) | |
{ | |
var ratioX = (double)maxWidth / image.Width; | |
var ratioY = (double)maxHeight / image.Height; | |
var ratio = Math.Min(ratioX, ratioY); | |
var newWidth = (int)(image.Width * ratio); | |
var newImage = new Bitmap(newWidth, maxHeight);// | |
Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, maxHeight);// | |
return newImage; | |
} |
Check the results now:
Step 3 – Putting it all together for Image ManipulationWhen I receive an MMS message what I get is not the actual file (binary) but a link to the media file in Twilio’s servers. Therefore I needed to do a webrequest to get the media file (this is the MediaUrl0 parameter). I grabbed the flag image from a public Flicker url.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private static Image CreateBlendedImage(string backgroundimageurl) | |
{ | |
Image imageBackground; | |
Image imageOverlay; | |
var request = WebRequest.Create(backgroundimageurl); | |
using (var response = request.GetResponse()) | |
using (var stream = response.GetResponseStream()) | |
{ | |
imageBackground = Bitmap.FromStream(stream); | |
} | |
var request2 = WebRequest.Create("http://c1.staticflickr.com/1/286/19041020628_2657a057cc_k.jpg"); //Rainbow Flag | |
using (var response2 = request2.GetResponse()) | |
using (var stream2 = response2.GetResponseStream()) | |
{ | |
imageOverlay = Bitmap.FromStream(stream2); | |
} | |
imageOverlay = ChangeOpacity(imageOverlay, 0.5F); | |
imageOverlay = ScaleImage(imageOverlay, imageBackground.Width, imageBackground.Height); | |
imageOverlay = imageOverlay.GetThumbnailImage(imageBackground.Width, imageBackground.Height, null, IntPtr.Zero); | |
Image img = new Bitmap(imageBackground.Width, imageBackground.Height); | |
using (Graphics gr = Graphics.FromImage(img)) | |
{ | |
gr.DrawImage(imageBackground, new Point(0, 0)); | |
gr.DrawImage(imageOverlay, new Point(0, 0)); | |
} | |
return img; | |
} |
I then do the scaling, overlay and return the (in memory) image to the main controller.
Step 4 – The MMS Controller
I created an MVC controller to handle the incoming images and return back TwiML markup (Note: This controller must inherit from TwilioController in order to be able to send that TwiML markup back). You can do the same with a WebAPI controller, Node, etc. I just went for simple here
The same way that Twilio sends images via MMS, I needed to send them back; this means I had to save the image somewhere and then send the URL to that media file back. To do this I used Azure Blob Storage; again nothing fancy here, check this tutorial for a quick how to. I created a container for my images,created a blob and uploaded the image to that blob.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Reminder this class needs to inherit from TwilioController –> public class MMSController : TwilioController | |
public ActionResult Index(string from, string mediaurl0) | |
{ | |
Image blended = CreateBlendedImage(mediaurl0); | |
//We are using Azure Storage, and loading our credentials from our config file | |
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["<CONNECTIONKEY>"].ToString()); | |
// Create the blob client | |
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); | |
// Retrieve a reference to a container. | |
CloudBlobContainer container = blobClient.GetContainerReference("<CONTAINERNAME>"); | |
//Allow public access to the blob (but not to the container) | |
container.SetPermissions(new BlobContainerPermissions {PublicAccess = BlobContainerPublicAccessType.Blob }); | |
// Create the container if it doesn't already exist. | |
container.CreateIfNotExists(); | |
// Retrieve reference to a blob names using the from phone number. | |
//We add the png file extension so its easier for us when looking at a list of blobs | |
CloudBlockBlob blockBlob = container.GetBlockBlobReference(from + ".png"); | |
// Create or overwrite the phone mumber blob with contents from a local file. | |
//We re using temp file space for file creation | |
var filepath = System.IO.Path.GetTempFileName(); | |
blended.Save(filepath, ImageFormat.Png); | |
//remmeber to set the Content Type, else Azure will return appliction/octet and Twilio won't be able to read the image | |
blockBlob.Properties.ContentType = "image/png"; | |
//Upload the file to Azure storage | |
blockBlob.UploadFromFile(filepath, FileMode.Open); | |
//Create th Twilio TwiML markup response | |
var response = new TwilioResponse(); | |
string[] mediaurls = new string[1]; | |
//For some reason only http worked for me | |
mediaurls[0] = blockBlob.Uri.AbsoluteUri.Replace("https://","http://"); | |
//Add the Blended Image URL from Azure to the response | |
response.Message(mediaurls); | |
//Note how we return a TwiML respone and not a View | |
return TwiML(response); | |
} |
Warning: don’t forget to set the Content-Type for the blob, failure to do this will serve the blob as “application/octet” which Twilio won’t be able to handle.
Hopefully you enjoyed this little project, I surely did. Feel free to reach out if you have any questions with this demo.
Have fun and celebrate love