// before we embed we need to check if we have any old shape on the slide. If // we have, we need to delete it AFTER the new shape is inserted to preserve // the original timeline. public void EmbedOnSlide(PowerPointSlide slide, int clickNumber) { var isOnClick = clickNumber > 0; var shapeName = Name; if (slide != null) { // embed new shape using two-turn method. In the first turn, embed the shape, name it to // something special to distinguish from the old shape; in the second turn, delete the // old shape using timeline invariant deletion, and rename the new shape to the correct // name. try { var audioShape = AudioHelper.InsertAudioFileOnSlide(slide, SaveName); audioShape.Name = "#"; slide.RemoveAnimationsForShape(audioShape); if (isOnClick) { slide.SetShapeAsClickTriggered(audioShape, clickNumber, MsoAnimEffect.msoAnimEffectMediaPlay); } else { slide.SetAudioAsAutoplay(audioShape); } // delete old shape slide.DeleteShapesWithPrefixTimelineInvariant(Name); audioShape.Name = shapeName; } catch (COMException) { // Adding the file failed for one reason or another - probably cancelled by the user. } } else { MessageBox.Show("Slide selection error"); } }
public static Shape InsertAudioFileOnSlide(PowerPointSlide slide, string fileName) { float slideWidth = PowerPointPresentation.Current.SlideWidth; Shape audioShape = slide.Shapes.AddMediaObject2(fileName, MsoTriState.msoFalse, MsoTriState.msoTrue, slideWidth + 20); slide.RemoveAnimationsForShape(audioShape); return audioShape; }
/// <summary> /// Creates a cover image from a copy of the shape to obstruct the viewer while preloading images in the background. /// </summary> public static void DuplicateAsCoverImage(PowerPointSlide animationSlide, PowerPoint.Shape shape) { var coverImage = shape.Duplicate()[1]; coverImage.Left = shape.Left; coverImage.Top = shape.Top; animationSlide.RemoveAnimationsForShape(coverImage); var sequence = animationSlide.TimeLine.MainSequence; var effectDisappear = sequence.AddEffect(coverImage, PowerPoint.MsoAnimEffect.msoAnimEffectFade, PowerPoint.MsoAnimateByLevel.msoAnimateLevelNone, PowerPoint.MsoAnimTriggerType.msoAnimTriggerWithPrevious); effectDisappear.Exit = Office.MsoTriState.msoTrue; effectDisappear.Timing.Duration = 0.01f; effectDisappear.MoveTo(1); }
/// <summary> /// Preloads a shape within the slide to reduce lag. Call after the animations for the shape have been created. /// </summary> public static void PreloadShape(PowerPointSlide animationSlide, PowerPoint.Shape shape, bool addCoverImage=true) { // The cover image is used to cover the screen while the preloading happens behind the cover image. PowerPoint.Shape coverImage = null; if (addCoverImage) { coverImage = shape.Duplicate()[1]; coverImage.Left = shape.Left; coverImage.Top = shape.Top; animationSlide.RemoveAnimationsForShape(coverImage); } float originalWidth = shape.Width; float originalHeight = shape.Height; float originalLeft = shape.Left; float originalTop = shape.Top; // fit the shape exactly in the screen for preloading. float scaleRatio = Math.Min(PowerPointPresentation.Current.SlideWidth / shape.Width, PowerPointPresentation.Current.SlideHeight / shape.Height); animationSlide.RelocateShapeWithoutPath(shape, 0, 0, shape.Width * scaleRatio, shape.Height * scaleRatio); var trigger = PowerPoint.MsoAnimTriggerType.msoAnimTriggerWithPrevious; var effectMotion = AddMotionAnimation(animationSlide, shape, shape.Left, shape.Top, originalLeft + (originalWidth - shape.Width) / 2, originalTop + (originalHeight - shape.Height) / 2, 0, ref trigger); var effectResize = AddResizeAnimation(animationSlide, shape, shape.Width, shape.Height, originalWidth, originalHeight, 0, ref trigger); // Make "cover" image disappear after preload. PowerPoint.Effect effectDisappear = null; if (addCoverImage) { var sequence = animationSlide.TimeLine.MainSequence; effectDisappear = sequence.AddEffect(coverImage, PowerPoint.MsoAnimEffect.msoAnimEffectFade, PowerPoint.MsoAnimateByLevel.msoAnimateLevelNone, PowerPoint.MsoAnimTriggerType.msoAnimTriggerWithPrevious); effectDisappear.Exit = Office.MsoTriState.msoTrue; effectDisappear.Timing.Duration = 0.01f; } int firstEffectIndex = animationSlide.IndexOfFirstEffect(shape); // Move the animations to just before the index of the first effect. if (effectDisappear != null) effectDisappear.MoveTo(firstEffectIndex); if (effectResize != null) effectResize.MoveTo(firstEffectIndex); if (effectMotion != null) effectMotion.MoveTo(firstEffectIndex); }
/// <summary> /// This function will embed the auto generated speech to the current slide. /// File names of generated audios will be returned. /// </summary> /// <param name="slide">Current slide reference.</param> /// <returns>An array of auto generated audios' name.</returns> private static string[] EmbedSlideNotes(PowerPointSlide slide) { String folderPath = Path.GetTempPath() + TempFolderName; String fileNameSearchPattern = String.Format("Slide {0} Speech", slide.ID); Directory.CreateDirectory(folderPath); // TODO: // obviously deleting all audios in current slide may not a good idea, some lines of script // may still be the same. Check the line first before deleting, if the line has not been // changed, leave the audio. // to avoid duplicate records, delete all old audios in the current slide var audiosInCurrentSlide = Directory.GetFiles(folderPath); foreach (var audio in audiosInCurrentSlide) { if (audio.Contains(fileNameSearchPattern)) { try { File.Delete(audio); } catch (Exception e) { Logger.LogException(e, "Failed to delete audio, it may be still playing. " + e.Message); } } } bool isSaveSuccessful = OutputSlideNotesToFiles(slide, folderPath); string[] audioFiles = null; if (isSaveSuccessful) { slide.DeleteShapesWithPrefix(SpeechShapePrefix); audioFiles = GetAudioFilePaths(folderPath, fileNameSearchPattern); for (int i = 0; i < audioFiles.Length; i++) { String fileName = audioFiles[i]; bool isOnClick = fileName.Contains("OnClick"); try { Shape audioShape = InsertAudioFileOnSlide(slide, fileName); audioShape.Name = String.Format("PowerPointLabs Speech {0}", i); slide.RemoveAnimationsForShape(audioShape); if (isOnClick) { slide.SetShapeAsClickTriggered(audioShape, i, MsoAnimEffect.msoAnimEffectMediaPlay); } else { slide.SetAudioAsAutoplay(audioShape); } } catch (COMException) { // Adding the file failed for one reason or another - probably cancelled by the user. } } } return audioFiles; }