I'm trying to compare two Images via their byte content. However, they do not match.
Both images were generated from the same source image, using the same method with the same parameters. I am guessing that something in the image generation or the way I convert to a byte array is not deterministic. Does anyone know where the non-deterministic behavior is occurring and whether or not I can readily force deterministic behavior for my unit testing?
This method within my test class converts the image to a byte array - is image.Save
deterministic? Is memStream.ToArray()
deterministic?
private static byte[] ImageToByteArray(Image image)
{
byte[] actualBytes;
using (MemoryStream memStream = new MemoryStream())
{
image.Save(memStream, ImageFormat.Bmp);
actualBytes = memStream.ToArray();
}
return actualBytes;
}
Here is the unit test, which is failing - TestImageLandscapeDesertResized_300_300
was generated from TestImageLandscapeDesert
using the ImageHelper.ResizeImage(testImageLandscape, 300, 300)
and then saving to a file before loading into the project's resource file. If all calls within my code were deterministic based upon my input parameters, this test should pass.
public void ResizeImage_Landscape_SmallerLandscape()
{
Image testImageLandscape = Resources.TestImageLandscapeDesert;
Image expectedImage = Resources.TestImageLandscapeDesertResized_300_300;
byte[] expectedBytes = ImageToByteArray(expectedImage);
byte[] actualBytes;
using (Image resizedImage = ImageHelper.ResizeImage(testImageLandscape, 300, 300))
{
actualBytes = ImageToByteArray(resizedImage);
}
Assert.IsTrue(expectedBytes.SequenceEqual(actualBytes));
}
The method under test - this method will shrink the input image so its height and width are less than maxHeight
and maxWidth
, retaining the existing aspect ratio. Some of the graphics calls may be non-deterministic, I cannot tell from Microsoft's limited documentation.
public static Image ResizeImage(Image image, int maxWidth, int maxHeight)
{
decimal width = image.Width;
decimal height = image.Height;
decimal newWidth;
decimal newHeight;
//Calculate new width and height
if (width > maxWidth || height > maxHeight)
{
// need to preserve the original aspect ratio
decimal originalAspectRatio = width / height;
decimal widthReductionFactor = maxWidth / width;
decimal heightReductionFactor = maxHeight / height;
if (widthReductionFactor < heightReductionFactor)
{
newWidth = maxWidth;
newHeight = newWidth / originalAspectRatio;
}
else
{
newHeight = maxHeight;
newWidth = newHeight * originalAspectRatio;
}
}
else
//Return a copy of the image if smaller than allowed width and height
return new Bitmap(image);
//Resize image
Bitmap bitmap = new Bitmap((int)newWidth, (int)newHeight, PixelFormat.Format48bppRgb);
Graphics graphic = Graphics.FromImage(bitmap);
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.DrawImage(image, 0, 0, (int)newWidth, (int)newHeight);
graphic.Dispose();
return bitmap;
}