c# openxml set up self running power point presentation - c#

I am working on one demo application (Asp.net MVC) where i want to apply self running and transition time animation on existing Power Points. I wrote below code,
using (var templateFile = System.IO.File.Open(Server.MapPath("~/OurCompanyTeam.pptx"), FileMode.Open, FileAccess.Read))
{
using (var stream = new MemoryStream())
{
templateFile.CopyTo(stream);
using (var presentationDocument = PresentationDocument.Open(stream, true))
{
var presentationPart = presentationDocument.PresentationPart;
var presentation = presentationPart.Presentation;
var slideList = new List<SlidePart>();
foreach (SlideId slideID in presentation.SlideIdList)
{
var slide = (SlidePart)presentationPart.GetPartById(slideID.RelationshipId);
Transition trns = new Transition();
trns.Duration = "2.5";
trns.Speed = TransitionSpeedValues.Fast;
slide.Slide.Transition = trns;
slideList.Add(slide);
}
presentationPart.Presentation.Save();
}
byte[] buffer = stream.ToArray();
MemoryStream ms = new MemoryStream(buffer);
FileStream file = new FileStream(Server.MapPath("~/output.pptx"), FileMode.Create, FileAccess.Write);
ms.WriteTo(file);
file.Close();
}
}
How could i improve this code to set up self running presentation?

The code in this answer will make any presentation(.pptx) a self running Slide Show (.ppsx). It does the following items:
Puts the presentation in kiosk mode
Sets the AdvanceAfterTime attribute to 2 seconds for each slide
Change the Document type to Slide Show
Saves contents of .pptx to a new .ppsx file.
You can replace your code above with the following code. Add a _sourceFile string local variable to save the full path to your file. Notes in the comments for the items above:
using (var templateFile = System.IO.File.Open(Server.MapPath("~/OurCompanyTeam.pptx"), FileMode.Open, FileAccess.Read))
{
using (var stream = new MemoryStream())
{
templateFile.CopyTo(stream);
using (var presentationDocument = PresentationDocument.Open(stream, true))
{
var presentationPart = presentationDocument.PresentationPart;
var presentation = presentationPart.Presentation;
var slideList = new List<SlidePart>();
foreach (SlideId slideID in presentation.SlideIdList)
{
var slidePart = (SlidePart)presentationPart.GetPartById(slideID.RelationshipId);
AlternateContent alternateContent1 = slidePart.Slide.GetFirstChild<AlternateContent>();
if (alternateContent1 != null)
{
slidePart.Slide.RemoveAllChildren<AlternateContent>();
}
var trns1 = new Transition();
trns1.Duration = "2000";
trns1.AdvanceOnClick = false;
trns1.AdvanceAfterTime = "2000"; //ITEM #2
trns1.Speed = TransitionSpeedValues.Slow;
var alternateContent = new AlternateContent();
alternateContent.AddNamespaceDeclaration("mc", "http://schemas.openxmlformats.org/markup-compatibility/2006");
AlternateContentChoice alternateContentChoice = new AlternateContentChoice() { Requires = "p14" };
alternateContentChoice.AddNamespaceDeclaration("p14", "http://schemas.microsoft.com/office/powerpoint/2010/main");
alternateContentChoice.Append(trns1);
alternateContent.Append(alternateContentChoice);
slidePart.Slide.Append(alternateContent);
}
var presentationPropertiesPart = presentationPart.PresentationPropertiesPart;
var presentationProperties = presentationPropertiesPart.PresentationProperties;
presentationProperties.RemoveAllChildren<ShowProperties>();
presentationProperties.Append(NewShowProperties());
presentationDocument.ChangeDocumentType(PresentationDocumentType.Slideshow); //ITEM #3
}
byte[] buffer = stream.ToArray();
MemoryStream ms = new MemoryStream(buffer);
FileStream file = new FileStream(System.IO.Path.GetDirectoryName(_sourceFile) + "/NewSlideShow.ppsx",
FileMode.Create, FileAccess.Write); //ITEM #4
ms.WriteTo(file);
file.Close();
}
}
then add this method at the bottom of your class:
private ShowProperties NewShowProperties()
{
var showProperties = new ShowProperties { Loop = true, ShowNarration = true };
showProperties.Append(new KioskSlideMode()); //ITEM #1
showProperties.Append(new SlideAll());
showProperties.Append(new PresenterSlideMode());
return showProperties;
}
I've tested this to work on newly created PowerPoint 2013 and 2016 Presentations. Double click on the .ppsx file and it will launch the self-running presentation.

Related

Creating Zip file with multiple entries in C# .net

I created the functionality to get documents from blob storage and then add them to a zip file for download.
[HttpPost]
public FileContentResult DownloadDocumentsByDocIDZIP(List<int> documentIDs)
{
List<Document> docs = new List<Document>();
foreach (int doc in documentIDs)
{
if (doc != 0)
{
Document document = documentService.GetDocumentByID(doc, false);
docs.Add(document);
}
}
MemoryStream outms = new MemoryStream();
using (ZipArchive zar = new ZipArchive(outms, ZipArchiveMode.Create, false))
{
foreach (Document docu in docs)
{
if (docu != null)
{
byte[] documentdata = documentService.DownloadDocumentData(docu.DocumentID);
string name = docu.DocumentNiceName ?? docu.DocumentFileName;
byte[] unzipped = documentdata;
ZipArchiveEntry entry = zar.CreateEntry(name);
Stream str = entry.Open();
MemoryStream ms = new MemoryStream(unzipped);
ms.CopyTo(str);
}
}
outms.Seek(0, SeekOrigin.Begin);
}
var outdata = outms.ToArray();
var result = File(outdata, "application/zip", "documents.zip");
return result;
}
When I hit the function via ajax, It fails at
ZipArchiveEntry entry = zar.CreateEntry(name);
I'm given the exception,
System.IO.IOException: 'Entries cannot be created while previously created entries are still open.'
So I added str.close()
using (ZipArchive zar = new ZipArchive(outms, ZipArchiveMode.Create, false))
{
foreach (Document docu in docs)
{
if (docu != null)
{
byte[] documentdata = documentService.DownloadDocumentData(docu.DocumentID);
string name = docu.DocumentNiceName ?? docu.DocumentFileName;
byte[] unzipped = documentdata;
ZipArchiveEntry entry = zar.CreateEntry(name);
Stream str = entry.Open();
MemoryStream ms = new MemoryStream(unzipped);
ms.CopyTo(str);
str.Close();
}
}
outms.Seek(0, SeekOrigin.Begin);
}
var outdata = outms.ToArray();
var result = File(outdata, "application/zip", "documents.zip");
return result;
Now it creates the file but when you try to unzip it after download.
It gives me an error in WinZip. Error: unable to seek to beginning of Central Directory.
Can someone please assist I have no idea what I'm doing wrong?
you have to dispose the Stream before add new stream to zip but the real problem is that you call Seek on stream, try the following code:
using (ZipArchive zar = new ZipArchive(outms, ZipArchiveMode.Create, false))
{
foreach (Document docu in docs)
{
if (docu != null)
{
byte[] documentdata = documentService.DownloadDocumentData(docu.DocumentID);
string name = docu.DocumentNiceName ?? docu.DocumentFileName;
byte[] unzipped = documentdata;
ZipArchiveEntry entry = zar.CreateEntry(name);
using (Stream str = entry.Open())
{
str.Write(unzipped);
}
}
}
//outms.Seek(0, SeekOrigin.Begin); //This causes "Error: unable to seek to beginning of Central Directory."
}
var outdata = outms.ToArray();
var result = File(outdata, "application/zip", "documents.zip");
return result;

How write memorystream into ZipFile

I have a zip file. I want open it with SharpZipLib and add a new ZipEntry to it that it is created in memory.
I am new to SharpZipLib. I googled very much but couldn't find similar problem.
My Sample Code is:
public Stream GetNewZipFileStream(string zipFilePath)
{
byte[] zipFileBytes = null;
zipFileBytes = ReadFileBytes(zipFilePath);
var zipFileMemoryStream = new MemoryStream(zipFileBytes);
ZipOutputStream zipOutStream = new ZipOutputStream(zipFileMemoryStream);
var newEntry = new ZipEntry("NewFile.txt");
zipOutStream.PutNextEntry(newEntry);
var newFileMemoryStream = MakeOnTheFlyStream();
StreamUtils.Copy(newFileMemoryStream , zipOutStream, new byte[4096]);
zipOutStream.CloseEntry();
newFileMemoryStream.Close();
zipOutStream.IsStreamOwner = false;
zipOutStream.Close();
newFileMemoryStream.Position = 0;
return newFileMemoryStream;
}
ReadFileBytes and MakeOnTheFlyStream are my methods.

How to insert one wav audio file into antoher wav file?

I am working on xamarin. And I have developed an app in which I record voice of user. Now I want that user can insert again in his already recorded file. I mean if a user has alrady recorded for 10 min and now he want to insert some more content at 6 min, he should be able to do that. I tried some examples but not getting success. When I am inserting some times its working and sometimes the inserted content get corrupt after insertion.
Following is my code that I have implemente. It is working for some time and some time inserted content get corrupt.
string[] files = new string[] { originalFile, insertFile };
if (!files[0].Contains("tempfile_") && files.Length > 1)
{
if (File.Exists(files[0]))
{
string newPath = files[1].Replace("tempfile_1",
"tempfile_0");
MoveExistingFile(files[0], newPath);
files[0] = newPath;
}
else
{
files = files.Skip(1).ToArray();
}
}
var duration = DependencyService.Get<IPlayService>
().GetDuration(files[0]);
var bufferTime = Math.Round(duration);
FileStream originalStream = new FileStream(files[0],
FileMode.Open, FileAccess.Read);
byte[] originalByteArray = new byte[originalStream.Length - 44];
var perSecondLength = originalByteArray.Length / (int)bufferTime;
var splitIndex = (perSecondLength * SplitSecond);
var byteArray1 = new byte[(splitIndex)];
var byteArray2 = new byte[originalByteArray.Length - splitIndex];
FileStream insertStream = new FileStream(files[1], FileMode.Open,
FileAccess.Read);
byte[] insertByteArray = new byte[insertStream.Length - 44];
var byteArray3 = new byte[insertByteArray.Length];
originalStream.Position = 44;
originalStream.Read(byteArray1, 0, byteArray1.Length);
originalStream.Position = byteArray1.Length;
originalStream.Read(byteArray2, 0, byteArray2.Length);
originalStream.Close();
insertStream.Position = 44;
insertStream.Read(byteArray3, 0, byteArray3.Length);
insertStream.Close();
WaveIO wa_IN = new WaveIO();
WaveIO wa_out = new WaveIO();
wa_out.DataLength = 0;
wa_out.length = 0;
//Gather header data
foreach (string path in files)
{
wa_IN.WaveHeaderIN(#path);
wa_out.DataLength += wa_IN.DataLength;
wa_out.length += wa_IN.length;
}
//Recontruct new header
wa_out.BitsPerSample = wa_IN.BitsPerSample;
wa_out.channels = wa_IN.channels;
wa_out.samplerate = wa_IN.samplerate;
wa_out.WaveHeaderOUT(#outfile);
FileStream fo = new FileStream(#outfile, FileMode.Append,
FileAccess.Write);
BinaryWriter bw = new BinaryWriter(fo);
bw.Write(byteArray1);
bw.Write(byteArray3);
bw.Write(byteArray2);
bw.Close();
fo.Close();

Got a message " MEMORY STREAM IS NOT EXPANDABLE" after using WordprocessingDocument base on Microsoft site on MVC

Currently, I was base on "Search and replace text in a document part (Open XML SDK)" on the Microsoft site. I've realized that the code got an issue after the file has downloaded to my drive.
So I opened that file and got a message
MEMORY STREAM IS NOT EXPANDABLE at sw.Write(docText);
How to fix that?
In GenerateDocxHelper class:
private readonly MemoryStream _mem;
private Dictionary<string, string> _dicData;
public GenerateDocxHelper(string path)
{
_mem = new MemoryStream(System.IO.File.ReadAllBytes(path));
_dicData = new Dictionary<string, string>();
}
public MemoryStream ReplaceTextInWord()
{
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(_mem, true))
{
string docText = null;
using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
{
docText = sr.ReadToEnd();
}
foreach (var data in _dicData)
{
docText = docText.Replace(data.Key, data.Value);
}
using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
{
sw.Write(docText);
}
}
_mem.Seek(0, SeekOrigin.Begin);
return _mem;
}
You should create the MemoryStream with capacity = 0 which means it is resizeable,
and then add the bytes you have read from the file.
var allBytes = File.ReadAllBytes(path);
//this makes _mem resizeable
_mem = new MemoryStream(0);
_mem.Write(allBytes, 0, allBytes.Length);
Check this answer

C# ZipArchive losing data

I'm trying to copy the contents of one Excel file to another Excel file while replacing a string inside of the file on the copy. It's working for the most part, but the file is losing 27 kb of data. Any suggestions?
public void ReplaceString(string what, string with, string path) {
List < string > doneContents = new List < string > ();
List < string > doneNames = new List < string > ();
using(ZipArchive archive = ZipFile.Open(_path, ZipArchiveMode.Read)) {
int count = archive.Entries.Count;
for (int i = 0; i < count; i++) {
ZipArchiveEntry entry = archive.Entries[i];
using(var entryStream = entry.Open())
using(StreamReader reader = new StreamReader(entryStream)) {
string txt = reader.ReadToEnd();
if (txt.Contains(what)) {
txt = txt.Replace(what, with);
}
doneContents.Add(txt);
string name = entry.FullName;
doneNames.Add(name);
}
}
}
using(MemoryStream zipStream = new MemoryStream()) {
using(ZipArchive newArchive = new ZipArchive(zipStream, ZipArchiveMode.Create, true, Encoding.UTF8)) {
for (int i = 0; i < doneContents.Count; i++) {
int spot = i;
ZipArchiveEntry entry = newArchive.CreateEntry(doneNames[spot]);
using(var entryStream = entry.Open())
using(var sw = new StreamWriter(entryStream)) {
sw.Write(doneContents[spot]);
}
}
}
using(var fileStream = new FileStream(path, FileMode.Create)) {
zipStream.Seek(0, SeekOrigin.Begin);
zipStream.CopyTo(fileStream);
}
}
}
I've used Microsoft's DocumentFormat.OpenXML and Excel Interop, however, they are both lacking in a few main components that I need.
Update:
using(var fileStream = new FileStream(path, FileMode.Create)) {
var wrapper = new StreamWriter(fileStream);
wrapper.AutoFlush = true;
zipStream.Seek(0, SeekOrigin.Begin);
zipStream.CopyTo(wrapper.BaseStream);
wrapper.Flush();
wrapper.Close();
}
Try the process without changing the string and see if the file size is the same. If so then it would seem that your copy is working correctly, however as Marc B suggested, with compression, even a small change can result in a larger change in the overall size.

Categories

Resources