最近客戶突然讓整理所有施工站點的完工照片,他們需要留檔,所以不想通過平台直接查看,想把所有完工照片,按照操作步驟把圖片放在word文檔中。一個市一千多個站點要用人工去做,那一個人也得一個月。所以就寫了一個簡單的程序,動態生成word的方式。信息化統計肯定比人效率高。
我選擇了NPOI插件做的,因為也就是一次性,我就直接用控制台簡單的實現了一下。不多說直接上代碼:
這次的邏輯是記錄鄭州市各個區域的站點。所以要分區域見文件夾,各個站點的word文檔就放在各個區域的文件夾下。
using NPOI.OpenXmlFormats.Wordprocessing; using NPOI.Util; using NPOI.XWPF.UserModel; using System; using System.Data; using System.Drawing; using System.IO; using System.Net; using System.Threading.Tasks; namespace WordExportDemo { internal class Program { private static void Main(string[] args) { DataTable dtlist = SqlHelper.Query(" SELECT PTId,PId,TaskName,TaskLable,TaskTemplateId ,JZ_Id ,JZ_Type,(select AreaName from Sys_Area where AreaCode=JZ_AREAID) AreaName FROM Project_Task where TaskType=2 and PId=8 and JZ_Type!=3 and State>0 and JZ_CityID=410100"); foreach (DataRow item in dtlist.Rows) { string areaname = item["AreaName"].ToString().Trim();//城市名稱 string taskName = item["TaskName"].ToString().Trim();//任務名稱,或者城市名稱 int Temple = int.Parse(item["PTId"].ToString());//任務模板id string path = System.AppDomain.CurrentDomain.BaseDirectory + "鄭州市\\" + areaname;//拼接路徑 CreatePath(path);//判斷路徑是否存在,不存在先建路徑 path = path + "\\" + taskName + ".docx";//給word文檔命名 XWPFDocument doc = new XWPFDocument();//創建一個word文檔 // 添加段落 XWPFParagraph gp = doc.CreateParagraph(); gp.Alignment = ParagraphAlignment.CENTER;//水平居中 XWPFRun gr = gp.CreateRun(); gp = doc.CreateParagraph(); gr = gp.CreateRun(); gr.GetCTR().AddNewRPr().AddNewRFonts().ascii = "黑體"; gr.GetCTR().AddNewRPr().AddNewRFonts().eastAsia = "黑體"; gr.GetCTR().AddNewRPr().AddNewRFonts().hint = ST_Hint.eastAsia; gr.GetCTR().AddNewRPr().AddNewSz().val = (ulong)42;//2號字體 gr.GetCTR().AddNewRPr().AddNewSzCs().val = (ulong)42; gr.GetCTR().AddNewRPr().AddNewB().val = true; //加粗 gr.GetCTR().AddNewRPr().AddNewColor().val = "red";//字體顏色 gr.SetText("站點名稱:" + taskName); DataTable dttemple = SqlHelper.Query("SELECT Id,Description ,AddTime ,TempStepId,(select Description from Project_TemplateStep where Id=TempStepId) StepDescription ,OrderNum FROM Project_TaskStep where PTId=" + Temple + " order by OrderNum asc"); foreach (DataRow item1 in dttemple.Rows) { int tempid = int.Parse(item1["Id"].ToString());//步驟Id string TempName = item1["StepDescription"].ToString();//步驟名稱 int step = int.Parse(item1["OrderNum"].ToString());//步驟數 string stepDescrip = item1["Description"].ToString();//步驟描述 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //添加任務步驟描述 gp = doc.CreateParagraph(); gr = gp.CreateRun(); CT_RPr rpr = gr.GetCTR().AddNewRPr(); CT_Fonts rfonts = rpr.AddNewRFonts(); rfonts.ascii = "宋體"; rfonts.eastAsia = "宋體"; rpr.AddNewSz().val = (ulong)21;//5號字體 rpr.AddNewSzCs().val = (ulong)21; gr.SetText("步驟" + step + ":" + TempName + " 描述:" + stepDescrip); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// DataTable dtimg = SqlHelper.Query("SELECT TableName,Path,AddTime FROM Project_TaskFile where TableName='Project_TaskStep' and TableKey=" + tempid + " order by AddTime asc"); gp = doc.CreateParagraph(); gr = gp.CreateRun(); foreach (DataRow item3 in dtimg.Rows) { string s = "ip" + item3["Path"].ToString(); try { HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://ip" + item3["Path"].ToString()); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Stream imgstream = response.GetResponseStream();//獲取圖片的流 Image image = Image.FromStream(imgstream);//將流轉化成Image,這樣做是為了得到原圖的寬(image.Width)和高(image.Height),放在word中可以通過寬和高等比縮放,這樣就可以保證圖片不變形。 gr.AddPicture(ImgToStream(image), (int)PictureType.PNG, "1.png", image.Width * 800, image.Height * 800);//ImgToTream(image) } catch (Exception e) { Console.WriteLine("---------------------------------------------------------------------------------------------------"); Console.WriteLine("區域:" + areaname + "--任務名稱:" + taskName + "--" + "步驟" + tempid + "--這個圖片路徑有異常:URL=" + s); Console.WriteLine("---------------------------------------------------------------------------------------------------"); } } } using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write)) { doc.Write(fs); Console.WriteLine("生成word成功"); } } Console.ReadKey(); } } }
下面是遠程下載圖片並且將圖片插入word中,
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://ip" + item3["Path"].ToString()); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Stream imgstream = response.GetResponseStream();//獲取圖片的流 Image image = Image.FromStream(imgstream); gr.AddPicture(ImgToStream(image), (int)PictureType.PNG, "1.png", image.Width * 800, image.Height * 800);
AddPicture這個是NPOI里面的程序集,他提供了傳入圖片的方式是一個Stream流: pictureData:表示傳入一個圖片的流。 pictureType:表示圖片的類型:png,jpeg..... filename:圖片的名字.width:圖片的寬。height:圖片的高。
或許有人會問,既然傳入的是一個流,為什么還有用Imag轉化成流在傳入,遠程下載的時候就是一個流,直接傳入不就行了。我一開始也是這樣做的。但是我必須要先轉換成Image,不然我無法得到原圖的寬和高。有人或許還會問,那轉成Image也不影響把流傳入進去。我試過了,這個流一旦轉換成Image之后,這個流的長度就是0,如果作為參數傳入AddPicture方法會報異常。我也試了先把流轉換成字節存起來,然后利用字節轉換成Image和Stream流,但是也失敗了,所有我最后選擇先用Stream流轉換成Image得到寬和高后再把Image轉換為字節,通過字節在轉換成流,結果成功了。
判斷路徑是否存在的方法
/// <summary> /// 創建目錄,如果目錄不存在就創建,存在則直接返回。 /// </summary> /// <param name="path"></param> public static string CreatePath(string strPath) { if (!System.IO.Directory.Exists(strPath)) System.IO.Directory.CreateDirectory(strPath); return strPath; }
圖片轉換成字節流
/// <summary> /// 圖片轉換成字節流 /// </summary> /// <param name="img">要轉換的Image對象</param> /// <returns>轉換后返回的字節流</returns> public static Stream ImgToStream(Image img) { byte[] imgByte = ImgToByt(img); //img.Save(ms, img.RawFormat);//System.Drawing.Imaging.ImageFormat.Jpeg Stream stream = new MemoryStream(imgByte); return stream; } /// <summary> /// 圖片轉換成字節流 /// </summary> /// <param name="img">要轉換的Image對象</param> /// <returns>轉換后返回的字節流</returns> public static byte[] ImgToByt(Image img) { MemoryStream ms = new MemoryStream(); byte[] imagedata = null; img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); imagedata = ms.GetBuffer(); return imagedata; }
運行后結果: