最近一个exe项目需要在unity打开各种word,ppt文档,但通过代码直接打开office工具从而达到打开文档的功能,明显不太合适,文档容易被串改。我们要的是把文档当成一帧一帧的图片显示出来即可
而后我尝试了使用office.word.dll及office.ppt.dll在unity内进行转化,实验结果:编辑器内运行无误,也可正常转化文档,但是一发布就闪退,原因可能是unity内的dll与系统的相斥了,这个实践过程及unity内使用office.word.dll及office.ppt.dl转化代码就不贴出来了,因为不是本博客的重点。
后来我仔细想了想,还不如自己写一个插件用来满足自己的需求,反正unity内只要拿到数据图片。说干就干。
这边只是讲一下大体步骤,整个项目都有链接可以下载。如果是对代码不懂的,可以到项目源代码bin/Debug内直接运行.exe即可使用,使用一键转化功能,则到bin/course_path.txt 把需要转换的文件夹路径赋予进去,插件会根据路径把整个文件夹下的word,ppt全部隐式转换。(注意:转换是隐式转换,需在电脑上勾选查看隐藏文件才可以看到)
1.首先打开vs2015,新建一个窗体应用
2.因为是做插件,因此不需要多余的窗口,我们只需要使用默认窗口Form1即可,功能很简单,因为有一个选取路径转换的功能,也要有一个可以一键使用的功能,一个进度条和提示文字等。因此我在工具箱拉取了相对的控件到Form1上,可以在Form1上选取控件,在右下角修改属性
3.开始写代码,利用Aspose转图片的代码很多。我在网上找了一个Aspose转图片的代码,具体谁的我忘了,如果有笔者刚好读到我这篇文章可以私信我下哈。咔咔咔,根据我自己的要求,对该代码进行了修整,这里只贴出一部分代码,此外我需要用到json解析工具并对其进行工具类的方法封装,这部分代码也不贴了,具体的可以下载项目查看。
using System;
using System.Collections.Generic;
using System.Text;
using ESBasic;
using System.Drawing.Imaging;
using System.IO;
using System.Drawing;
namespace FengYun
{
/*
*
* 将pdf、ppf、word转换给图片的组件有很多,这里仅使用Aspose组件(试用版)作为示例。
*
* Aspose官网:www.aspose.com, 请支持和购买正版Aspose组件。
*
*/
#region 图片转换器工厂 -> 将被注入到OMCS的多媒体管理器IMultimediaManager的ImageConverterFactory属性
/// <summary>
/// 图片转换器工厂。
/// </summary>
public class ImageConverterFactory : IImageConverterFactory
{
public static void ToJpgSingle(string path)
{
if (path != null)
{
string outStr = path + "_目录";
if (Directory.Exists(outStr))
{
Directory.Delete(outStr,true);
}
if(path.EndsWith("docx") || path.EndsWith("doc"))
{
Word2ImageConverter b = new Word2ImageConverter();
b.ConvertToImage(path, outStr);
}
if (path.EndsWith("pptx") || path.EndsWith("ppt"))
{
Ppt2ImageConverter b = new Ppt2ImageConverter();
b.ConvertToImage(path, outStr);
}
if (path.EndsWith("pdf") )
{
Pdf2ImageConverter b = new Pdf2ImageConverter();
b.ConvertToImage(path, outStr);
}
}
}
public IImageConverter CreateImageConverter(string extendName)
{
if (extendName == ".doc" || extendName == ".docx")
{
return new Word2ImageConverter();
}
if (extendName == ".pdf")
{
return new Pdf2ImageConverter();
}
if (extendName == ".ppt" || extendName == ".pptx")
{
return new Ppt2ImageConverter();
}
if (extendName == ".rar")
{
return new Rar2ImageConverter();
}
return null;
}
public bool Support(string extendName)
{
return extendName == ".doc" || extendName == ".docx" || extendName == ".pdf" || extendName == ".ppt" || extendName == ".pptx" || extendName == ".rar";
}
public List<string> GetSupportedFileTypes()
{
List<string> list = new List<string>();
list.Add(".doc");
list.Add(".docx");
list.Add(".pdf");
list.Add(".ppt");
list.Add(".pptx");
list.Add(".rar");
return list;
}
}
#endregion
#region 将word文档转换为图片
public class Word2ImageConverter : IImageConverter
{
private bool cancelled = false;
public event CbGeneric<int, int> ProgressChanged;
public event CbGeneric ConvertSucceed;
public event CbGeneric<string> ConvertFailed;
public void Cancel()
{
if (this.cancelled)
{
return;
}
this.cancelled = true;
}
public void ConvertToImage(string originFilePath, string imageOutputDirPath)
{
this.cancelled = false;
ConvertToImage(originFilePath, imageOutputDirPath, 0, 0, null, 200);
}
/// <summary>
/// 将Word文档转换为图片的方法
/// </summary>
/// <param name="wordInputPath">Word文件路径</param>
/// <param name="imageOutputDirPath">图片输出路径,如果为空,默认值为Word所在路径</param>
/// <param name="startPageNum">从PDF文档的第几页开始转换,如果为0,默认值为1</param>
/// <param name="endPageNum">从PDF文档的第几页开始停止转换,如果为0,默认值为Word总页数</param>
/// <param name="imageFormat">设置所需图片格式,如果为null,默认格式为PNG</param>
/// <param name="resolution">设置图片的像素,数字越大越清晰,如果为0,默认值为128,建议最大值不要超过1024</param>
private void ConvertToImage(string wordInputPath, string imageOutputDirPath, int startPageNum, int endPageNum, ImageFormat imageFormat, int resolution)
{
try
{
Aspose.Words.Document doc = new Aspose.Words.Document(wordInputPath);
if (doc == null)
{
throw new Exception("Word文件无效或者Word文件被加密!");
}
if (imageOutputDirPath.Trim().Length == 0)
{
imageOutputDirPath = Path.GetDirectoryName(wordInputPath);
}
if (!Directory.Exists(imageOutputDirPath))
{
DirectoryInfo a = Directory.CreateDirectory(imageOutputDirPath);
a.Attributes = FileAttributes.Hidden;
}
if (startPageNum <= 0)
{
startPageNum = 1;
}
if (endPageNum > doc.PageCount || endPageNum <= 0)
{
endPageNum = doc.PageCount;
}
if (startPageNum > endPageNum)
{
int tempPageNum = startPageNum; startPageNum = endPageNum; endPageNum = startPageNum;
}
if (imageFormat == null)
{
imageFormat = ImageFormat.Png;
}
if (resolution <= 0)
{
resolution = 128;
}
string imageName = Path.GetFileNameWithoutExtension(wordInputPath);
Aspose.Words.Saving.ImageSaveOptions imageSaveOptions = new Aspose.Words.Saving.ImageSaveOptions(Aspose.Words.SaveFormat.Png);
imageSaveOptions.Resolution = resolution;
for (int i = startPageNum; i <= endPageNum; i++)
{
if (this.cancelled)
{
break;
}
MemoryStream stream = new MemoryStream();
imageSaveOptions.PageIndex = i - 1;
string imgPath = Path.Combine(imageOutputDirPath, imageName) + "_" + i.ToString("000") + "." + imageFormat.ToString();
doc.Save(stream, imageSaveOptions);
Image img = Image.FromStream(stream);
Bitmap bm = ESBasic.Helpers.ImageHelper.Zoom(img, 0.6f);
bm.Save(imgPath, imageFormat);
img.Dispose();
stream.Dispose();
bm.Dispose();
System.Threading.Thread.Sleep(200);
if (this.ProgressChanged != null)
{
this.ProgressChanged(i - 1, endPageNum);
}
}
if (this.cancelled)
{
return;
}
if (this.ConvertSucceed != null)
{
this.ConvertSucceed();
}
}
catch (Exception ex)
{
if (this.ConvertFailed != null)
{
this.ConvertFailed(ex.Message);
}
}
}
}
#endregion
#region 将pdf文档转换为图片
public class Pdf2ImageConverter : IImageConverter
{
private bool cancelled = false;
public event CbGeneric<int, int> ProgressChanged;
public event CbGeneric ConvertSucceed;
public event CbGeneric<string> ConvertFailed;
public void Cancel()
{
if (this.cancelled)
{
return;
}
this.cancelled = true;
}
public void ConvertToImage(string originFilePath, string imageOutputDirPath)
{
this.cancelled = false;
ConvertToImage(originFilePath, imageOutputDirPath, 0, 0, 200);
}
/// <summary>
/// 将pdf文档转换为图片的方法
/// </summary>
/// <param name="originFilePath">pdf文件路径</param>
/// <param name="imageOutputDirPath">图片输出路径,如果为空,默认值为pdf所在路径</param>
/// <param name="startPageNum">从PDF文档的第几页开始转换,如果为0,默认值为1</param>
/// <param name="endPageNum">从PDF文档的第几页开始停止转换,如果为0,默认值为pdf总页数</param>
/// <param name="resolution">设置图片的像素,数字越大越清晰,如果为0,默认值为128,建议最大值不要超过1024</param>
private void ConvertToImage(string originFilePath, string imageOutputDirPath, int startPageNum, int endPageNum, int resolution)
{
try
{
Aspose.Pdf.Document doc = new Aspose.Pdf.Document(originFilePath);
if (doc == null)
{
throw new Exception("pdf文件无效或者pdf文件被加密!");
}
if (imageOutputDirPath.Trim().Length == 0)
{
imageOutputDirPath = Path.GetDirectoryName(originFilePath);
}
if (!Directory.Exists(imageOutputDirPath))
{
DirectoryInfo a= Directory.CreateDirectory(imageOutputDirPath);
a.Attributes = FileAttributes.Hidden;
}
if (startPageNum <= 0)
{
startPageNum = 1;
}
if (endPageNum > doc.Pages.Count || endPageNum <= 0)
{
endPageNum = doc.Pages.Count;
}
if (startPageNum > endPageNum)
{
int tempPageNum = startPageNum; startPageNum = endPageNum; endPageNum = startPageNum;
}
if (resolution <= 0)
{
resolution = 128;
}
string imageNamePrefix = Path.GetFileNameWithoutExtension(originFilePath);
for (int i = startPageNum; i <= endPageNum; i++)
{
if (this.cancelled)
{
break;
}
MemoryStream stream = new MemoryStream();
string imgPath = Path.Combine(imageOutputDirPath, imageNamePrefix) + "_" + i.ToString("000") + ".jpg";
Aspose.Pdf.Devices.Resolution reso = new Aspose.Pdf.Devices.Resolution(resolution);
Aspose.Pdf.Devices.JpegDevice jpegDevice = new Aspose.Pdf.Devices.JpegDevice(reso, 100);
jpegDevice.Process(doc.Pages[i], stream);
Image img = Image.FromStream(stream);
Bitmap bm = ESBasic.Helpers.ImageHelper.Zoom(img, 0.6f);
bm.Save(imgPath, ImageFormat.Jpeg);
img.Dispose();
stream.Dispose();
bm.Dispose();
System.Threading.Thread.Sleep(200);
if (this.ProgressChanged != null)
{
this.ProgressChanged(i - 1, endPageNum);
}
}
if (this.cancelled)
{
return;
}
if (this.ConvertSucceed != null)
{
this.ConvertSucceed();
}
}
catch (Exception ex)
{
if (this.ConvertFailed != null)
{
this.ConvertFailed(ex.Message);
}
}
}
}
#endregion
#region 将ppt文档转换为图片
public class Ppt2ImageConverter : IImageConverter
{
private Pdf2ImageConverter pdf2ImageConverter;
public event CbGeneric<int, int> ProgressChanged;
public event CbGeneric ConvertSucceed;
public event CbGeneric<string> ConvertFailed;
public void Cancel()
{
if (this.pdf2ImageConverter != null)
{
this.pdf2ImageConverter.Cancel();
}
}
public void ConvertToImage(string originFilePath, string imageOutputDirPath)
{
ConvertToImage(originFilePath, imageOutputDirPath, 0, 0, 200);
}
/// <summary>
/// 将pdf文档转换为图片的方法
/// </summary>
/// <param name="originFilePath">ppt文件路径</param>
/// <param name="imageOutputDirPath">图片输出路径,如果为空,默认值为pdf所在路径</param>
/// <param name="startPageNum">从PDF文档的第几页开始转换,如果为0,默认值为1</param>
/// <param name="endPageNum">从PDF文档的第几页开始停止转换,如果为0,默认值为pdf总页数</param>
/// <param name="resolution">设置图片的像素,数字越大越清晰,如果为0,默认值为128,建议最大值不要超过1024</param>
private void ConvertToImage(string originFilePath, string imageOutputDirPath, int startPageNum, int endPageNum, int resolution)
{
try
{
string key = "PExpY2Vuc2U+DQogIDxEYXRhPg0KICAgIDxMaWNlbnNlZFRvPkFzcG9zZSBTY290bGFuZCB" +
"UZWFtPC9MaWNlbnNlZFRvPg0KICAgIDxFbWFpbFRvPmJpbGx5Lmx1bmRpZUBhc3Bvc2UuY2" +
"9tPC9FbWFpbFRvPg0KICAgIDxMaWNlbnNlVHlwZT5EZXZlbG9wZXIgT0VNPC9MaWNlbnNlV" +
"HlwZT4NCiAgICA8TGljZW5zZU5vdGU+TGltaXRlZCB0byAxIGRldmVsb3BlciwgdW5saW1p" +
"dGVkIHBoeXNpY2FsIGxvY2F0aW9uczwvTGljZW5zZU5vdGU+DQogICAgPE9yZGVySUQ+MTQ" +
"wNDA4MDUyMzI0PC9PcmRlcklEPg0KICAgIDxVc2VySUQ+OTQyMzY8L1VzZXJJRD4NCiAgIC" +
"A8T0VNPlRoaXMgaXMgYSByZWRpc3RyaWJ1dGFibGUgbGljZW5zZTwvT0VNPg0KICAgIDxQc" +
"m9kdWN0cz4NCiAgICAgIDxQcm9kdWN0PkFzcG9zZS5Ub3RhbCBmb3IgLk5FVDwvUHJvZHVj" +
"dD4NCiAgICA8L1Byb2R1Y3RzPg0KICAgIDxFZGl0aW9uVHlwZT5FbnRlcnByaXNlPC9FZGl" +
"0aW9uVHlwZT4NCiAgICA8U2VyaWFsTnVtYmVyPjlhNTk1NDdjLTQxZjAtNDI4Yi1iYTcyLT" +
"djNDM2OGYxNTFkNzwvU2VyaWFsTnVtYmVyPg0KICAgIDxTdWJzY3JpcHRpb25FeHBpcnk+M" +
"jAxNTEyMzE8L1N1YnNjcmlwdGlvbkV4cGlyeT4NCiAgICA8TGljZW5zZVZlcnNpb24+My4w" +
"PC9MaWNlbnNlVmVyc2lvbj4NCiAgICA8TGljZW5zZUluc3RydWN0aW9ucz5odHRwOi8vd3d" +
"3LmFzcG9zZS5jb20vY29ycG9yYXRlL3B1cmNoYXNlL2xpY2Vuc2UtaW5zdHJ1Y3Rpb25zLm" +
"FzcHg8L0xpY2Vuc2VJbnN0cnVjdGlvbnM+DQogIDwvRGF0YT4NCiAgPFNpZ25hdHVyZT5GT" +
"zNQSHNibGdEdDhGNTlzTVQxbDFhbXlpOXFrMlY2RThkUWtJUDdMZFRKU3hEaWJORUZ1MXpP" +
"aW5RYnFGZkt2L3J1dHR2Y3hvUk9rYzF0VWUwRHRPNmNQMVpmNkowVmVtZ1NZOGkvTFpFQ1R" +
"Hc3pScUpWUVJaME1vVm5CaHVQQUprNWVsaTdmaFZjRjhoV2QzRTRYUTNMemZtSkN1YWoyTk" +
"V0ZVJpNUhyZmc9PC9TaWduYXR1cmU+DQo8L0xpY2Vuc2U+";
new Aspose.Slides.License().SetLicense(new MemoryStream(Convert.FromBase64String(key)));
Aspose.Slides.Presentation doc = new Aspose.Slides.Presentation(originFilePath);
if (doc == null)
{
throw new Exception("ppt文件无效或者ppt文件被加密!");
}
if (imageOutputDirPath.Trim().Length == 0)
{
imageOutputDirPath = Path.GetDirectoryName(originFilePath);
}
if (!Directory.Exists(imageOutputDirPath))
{
DirectoryInfo a = Directory.CreateDirectory(imageOutputDirPath);
a.Attributes = FileAttributes.Hidden;
}
if (startPageNum <= 0)
{
startPageNum = 1;
}
if (endPageNum > doc.Slides.Count || endPageNum <= 0)
{
endPageNum = doc.Slides.Count;
}
if (startPageNum > endPageNum)
{
int tempPageNum = startPageNum; startPageNum = endPageNum; endPageNum = startPageNum;
}
if (resolution <= 0)
{
resolution = 128;
}
//先将ppt转换为pdf临时文件
string tmpPdfPath = originFilePath + ".pdf";
doc.Save(tmpPdfPath, Aspose.Slides.Export.SaveFormat.Pdf);
//再将pdf转换为图片
Pdf2ImageConverter converter = new Pdf2ImageConverter();
converter.ConvertFailed += new CbGeneric<string>(converter_ConvertFailed);
converter.ConvertSucceed += new CbGeneric(converter_ConvertSucceed);
converter.ProgressChanged += new CbGeneric<int, int>(converter_ProgressChanged);
converter.ConvertToImage(tmpPdfPath, imageOutputDirPath);
//删除pdf临时文件
File.Delete(tmpPdfPath);
if (this.ConvertSucceed != null)
{
this.ConvertSucceed();
}
}
catch (Exception ex)
{
if (this.ConvertFailed != null)
{
this.ConvertFailed(ex.Message);
}
}
this.pdf2ImageConverter = null;
}
void converter_ProgressChanged(int done, int total)
{
if (this.ProgressChanged != null)
{
this.ProgressChanged(done, total);
}
}
void converter_ConvertSucceed()
{
if (this.ConvertSucceed != null)
{
this.ConvertSucceed();
}
}
void converter_ConvertFailed(string msg)
{
if (this.ConvertFailed != null)
{
this.ConvertFailed(msg);
}
}
}
#endregion
#region 将图片压缩包解压。(如果课件本身就是多张图片,那么可以将它们压缩成一个rar,作为一个课件)
/// <summary>
/// 将图片压缩包解压。(如果课件本身就是多张图片,那么可以将它们压缩成一个rar,作为一个课件)
/// </summary>
public class Rar2ImageConverter : IImageConverter
{
private bool cancelled = false;
public event CbGeneric<string> ConvertFailed;
public event CbGeneric<int, int> ProgressChanged;
public event CbGeneric ConvertSucceed;
public void Cancel()
{
this.cancelled = true;
}
public void ConvertToImage(string rarPath, string imageOutputDirPath)
{
try
{
Unrar tmp = new Unrar(rarPath);
tmp.Open(Unrar.OpenMode.List);
string[] files = tmp.ListFiles();
tmp.Close();
int total = files.Length;
int done = 0;
Unrar unrar = new Unrar(rarPath);
unrar.Open(Unrar.OpenMode.Extract);
unrar.DestinationPath = imageOutputDirPath;
while (unrar.ReadHeader() && !cancelled)
{
if (unrar.CurrentFile.IsDirectory)
{
unrar.Skip();
}
else
{
unrar.Extract();
++done;
if (this.ProgressChanged != null)
{
this.ProgressChanged(done, total);
}
}
}
unrar.Close();
if (this.ConvertSucceed != null)
{
this.ConvertSucceed();
}
}
catch (Exception ex)
{
if (this.ConvertFailed != null)
{
this.ConvertFailed(ex.Message);
}
}
}
}
#endregion
}
4.现在编写Form1的按钮功能,回到Form1设计界面,先编写一键转换功能,双击按钮,进入Form1.cs*。说下思路,代码我直接贴出来或者到项目里查看。
思路:因为我这个是要与unity路径同步的,所以我新建了一个叫course_path.txt的文件,里面填写我需要转换的文件夹,然后代码去遍历这个文件,这里需要使用递归的思想(递归不懂的去百度下),直到获取到所有的文档,并根据文档类型执行Aspose内不同的转换代码
private void button1_Click(object sender, EventArgs e)
{
SetVisible(false);
string a = System.Environment.CurrentDirectory;
a = a.Substring(0, a.LastIndexOf(@"\"));
a += "/course_path.txt";
//根据路径得到txt文件,并获取到txt内的自定义路径
string dataTxt =WJJsonUtil. ReadFile(a);
if (dataTxt == null)
return;
dataTxt = dataTxt.Replace(@"\", "/").Trim();
DateTime dt1 = DateTime.Now;
FileUtil(dataTxt);
DateTime dt2 = DateTime.Now;
string timeText = null;
timeText= (dt2 - dt1).TotalSeconds.ToString();
bool b = true;
while (b)
{
if (timeText!= null)
{
b = false;
SetVisible(true);
string c = string.Format("转换结束,耗时:{0}秒", timeText);
this.Text = "文档转换工具";
MessageBox.Show(c,"转换结果");
}
}
}
string fileFolderName = "";
public void FileUtil(string path)
{
if (Directory.Exists(path))
{
DirectoryInfo dirInfo = new DirectoryInfo(path);
DirectoryInfo[] fileFolder = dirInfo.GetDirectories();
fileFolder = fileFolder.Where(o => !o.Name.Contains("_目录")).ToArray();
FileInfo[] files = dirInfo.GetFiles("*", SearchOption.TopDirectoryOnly);
for (int i = 0; i < fileFolder.Length; i++)
{
fileFolderName = fileFolder[i].Name;
FileUtil(fileFolder[i].FullName);
}
for (int i = 0; i < files.Length; i++)
{
ToJpgUtil.ToJpgSingle(files[i].FullName);
this.progressBar1.Value = (i+1) *100/ files.Length;
this.Text = string.Format("{0} 当前文件夹进程:{1}", fileFolderName, (i + 1 + "/" + files.Length));
}
}
}
5.编写根据路径转换的代码,双击设计窗口From1的按钮
private void button2_Click(object sender, EventArgs e)
{
SelectPath();
}
private void SelectPath()
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.Multiselect = false;//该值确定是否可以选择多个文件
dialog.Title = "请选择文件";
dialog.Filter = "ppt(*.pptx,*.ppt,*,*.doc,*,*.docx,*,*.pdf*,)|*.pptx;*.ppt;*.docx;**.doc;**.pdf;*,*.doc;*,*.pdf*;";
dialog.RestoreDirectory = true;
string file = null;
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
DateTime dt1 = DateTime.Now;
this.Text = "转换中";
file = dialog.FileName;
ToJpgUtil.ToJpgSingle(file);
DateTime dt2 = DateTime.Now;
string timeText = null;
timeText = (dt2 - dt1).TotalSeconds.ToString();
bool a = true;
while (a)
{
if (timeText != null)
{
a = false;
SetVisible(true);
string b = string.Format("转换结束,耗时:{0}秒", timeText);
this.Text = "文档转换工具";
MessageBox.Show(b, "转换结果");
}
}
}
}
5.大功告成,因为只是一个插件,可以直接运行,没必要打包成安装包,所以安装包教程就没有了,网上关于安装包的也很多。