Image type convertion

Posted on

Problem

So I have a piece a code that, altough it does what is expected, it doesn’t seam very performant to me. I just wanted to know if there’s a better way to do this or if my code is alright as it is.

The objective of the code is to recieve an image path, check if the image exists or if it isn’t png, if the image isn’t png convert it to png and return a byte[] of the stream.

the code:

    // the speed of the method, on my computer, as is, right now, is of 40ms per cycle, this means 10 cycles are around 400ms
    public static byte[] GetBytesFromImage(string imageName)
    {
        byte[] bytes = null;

        string imagePath = "..\..\Imagens";
        imageName = imageName == "" ? "\logotipos-prototipo_logo_prototipo_print.jpg" : imageName;
        string fpath = imagePath + imageName;

            if (File.Exists(fpath) && !imageName.EndsWith("png"))
            {
                using (MemoryStream image = new MemoryStream())
                using (System.Drawing.Image bmpImageToConvert = System.Drawing.Image.FromFile(fpath))
                using (System.Drawing.Image bmpNewImage = new Bitmap(bmpImageToConvert.Width, bmpImageToConvert.Height))
                using (Graphics gfxNewImage = Graphics.FromImage(bmpNewImage))
                {
                    gfxNewImage.DrawImage(bmpImageToConvert, new Rectangle(0, 0, bmpNewImage.Width, bmpNewImage.Height), 0, 0, bmpImageToConvert.Width, bmpImageToConvert.Height, GraphicsUnit.Pixel);

                    bmpNewImage.Save(image, ImageFormat.Png);
                    bytes = image.ToArray();
                }
            }

        return bytes;
    }

1st Update:
As the @Nkosi’s answer mentioned, I forgot to make a case for when the image is PNG, and also to deal with the method returning a potencial null byte[].
Also in his change now the MemoryStream is shared in both cases, and the string comparison now ignores the string case.

    readonly string BASEIMAGEPATH = "..\..\Imagens\";
    readonly string DEFAULTIMAGENAME = "logotipos-prototipo_logo_prototipo_print.jpg";


    // the speed of the method, on my computer, as is, right now, is of 40ms per cycle, this means 10 cycles are around 400ms
    public static byte[] GetBytesFromImage(string imageName)
    {
        byte[] bytes = null;
        imageName = imageName == "" ? DEFAULTIMAGENAME : imageName;
        string path = Path.Combine(BASEIMAGEPATH, imageName);
        if (File.Exists(path))
        {
            // Now both cases use the same MemoryStream
            using (MemoryStream image = new MemoryStream())
            {
                // The comparison now ignores case
                if (imageName.EndsWith("png", StringComparison.InvariantCultureIgnoreCase))
                {
                    using (FileStream imageStream = new FileStream(path, FileMode.Open, FileAccess.Read))
                    {
                        imageStream.CopyTo(image);
                        bytes = image.ToArray();
                    }
                }
                else
                {
                    using (System.Drawing.Image bmpImageToConvert = System.Drawing.Image.FromFile(path))
                    using (System.Drawing.Image bmpNewImage = new Bitmap(bmpImageToConvert.Width, bmpImageToConvert.Height))
                    using (Graphics gfxNewImage = Graphics.FromImage(bmpNewImage))
                    {
                        gfxNewImage.DrawImage(bmpImageToConvert, new Rectangle(0, 0, bmpNewImage.Width, bmpNewImage.Height), 0, 0, bmpImageToConvert.Width, bmpImageToConvert.Height, GraphicsUnit.Pixel);
                        bmpNewImage.Save(image, ImageFormat.Png);
                        bytes = image.ToArray();
                    }
                }
            }
        }
        // I changed his code here because `Array.Empty<byte>()` didn't exist.
        return bytes ?? new byte[0];
    }

Solution

There is a lot of unnecessary noise in the function.

If the base path is not expected to change it can be moved out into a constant.

System.IO.Path can be used to construct the path to the desired image.

To avoid null reference errors when consuming this function, try to avoid returning null. An empty array should be returned.

const string BASEIMAGEPATH = "..\..\Imagens";
const string DEFAULTIMAGENAME = "\logotipos-prototipo_logo_prototipo_print.jpg";

public static byte[] GetBytesFromImage(string imageName) {
    byte[] bytes = null;
    imageName = imageName == "" ? DEFAULTIMAGENAME : imageName;
    string path = Path.Combine(BASEIMAGEPATH, imageName);
    if (File.Exists(path) && !imageName.EndsWith("png", StringComparison.InvariantCultureIgnoreCase)) {
        using (MemoryStream image = new MemoryStream())
        using (System.Drawing.Image bmpImageToConvert = System.Drawing.Image.FromFile(path))
        using (System.Drawing.Image bmpNewImage = new Bitmap(bmpImageToConvert.Width, bmpImageToConvert.Height))
        using (Graphics gfxNewImage = Graphics.FromImage(bmpNewImage)) {
            gfxNewImage.DrawImage(bmpImageToConvert, new Rectangle(0, 0, bmpNewImage.Width, bmpNewImage.Height), 0, 0, bmpImageToConvert.Width, bmpImageToConvert.Height, GraphicsUnit.Pixel);
            bmpNewImage.Save(image, ImageFormat.Png);
            bytes = image.ToArray();
        }
    }
    return bytes ?? Array.Empty<byte>();
}

The logic should also be reviewed as it was stated

The objective of the code is to receive an image path, check if the image exists or if it isn’t png, if the image isn’t png convert it to png and return a byte[] of the stream.

but currently, if the image exists and is already a PNG, it wont return the contents of the file.

const string BASEIMAGEPATH = "..\..\Imagens";
const string DEFAULTIMAGENAME = "\logotipos-prototipo_logo_prototipo_print.jpg";

public static byte[] GetBytesFromImage(string imageName) {
    byte[] bytes = null;
    imageName = imageName == "" ? DEFAULTIMAGENAME : imageName;
    string path = Path.Combine(BASEIMAGEPATH, imageName);
    if (File.Exists(path)) {
        using (MemoryStream image = new MemoryStream()) {
            if (imageName.EndsWith("png", StringComparison.InvariantCultureIgnoreCase)) {
                using (FileStream imageStream = new FileStream(path, FileMode.Open, FileAccess.Read)) {
                    imageStream.CopyTo(image);
                    bytes = image.ToArray();
                }
            } else {
                using (System.Drawing.Image bmpImageToConvert = System.Drawing.Image.FromFile(path))
                using (System.Drawing.Image bmpNewImage = new Bitmap(bmpImageToConvert.Width, bmpImageToConvert.Height))
                using (Graphics gfxNewImage = Graphics.FromImage(bmpNewImage)) {
                    gfxNewImage.DrawImage(bmpImageToConvert, new Rectangle(0, 0, bmpNewImage.Width, bmpNewImage.Height), 0, 0, bmpImageToConvert.Width, bmpImageToConvert.Height, GraphicsUnit.Pixel);
                    bmpNewImage.Save(image, ImageFormat.Png);
                    bytes = image.ToArray();
                }
            }
        }
    }
    return bytes ?? Array.Empty<byte>();
}

Leave a Reply

Your email address will not be published. Required fields are marked *