/// <inheritdoc /> protected override async Task <bool> Render( ThumbnailsRenderContext ctx, ThumbnailsRenderFileInfo fileInfo, ThumbnailsRenderOption option) { // use the following code maybe faster. https://github.com/kleisauke/net-vips/issues/128 // > sourceVipsImage = Image.Thumbnail(localPath, loadImageSize, loadImageSize, noRotate: false); return(await _fileService.ReadFileStream( fileInfo.FileHandle, stream => { var sourceVipsImage = Image.ThumbnailStream( stream, (int)(ThumbnailUtils.DefaultMaxWidth * ctx.Density), height: (int)(ThumbnailUtils.DefaultMaxHeight * ctx.Density), noRotate: false); sourceVipsImage = sourceVipsImage.Colourspace(Enums.Interpretation.Srgb).Cast(Enums.BandFormat.Uchar); if (!sourceVipsImage.HasAlpha()) { sourceVipsImage = sourceVipsImage.Bandjoin(255); } var imageWidth = sourceVipsImage.Width; var imageHeight = sourceVipsImage.Height; var sourceImageDataPtr = sourceVipsImage.WriteToMemory(out _); sourceVipsImage.Close(); try { using var colorspace = SKColorSpace.CreateSrgb(); var sourceImageInfo = new SKImageInfo( imageWidth, imageHeight, SKColorType.Rgba8888, SKAlphaType.Unpremul, colorspace); using var image = SKImage.FromPixels(sourceImageInfo, sourceImageDataPtr, sourceImageInfo.RowBytes); ThumbnailUtils.DrawShadowView(ctx, new SkImageView(image)); } finally { NetVips.NetVips.Free(sourceImageDataPtr); } return ValueTask.FromResult(true); })); }
private static void DrawAttachedPicture(ThumbnailsRenderContext ctx, MediaStream attachedPicStream) { using var attachedPicture = attachedPicStream.ReadAttachedPicture(); var attachedPictureVipsImage = Image.ThumbnailStream( attachedPicture, (int)(ThumbnailUtils.DefaultMaxWidth * ctx.Density), height: (int)(ThumbnailUtils.DefaultMaxHeight * ctx.Density), noRotate: false); attachedPictureVipsImage = attachedPictureVipsImage.Colourspace(Enums.Interpretation.Srgb).Cast(Enums.BandFormat.Uchar); if (!attachedPictureVipsImage.HasAlpha()) { attachedPictureVipsImage = attachedPictureVipsImage.Bandjoin(255); } var imageWidth = attachedPictureVipsImage.Width; var imageHeight = attachedPictureVipsImage.Height; var sourceImageDataPtr = attachedPictureVipsImage.WriteToMemory(out _); attachedPictureVipsImage.Close(); try { using var colorspace = SKColorSpace.CreateSrgb(); var sourceImageInfo = new SKImageInfo( imageWidth, imageHeight, SKColorType.Rgba8888, SKAlphaType.Unpremul, colorspace); using var image = SKImage.FromPixels(sourceImageInfo, sourceImageDataPtr, sourceImageInfo.RowBytes); _cachedDecorationImage ??= SKImage.FromEncodedData(ReadDecorationImage()); ThumbnailUtils.DrawShadowView( ctx, new SkImageView(image), _cachedDecorationImage, new SKColor(0, 0, 0), minSize: new SKSize(24, 24)); } finally { NetVips.NetVips.Free(sourceImageDataPtr); } }
private static unsafe void DrawWaves(ThumbnailsRenderContext ctx, MediaStream audioStream) { var height = 88; var width = 88; using var recorder = new SKPictureRecorder(); using var canvas = recorder.BeginRecording(SKRect.Create(width, height)); var columnCount = 88 * 2; var columnWidth = (float)width / columnCount; using var wavePaint = new SKPaint { Color = new SKColor(128, 128, 128, 76), StrokeWidth = columnWidth }; var totalSample = audioStream.SampleRate * audioStream.Duration; var columnMaxSample = (int)(totalSample / columnCount); var columns = new short[columnCount]; using var decoder = audioStream.CreateStreamDecoder(); using var filter = new AudioFormatFilter("sample_fmts=s16:channel_layouts=mono", audioStream, decoder); filter.Build(); long sum = 0; var n = 0; var c = 0; while (filter.MoveNext()) { var frame = filter.Current.Value; var p = (short *)frame->data[0]; for (var i = 0; i < frame->nb_samples; i++) { sum += SampleAbs(p[i]); n++; if (n == columnMaxSample && c < columnCount) { columns[c] = (short)(sum / n); n = 0; sum = 0; c++; } } } for (var i = 0; i < columnCount; i++) { var h = Math.Max((float)columns[i] * height / short.MaxValue, 0.5f); var x = i * columnWidth; canvas.DrawLine(x, (height - h) / 2.0f, x, (height + h) / 2.0f, wavePaint); } _cachedWaveformDecorationImage ??= SKImage.FromEncodedData(ReadWaveformDecorationImage()); canvas.DrawImage(_cachedWaveformDecorationImage, SKRect.Create((width - 28) / 2.0f, (height - 36) / 2.0f, 28, 36)); using var picture = recorder.EndRecording(); ThumbnailUtils.DrawShadowView( ctx, new SkPictureView( picture, new SKSize(88, 88))); }
private static unsafe bool DrawVideo(Stream videoStream, ThumbnailsRenderContext ctx) { using var formatContext = new FormatContext(videoStream); var stream = formatContext.FindBestVideoStream(); if (stream == null) { return(false); } using var videoStreamDecoder = stream.CreateStreamDecoder(); try { if (videoStreamDecoder.Duration <= 0) { videoStreamDecoder.SeekFrame(10 * 1000000); } if (videoStreamDecoder.Duration > 3) { videoStreamDecoder.SeekFrame(videoStreamDecoder.Duration / 3); } } catch (FFmpegException err) { Console.WriteLine("Seek failed: " + err); } var destinationSize = ThumbnailUtils.ContainSize( new SKSize(videoStreamDecoder.FrameWidth, videoStreamDecoder.FrameHeight), new SKSize(ThumbnailUtils.DefaultMaxWidth * ctx.Density, ThumbnailUtils.DefaultMaxHeight * ctx.Density)).ToSizeI(); var sourcePixelFormat = videoStreamDecoder.PixelFormat; if (!videoStreamDecoder.MoveNext()) { throw new InvalidDataException("Can't decode the video."); } using var vfc = new VideoFrameConverter( videoStreamDecoder.FrameWidth, videoStreamDecoder.FrameHeight, sourcePixelFormat, destinationSize.Width, destinationSize.Height); var convertedFrame = vfc.Convert(videoStreamDecoder.Current.Value); using var colorspace = SKColorSpace.CreateSrgb(); var sourceImageInfo = new SKImageInfo( convertedFrame.width, convertedFrame.height, SKColorType.Rgba8888, SKAlphaType.Unpremul, colorspace); using var image = SKImage.FromPixels(sourceImageInfo, (IntPtr)convertedFrame.data[0], sourceImageInfo.RowBytes); _cachedDecorationImage ??= SKImage.FromEncodedData(ReadDecorationImage()); ThumbnailUtils.DrawShadowView( ctx, new SkImageView(image), _cachedDecorationImage, new SKColor(0, 0, 0), minSize: new SKSize(24, 24)); return(true); }