支持的文件类型包括pdf,xls,xlsx,ppt,pptx,docx,doc,
Cache.cs:
using System;
using System.Runtime.Caching;
using Newtonsoft.Json.Linq;
namespace Online.Core
{
/// <summary>
/// 缓存框架
/// </summary>
public class CacheData
{
private const string CacheName = "System";
private static readonly MemoryCache MemoryCache = new MemoryCache(CacheName);
/// <summary>
/// 缓存过期时间
/// </summary>
private static DateTimeOffset DestroyTime
{
get { return DateTimeOffset.Now.AddMinutes(5); }
}
/// <summary>
/// 设置缓存
/// </summary>
/// <param name="name">要插入的缓存项的唯一标识符</param>
/// <param name="value">该缓存项的数据</param>
public static void Set(string name, JObject value)
{
if (MemoryCache.Contains(name))
{
MemoryCache[name] = value;
}
else
{
MemoryCache.Set(name, value, DestroyTime);
}
}
/// <summary>
/// 从缓存中返回一个项
/// </summary>
/// <param name="name">要获取的缓存项的唯一标识符</param>
/// <returns></returns>
public static JObject Get(string name)
{
return MemoryCache.Contains(name) ? JObject.Parse(MemoryCache.Get(name).ToString()) : null;
}
/// <summary>
/// 从缓存中移除某个缓存项
/// </summary>
/// <param name="name">要移除的缓存项的唯一标识符</param>
public static void Remove(string name)
{
MemoryCache.Remove(name);
}
/// <summary>
/// 确定缓存中是否包括指定的键值
/// </summary>
/// <param name="name">要搜索的缓存项的唯一标识符</param>
/// <returns></returns>
public static bool ContainsKey(string name)
{
return MemoryCache.Contains(name);
}
}
}
Conversion.cs代码:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Aspose.Cells;
using Aspose.Pdf.Devices;
using Aspose.Slides;
using Document = Aspose.Pdf.Document;
using SaveFormat = Aspose.Words.SaveFormat;
namespace Online.Core
{
public interface IConversion
{
/// <summary>
/// 回调方法
/// </summary>
Action<int, string> CallBack { get; set; }
/// <summary>
/// Office转换成图片
/// </summary>
/// <param name="filePath">文件路径</param>
/// <param name="resolution">图片质量</param>
void ConvertToImage(string filePath, int resolution);
}
/// <summary>
/// Office转换工具
/// </summary>
public class Conversion
{
/// <summary>
/// 图片转换质量
/// </summary>
private const int Resolution = 170;
/// <summary>
/// 实例化转换工具
/// </summary>
/// <param name="filePath">文件路径</param>
/// <param name="fileExtension">文件扩展名</param>
/// <param name="callBack">回调方法</param>
public Conversion(string filePath, string fileExtension, Action<int, string> callBack)
{
switch (fileExtension.ToLower())
{
case ".doc":
case ".docx":
ConversionFunc = new WordConversion();
break;
case ".pdf":
ConversionFunc = new PdfConversion();
break;
case ".xls":
case ".xlsx":
ConversionFunc = new ExcelConversion();
break;
case ".ppt":
case ".pptx":
ConversionFunc = new PptConversion();
break;
default:
throw new Exception("不支持的文件类型。");
}
FilePath = filePath;
ConversionFunc.CallBack = callBack;
}
private IConversion ConversionFunc { get; set; }
/// <summary>
/// 文件路径
/// </summary>
private string FilePath { get; set; }
/// <summary>
/// Office转换成图片
/// </summary>
public void ConvertToImage()
{
ConversionFunc.ConvertToImage(FilePath, Resolution);
ConversionFunc.CallBack(0, "");
}
}
internal class PdfConversion : IConversion
{
private readonly List<Task> TaskList = new List<Task>();
public Action<int, string> CallBack { get; set; }
public void ConvertToImage(string filePath, int resolution)
{
var doc = new Document(filePath);
string imageName = Path.GetFileNameWithoutExtension(filePath);
for (int i = 1; i <= doc.Pages.Count; i++)
{
int pageNum = i;
string imgPath = string.Format("{0}_{1}.Jpeg", Path.Combine(Path.GetDirectoryName(filePath), imageName),
i.ToString("000"));
if (File.Exists(imgPath))
{
InvokeCallBack(pageNum, imgPath);
continue;
}
using (var stream = new MemoryStream())
{
var reso = new Resolution(resolution);
var jpegDevice = new JpegDevice(reso, 100);
jpegDevice.Process(doc.Pages[i], stream);
using (Image image = Image.FromStream(stream))
{
new Bitmap(image).Save(imgPath, ImageFormat.Jpeg);
}
}
InvokeCallBack(pageNum, imgPath);
}
Task.WaitAll(TaskList.ToArray());
}
private void InvokeCallBack(int pageNum, string imagePath)
{
var task = new Task(() => { CallBack.Invoke(pageNum, imagePath); });
TaskList.Add(task);
task.Start();
}
}
internal class WordConversion : IConversion
{
private readonly List<Task> TaskList = new List<Task>();
public Action<int, string> CallBack { get; set; }
public void ConvertToImage(string filePath, int resolution)
{
//先将Word转换为PDF文件
string pdfPath;
try
{
using (var convert = new WordToPdf())
{
pdfPath = convert.ToPdf(filePath);
}
}
catch (COMException)
{
pdfPath = Path.ChangeExtension(filePath, "pdf");
if (!File.Exists(pdfPath))
{
var doc = new Aspose.Words.Document(filePath);
doc.Save(pdfPath, SaveFormat.Pdf);
}
}
//再将PDF转换为图片
var converter = new PdfConversion {CallBack = CallBack};
converter.ConvertToImage(pdfPath, resolution);
}
private void InvokeCallBack(int pageNum, string imagePath)
{
var task = new Task(() => { CallBack.Invoke(pageNum, imagePath); });
TaskList.Add(task);
task.Start();
}
}
internal class ExcelConversion : IConversion
{
public Action<int, string> CallBack { get; set; }
public void ConvertToImage(string filePath, int resolution)
{
var doc = new Workbook(filePath);
//先将Excel转换为PDF临时文件
string pdfPath = Path.ChangeExtension(filePath, "pdf");
doc.Save(pdfPath, Aspose.Cells.SaveFormat.Pdf);
//再将PDF转换为图片
var converter = new PdfConversion {CallBack = CallBack};
converter.ConvertToImage(filePath, resolution);
}
}
internal class PptConversion : IConversion
{
public Action<int, string> CallBack { get; set; }
public void ConvertToImage(string filePath, int resolution)
{
var doc = new Presentation(filePath);
//先将ppt转换为PDF文件
string tmpPdfPath = Path.ChangeExtension(filePath, "pdf");
doc.Save(tmpPdfPath, Aspose.Slides.Export.SaveFormat.Pdf);
//再将PDF转换为图片
var converter = new PdfConversion {CallBack = CallBack};
converter.ConvertToImage(filePath, resolution);
}
}
}
FileManagement.cs代码:
using System;
using System.Configuration;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Online.Core
{
/// <summary>
/// 文件管理
/// </summary>
public class FileManagement
{
private static readonly FileManagement Instance = new FileManagement();
private FileManagement()
{
var task = new Task(() =>
{
if (bool.Parse(AutoClear))
{
Clear();
}
Thread.Sleep(24*60*60*1000);
});
task.Start();
}
/// <summary>
/// 文件清理时间
/// </summary>
public static string FileClearDay
{
get { return ConfigurationManager.AppSettings["FileClearDay"] ?? 10.ToString(); }
set
{
int day;
if (int.TryParse(value, out day))
{
ConfigurationManager.AppSettings["FileClearDay"] = value;
}
}
}
/// <summary>
/// 是否自动清理
/// </summary>
public static string AutoClear
{
get { return ConfigurationManager.AppSettings["AutoClear"] ?? false.ToString(); }
set
{
bool auto;
if (bool.TryParse(value, out auto))
{
ConfigurationManager.AppSettings["AutoClear"] = value;
}
}
}
private static DirectoryInfo FileDirectory
{
get { return new DirectoryInfo(string.Format(@"{0}\FileInfo\", AppDomain.CurrentDomain.BaseDirectory)); }
}
/// <summary>
/// 清理过期缓存
/// </summary>
public static void Clear()
{
foreach (FileInfo file in FileDirectory.GetFiles("*", SearchOption.AllDirectories))
{
if ((DateTime.Now - file.CreationTime).TotalDays > double.Parse(FileClearDay))
{
file.Delete();
}
}
}
/// <summary>
/// 清理全部缓存
/// </summary>
public static void ClearAll()
{
FileDirectory.Delete(true);
}
}
}
Network.cs
using System;
using System.IO;
using System.Net;
namespace Online.Core
{
/// <summary>
/// 从URL获取文件
/// </summary>
public class Network
{
public Network(string url)
{
FilePath = GetFileInfo(new Uri(url));
}
/// <summary>
/// 文件本地路径
/// </summary>
public string FilePath { get; set; }
/// <summary>
/// 文件扩展名
/// </summary>
public string FileExtension
{
get { return FilePath.Substring(FilePath.LastIndexOf(".")); }
}
private static string GetFileInfo(Uri uri)
{
var request = (HttpWebRequest) WebRequest.Create(uri);
request.ContentType = "application/x-www-form-urlencoded";
string filePath = GetFilePath(uri);
if (!File.Exists(filePath))
{
using (WebResponse response = request.GetResponse())
{
var length = (int) response.ContentLength;
using (var reader = new BinaryReader(response.GetResponseStream()))
{
using (FileStream stream = File.Create(filePath))
{
stream.Write(reader.ReadBytes(length), 0, length);
}
}
}
}
return filePath;
}
/// <summary>
/// 获取文件本地路径
/// </summary>
/// <param name="uri">网络请求地址</param>
private static string GetFilePath(Uri uri)
{
string localPath = uri.LocalPath;
string filePath = localPath.Substring(localPath.LastIndexOf("/") + 1);
string folderPath = string.Format(@"{0}\FileInfo\{1}\{2}\", AppDomain.CurrentDomain.BaseDirectory, uri.Host,
localPath.Remove(localPath.LastIndexOf("/")).Replace("/", @"\"));
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
return folderPath + filePath;
}
}
}
WordToPdf.cs代码:
using System;
using System.IO;
using System.Runtime.InteropServices;
using Word;
namespace Online.Core
{
/// <summary>
/// 通过COM组件进行格式转换
/// </summary>
internal class WordToPdf : IDisposable
{
private readonly dynamic office;
public WordToPdf()
{
foreach (
Type type in
new[]
{
Type.GetTypeFromProgID("Word.Application"), Type.GetTypeFromProgID("KWps.Application"),
Type.GetTypeFromProgID("wps.Application")
})
{
if (type != null)
{
try
{
office = Activator.CreateInstance(type);
return;
}
catch (COMException)
{
}
}
}
throw new COMException("未找到可用的COM组件。");
}
public void Dispose()
{
if (office != null)
{
office.Quit();
}
}
public string ToPdf(string wpsFilename, string pdfFilename = null)
{
if (wpsFilename == null)
{
throw new COMException("未找到指定文件。");
}
if (pdfFilename == null)
{
pdfFilename = Path.ChangeExtension(wpsFilename, "pdf");
}
if (!File.Exists(pdfFilename))
{
dynamic doc = office.Documents.Open(wpsFilename, Visible: false);
doc.ExportAsFixedFormat(pdfFilename, WdExportFormat.wdExportFormatPDF);
doc.Close();
}
return pdfFilename;
}
}
}
Office.aspx
<!DOCTYPE html>
<html>
<head runat="server">
<title>Office在线预览</title>
<link type="text/css" rel="stylesheet" href="/Resources/Style/Office.css" />
</head>
<body>
<div ng-app="app" ng-controller="controller">
<div ng-cloak class="Loading ng-cloak" ng-show="imageList == null || imageList.length == 0">
<img alt="" src="/Resources/Images/Loading.gif" />
</div>
<div ng-cloak class="Error ng-cloak" ng-show="status == 'error'">
<h1>:(</h1>
<p class="Explain">真抱歉,页面发生了错误。</p>
<p class="Hint"><span>错误原因:</span><span ng-bind="message"></span></p>
</div>
<div ng-cloak class="ImageList ng-cloak" ng-show="status == 'running' || status == 'finish'">
<div class="Image" ng-repeat="item in imageList | orderBy : 'pageNum'">
<img ng-src="{{item.imageUrl}}" />
</div>
</div>
<div ng-cloak class="Loading_Bottom ng-cloak" ng-show="status == 'running' && imageList != null && imageList.length != 0">
<img alt="" src="/Resources/Images/Loading.gif" />
</div>
</div>
<script type='text/javascript' src='/Resources/Scripts/jquery-1.8.0.min.js'></script>
<script type='text/javascript' src='/Resources/Scripts/angular.min.js'></script>
<script type="text/javascript">
angular.module('app', []).controller('controller', function($scope, $http) {
$scope.status = "loading";
$scope.GetImage = function() {
$http({
method: 'POST',
url: 'Office.aspx',
data: "Mode=GetResult&PageId=<%= SessionId %>",
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
}).success(function(data) {
$scope.status = data.status;
if (data.status == "running") {
$scope.imageList = data.imageList;
setTimeout(function() {
$scope.GetImage();
}, 100);
} else if (data.status == "finish") {
$scope.imageList = data.imageList;
} else {
$scope.message = data.message;
}
});
};
$scope.GetImage();
});
</script>
</body>
</html>
Office.aspx.cs
using System;
using System.Threading.Tasks;
using System.Web.UI;
using Newtonsoft.Json.Linq;
using Online.Core;
namespace Web
{
public partial class Office : Page
{
/// <summary>
/// 页面ID
/// </summary>
public string SessionId { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
switch (Request["Mode"])
{
case "GetResult":
GetResult(Request["PageId"]);
return;
default:
SessionId = Session.SessionID + Request["FileUrl"];
GetFile(Request["FileUrl"]);
return;
}
}
/// <summary>
/// 开始加载Office文件
/// </summary>
/// <param name="fileUrl">文件Url</param>
private void GetFile(string fileUrl)
{
//避免页面加载完成前重复刷新造成的重复获取
if (!CacheData.ContainsKey(SessionId))
{
CacheData.Set(SessionId,
new JObject {{"status", "running"}, {"message", ""}, {"imageList", new JArray()}});
new Task(() =>
{
if (!string.IsNullOrEmpty(fileUrl))
{
try
{
var network = new Network(fileUrl);
new Conversion(network.FilePath, network.FileExtension, CallBack).ConvertToImage();
}
catch (Exception ex)
{
AlertError(ex.Message);
}
}
else
{
AlertError("请输入文件地址");
}
}).Start();
}
}
/// <summary>
/// 返回处理结果
/// </summary>
/// <param name="pageId">页面唯一ID</param>
private void GetResult(string pageId)
{
Response.Clear();
Response.ContentType = "application/json";
Response.Write(CacheData.Get(pageId));
string status = CacheData.Get(pageId)["status"].ToString();
if (status == "finish" || status == "error")
{
CacheData.Remove(pageId);
}
Response.End();
}
/// <summary>
/// 获取图片地址
/// </summary>
/// <param name="pageNum">当前图片次序</param>
/// <param name="imageUrl">图片Url</param>
public void CallBack(int pageNum, string imageUrl)
{
lock (this)
{
JObject jObject = CacheData.Get(SessionId);
if (jObject["status"].ToString() == "running")
{
if (pageNum == 0)
{
jObject["status"] = "finish";
}
else
{
((JArray) jObject["imageList"]).Add(new JObject
{
{"pageNum", pageNum},
{"imageUrl", FromLocal(imageUrl)}
});
}
CacheData.Set(SessionId, jObject);
}
}
}
/// <summary>
/// 页码报错提示
/// </summary>
/// <param name="message">提示信息</param>
private void AlertError(string message)
{
CacheData.Set(SessionId,
new JObject {{"status", "error"}, {"message", message}, {"imageList", new JArray()}});
}
/// <summary>
/// 本地路径转Url
/// </summary>
private string FromLocal(string filePath)
{
string fileUrl = filePath.Replace(AppDomain.CurrentDomain.BaseDirectory, ""); //转换成相对路径
fileUrl = "/" + fileUrl.Replace(@"\", @"/");
return fileUrl;
}
}
}
Setting.aspx内容:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Setting.aspx.cs" Inherits="Web.Setting" %>
<%@ Import Namespace="Online.Core" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Office在线设置页面</title>
<link type="text/css" rel="stylesheet" href="/Resources/Style/bootstrap/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="/Resources/Style/bootstrap/css/docs.min.css" />
<link type="text/css" rel="stylesheet" href="/Resources/Style/Setting.css" />
</head>
<body>
<div ng-app="app" ng-controller="controller">
<div class="panel panel-info">
<div class="panel-heading">
<h3 class="panel-title">参数设置</h3>
</div>
<div ng-cloak class="panel-body ng-cloak">
<div class="input-group">
<span class="input-group-addon">设置文件过期时间(天)</span>
<input type="text" class="form-control" ng-model="clearDay">
</div>
</div>
<div ng-cloak class="panel-body ng-cloak">
<div class="btn-group btn-group-justified">
<div class="btn-group" role="group">
<button type="button" class="btn btn-default" ng-click="Query('Function', 'Clear', '', '清理成功')">清理过期缓存文件</button>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-default btn-center" ng-click="Query('Function', 'ClearAll', '', '清理成功')">清理所有缓存文件</button>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-default" ng-class="{true:'active'}[auto]" ng-click="AutoClear()">自动清理过期文件</button>
</div>
</div>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading">
<h3 class="panel-title">COM检测</h3>
</div>
<div ng-cloak class="panel-body ng-cloak">
<p>COM组件可以使OFFICE在页面总呈现更好的效果。</p>
<div class="bs-callout bs-callout-info" ng-repeat="item in environment">
<h4 style="margin-bottom: 25px;" ng-bind="item.Name"></h4>
<div class="alert" ng-repeat="node in item.Data" ng-class="{true:'alert-success',false:'alert-danger'}[node.Status]">
<span ng-bind="node.Name"></span>
<span ng-if="node.Status">检测成功</span>
<span ng-if="!node.Status">检测失败</span>
<p style="font-size: 11px; margin: 10px 0;" ng-if="!node.Status" ng-bind="node.Message"></p>
</div>
</div>
</div>
</div>
</div>
<script type='text/javascript' src='/Resources/Scripts/jquery-1.8.0.min.js'></script>
<script type='text/javascript' src='/Resources/Scripts/angular.min.js'></script>
<script type="text/javascript">
angular.module('app', []).controller('controller', function($scope, $http) {
$scope.auto = <%= FileManagement.AutoClear %>;
$scope.clearDay = <%= FileManagement.FileClearDay %>;
$scope.environment = <%= EnvironmentCheck %>;
$scope.Query = function(action, name, value, message) {
$http.get("/Setting.aspx?Action=" + action + "&name=" + name + "&value=" + value).success(function() {
alert(message || '设置成功');
}).error(function(data) {
alert(data);
});
};
$scope.AutoClear = function() {
$scope.auto = !$scope.auto;
$scope.Query('Property', 'AutoClear', $scope.auto);
};
});
</script>
</body>
</html>
Setting.aspx.cs代码:
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Web.UI;
using Newtonsoft.Json.Linq;
using Online.Core;
namespace Web
{
public partial class Setting : Page
{
/// <summary>
/// COM环境检测
/// </summary>
public JArray EnvironmentCheck
{
get
{
var checks = new Dictionary<string, CheckModel[]>();
checks.Add("Word: 检测COM组件是否存在", new[]
{
new CheckModel
{
Name = "WPS",
Status =
Type.GetTypeFromProgID("KWps.Application") != null ||
Type.GetTypeFromProgID("wps.Application") != null
},
new CheckModel {Name = "OFFICE", Status = Type.GetTypeFromProgID("Word.Application") != null}
});
checks.Add("Word: 检测COM组件是否可用", new Func<CheckModel[]>(() =>
{
CheckModel[] checkModels = { new CheckModel { Name = "WPS" }, new CheckModel { Name = "OFFICE" } };
Type[] typeArray =
{
Type.GetTypeFromProgID("KWps.Application") ?? Type.GetTypeFromProgID("wps.Application"),
Type.GetTypeFromProgID("Word.Application")
};
for (int i = 0; i < typeArray.Length; i++)
{
try
{
if (typeArray[i] != null)
{
Activator.CreateInstance(typeArray[i]);
checkModels[i].Status = true;
}
}
catch (COMException e)
{
checkModels[i].Message = e.Message;
}
}
return checkModels;
}).Invoke());
var resultArray = new JArray();
foreach (string check in checks.Keys)
{
var result = new JObject();
result.Add("Name", check);
result.Add("Data", new JArray());
foreach (CheckModel checkModel in checks[check])
{
var item = new JObject();
foreach (PropertyInfo property in checkModel.GetType().GetProperties())
{
object value = property.GetValue(checkModel, null);
switch (property.PropertyType.Name)
{
case "Boolean":
item.Add(property.Name, bool.Parse(value.ToString()));
break;
case "String":
item.Add(property.Name, value as string);
break;
}
}
(result["Data"] as JArray).Add(item);
}
resultArray.Add(result);
}
return resultArray;
}
}
protected void Page_Load(object sender, EventArgs e)
{
try
{
switch (Request["Action"])
{
case "Property":
if (typeof(FileManagement).GetProperty(Request["Name"]) != null)
{
typeof(FileManagement).GetProperty(Request["Name"]).SetValue(null, Request["Value"], null);
}
return;
case "Function":
if (typeof(FileManagement).GetMethod(Request["Name"]) != null)
{
typeof(FileManagement).GetMethod(Request["Name"]).Invoke(null, null);
}
return;
default:
return;
}
}
catch (Exception ex)
{
Response.Clear();
Response.Write(ex.Message);
Response.End();
}
}
public class CheckModel
{
public string Name { get; set; }
public bool Status { get; set; }
public string Message { get; set; }
}
}
}
注意:电脑需要安装office 2007或以上版本