public const int PPT_SAVE_AS_ID = 748; // Determined by experimentation; should hold regardless of language. /// <summary> /// Creates the PPT automation component which handles exporting CSD decks from PPT. /// </summary> /// <param name="ppt">non-null ppt library accessor</param> /// <param name="paneManager">pane manager or null if no pane management is to be used</param> public PPTDeckBuilder(PPTLibrary.PPT ppt, PPTPaneManagement.PPTPaneManager paneManager) #endif { if (ppt == null) throw new ArgumentNullException("ppt"); // Hook up to arguments. this.myPPT = ppt; // Prepare the loader. this.myLoader = new PPTSlideLoader(DEFAULT_SIZE, DEFAULT_COMMENT_TYPE, this.myPPT, paneManager #if SIP_MODE , propertyManager #endif ); // Find the menubar. Core.CommandBar menu = null; foreach (Core.CommandBar cb in this.myPPT.App.CommandBars) if (cb.Id == PPT_MENU_BAR_ID) { menu = cb; break; } if (menu == null) throw new Exception("PPTDeckBuilderAddin: Unable to find the PowerPoint menu bar."); // Find the file menu. Core.CommandBarPopup fileMenu = null; foreach (Core.CommandBarControl bar in menu.Controls) if (bar.Id == PPT_FILE_ID) { fileMenu = (Core.CommandBarPopup)bar; break; } if (fileMenu == null) throw new Exception("PPTDeckBuilderAddin: Unable to find the PowerPoint file menu."); // Find the Save As.. button. // And see if the export to CSD button is already there. Core.CommandBarControl saveAs = null; foreach (Core.CommandBarControl control in fileMenu.Controls) { if (control.Id == PPT_SAVE_AS_ID) saveAs = control; if (control.Caption == "&Export to CSD...") control.Delete(false); // Delete permanently. if (control.Caption == "Load &Feedback Menu...") control.Delete(false); } // Add and configure the export to CSD button... this.myExportButton = (Core.CommandBarButton)fileMenu.Controls.Add( Core.MsoControlType.msoControlButton, System.Reflection.Missing.Value, // Not a built in button: no ID. System.Reflection.Missing.Value, // No parameters used. (saveAs == null) ? (object)System.Reflection.Missing.Value : (object)(saveAs.Index + 1), // Place just after Save As... if possible. true); // Temporary (disappear on closing PPT). this.myExportButton.Caption = "&Export to CSD..."; this.myExportButton.DescriptionText = "Export the current presentation to the Conferencing Slide Deck format."; this.myExportButton.TooltipText = this.myExportButton.DescriptionText; this.myExportButton.Click += new Core._CommandBarButtonEvents_ClickEventHandler(this.HandleCSDButtonClick); this.myExportButton.Visible = true; this.ConfigureButton(); // Add and configure the load feedback menu button... this.myFeedbackButton = (Core.CommandBarButton)fileMenu.Controls.Add( Core.MsoControlType.msoControlButton, System.Reflection.Missing.Value, // Not a built in button: no ID. System.Reflection.Missing.Value, // No parameters used. (object)(this.myExportButton.Index + 1), // Place just after Export to CSD true); // Temporary (disappear on closing PPT). this.myFeedbackButton.Caption = "Load &Feedback Menu..."; this.myFeedbackButton.DescriptionText = "Load a feedback menu to associate with this deck."; this.myFeedbackButton.TooltipText = this.myFeedbackButton.DescriptionText; this.myFeedbackButton.Click += new Core._CommandBarButtonEvents_ClickEventHandler(this.HandleFeedbackButtonClick); this.myFeedbackButton.Visible = true; this.ConfigureButton(); // Hook up to events to enable/disable the export button. this.myPPT.App.PresentationClose += new PowerPoint.EApplication_PresentationCloseEventHandler(this.HandlePresentation); this.myPPT.App.PresentationOpen += new PowerPoint.EApplication_PresentationOpenEventHandler(this.HandlePresentation); this.myPPT.App.WindowActivate += new PowerPoint.EApplication_WindowActivateEventHandler(this.HandleWindow); this.myPPT.App.WindowDeactivate += new PowerPoint.EApplication_WindowDeactivateEventHandler(this.HandleWindow); }
/// <summary> /// Create a slide model from a powerpoint slide /// </summary> /// <param name="pageSetup"></param> /// <param name="pptpm"></param> /// <param name="deck"></param> /// <param name="tempFileCollection"></param> /// <param name="dirpath"></param> /// <param name="currentSlide"></param> /// <returns></returns> private static SlideModel CreateSlide(PowerPoint.PageSetup pageSetup, PPTPaneManagement.PPTPaneManager pptpm, DeckModel deck, TempFileCollection tempFileCollection, string dirpath, PowerPoint._Slide currentSlide) { int slideWidth = (int)pageSetup.SlideWidth; //Standard = 720 => 6000 int slideHeight = (int)pageSetup.SlideHeight; //Standard = 540 => 4500 float emfWidth = slideWidth * 25 / 3; float emfHeight = slideHeight * 25 / 3; // Adding an empty textbox in the upper left corner of the the // slide before layers are exported works around a common // issue with shape positioning. Without this, text shapes often get pushed too far // to the right and down due to some extra padding that PPT inserts on // the top and left of the exported images. It doesn't pad the top left of an // empty text box, so the positioning is corrected. // This isn't perfect since the workaround should probably be applied to // every layer with text boxes. currentSlide.Shapes.AddTextbox(Core.MsoTextOrientation.msoTextOrientationHorizontal, 0, 0, 1, 1); PowerPoint.Shapes currentShapes = currentSlide.Shapes; List<TaggedShape> taggedShapeList = PPTDeckIO.BuildTaggedShapeList(currentShapes, pptpm); //Create a new SlideModel SlideModel newSlideModel = new SlideModel(Guid.NewGuid(), new LocalId(), SlideDisposition.Empty, new Rectangle(0, 0, slideWidth, slideHeight)); //Lock it using (Synchronizer.Lock(newSlideModel.SyncRoot)) { //Set the slide's title newSlideModel.Title = PPTDeckIO.FindSlideTitle(taggedShapeList, currentSlide); PPTDeckIO.MakeShapesInvisible(currentShapes); //Create the Background image //Generate a new filename string filename = PPTDeckIO.GenerateFilename(); bool bitmapMode = true; if (bitmapMode) { filename = dirpath + "\\" + filename + ".png"; currentSlide.Export(filename, "PNG", 0, 0); // Need to also export as EMF to get the size of the slide in inches currentSlide.Export(filename + "_TEMP", "EMF", 0, 0); tempFileCollection.AddFile( filename + "_TEMP", false ); } else { filename = dirpath + "\\" + filename + ".emf"; currentSlide.Export(filename, "EMF", 0, 0); } tempFileCollection.AddFile(filename, false); //Compute the MD5 of the BG FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read); MD5 md5Provider = new MD5CryptoServiceProvider(); byte[] md5 = md5Provider.ComputeHash(fs); fs.Seek(0, SeekOrigin.Begin); Image image = Image.FromStream(fs); if (bitmapMode) { image = DisassociateBitmap(image); } fs.Close(); // Open the EMF version if we used a bitmap to get the conversion if( bitmapMode ) { FileStream fsEMF = new FileStream( filename + "_TEMP", FileMode.Open, FileAccess.Read ); Image image_emf = Image.FromStream( fsEMF ); emfWidth = image_emf.Width; emfHeight = image_emf.Height; fsEMF.Close(); image_emf.Dispose(); } else { emfWidth = image.Width; emfHeight = image.Height; } //Create the ImageSheet ImageSheetModel sheet = new ImageSheetModel(deck, Guid.NewGuid(), Model.Presentation.SheetDisposition.Background, new Rectangle(0, 0, slideWidth, slideHeight), (ByteArray)md5, 1); //Add the ImageSheet to the Slide newSlideModel.ContentSheets.Add(sheet); //Add the Image+MD5 to the deck deck.AddSlideContent((ByteArray)md5, image); // Restore visibility - this makes everything visible - a bug? PPTDeckIO.MakeShapesVisible(currentShapes); List<List<TaggedShape>> layerList = PPTDeckIO.SeparateIntoLayers(taggedShapeList); int startHeight = 2; foreach (List<TaggedShape> layer in layerList) PPTDeckIO.ProcessLayer( layer, tempFileCollection, currentShapes, deck, newSlideModel, slideWidth/emfWidth, slideHeight/emfHeight, startHeight++ ); //Add SlideModel to the deck deck.InsertSlide(newSlideModel); } return newSlideModel; }
/// <summary> /// Creates the PPT automation component which handles exporting CSD decks from PPT. /// </summary> /// <param name="ppt">non-null ppt library accessor</param> /// <param name="paneManager">pane manager or null if no pane management is to be used</param> /// <param name="propertyManager">widget property manager or null if the builder should assume no widgets exist</param> public PPTDeckBuilder(PPTLibrary.PPT ppt, PPTPaneManagement.PPTPaneManager paneManager, PPTPropertyManagement.PPTPropertyManager propertyManager)
/// <summary> /// Tag all the shapes with their visibility mode, index, and whether or not they are a picture /// </summary> /// <param name="shapes"></param> /// <param name="pptpm"></param> /// <returns></returns> private static List<TaggedShape> BuildTaggedShapeList(PowerPoint.Shapes shapes, PPTPaneManagement.PPTPaneManager pptpm) { List<TaggedShape> tsList = new List<TaggedShape>(); int index = 1; double version; if (!double.TryParse(((PowerPoint.Application)shapes.Application).Version,out version)) { version = 0.0; } for (int i = 1; i <= shapes.Count; i++) { PowerPoint.Shape shape = shapes[i]; if(version >= 12.0) Scrub2007EffectsFromShape(shape); if( shape.Type == Microsoft.Office.Core.MsoShapeType.msoGroup && (version < 12.0)) { shape.Ungroup(); i--; continue; } else AddTaggedShapeToList( tsList, ref index, shape, pptpm ); } return tsList; }
private static void AddTaggedShapeToList( List<TaggedShape> tsList, ref int index, PowerPoint.Shape shape, PPTPaneManagement.PPTPaneManager pptpm ) { TaggedShape ts; ts.shape = shape; ts.index = index; index++; ts.isImage = (shape.Name.StartsWith( "Picture" )); // A shape is an image if its called a picture! string[] modes = pptpm.GetModes( shape ); if( modes.Length == 0 ) { ts.disp = SheetDisposition.All; tsList.Add( ts ); } else { foreach( string mode in modes ) { ts.disp = PPTDeckIO.Disposition( mode ); // Make a copy for each mode, and add to the list tsList.Add( ts ); } } }
/// <param name="ppt">non-null ppt library accessor</param> /// <param name="paneManager">pane manager or null if no pane management is to be used</param> public PPTSlideLoader(Size viewerSize, int commentMenuType, PPTLibrary.PPT ppt, PPTPaneManagement.PPTPaneManager paneManager) #endif { if (ppt == null) throw new ArgumentNullException("ppt"); this.myPPT = ppt; this.myPaneManager = paneManager; #if SIP_MODE this.myPropertyManager = propertyManager; #endif this.myViewerSize = viewerSize; this.myDefaultCommentMenuType = commentMenuType; this.myFilesLoaded = 0; this.myTemporaryDirectoryPath = Path.GetTempPath() + "\\DeckBuilderTempFiles"; try { if (Directory.Exists(this.myTemporaryDirectoryPath)) Directory.Delete(this.myTemporaryDirectoryPath, true); // Delete directory to clean up old files Directory.CreateDirectory(this.myTemporaryDirectoryPath); } catch (IOException e) { Console.WriteLine(e.Message); } }
/// <summary> /// Create a slide model from a powerpoint slide /// </summary> /// <param name="pageSetup"></param> /// <param name="pptpm"></param> /// <param name="deck"></param> /// <param name="tempFileCollection"></param> /// <param name="dirpath"></param> /// <param name="currentSlide"></param> /// <returns></returns> private static SlideModel CreateSlide(PowerPoint.PageSetup pageSetup, PPTPaneManagement.PPTPaneManager pptpm, DeckModel deck, TempFileCollection tempFileCollection, string dirpath, PowerPoint._Slide currentSlide) { int slideWidth = (int)pageSetup.SlideWidth; //Standard = 720 => 6000 int slideHeight = (int)pageSetup.SlideHeight; //Standard = 540 => 4500 float emfWidth = slideWidth * 25 / 3; float emfHeight = slideHeight * 25 / 3; PowerPoint.Shapes currentShapes = currentSlide.Shapes; List<TaggedShape> taggedShapeList = PPTDeckIO.BuildTaggedShapeList(currentShapes, pptpm); //Create a new SlideModel SlideModel newSlideModel = new SlideModel(Guid.NewGuid(), new LocalId(), SlideDisposition.Empty, new Rectangle(0, 0, slideWidth, slideHeight)); //Lock it using (Synchronizer.Lock(newSlideModel.SyncRoot)) { //Set the slide's title newSlideModel.Title = PPTDeckIO.FindSlideTitle(taggedShapeList); PPTDeckIO.MakeShapesInvisible(currentShapes); //Create the Background image //Generate a new filename string filename = PPTDeckIO.GenerateFilename(); bool bitmapMode = true; if (bitmapMode) { filename = dirpath + "\\" + filename + ".JPG"; currentSlide.Export(filename, "JPG", 0, 0); // Need to also export as EMF to get the size of the slide in inches currentSlide.Export(filename + "_TEMP", "EMF", 0, 0); tempFileCollection.AddFile( filename + "_TEMP", false ); } else { filename = dirpath + "\\" + filename + ".emf"; currentSlide.Export(filename, "EMF", 0, 0); } tempFileCollection.AddFile(filename, false); //Compute the MD5 of the BG FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read); MD5 md5Provider = new MD5CryptoServiceProvider(); byte[] md5 = md5Provider.ComputeHash(fs); fs.Seek(0, SeekOrigin.Begin); Image image = Image.FromStream(fs); if (bitmapMode) { image = DisassociateBitmap(image); } fs.Close(); // Open the EMF version if we used a bitmap to get the conversion if( bitmapMode ) { FileStream fsEMF = new FileStream( filename + "_TEMP", FileMode.Open, FileAccess.Read ); Image image_emf = Image.FromStream( fsEMF ); emfWidth = image_emf.Width; emfHeight = image_emf.Height; fsEMF.Close(); image_emf.Dispose(); } else { emfWidth = image.Width; emfHeight = image.Height; } //Create the ImageSheet ImageSheetModel sheet = new ImageSheetModel(deck, Guid.NewGuid(), Model.Presentation.SheetDisposition.Background, new Rectangle(0, 0, slideWidth, slideHeight), (ByteArray)md5, 1); //Add the ImageSheet to the Slide newSlideModel.ContentSheets.Add(sheet); //Add the Image+MD5 to the deck deck.AddSlideContent((ByteArray)md5, image); // Restore visibility - this makes everything visible - a bug? PPTDeckIO.MakeShapesVisible(currentShapes); List<List<TaggedShape>> layerList = PPTDeckIO.SeparateIntoLayers(taggedShapeList); int startHeight = 2; foreach (List<TaggedShape> layer in layerList) PPTDeckIO.ProcessLayer( layer, tempFileCollection, currentShapes, deck, newSlideModel, slideWidth/emfWidth, slideHeight/emfHeight, startHeight++ ); //Add SlideModel to the deck deck.InsertSlide(newSlideModel); } return newSlideModel; }
/// <summary> /// Tag all the shapes with their visibility mode, index, and whether or not they are a picture /// </summary> /// <param name="shapes"></param> /// <param name="pptpm"></param> /// <returns></returns> private static List<TaggedShape> BuildTaggedShapeList(PowerPoint.Shapes shapes, PPTPaneManagement.PPTPaneManager pptpm) { List<TaggedShape> tsList = new List<TaggedShape>(); int index = 1; for (int i = 1; i <= shapes.Count; i++) { PowerPoint.Shape shape = shapes[i]; if( shape.Type == Microsoft.Office.Core.MsoShapeType.msoGroup ) { shape.Ungroup(); i--; continue; } else AddTaggedShapeToList( tsList, ref index, shape, pptpm ); } return tsList; }