public static ImageSource CreatePreview(ThumbnailBannerGeneratorSettings settings) { ThumbnailBannerGeneratorData data = new ThumbnailBannerGeneratorData { Settings = settings, Images = new ThumbnailBannerGeneratorImage[settings.Rows * settings.Columns], VideoInfo = new VideoInfo { AudioCodec = "Audio Codec", Duration = new TimeSpan(1, 23, 45), Resolution = new Resolution(1920, 1080), FrameRate = 29.9, VideoCodec = "Video Codec", SampleRate = 40000 }, VideoName = "Video File Name.ext", FileSize = 1234567890 }; for (int i = 0; i < data.Images.Length; i++) { data.Images[i] = new ThumbnailBannerGeneratorImage { Image = CreateImage(800, 600, Brushes.DimGray), Position = TimeSpan.FromMinutes(i) } } ; return(CreateBanner(data)); }
private static ImageSource CreateBanner(ThumbnailBannerGeneratorData data) { Brush backgroundBrush = new SolidColorBrush(Color.FromRgb(0xF0, 0xF0, 0xF0)); Brush shadowBrush = Brushes.Black; Brush borderBrush = Brushes.Black; double shadowOpacity = 0.5; double textOpacity = 0.7; int shadowOffset = 4; int headerHeight = 95; int horizontalSpacing = 8; int verticalSpacing = 8; int positionTextOutlineWidth = 4; int textSpacing = 5; int fontSize = 16; int borderWidth = 1; string font = "Arial"; // ------------------------------ int horizontalImageResolution = ((BitmapSource)data.Images[0].Image).PixelWidth; int verticalImageResolution = ((BitmapSource)data.Images[0].Image).PixelHeight; int imageWidth = (data.Settings.TotalWidth - (data.Settings.Columns + 1) * horizontalSpacing) / data.Settings.Columns; int imageHeight = (int)Math.Round((imageWidth / (double)horizontalImageResolution) * verticalImageResolution); int width = data.Settings.TotalWidth; int height = headerHeight + (data.Settings.Rows + 1) * verticalSpacing + data.Settings.Rows * imageHeight; Typeface typefaceBold = new Typeface(new FontFamily(font), new FontStyle(), FontWeights.Bold, FontStretches.Normal); Typeface typefaceNormal = new Typeface(new FontFamily(font), new FontStyle(), FontWeights.Normal, FontStretches.Normal); ImageSource logo = new BitmapImage(new Uri("pack://application:,,,/Images/ScriptPlayerIcon.png", UriKind.RelativeOrAbsolute)); DrawingVisual image = new DrawingVisual(); using (DrawingContext dc = image.RenderOpen()) { RenderOptions.SetBitmapScalingMode(image, BitmapScalingMode.LowQuality); dc.DrawRectangle(backgroundBrush, null, new Rect(0, 0, width, height)); dc.DrawText(CreateText(Path.GetFileName(data.VideoName), typefaceBold, 18), new Point(horizontalSpacing, verticalSpacing)); string infoText = string.Format(CultureInfo.InvariantCulture, "File Size: {0}\r\n", MakeReadable(data.FileSize)) + string.Format(CultureInfo.InvariantCulture, "Resolution: {0}\r\n", data.VideoInfo.Resolution) + string.Format(CultureInfo.InvariantCulture, "Duration: {0:hh\\:mm\\:ss\\.f}", data.VideoInfo.Duration); dc.DrawText(CreateText(infoText, typefaceNormal, 16), new Point(horizontalSpacing, verticalSpacing + 25)); double logoSize = headerHeight - 2 * verticalSpacing; Rect logoDest = new Rect(width - logoSize - horizontalSpacing, verticalSpacing, logoSize, logoSize); dc.DrawImage(logo, logoDest); for (int column = 0; column < data.Settings.Columns; column++) { for (int row = 0; row < data.Settings.Rows; row++) { int index = row * data.Settings.Columns + column; int x = horizontalSpacing + column * (horizontalSpacing + imageWidth); int y = headerHeight + verticalSpacing + row * (verticalSpacing + imageHeight); Rect imageRect = new Rect(x, y, imageWidth, imageHeight); Rect borderRect = imageRect; borderRect.X -= borderWidth; borderRect.Y -= borderWidth; borderRect.Width += 2 * borderWidth; borderRect.Height += 2 * borderWidth; Rect shadowRect = borderRect; shadowRect.Offset(shadowOffset, shadowOffset); dc.PushOpacity(shadowOpacity); dc.DrawRectangle(shadowBrush, null, shadowRect); dc.Pop(); dc.DrawRectangle(borderBrush, null, borderRect); dc.DrawImage(data.Images[index].Image, imageRect); FormattedText text = CreateText(data.Images[index].Position.ToString("mm\\:ss"), typefaceBold, fontSize); Point origin = new Point(x + imageWidth - textSpacing - text.Width, y + imageHeight - textSpacing - text.Height); Geometry textGeometry = text.BuildGeometry(origin); Geometry textOutline = textGeometry.GetWidenedPathGeometry(new Pen(Brushes.Black, positionTextOutlineWidth)); dc.PushOpacity(textOpacity); dc.DrawGeometry(Brushes.Black, null, textOutline); dc.DrawGeometry(Brushes.White, null, textGeometry); dc.Pop(); } } } RenderTargetBitmap bitmap = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32); bitmap.Render(image); return(bitmap); }
protected override GeneratorResult ProcessInternal(ThumbnailBannerGeneratorSettings settings, GeneratorEntry entry) { try { entry.State = JobStates.Processing; _wrapper = new FfmpegWrapper(FfmpegExePath); var videoInfo = _wrapper.GetVideoInfo(settings.VideoFile); if (!videoInfo.IsGoodEnough()) { entry.State = JobStates.Done; entry.DoneType = JobDoneTypes.Failure; entry.Update("Failed", 1); return(GeneratorResult.Failed()); } TimeSpan duration = videoInfo.Duration; TimeSpan intervall = duration.Divide(settings.Columns * settings.Rows + 1); var frameArguments = new FrameConverterArguments { Width = 800, Intervall = intervall.TotalSeconds, StatusUpdateHandler = (progress) => { entry.Update(null, progress); }, InputFile = settings.VideoFile, OutputDirectory = FfmpegWrapper.CreateRandomTempDirectory() }; entry.Update("Extracting Frames", 0); var frames = _wrapper.ExtractFrames(frameArguments); if (_canceled) { return(GeneratorResult.Failed()); } entry.Update("Saving Thumbnails", 1); List <ThumbnailBannerGeneratorImage> images = new List <ThumbnailBannerGeneratorImage>(); foreach (var frame in frames) { images.Add(new ThumbnailBannerGeneratorImage { Image = frame.Item2, Position = frame.Item1 }); } ThumbnailBannerGeneratorData data = new ThumbnailBannerGeneratorData(); data.Settings = settings; data.Images = images.ToArray(); data.VideoName = settings.VideoFile; data.VideoInfo = videoInfo; data.FileSize = new FileInfo(settings.VideoFile).Length; var result = CreateBanner(data); JpegBitmapEncoder encoder = new JpegBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create((BitmapSource)result)); using (FileStream stream = new FileStream(settings.OutputFile, FileMode.Create)) encoder.Save(stream); Directory.Delete(frameArguments.OutputDirectory); entry.DoneType = JobDoneTypes.Success; entry.Update("Done", 1); return(GeneratorResult.Succeeded(settings.OutputFile)); } catch (Exception) { entry.Update("Failed", 1); entry.DoneType = JobDoneTypes.Failure; return(GeneratorResult.Failed()); } finally { entry.State = JobStates.Done; if (_canceled) { entry.DoneType = JobDoneTypes.Cancelled; entry.Update("Cancelled", 1); } } }