using SkiaSharp; using System; using System.IO; using Vinno.IUS.Common.Log; namespace Vinno.vCloud.Common.Vid2.Codec { public class VinnoImageEncoder { private readonly float _xScale; private readonly float _yScale; private int _currentIndex; public VinnoImageEncoder(float xScale = 1.0f, float yScale = 1.0f) { _currentIndex = -1; _xScale = xScale; _yScale = yScale; } /// /// Convert bitmap to jpeg image bytes. /// /// /// The compress level for image, default is 75 /// private byte[] ImageToBytes(SKBitmap image, long compressLevel = 80) { try { var newWidth = (int)(image.Width * _xScale); var newHeight = (int)(image.Height * _yScale); SKBitmap tempImage = image; if (image.Width != newWidth || image.Height != newHeight) { tempImage = image.Resize(new SKImageInfo(newWidth, newHeight), SKFilterQuality.None); } try { using (var map = new SKPixmap(new SKImageInfo(tempImage.Width, tempImage.Height, tempImage.ColorType), tempImage.GetPixels())) { using (var stream = new SKDynamicMemoryWStream()) { SKPixmap.Encode(stream, map, SKEncodedImageFormat.Jpeg, (int)compressLevel); return stream.CopyToData().ToArray(); } } } catch (Exception exception) { throw new Exception($"ImageToBytes error:{exception}"); } finally { tempImage.Dispose(); } } catch (Exception e) { Logger.WriteLineError( $"Vinno image encode error image width :{image.Width}, image height :{image.Height}, stack is {e}"); } return new byte[0]; } /// /// Encode a bitmap to VinnoImage. /// /// The bitmap to be encoded. /// The VinnoImage public VinnoImage Encode(SKBitmap image) { _currentIndex++; return new VinnoImage(_currentIndex, image.Width, image.Height, ImageToBytes(image)); } /// /// Compress a VinnoImage to a 480p image with 50 quality. /// /// /// public VinnoImage Compress(VinnoImage vinnoImage) { byte[] compressedData = vinnoImage.ImageData; using (var ms = new MemoryStream(compressedData)) { using (var image = SKBitmap.Decode(ms)) { //Get 480p ratio var ratio = (double)480 / image.Height; if (ratio < 1) { var width = (int)(image.Width * ratio); var height = (int)(image.Height * ratio); SKBitmap tempImage = image; if (image.Width != width || image.Height != height) { tempImage = image.Resize(new SKImageInfo(width, height), SKFilterQuality.High); } try { using (var map = new SKPixmap(new SKImageInfo(tempImage.Width, tempImage.Height, tempImage.ColorType), tempImage.GetPixels())) { using (var stream = new SKDynamicMemoryWStream()) { SKPixmap.Encode(stream, map, SKEncodedImageFormat.Jpeg, 50); compressedData = stream.CopyToData().ToArray(); } } } catch (Exception exception) { throw new Exception($"Compress error:{exception}"); } finally { tempImage.Dispose(); } } } } var updater = new VinnoImageUpdater(vinnoImage); updater.Update(compressedData); return vinnoImage; } } }