需求
导出PPT到MP4,并记录每页,每个动作的时间线。通过 MP4+时间线 就可以在页面上很方便的放映PPT的内容,并支持翻页点击。
代码
保存每一页的图像信息,用做播放器的缩略图
public void SaveThumbnail(string ppt_filepath, string targetdir)
记录下时间线
public void ResetTimeline(string ppt_filepath,string targetdir)
打开PPT并绑定事件
presentation = PPT.Presentations.Open(fn, MsoTriState.msoFalse, MsoTriState.msoFalse, MsoTriState.msoTrue);
PPT.SlideShowBegin += SlideShowBeginEvent;//开始运行PPT
PPT.SlideShowEnd += SlideShowEndEvent;//开始运行PPT
PPT.SlideShowNextSlide += SlideShowNextSlideEvent;//PPT翻页事件
PPT.SlideShowNextClick += SlideShowNextClickEvent;
PPT.WindowActivate += WindowActivateEvent;
开始播放
presentation.SlideShowSettings.AdvanceMode = PpSlideShowAdvanceMode.ppSlideShowRehearseNewTimings;
presentation.SlideShowSettings.ShowWithNarration = MsoTriState.msoFalse;
presentation.SlideShowSettings.ShowMediaControls = MsoTriState.msoTrue;
presentation.SlideShowSettings.Run();
保存MP4文件
presentation.CreateVideo(fn_mp4, true, 1, 720);
保存时间线json
string json = Newtonsoft.Json.JsonConvert.SerializeObject(list_TimeRec);
string json_fn = Path.ChangeExtension(fn_mp4,".json");
File.WriteAllText(json_fn, json);
全部代码
public class PPTTools
{
public static void ClosePPT()
{
Process[] powerPointProcesses = Process.GetProcessesByName("powerpnt");
foreach (Process powerPointProcess in powerPointProcesses)
{
try
{
// 尝试关闭进程,并等待一段时间
powerPointProcess.CloseMainWindow();
powerPointProcess.WaitForExit(1000);
// 如果进程仍然没有关闭,强制结束
if (!powerPointProcess.HasExited)
{
powerPointProcess.Kill();
}
}
catch (Exception ex)
{
//无法关闭PowerPoint进程
}
}
}
public void SaveThumbnail(string ppt_filepath, string targetdir)
{
ClosePPT();
string tmpdir = get_tmpdir();
string fn = Path.GetFileNameWithoutExtension(ppt_filepath) + "_tmp" + Path.GetExtension(ppt_filepath);
fn = Path.Combine(tmpdir, fn);
File.Copy(ppt_filepath, fn, true);
list_TimeRec.Clear();
will_next = false;
PPT = new Microsoft.Office.Interop.PowerPoint.Application();
presentation = null;
presentation = PPT.Presentations.Open(fn, MsoTriState.msoFalse, MsoTriState.msoFalse, MsoTriState.msoTrue);
for (int i = 1; i <= presentation.Slides.Count; i++)
{
string thumbnail_fn = presentation.Slides[i].SlideNumber.ToString() + ".jpg";
thumbnail_fn = Path.Combine(targetdir, thumbnail_fn);
presentation.Slides[i].Export(thumbnail_fn, "JPG",1280);
}
PPT.Quit();
ClosePPT();
}
public static string exefilename()
{
return System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
}
public static string get_tmpdir()
{
string dir = Path.GetDirectoryName(exefilename());
dir = Path.Combine(dir, "temp");
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
return dir;
}
private bool is_Timeline = false;
private bool is_Completed = false;
private DateTime SlideShowNextSlideEvent_Time;
private bool will_next = false;
private Microsoft.Office.Interop.PowerPoint.Application PPT = null;
private Presentation presentation = null;
private SlideShowWindow CurrShowWindow;
private List<TimeRec> list_TimeRec = new List<TimeRec>();
public void ResetTimeline(string ppt_filepath,string targetdir)
{
if (is_Timeline)
return;
is_Timeline = true;
is_Completed = false;
ClosePPT();
string tmpdir = get_tmpdir();
string fn = Path.GetFileNameWithoutExtension(ppt_filepath )+ "_tmp" + Path.GetExtension(ppt_filepath);
fn = Path.Combine(tmpdir, fn);
File.Copy(ppt_filepath, fn, true);
list_TimeRec.Clear();
will_next = false;
PPT = new Microsoft.Office.Interop.PowerPoint.Application();
presentation = null;
presentation = PPT.Presentations.Open(fn, MsoTriState.msoFalse, MsoTriState.msoFalse, MsoTriState.msoTrue);
PPT.SlideShowBegin += SlideShowBeginEvent;//开始运行PPT
PPT.SlideShowEnd += SlideShowEndEvent;//开始运行PPT
PPT.SlideShowNextSlide += SlideShowNextSlideEvent;//PPT翻页事件
PPT.SlideShowNextClick += SlideShowNextClickEvent;
PPT.WindowActivate += WindowActivateEvent;
//presentation.SlideShowSettings.LoopUntilStopped = MsoTriState.msoFalse;
presentation.SlideShowSettings.AdvanceMode = PpSlideShowAdvanceMode.ppSlideShowRehearseNewTimings;
presentation.SlideShowSettings.ShowWithNarration = MsoTriState.msoFalse;
presentation.SlideShowSettings.ShowMediaControls = MsoTriState.msoTrue;
presentation.SlideShowSettings.Run();
System.Windows.Forms.Application.DoEvents();
while (!is_Completed)
{
System.Windows.Forms.Application.DoEvents();
System.Threading.Thread.Sleep(10);
if (will_next)
{
if ((DateTime.Now - SlideShowNextSlideEvent_Time).TotalMilliseconds > 1000 * 8)
{
will_next = true;
SlideShowNextSlideEvent_Time = DateTime.Now;
int ClickCount = CurrShowWindow.View.GetClickCount();
int ClickIndex = CurrShowWindow.View.GetClickIndex();
if (ClickCount <= 0)
{
if (CurrShowWindow.View.Slide.SlideIndex == presentation.Slides.Count )
{
break;
}
CurrShowWindow.View.Next();
}
else
{
if (ClickIndex <= (ClickCount -1))
{
CurrShowWindow.View.GotoClick(ClickIndex + 1);
//add_rec(ShowWindow);
SlideShowNextSlideEvent_Time = DateTime.Now;
}
else
{
if (CurrShowWindow.View.Slide.SlideIndex == presentation.Slides.Count )
{
break;
}
else
{
CurrShowWindow.View.Next();
}
}
}
}
}
}
exited = false;
Thread trd = new Thread( this.thread_proc );
trd.Start();
CurrShowWindow.View.Exit();
exited = true;
presentation.Save();
if (!System.IO.Directory.Exists(targetdir))
System.IO.Directory.CreateDirectory(targetdir);
string fn_mp4 =Path.ChangeExtension( Path.Combine(targetdir, Path.GetFileName(ppt_filepath)),".mp4");
presentation.CreateVideo(fn_mp4, true, 1, 720);
for (int i = 0; i < 20; i++)
{
System.Windows.Forms.Application.DoEvents();
System.Threading.Thread.Sleep(100);
}
while (presentation.CreateVideoStatus == PpMediaTaskStatus.ppMediaTaskStatusInProgress)
{
System.Windows.Forms.Application.DoEvents();
System.Threading.Thread.Sleep(10);
}
string json = Newtonsoft.Json.JsonConvert.SerializeObject(list_TimeRec);
string json_fn = Path.ChangeExtension(fn_mp4,".json");
File.WriteAllText(json_fn, json);
ClosePPT();
is_Timeline = false;
}
private bool exited = false;
public void thread_proc()
{
while (!exited)
{
try
{
System.Threading.Thread.Sleep(100);
IntPtr h = IntPtr.Zero;
h = FindWindow(null, "Microsoft PowerPoint");
if (h != IntPtr.Zero)
{
ForceWindowIntoForeground(h);//置顶
SendKeys.SendWait("\r");
SendKeys.SendWait(" ");
}
else
{
}
}
catch (Exception err)
{
}
Thread.Sleep(500);
}
}
public void SlideShowBeginEvent(SlideShowWindow Wn)
{
}
public void SlideShowEndEvent(Presentation Pres)
{
is_Completed = true;
}
public void add_rec(SlideShowWindow Wn,string Event)
{
Slide slide = Wn.View.Slide;
TimeRec rec = new TimeRec();
rec.Event = Event;
rec.ShowPosition = Wn.View.CurrentShowPosition;
rec.PresentationElapsedTime = Wn.View.PresentationElapsedTime;
rec.SlideElapsedTime = Wn.View.SlideElapsedTime;
rec.SlideIndex = slide.SlideIndex;
rec.SlideNumber = slide.SlideNumber;
rec.ClickCount = Wn.View.GetClickCount();
rec.ClickIndex = Wn.View.GetClickIndex();
list_TimeRec.Add(rec);
}
public void SlideShowNextSlideEvent(SlideShowWindow Wn)
{
add_rec(Wn, "NextSlide");
CurrShowWindow = Wn;
SlideShowNextSlideEvent_Time = DateTime.Now ;
will_next = true;
}
public void SlideShowNextClickEvent(SlideShowWindow Wn, Effect nEffect) {
add_rec(Wn, "NextClick");
CurrShowWindow = Wn;
SlideShowNextSlideEvent_Time = DateTime.Now;
will_next = true;
}
public void WindowActivateEvent(Presentation Pres, DocumentWindow Wn)
{
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
//I'd double check this constant, just in case
static uint WM_CLOSE = 0x10;
public void CloseWindow(IntPtr hWindow)
{
SendMessage(hWindow, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}
[DllImport("USER32.DLL")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
public const int HWND_TOP = 0;
public const int HWND_BOTTOM = 1;
public const int HWND_TOPMOST = -1;
public const int HWND_NOTOPMOST = -2;
public struct WindowRect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
private const int SW_HIDE = 0;
private const int SW_SHOWNORMAL = 1;
private const int SW_NORMAL = 1;
private const int SW_SHOWMINIMIZED = 2;
private const int SW_SHOWMAXIMIZED = 3;
private const int SW_MAXIMIZE = 3;
private const int SW_SHOWNOACTIVATE = 4;
private const int SW_SHOW = 5;
private const int SW_MINIMIZE = 6;
private const int SW_SHOWMINNOACTIVE = 7;
private const int SW_SHOWNA = 8;
private const int SW_RESTORE = 9;
private const int SW_SHOWDEFAULT = 10;
private const int SW_MAX = 10;
private const int SPI_GETFOREGROUNDLOCKTIMEOUT = 0x2000;
private const int SPI_SETFOREGROUNDLOCKTIMEOUT = 0x2001;
private const int SPIF_SENDCHANGE = 0x2;
[DllImport("user32.dll", SetLastError = true)]
static extern bool SystemParametersInfo(int uiAction, int uiParam, ref uint pvParam, int fWinIni);
[DllImport("user32.dll")]
private static extern IntPtr AttachThreadInput(IntPtr idAttach, IntPtr idAttachTo, Boolean fAttach);
[DllImport("user32", EntryPoint = "GetWindowThreadProcessId")]
private static extern IntPtr GetWindowThreadProcessId(IntPtr hwnd, out IntPtr lpdwProcessId);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetForegroundWindow();
[DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
public static extern IntPtr GetCurrentThreadId();
[DllImport("user32.dll", EntryPoint = "SetForegroundWindow")]
public static extern bool SetForegroundWindow(IntPtr hWnd);//设置此窗体为活动窗体
[DllImport("user32.dll")]
public static extern IntPtr SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint wFlags);
[DllImport("user32.dll")]
public static extern bool GetWindowRect(IntPtr hWnd, out WindowRect lpRect);
[DllImport("user32", CharSet = CharSet.Auto)]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
public static void SetTopomost(IntPtr hWnd)
{
WindowRect rect = new WindowRect();
GetWindowRect(hWnd, out rect);
SetWindowPos(hWnd, (IntPtr)HWND_TOPMOST, rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top, 0);
}
public static void ForceWindowIntoForeground(IntPtr window)
{
try
{
SetTopomost(window);
IntPtr currentThread = GetCurrentThreadId();
IntPtr activeWindow = GetForegroundWindow();
IntPtr activeProcess;
IntPtr activeThread = GetWindowThreadProcessId(activeWindow, out activeProcess);
IntPtr windowProcess;
IntPtr windowThread = GetWindowThreadProcessId(window, out windowProcess);
if (currentThread != activeThread)
AttachThreadInput(currentThread, activeThread, true);
if (windowThread != currentThread)
AttachThreadInput(windowThread, currentThread, true);
uint oldTimeout = 0, newTimeout = 0;
SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, ref oldTimeout, 0);
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, ref newTimeout, 0);
// LockSetForegroundWindow(LSFW_UNLOCK);
// AllowSetForegroundWindow(ASFW_ANY);
SetForegroundWindow(window);
ShowWindow(window, SW_RESTORE);
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, ref oldTimeout, 0);
if (currentThread != activeThread)
AttachThreadInput(currentThread, activeThread, false);
if (windowThread != currentThread)
AttachThreadInput(windowThread, currentThread, false);
SetTopomost(window);
}
catch (Exception e)
{
}
}
}
public class TimeRec
{
public string Event = "";
public int ShowPosition = 0;
public float PresentationElapsedTime = 0;
public float SlideElapsedTime = 0;
public int SlideIndex = 0;
public int SlideNumber = 0;
public int ClickCount = 0;
public int ClickIndex = 0;
}