需求
导出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;//开始运行PPTPPT.SlideShowEnd += SlideShowEndEvent;//开始运行PPTPPT.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 casestatic 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;}