Question

I have a task of posting two images to the server, combining them (one on top of the other) and then saving the resulting image to Azure Storage. I have code that works, but it just looks...wrong. Is there a less ugly way to do this? I hate seeing all those "Using" statements and the long indent.

This code combines a signature image and an initials image, then saves the result to Azure Storage.

code:

        string initialscontainerPath = "signatures/initailsdata.png";

        CloudStorageAccount storageAccount = CloudStorageAccount.Parse(Microsoft.WindowsAzure.CloudConfigurationManager.GetSetting("StorageConnection"));
        CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
        CloudBlobContainer container = blobClient.GetContainerReference(Request.Url.Host.ToLower().Replace(".", "-"));
        CloudBlockBlob blockBlob = container.GetBlockBlobReference(initialscontainerPath);
        blockBlob.Properties.ContentType = "image/png";

        byte[] initialsbytes = Convert.FromBase64String(initialsData);

        byte[] signaturebytes = Convert.FromBase64String(signatureData);


        using (System.IO.MemoryStream msinitials = new System.IO.MemoryStream(initialsbytes))
        {
            using (System.IO.MemoryStream mssignature = new System.IO.MemoryStream(signaturebytes))
            {
                using (System.Drawing.Image bminitials = new System.Drawing.Bitmap(msinitials))
                {
                    using (System.Drawing.Image bmsignature = new System.Drawing.Bitmap(mssignature))
                    {
                        using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmsignature))
                        {
                            g.DrawImage(bminitials, 0, 0);

                            using (System.IO.MemoryStream savestream = new System.IO.MemoryStream())
                            {
                                bmsignature.Save(savestream, System.Drawing.Imaging.ImageFormat.Png);

                                using (System.IO.MemoryStream uploadstream = new System.IO.MemoryStream(savestream.ToArray()))
                                {
                                    blockBlob.UploadFromStream(uploadstream);
                                }
                            }
                        }
                    }
                }
            }
        }
Was it helpful?

Solution 2

Using just gets converted into a try...catch...finaly block and in the finaly the variable gets disposed. And also you could eliminate the namespace and put more using statements in the begining of the code. I think this is more readable:

string initialscontainerPath = "signatures/initailsdata.png";

CloudStorageAccount storageAccount = CloudStorageAccount.Parse(Microsoft.WindowsAzure.CloudConfigurationManager.GetSetting("StorageConnection"));
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(Request.Url.Host.ToLower().Replace(".", "-"));
CloudBlockBlob blockBlob = container.GetBlockBlobReference(initialscontainerPath);
blockBlob.Properties.ContentType = "image/png";

byte[] initialsbytes = Convert.FromBase64String(initialsData);

byte[] signaturebytes = Convert.FromBase64String(signatureData);

CombineBitmaps(initialsbytes, signaturebytes);

Where CombineBitmaps is

private void CombineBitmaps(byte[] initialsbytes, byte[] signaturebytes, CloudBlockBlob blockBlob)
{
    MemoryStream msinitials   = null;
    MemoryStream mssignature  = null;
    MemoryStream savestream   = null;
    MemoryStream uploadstream = null;
    Bitmap bminitials         = null;
    Bitmap bmsignature        = null;
    Graphics g                = null;

    try
    {
        msinitials  = new MemoryStream(initialsbytes);
        mssignature = new MemoryStream(signaturebytes);
        bminitials  = new Bitmap(msinitials);
        bmsignature = new Bitmap(mssignature);
        savestream  = new MemoryStream();

        g = Graphics.FromImage(bmsignature);

        g.DrawImage(bminitials, 0, 0);

        bmsignature.Save(savestream, ImageFormat.Png);

        uploadstream = new MemoryStream(savestream.ToArray());

        blockBlob.UploadFromStream(uploadstream);
    }
    finally
    {
        DisposeNotNull(msinitials,  mssignature, bminitials, bmsignature, g, savestream, uploadstream);
    }
}

private void DisposeNotNull(params IDisposable[] objects)
{
    foreach(IDisposable obj in objects)
        if (obj != null) obj.Dispose();
}

And the variable names could use some pascal caseing (or what ever the name is).

OTHER TIPS

Have you looked into drawing one on top of the other? Just read the images into bitmap objects and draw the smaller one on top of the other, kinda like this:

public Bitmap Combine(Bitmap largeBmp, Bitmap smallBmp) {
    Graphics g = Graphics.FromImage(largeBmp);
    g.CompositingMode = CompositingMode.SourceOver;
    int margin = 5;
    int x = largeBmp.Width - smallBmp.Width - margin;
    int y = largeBmp.Height - smallBmp.Height - margin;
    g.DrawImage(smallBmp, new Point(x, y));
    return largeBmp;
}

note that x and y are the coordinates on which the small image is gonna exit on the larger image.

Hope it helps

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top