有時候我們從其他網頁上拷貝來的內容中含有圖片,當原始地址失效後就會影響讀者閱讀。
所以我制作了這樣一個插件,可以將遠程圖片保存到本地服務器。
聲明:下面的文字是本文不可缺少的部分,轉載請保留,謝謝!
////////////////////////////////////////////////////
作者:武眉博<活靶子.Net>
同時首發於:
落伍者 && 博客園
開發者學院 && .Net男孩社區
////////////////////////////////////////////////////
今天轉載了[author]xiaozhuang[/author]朋友的文章同時從博客園服務器上下載了圖片
演示見:http://www.devedu.com/Doc/DotNet/AspNet/AspNet-AJaxWCF-ServiceADONET-Entity-FrameworkShiXianShuJuLIEBiaoShuJuShaiXuanFenYePaiXuShanChu.ASPx
原理如下:
1.實現ICallbackEventHandler接口以用啟用客戶端回調。
2.從當前FckEdiotr內容分析出所有<img標簽,取得src的地址。
3.回調下載到服務器。
4.返回下載後位於本服務器上的路徑。
5.替換當前FckEdiotr內容內對應的<img標簽的src屬性。
其他廢話不多說了,代碼中都有注釋。
如果您熟悉Fckeditor的插件工作流程,請繼續向下閱讀,另請不要留言要我直接提供下載,下面的代碼已經可以完整調試了。
E:\IISROOT\FckTest\FckTest\fckeditor\editor\plugins\remoteimagerubber\remoteimagerubber.ASPx
1 <%--
2 使用單頁模型(非代碼後置),是為了便於此插件部署,
3 不需編譯成dll,只需拷貝remoteimagerubber.ASPx 和 fckplugin.JS 到plugn目錄,
4 並配置一下fckconfig.JS及相應的語言包,就可以使用了。
5 --%>
6
7 <%@ Page Language="C#" %>
8
9 <%@ Import Namespace="System.Net" %>
10 <%--
11 實現ICallbackEventHandler接口以提供客戶端回調功能。
12 --%>
13 <%@ Implements Interface="System.Web.UI.ICallbackEventHandler" %>
14
15 <script runat="server">
16
17 /// <summary>
18 /// 此處配置遠程文件保存目錄
19 /// </summary>
20 private static readonly string savePath = "~/Uploads/";
21
22 /// <summary>
23 /// 此處配置允許下載的文件擴展名
24 /// <remarks>
25 /// 暫未考慮使用動態網頁輸出的圖片如:http://site/image.ASPx?uid=00001 這樣的URI;
26 /// 若要實現此功能可讀取流並判斷ContentType,將流另存為相應文件格式即可。
27 /// </remarks>
28 /// </summary>
29 private static readonly string[ ] allowImageExtension = new string[ ] { ".jpg" , ".png" , ".gif" };
30
31 /// <summary>
32 /// 此處配置本地(網站)主機名
33 /// </summary>
34 private static readonly string[ ] localhost = new string[ ] { "localhost" , "www.devedu.com" };
35
36 private string localImageSrc = string.Empty;
37
38 private void Page_Load( object obj , EventArgs args )
39 {
40 if ( !Page.IsPostBack )
41 {
42 ClientScriptManager csm = Page.ClIEntScript;
43
44 string scripCallServerDownLoad = csm.GetCallbackEventReference( this , "args" , "__ReceiveServerData" , "context" );
45 string callbackScriptDwonLoad = "function __CallServerDownLoad(args , context) {" + scripCallServerDownLoad + "; }";
46 if ( !csm.IsClIEntScriptBlockRegistered( "__CallServerDownLoad" ) )
47 {
48 csm.RegisterClIEntScriptBlock( this.GetType( ) , "__CallServerDownLoad" , callbackScriptDwonLoad , true );
49 }
50 }
51 }
52
53 #region ICallbackEventHandler 成員
54
55 /// <summary>
56 /// 返回數據
57 /// </summary>
58 /// <remarks>如果處理過程中出現錯誤,則仍然返回遠程路徑</remarks>
59 /// <returns>服務器端處理後的本地圖片路徑</returns>
60 public string GetCallbackResult( )
61 {
62 return localImageSrc;
63
64 }
65
66 /// <summary>
67 /// 處理回調事件
68 /// </summary>
69 /// <param name="eventArgument">一個字符串,表示要傳遞到事件處理程序的事件參數</param>
70 public void RaiseCallbackEvent( string eventArgument )
71 {
72
73 string remoteImageSrc = eventArgument;
74
75 string fileName = remoteImageSrc.Substring( remoteImageSrc.LastIndexOf( "/" ) + 1 );
76 string ext = System.IO.Path.GetExtension( fileName );
77
78 if ( !IsAllowedDownloadFile( ext ) )
79 {
80 //非指定類型圖片不進行下載,直接返回原地址。
81 localImageSrc = remoteImageSrc;
82 return;
83 }
84
85 Uri uri = new Uri( remoteImageSrc );
86 if ( IsLocalSource( uri ) )
87 {
88 //本地(本網站下)圖片不進行下載,直接返回原地址。
89 localImageSrc = remoteImageSrc;
90 return;
91 }
92
93 try
94 {
95 //自動創建一個目錄。
96 DateTime now = DateTime.Now;
97 string datePath = string.Format( @"{0}\{1}\{2}\{3}" , now.Year , now.Month.ToString( "00" ) , now.Day.ToString( "00" ) , Guid.NewGuid( ).ToString( ) );
98
99 string localDirectory = System.IO.Path.Combine( Server.MapPath( savePath ) , datePath );
100 if ( !System.IO.Directory.Exists( localDirectory ) )
101 {
102 System.IO.Directory.CreateDirectory( localDirectory );
103 }
104
105 string localFilePath = System.IO.Path.Combine( localDirectory , fileName );
106
107 //不存在同名文件則開始下載,若已經存在則不下載該文件,直接返回已有文件路徑。
108 if ( !System.IO.File.Exists( localFilePath ) )
109 {
110 ClIEnt.DownloadFile( uri , localFilePath );
111 }
112
113 string localImageSrc = ResolveUrl( "~/" + localFilePath.Replace( Server.MapPath( "~/" ) , string.Empty ).Replace( "\\" , "/" ) );
114
115 }
116 catch
117 {
118 //下載過程中出現任何異常都不拋出( 有點狠啊 :) ),仍然用遠程圖片鏈接。
119 localImageSrc = remoteImageSrc;
120 }
121
122 }
123
124
125 #endregion
126
127 private WebClient clIEnt;
128
129 /// <summary>
130 /// <see cref="System.Net.WebClIEnt"/>
131 /// </summary>
132 public WebClient ClIEnt
133 {
134 get
135 {
136 if ( clIEnt != null )
137 {
138 return clIEnt;
139 }
140
141 client = new WebClIEnt( );
142 client.Headers.Add( "user-agent" , "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2;)" );
143
144 return clIEnt;
145
146 }
147 }
148
149 /// <summary>
150 /// 判斷Uri是否為本地路徑
151 /// </summary>
152 /// <param name="uri"></param>
153 /// <returns></returns>
154 private bool IsLocalSource( Uri uri )
155 {
156 for ( int i = localhost.Length ; --i >= 0 ; )
157 {
158 if ( localhost[ i ].ToLower( ) == uri.Host.ToLower( ) )
159 {
160 return true;
161 }
162 }
163
164 return false;
165
166 }
167
168 /// <summary>
169 /// 檢測文件類型是否為允許下載的文件類型
170 /// </summary>
171 /// <param name="extension">擴展名 eg: ".jpg"</param>
172 /// <returns></returns>
173 private bool IsAllowedDownloadFile( string extension )
174 {
175 for ( int i = allowImageExtension.Length ; --i >= 0 ; )
176 {
177 if ( allowImageExtension[ i ].ToLower( ) == extension.ToLower( ) )
178 {
179 return true;
180 }
181 }
182
183 return false;
184 }
185
186 </script>
187
188 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xHtml1-transitional.dtd">
189 <html XMLns="http://www.w3.org/1999/xHtml">
190 <head runat="server">
191 <title></title>
192 <style type="text/CSS">
193 body { margin: 0px; overflow: hidden; background-color: buttonface; }
194 td { font-size: 11pt; font-family: Arial;text-align: left;}
195 #domProgressBarId{
196 ;width: 0%;
197 height: 15px;
198 border-right: buttonhighlight 1px solid;
199 border-top: buttonshadow 1px solid;
200 border-left: buttonshadow 1px solid;
201 border-bottom: buttonhighlight 1px solid;
202 background-color: highlight;
203 }
204 </style>
205
206 <script type="text/Javascript" language="Javascript">
207
208 var RemoteImageRubber = function ( remoteSrcList )
209 {
210 this._remoteSrcList = remoteSrcList;
211 this._totalFilesCount = remoteSrcList.length;
212 }
213
214 RemoteImageRubber.prototype.CurrentPercent = function()
215 {
216 return Math.round( 100 * (1- this.CurrentFilesCount() / this.TotalFilesCount() ) )+"%";
217 }
218
219 RemoteImageRubber.prototype.TotalFilesCount = function()
220 {
221 return this._totalFilesCount;
222 }
223
224 RemoteImageRubber.prototype.CurrentFilesCount = function()
225 {
226 return this._remoteSrcList.length;
227 }
228
229 RemoteImageRubber.prototype.NextFile = function ()
230 {
231
232 if(this._remoteSrcList.length >0)
233 {
234 var currentRemoteSrc = this._remoteSrcList.shift( )
235 __PreCallServer(currentRemoteSrc);
236 }
237 }
238
239 </script>
240
241 <script type="text/Javascript" language="Javascript">
242
243 var oEditor;
244 var domProgressBar;
245 var domCurrentFile;
246 var domAllFilesCount;
247 var domAlreadyDownloadFilesCount;
248
249 var imageUrls;
250 var remoteList = new Array();
251 var localList = new Array();
252
253 var progressBar;
254
255 function Ok()
256 {
257 var __imgIndex;
258 for(__imgIndex = 0; __imgIndex < imageUrls.length; __imgIndex ++)
259 {
260 imageUrls[__imgIndex].src = localList[__imgIndex];
261 }
262
263 return true ;
264 }
265
266 </script>
267
268 <script language="Javascript" type="text/Javascript">
269
270 function __PreCallServer(currentRemoteSrc)
271 {
272 var start = currentRemoteSrc.lastIndexOf("/") + 1;
273 var end = currentRemoteSrc.length - currentRemoteSrc.lastIndexOf("/");
274
275 var currentFileName = currentRemoteSrc.substr(start,end);
276
277 domCurrentFile.innerHtml = currentFileName;
278 __CallServerDownLoad(currentRemoteSrc,'');
279
280 }
281
282 function __ReceiveServerData(receiveValue ,context)
283 {
284 // 注意:-------------------------------------------------------------------------------------------
285 //
286 // (1)不要在接收回調數據時使用變量 "i"。
287 // (2)如果再次回調請使用window.setTimeout(
.這樣的形式
288 //
289 // 否則會導致 "'__pendingCallbacks[
].async' 為空或不是對象"的錯誤產生。
290 //
291 // 因為MS的開發人員在WebForm_CallbackComplete函數內使用了全局變量"i" 。這是一個比較ugly的bug。
292 //
293 // 參見:
294 // http://connect.microsoft.com/VisualStudio/feedback/VIEwFeedback.ASPx?FeedbackID=101974
295 // http://developers.de/blogs/damir_dobric/archive/2006/03/02/4.ASPx?AJax_CallBack=true
296 // http://developers.de/files/folders/279/download.ASPx
297 // http://blogs.sqlXML.org/bryantlikes/archive/2005/12/20/4593.ASPx
298 //
299 //-------------------------------------------------------------------------------------------------
300
301 if(receiveValue )
302 {
303 var localSrc = receiveValue;
304 localList.push(localSrc);
305
306 domAlreadyDownloadFilesCount.innerHtml = progressBar.TotalFilesCount() - progressBar.CurrentFilesCount();
307 domProgressBar.style.width = progressBar.CurrentPercent();
308
309 if( progressBar.CurrentFilesCount() > 0 )
310 {
311 window.setTimeout("progressBar.NextFile()",0);
312 }
313 }
314
315 if(progressBar.CurrentFilesCount() == 0)
316 {
317 window.setTimeout("__reFlush()",500)
318 }
319 }
320
321 function __StartDownLoad()
322 {
323 imageUrls = oEditor.EditorDocument.body.getElementsByTagName("img");
324
325 var m;
326 for(m = 0; m < imageUrls.length; m ++)
327 {
328 remoteList[m] = imageUrls[m].src;
329 }
330
331 progressBar = new RemoteImageRubber(remoteList);
332 domAllFilesCount.innerHtml = progressBar.TotalFilesCount();
333
334 window.setTimeout("progressBar.NextFile()",0);
335
336 }
337
338 function __reFlush()
339 {
340
341 domProgressBar.style.width = "100%";
342
343 //display the 'OK' button
344 window.parent.SetOkButton( true ) ;
345 }
346
347
348 </script>
349
350 </head>
351 <body>
352 <form id="ASPnetForm" runat="server">
353 <div >
354 <table border="0" cellspacing="0" cellpadding="2">
355 <tr>
356 <td nowrap="nowrap" >
357 當前文件: <span id="domCurrentFile" ></span></td>
358 </tr>
359 <tr>
360 <td >
361 <div id="domProgressBarId">
362 </div>
363 </td>
364 </tr>
365 <tr>
366 <td nowrap="nowrap" >
367 共有: <span id="domAllFilesCount"></span> 個文件</td>
368 </tr>
369 <tr>
370 <td nowrap="nowrap" >
371 已下載: <span id="domAlreadyDownloadFilesCount"></span>個。</td>
372 </tr>
373 </table>
374 </div>
375 </form>
376
377 <script type="text/Javascript" language="Javascript">
378 window.parent.SetOkButton( false ) ;
379
380 oEditor = window.parent.InnerDialogLoaded().FCK;
381
382 domProgressBar = document.getElementById("domProgressBarId");
383 domCurrentFile = document.getElementById("domCurrentFile");
384 domAllFilesCount = document.getElementById("domAllFilesCount");
385 domAlreadyDownloadFilesCount = document.getElementById("domAlreadyDownloadFilesCount");
386
387 window.setTimeout("__StartDownLoad()",0);
388 </script>
389
390 </body>
391 </Html>
392
E:\IISROOT\FckTest\FckTest\fckeditor\editor\plugins\remoteimagerubber\fckplugin.JS
1 FCKCommands.RegisterCommand(
2 'RemoteImageRubber',
3 new FCKDialogCommand( 'RemoteImageRubber',
4 FCKLang["RemoteImageRubberBtn"],
5 FCKPlugins.Items['remoteimagerubber'].Path + 'remoteimagerubber.ASPx',
6 350,
7 200 )
8 ) ;
9 var oBtn=new FCKToolbarButton('RemoteImageRubber',null,FCKLang["RemoteImageRubber"],null,false,true,48);
10 FCKToolbarItems.RegisterItem('RemoteImageRubber',oBtn);
11
E:\IISROOT\FckTest\FckTest\fckeditor\editor\lang\zh-cn.JS(其他語言同樣)
1 var FCKLang =
2 {
3 //
4 RemoteImageRubberBtn: "保存遠程圖片"
5 };
配置一下fckconfig.JS
1FCKConfig.ToolbarSets["Default"] = [
2 ['Source','DocProps','-','Save','NewPage','PrevIEw','-','Templates'],
3 ['Cut','Copy','Paste','PasteText','PasteWord','-','Print','SpellCheck'],
4 ['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],
5 ['Form','Checkbox','Radio','TextField','Textarea','Select','Button','ImageButton','HiddenFIEld'],
6 '/',
7 ['Bold','Italic','Underline','StrikeThrough','-','Subscript','Superscript'],
8 ['OrderedList','UnorderedList','-','Outdent','Indent'],
9 ['JustifyLeft','JustifyCenter','JustifyRight','JustifyFull'],
10 ['Link','Unlink','Anchor'],
11 ['Image','Flash','Table','Rule','Smiley','SpecialChar','PageBreak'],
12 '/',
13 ['Style','FontFormat','FontName','FontSize'],
14 ['TextColor','BGColor'],
15 ['FitWindow','-','InsertCode','RemoteImageRubber','-','About']
16] ;