/// <summary> /// Scales down the byte size of the image by reducing dimensions and/or introducing compression. It aims to get it under 2MB so the web service won't reject it. /// </summary> private byte[] ResizePictureForDetection(byte[] data) { const int maxLength = 2*1000*1000; // be conservative if (data == null || data.Length < maxLength) return data; using (var ms = new MemoryStream(data)) { using (var rawImage = (Bitmap) Image.FromStream(ms)) { log.DebugFormat("Image is too big @ {0} bytes, {1}x{2}, shrinking", data.Length, rawImage.Width, rawImage.Height); // too big - try some measures to downsize things for (var cutSize = 1;; cutSize++) { // first, let's cut the image down using (var smallerImage = new ResizeBilinear(rawImage.Width/cutSize, rawImage.Height/cutSize).Apply(rawImage)) { log.DebugFormat("Sized down to {0}x{1}", smallerImage.Width, smallerImage.Height); // now, see what a PNG would be... var png = ImageHelper.GetBytes(s => smallerImage.Save(s, ImageFormat.Png)); log.DebugFormat("PNG is {0} bytes", png.Length); if (png.Length < maxLength) return png; // too big, try JPEG @ Q100 var jpgQ100 = ImageHelper.GetBytes(s => smallerImage.Save(s, ImageHelper.JPEGEncoder(), ImageHelper.Quality(100))); log.DebugFormat("JPG@Q100 is {0} bytes", jpgQ100.Length); if (jpgQ100.Length < maxLength) return jpgQ100; // too big, try JPEG @ Q99 var jpgQ99 = ImageHelper.GetBytes(s => smallerImage.Save(s, ImageHelper.JPEGEncoder(), ImageHelper.Quality(99))); log.DebugFormat("JPG@Q99 is {0} bytes", jpgQ99.Length); if (jpgQ99.Length < maxLength) return jpgQ99; // too big, try JPEG @ Q95 var jpgQ95 = ImageHelper.GetBytes(s => smallerImage.Save(s, ImageHelper.JPEGEncoder(), ImageHelper.Quality(95))); log.DebugFormat("JPG@Q95 is {0} bytes", jpgQ95.Length); if (jpgQ95.Length < maxLength) return jpgQ95; // still too big, guess we'll have to use a smaller image } } } } }