Last active
June 1, 2021 15:57
-
-
Save dolemite7/b50903c0002cc1c5c489364694c6c0cd to your computer and use it in GitHub Desktop.
C# Video Thumbnail Sheet
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
ThumbnailSheet uses MediaToolkit (https://github.com/AydinAdn/MediaToolkit) and Magick.NET (https://magick.codeplex.com/) | |
to create a sheet of timestamped thumbnails for a given video file. | |
Preview: http://imgur.com/a/iLGMs | |
Use Nuget to Install-Package MediaToolKit, and download a copy of Magick.NET, add it to your project's /bin folder and | |
create a reference to the .dll. | |
Usage example: | |
ThumbnailSheet oSheet = new ThumbnailSheet(); | |
oSheet.CreateThumbnailSheet(@"d:\temp\imagemagicktemp\capture-burial-1.mp4"); | |
*/ | |
using System; | |
using System.IO; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using System.Drawing; | |
using System.Diagnostics; | |
using MediaToolkit; | |
using MediaToolkit.Model; | |
using MediaToolkit.Options; | |
using ImageMagick; | |
namespace Thumbnailer | |
{ | |
public class ThumbnailSheet | |
{ | |
internal static void Main(string[] args) | |
{ | |
//MagickNET.Initialize(@"C:\MyProgram\MyImageMagickXmlFiles"); | |
MagickNET.SetTempDirectory(@"d:\\temp\\imagemagicktemp\\"); | |
} | |
public TimeSpan GetVideoLength(string inValue) | |
{ | |
var inputFile = new MediaFile { Filename = @inValue }; | |
using (var engine = new Engine()) | |
{ | |
engine.GetMetadata(inputFile); | |
} | |
return inputFile.Metadata.Duration; | |
} | |
public string CreateThumbnail(string inValue, double inSeconds) | |
{ | |
var inputFile = new MediaFile { Filename = @inValue }; | |
string outputFileName = inValue.Substring(0,inValue.LastIndexOf(".")) + ".jpg"; | |
var outputFile = new MediaFile { Filename = @outputFileName }; | |
using (var engine = new Engine()) | |
{ | |
engine.GetMetadata(inputFile); | |
var options = new ConversionOptions { Seek = TimeSpan.FromSeconds(inSeconds) }; | |
if (!System.IO.File.Exists(outputFileName)) | |
engine.GetThumbnail(inputFile, outputFile, options); | |
} | |
return outputFileName; | |
} | |
public void CreateThumbnails(string inFile, int inQty) | |
{ | |
if (!System.IO.File.Exists(inFile)) | |
{ | |
Console.WriteLine("File not found."); | |
return; | |
} | |
double dSeconds = GetVideoLength(inFile).TotalSeconds; | |
double dSecondSplit = (dSeconds == 0 || inQty < 1) ? 0 : dSeconds / inQty; | |
int fileCount = 1; | |
string fileOut = ""; | |
string fileNumber = ""; | |
for (double x = 0; x < dSeconds; x += dSecondSplit) | |
{ | |
fileOut = CreateThumbnail(inFile, x); | |
fileNumber = fileCount.ToString("000"); | |
if (Math.Round(x) < Math.Round(dSeconds) && !System.IO.File.Exists(fileOut.Replace(".jpg", "-" + fileNumber + ".jpg"))) | |
{ | |
string str = TimeSpan.FromSeconds(x).ToString(@"hh\:mm\:ss"); | |
StampImage(fileOut, str); | |
System.IO.File.Move(fileOut, fileOut.Replace(".jpg", "-" + fileNumber + ".jpg")); | |
} | |
fileCount++; | |
} | |
} | |
public void StampImage(string inFile, string inText) | |
{ | |
string tempPath = inFile.Substring(0, inFile.LastIndexOf("\\") + 1); | |
string tempFilename = inFile.Substring(inFile.LastIndexOf("\\") + 1); | |
string tempFileprefix = tempFilename.Substring(0, tempFilename.LastIndexOf(".")) + "-"; | |
var imageBackgroundColor = new MagickColor("Black"); | |
var img = new MagickImage(inFile); | |
var imageFileName = tempPath + tempFileprefix + "-overlay.jpg"; | |
using (MagickImage imgText = new MagickImage(inFile)) | |
{ | |
var drawable = new DrawableText(5, 5, inText); | |
var gravity = new DrawableGravity(Gravity.Southeast); | |
var font = new DrawableFont("Tahoma"); | |
var antialias = new DrawableTextAntialias(true); | |
var size = new DrawableFontPointSize(48); | |
var color = new DrawableFillColor(Color.Black); | |
var strokecolor = new DrawableStrokeColor(Color.AliceBlue); | |
imgText.Draw(drawable, gravity, font, antialias, size, color, strokecolor); | |
imgText.Write(imageFileName); | |
} | |
System.IO.File.Delete(inFile); | |
System.IO.File.Move(imageFileName, inFile); | |
} | |
public void CreateThumbnailSheet(string inFilepath) | |
{ | |
if (!System.IO.File.Exists(inFilepath)) | |
{ | |
Console.WriteLine("File not found."); | |
return; | |
} | |
Stopwatch sw = Stopwatch.StartNew(); | |
CreateThumbnails(inFilepath, 16); | |
string tempPath = inFilepath.Substring(0, inFilepath.LastIndexOf("\\") + 1); | |
string tempFilename = inFilepath.Substring(inFilepath.LastIndexOf("\\") + 1); | |
string tempFileprefix = tempFilename.Substring(0, tempFilename.LastIndexOf(".")) + "-"; | |
int tempWidth = 0; | |
int tempHeight = 0; | |
if (System.IO.File.Exists(tempPath + tempFileprefix + "sheet.png")) | |
System.IO.File.Delete(tempPath + tempFileprefix + "sheet.png"); | |
List<string> lFiles = new List<string>(); | |
foreach (string sFile in Directory.EnumerateFiles(tempPath, tempFileprefix + "*.jpg")) | |
lFiles.Add(sFile); | |
using (MagickImageCollection images = new MagickImageCollection()) | |
{ | |
foreach (string tempFile in lFiles) | |
{ | |
MagickImage magickinput = new MagickImage(tempFile); | |
tempWidth = magickinput.Width; | |
tempHeight = magickinput.Height; | |
images.Add(magickinput); | |
} | |
tempWidth /= 2; | |
tempHeight /= 2; | |
MontageSettings ms = new MontageSettings(); | |
//ms.Geometry = new MagickGeometry(string.Format("{0}x{1}", 200, 200)); | |
ms.Geometry = new MagickGeometry(string.Format("{0}x{1}", tempWidth, tempHeight)); | |
ms.TileGeometry = new MagickGeometry(string.Format("{0}x", 4)); | |
ms.BackgroundColor = Color.Black; | |
ms.BorderColor = Color.DarkGray; | |
ms.BorderWidth = 2; | |
ms.Font = "Tahoma"; | |
ms.FontPointsize = 20; | |
ms.FillColor = Color.LightGray; | |
ms.StrokeColor = Color.White; | |
ms.Title = tempFilename; | |
using (MagickImage montageResult = images.Montage(ms)) | |
{ | |
montageResult.Write(tempPath + tempFileprefix + "sheet.png"); | |
} | |
} | |
foreach (string tempFile in lFiles) | |
{ | |
if (System.IO.File.Exists(tempFile)) | |
System.IO.File.Delete(tempFile); | |
} | |
sw.Stop(); | |
Console.WriteLine("Montage complete: " + sw.Elapsed.TotalMilliseconds.ToString() + "ms."); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment