基于C#實現(xiàn)Word加蓋的騎縫章效果
實現(xiàn)效果
在OA的自動化處理系統(tǒng)中,通過審批的最終節(jié)點,可能會對WORD文件加蓋電子章,比如定位帶有指定文字的Range周圍加蓋電子章,騎縫章,甚至水印圖片。比如如下效果圖:
范例運(yùn)行環(huán)境
操作系統(tǒng): Windows Server 2019 DataCenter
操作系統(tǒng)上安裝 Office Word 2016 ,客戶端使用的 Office Word 2019
.net版本: .netFramework4.7.1 或以上
開發(fā)工具:VS2019 C#
Office DCOM 配置
請參考我的文章《C# 讀取Word表格到DataSet》有對Office DCOM詳細(xì)配置介紹,這里不再贅述。
設(shè)計實現(xiàn)
創(chuàng)建stamp圖章類
導(dǎo)出WORD文件可以傳入多個圖章類(如果需要的話),圖章類主要包括實現(xiàn)如下設(shè)置:
1、可設(shè)置三種圖片(標(biāo)準(zhǔn)的蓋章圖片、騎縫章圖片、水印圖片)
2、標(biāo)準(zhǔn)的蓋章圖片是否顯示,不顯示則可以只顯示騎縫章或水印圖片,這個可以模擬多次蓋騎縫章的效果
3、定位蓋章文字,可以設(shè)置一下 x、y的偏移量,以校準(zhǔn)指定的模板文件,達(dá)到最佳重疊效果。
4、可設(shè)置各種章的翻轉(zhuǎn)角度(可隨機(jī)選?。?/p>
示例代碼如下:
public class stamp { public string stampImageFilename = ""; //蓋章圖片 public string stampImageFilename2 = ""; //騎縫章圖片 public string stampImageFilename3 = ""; //水印章圖片 public bool stampImageVisible = true; //主章是否可顯示 public string findWord = ""; //查找蓋章定位文字 public int findWordOffsetX = 0; //查找蓋章文字后,章的定位偏移量 public int findWordOffsetY = 0; //查找蓋章文字后,章的定位偏移量 public int stamp2X = 0; //騎縫章偏移量 public int stamp2Y = 0; //騎縫章偏移量 public int roteAngle = 0; //騎縫章翻轉(zhuǎn)角度,12點方向為0度,順時針計算角度 public bool roteReFix = false; //騎縫章翻轉(zhuǎn)角度重新計算適應(yīng)圖片(多見于對角線) public bool randomRoteAngle = false; //騎縫章是否按指定角度的最大隨機(jī)值提取 public int stampImageWidth = 0; //章寬度 public int stampImageHeight = 0; //章高度 public string stamp2Direction = "right"; //騎縫章蓋章方向 默認(rèn)right ,包括 left/top/bottom public int stampAngle = 0; //騎縫章翻轉(zhuǎn)角度,12點方向為0度,順時針計算角度 public bool randomStampAngle = false; //騎縫章是否按指定角度的最大隨機(jī)值提取 public int stamp3X = 0; //水印章每頁X public int stamp3Y = 0; //水印章每頁Y public int stamp3Angle = 0; //水印章翻轉(zhuǎn)角度,12點方向為0度,順時針計算角度 }
電子章圖片的計算與定位
可以創(chuàng)建多個圖章類添加 ArrayList 中進(jìn)行方法傳遞, 初始值為public ArrayList Stamps = null;
創(chuàng)建方法 public string setWordStamps(string _filename,ArrayList Stamps)
實現(xiàn)的功能大致如下:
1、主章根據(jù)提供查找的關(guān)鍵字,如 “蓋章處:”、“蓋章:”,然后添加圖片重疊在文字的上方周圍
2、騎縫章根據(jù)頁數(shù)進(jìn)行分割計算,每頁分隔寬度不小于 1 像素
3、騎縫章可選擇“蓋”在頁面的上下左右位置,如果多個位置方向都需要“蓋”,則傳遞多個 stamp 圖章類
4、章可以隨機(jī)和指定旋轉(zhuǎn)角度
示例代碼如下:
public string setWordStamps(string _filename,ArrayList Stamps){ Object Nothing =System.Reflection.Missing.Value; string _file="",_path=Path.GetDirectoryName(_filename)+"\\tempbfile\\",_ext=""; _file=Path.GetFileNameWithoutExtension(_filename); _ext=Path.GetExtension(_filename); string _validfilename=Guid.NewGuid().ToString()+_ext; string _lastfile=_path+_validfilename; string _pdfFile = _path + Guid.NewGuid().ToString() + ".pdf"; System.IO.File.Copy(_filename,_lastfile,true); if(!File.Exists(_lastfile)) { return ""; } //取得Word文件保存路徑 object filename=_lastfile; //創(chuàng)建一個名為WordApp的組件對象 Word.Application WordApp=new Word.Application(); //創(chuàng)建一個名為WordDoc的文檔對象 WordApp.DisplayAlerts=Word.WdAlertLevel.wdAlertsNone; Word.Document WordDoc=WordApp.Documents.Open(ref filename,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing); WordDoc.SpellingChecked = false; WordDoc.ShowSpellingErrors = false; WordDoc.ActiveWindow.View.Type = Word.WdViewType.wdNormalView; //遍歷stamp圖章類 foreach (stamp Stamp in Stamps) { bool isfirst = true; int iii = 0; int selectStart = 0; ArrayList restoreRange = new ArrayList(); while (true) { iii++; bool findstamptext = false; if (Stamp.findWord != "") { WordApp.Selection.Range.Start = selectStart; Word.Find fnd = WordApp.Selection.Find; Object findText = Stamp.findWord; Object matchCase = false; Object matchWholeWord = Type.Missing; Object matchWildcards = false; Object matchSoundsLike = false; Object matchAllWordForms = false; Object forward = true; Object wrap = Word.WdFindWrap.wdFindContinue; Object format = false; Object replaceWith = ""; Object replace = Type.Missing; ; Object matchKashida = Type.Missing; Object matchDiacritics = Type.Missing; Object matchAlefHamza = Type.Missing; Object matchControl = Type.Missing; if (fnd.Execute(ref findText, ref matchCase, ref matchWholeWord, ref matchWildcards, ref matchSoundsLike, ref matchAllWordForms, ref forward, ref wrap, ref format, ref replaceWith, ref replace, ref matchKashida, ref matchDiacritics, ref matchAlefHamza, ref matchControl)) { selectStart = WordApp.Selection.Range.Start; restoreRange.Add(WordApp.Selection.Range); findstamptext = true; } else { findstamptext = false; } } if (findstamptext == false) { break; } Word.InlineShape pic = WordApp.Selection.Range.InlineShapes.AddPicture(Stamp.stampImageFilename, false, true); Word.Shape picshape = pic.ConvertToShape(); picshape.WrapFormat.Type = Word.WdWrapType.wdWrapNone; if (Stamp.stampImageWidth != 0) { picshape.Width = Stamp.stampImageWidth; } if (Stamp.stampImageHeight != 0) { picshape.Height = Stamp.stampImageHeight; } float pagewidth = 0; float pageheight = 0; if (findstamptext == true) { if (Stamp.stampAngle > 0) { Random rnd = new Random(); picshape.Rotation = Stamp.randomStampAngle == false ? Stamp.stampAngle : rnd.Next(Stamp.stampAngle); } pagewidth = WordApp.Selection.PageSetup.PageWidth; pageheight = WordApp.Selection.PageSetup.PageHeight; int ox = 0; int oy = 0; int ow = 0; int oh = 0; WordApp.Windows[1].GetPoint(out ox, out oy, out ow, out oh, WordApp.Selection.Range); WordApp.Selection.Range.Text = ""; picshape.RelativeHorizontalPosition = Word.WdRelativeHorizontalPosition.wdRelativeHorizontalPositionPage; picshape.RelativeVerticalPosition = Word.WdRelativeVerticalPosition.wdRelativeVerticalPositionPage; picshape.Left = (float)(ox * 0.405402299) - (picshape.Width / 2); picshape.Top = WordApp.Selection.Range.Information[Word.WdInformation.wdVerticalPositionRelativeToPage] - (picshape.Height / 2); if ((bool)WordApp.Selection.Range.Information[Word.WdInformation.wdWithInTable] == true) { picshape.RelativeHorizontalPosition = Word.WdRelativeHorizontalPosition.wdRelativeHorizontalPositionCharacter; picshape.RelativeVerticalPosition = Word.WdRelativeVerticalPosition.wdRelativeVerticalPositionLine; picshape.Left = 0; picshape.Top = 0; } } picshape.Left = picshape.Left + Stamp.findWordOffsetX; picshape.Top = picshape.Top + Stamp.findWordOffsetY; if (Stamp.stampImageVisible == false) { picshape.Visible = Microsoft.Office.Core.MsoTriState.msoFalse; } if (Stamp.stampImageFilename2 != ""&&isfirst==true) { int ra = Stamp.roteAngle; if (ra > 0) { Random rnd = new Random(); ra = Stamp.randomRoteAngle == false ? ra : rnd.Next(ra); } Bitmap cc = (Bitmap)Image.FromFile(Stamp.stampImageFilename2); Bitmap bb = Rotate(cc, -ra, Stamp.roteReFix); WordDoc.Windows[1].Panes[1].Pages; int pages2 = WordDoc.ComputeStatistics(Word.WdStatistic.wdStatisticPages, ref Nothing); if (pages2 == 1) { pages2 = 0; //如果一頁就不蓋騎縫章 } for (int pi = 1; pi <= pages2; pi++) { Word.Range pagerange = WordDoc.GoTo(Word.WdGoToItem.wdGoToPage, Word.WdGoToDirection.wdGoToAbsolute, pi.ToString()); int rx = (pi - 1) * bb.Width / pages2; int ry = 0; int rw = bb.Width / pages2; int rh = bb.Height; if (Stamp.stamp2Direction == "bottom") { rx = 0; ry = (pi - 1) * bb.Height / pages2; rw = bb.Width; rh = bb.Height / pages2; } else if (Stamp.stamp2Direction == "left") { rx = (pages2 - pi) * bb.Width / pages2; ry = 0; rw = bb.Width / pages2; rh = bb.Height; } else if (Stamp.stamp2Direction == "top") { rx = 0; ry = (pages2 - pi) * bb.Height / pages2; rw = bb.Width; rh = bb.Height / pages2; } if (rw < 1 || rh < 1) { continue; } Bitmap sepbitmap1 = bb.Clone(new System.Drawing.Rectangle(rx, ry, rw, rh), System.Drawing.Imaging.PixelFormat.Format32bppPArgb); string temppng = "d:\\" + System.Guid.NewGuid().ToString() + ".png"; sepbitmap1.Save(temppng); Word.InlineShape pic2 = pagerange.InlineShapes.AddPicture(temppng, false, true); Word.Shape picshape2 = pic2.ConvertToShape(); picshape2.WrapFormat.Type = Word.WdWrapType.wdWrapNone; picshape2.Width = picshape.Width / pages2; picshape2.Height = picshape.Height; if (Stamp.stamp2Direction == "bottom" || Stamp.stamp2Direction == "top") { picshape2.Width = picshape.Width; picshape2.Height = picshape.Height / pages2; } picshape2.RelativeHorizontalPosition = Word.WdRelativeHorizontalPosition.wdRelativeHorizontalPositionPage; picshape2.RelativeVerticalPosition = Word.WdRelativeVerticalPosition.wdRelativeVerticalPositionPage; picshape2.Left = pagewidth - picshape2.Width; picshape2.Top = Stamp.stamp2Y; if (Stamp.stamp2Direction == "bottom") { picshape2.Left = Stamp.stamp2X; picshape2.Top = pageheight - picshape2.Height; } else if (Stamp.stamp2Direction == "left") { picshape2.Left = 0; picshape2.Top = Stamp.stamp2Y; } else if (Stamp.stamp2Direction == "top") { picshape2.Left = Stamp.stamp2X; picshape2.Top = 0; } resultReport += string.Format("stamp2 {2} left: {0} top:{1} width:{3} height:{4}<br>", picshape2.Left, picshape2.Top,pi,picshape2.Width,picshape2.Height); File.Delete(temppng); } }//stamp2 if (Stamp.stampImageFilename3 != ""&&isfirst==true) { int ra = Stamp.stamp3Angle; if (ra > 0) { Random rnd = new Random(); ra = Stamp.randomRoteAngle == false ? ra : rnd.Next(ra); } Bitmap cc = (Bitmap)Image.FromFile(Stamp.stampImageFilename3); Bitmap bb = Rotate(cc, -ra, true); int pages2 = WordDoc.ComputeStatistics(Word.WdStatistic.wdStatisticPages, ref Nothing); resultReport += string.Format(" PageCount3:{0}<br>", pages2); for (int pi = 1; pi <= pages2; pi++) { Word.Range pagerange = WordDoc.GoTo(Word.WdGoToItem.wdGoToPage, Word.WdGoToDirection.wdGoToAbsolute, pi.ToString()); int rx = (pi - 1) * bb.Width / pages2; rx = 0; int ry = 0; int rw = bb.Width; int rh = bb.Height; Bitmap sepbitmap1 = bb.Clone(new System.Drawing.Rectangle(rx, ry, rw, rh), System.Drawing.Imaging.PixelFormat.Format32bppPArgb); string temppng = "d:\\" + System.Guid.NewGuid().ToString() + ".png"; Word.InlineShape pic2 = pagerange.InlineShapes.AddPicture(temppng, false, true); Word.Shape picshape2 = pic2.ConvertToShape(); picshape2.WrapFormat.Type = Word.WdWrapType.wdWrapNone; picshape2.Width = picshape.Width; picshape2.Height = picshape.Height; picshape2.RelativeHorizontalPosition = Word.WdRelativeHorizontalPosition.wdRelativeHorizontalPositionPage; picshape2.RelativeVerticalPosition = Word.WdRelativeVerticalPosition.wdRelativeVerticalPositionPage; picshape2.Left = Stamp.stamp3X; // picshape2.Left = Stamp.stamp2X; picshape2.Top = Stamp.stamp2Y; File.Delete(temppng); } }//stamp3 isfirst = false; }// while foreach (Word.Range range in restoreRange) { range.Text = Stamp.findWord; } }//foreach WordDoc.Save(); WordDoc.Close(ref Nothing, ref Nothing, ref Nothing); //關(guān)閉WordApp組件對象 WordApp.Quit(ref Nothing, ref Nothing, ref Nothing); return _lastfile; }
旋轉(zhuǎn)圖片方法
public Bitmap Rotate(Bitmap b, int angle,bool fix=false) { angle = angle % 360; //弧度轉(zhuǎn)換 double radian = angle * Math.PI / 180.0; double cos = Math.Cos(radian); double sin = Math.Sin(radian); //原圖的寬和高 int w = b.Width; int h = b.Height; int ow = w; int oh = h; int d = ((int)Math.Sqrt(Math.Pow(w - 0, 2) + Math.Pow(h- 0, 2))+1); if (fix == true) { w = d; h = d; } int W = (int)(Math.Max(Math.Abs(w * cos - h * sin), Math.Abs(w * cos + h * sin))); int H = (int)(Math.Max(Math.Abs(w * sin - h * cos), Math.Abs(w * sin + h * cos))); //目標(biāo)位圖 Bitmap dsImage = new Bitmap(w, h); System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(dsImage); g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; //計算偏移量 System.Drawing.Point Offset = new System.Drawing.Point((W - w) / 2, (H - h) / 2); //構(gòu)造圖像顯示區(qū)域:讓圖像的中心與窗口的中心點一致 System.Drawing.Rectangle rect = new System.Drawing.Rectangle(fix==false?0:(d-ow)/2, fix == false ? 0 : (d-oh)/2, ow, oh); // System.Drawing.Rectangle rect = new System.Drawing.Rectangle(Offset.X, Offset.Y, w, h); // System.Drawing.Point center = new System.Drawing.Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2); System.Drawing.Point center = new System.Drawing.Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2); g.TranslateTransform(center.X, center.Y); g.RotateTransform(360 - angle); //恢復(fù)圖像在水平和垂直方向的平移 g.TranslateTransform(-center.X, -center.Y); g.DrawImage(b, rect); //重至繪圖的所有變換 g.ResetTransform(); g.Save(); g.Dispose(); //dsImage.Save("yuancd.jpg", System.Drawing.Imaging.ImageFormat.Jpeg); return dsImage; }
總結(jié)
以上是實現(xiàn)設(shè)計的一些參考代碼,在實際的使用中,可能還會遇到如下問題:
1、定位關(guān)鍵字的疊加效果不好,因此針對每一個模板文件均需要調(diào)整圖片的x、y偏移量,以達(dá)到最佳效果
2、對于超多頁面的文件(如幾萬頁),騎縫的效果可能不佳,可以采取調(diào)整圖片像素寬度,或拆分模板文件進(jìn)行處理
到此這篇關(guān)于基于C#實現(xiàn)Word加蓋的騎縫章效果的文章就介紹到這了,更多相關(guān)C# Word騎縫章效果內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C# 串口掃描槍讀取數(shù)據(jù)的實現(xiàn)
本文主要介紹了C# 串口掃描槍讀取數(shù)據(jù)的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-04-04c# volatile 關(guān)鍵字的拾遺補(bǔ)漏
這篇文章主要介紹了c# volatile 關(guān)鍵字的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)c#的相關(guān)知識,感興趣的朋友可以了解下2020-10-10