1 /// <summary> 2 /// OpenXml扩展方法 3 /// </summary> 4 public static class OpenXmlExtension 5 { 6 /// <summary> 7 /// 获取word文档的书签 8 /// </summary> 9 /// <param name="wordDoc"></param> 10 /// <returns></returns> 11 public static List<BookmarkStart> GetBookmarkStart(this WordprocessingDocument wordDoc) 12 { 13 return wordDoc?.MainDocumentPart?.Document?.Descendants<BookmarkStart>()?.ToList()??new List<BookmarkStart>(); 14 } 15 /// <summary> 16 /// 替换书签为Text 17 /// </summary> 18 /// <param name="wordDoc"></param> 19 /// <param name="bookmarkStart"></param> 20 /// <param name="text"></param> 21 public static void ReplaceBookmarkToText(this WordprocessingDocument wordDoc, BookmarkStart bookmarkStart, string text) 22 { 23 //经研究发现,字体底层都是在Text前面设置 24 var oldRun = wordDoc.GetBookMarkStartNextRun(bookmarkStart); 25 wordDoc.RemoveBookmarkContent(bookmarkStart);//先移除里面的内容 26 Text str = new Text(text); 27 Run run = new Run(str); 28 if (oldRun != null) 29 { 30 run.RunProperties = (RunProperties)(oldRun.RunProperties?.CloneNode(true) ?? new RunProperties()); 31 } 32 var p = bookmarkStart.Parent; 33 p?.ReplaceChild(run, bookmarkStart); 34 run.NextSibling()?.Remove();//移除bookmarkEnd标签 35 } 36 /// <summary> 37 /// 获取书签里的第一个Run 38 /// </summary> 39 /// <param name="wordDoc"></param> 40 /// <param name="bookmarkStart"></param> 41 /// <returns></returns> 42 public static Run GetBookMarkStartNextRun(this WordprocessingDocument wordDoc,BookmarkStart bookmarkStart) 43 { 44 if (bookmarkStart == null) 45 { 46 return null; 47 } 48 Run run = null; 49 BookmarkEnd end = wordDoc.MainDocumentPart.Document.Descendants<BookmarkEnd>().Where(t => t.Id == bookmarkStart.Id).FirstOrDefault(); 50 if (end != null) 51 { 52 OpenXmlElement next = null; 53 while (true) 54 { 55 if (next == null) 56 { 57 next = bookmarkStart.NextSibling(); 58 } 59 else 60 { 61 next = next.NextSibling(); 62 } 63 64 if ((next) is BookmarkEnd && (BookmarkEnd)(next) == end) 65 { 66 break; 67 } 68 run = next as Run; 69 if (run != null) 70 { 71 break; 72 } 73 } 74 } 75 return run; 76 } 77 public static void RemoveBookmarkContent(this WordprocessingDocument wordDoc,BookmarkStart bookmarkStart) 78 { 79 BookmarkEnd end = wordDoc.MainDocumentPart.Document.Descendants<BookmarkEnd>().Where(t=>t.Id==bookmarkStart.Id).FirstOrDefault(); 80 if(end != null) 81 { 82 while (true) 83 { 84 var run = bookmarkStart.NextSibling(); 85 if (run == null) {break; } 86 if(run is BookmarkEnd && (BookmarkEnd)run == end) 87 { 88 break; 89 } 90 run.Remove(); 91 } 92 } 93 } 94 /// <summary> 95 /// 替换书签为图片 96 /// </summary> 97 /// <param name="wordDoc"></param> 98 /// <param name="bookmarkStart"></param> 99 /// <param name="imgPath">图片绝对路径</param> 100 public static void ReplaceBookmarkToImage(this WordprocessingDocument wordDoc, BookmarkStart bookmarkStart, string imgPath) 101 { 102 var mainPart = wordDoc.MainDocumentPart; 103 if(mainPart==null) 104 { 105 return; 106 } 107 ImagePart imagePart = mainPart.AddImagePart(imgPath.GetImagePartType()); 108 using (FileStream stream = new FileStream(imgPath, FileMode.Open)) 109 { 110 imagePart.FeedData(stream); 111 } 112 var relationshipId = mainPart.GetIdOfPart(imagePart); 113 var tuple = GetImageEmus(imgPath); 114 // Define the reference of the image. 115 var element = 116 new Drawing( 117 new DW.Inline( 118 new DW.Extent() 119 { 120 Cx = tuple.Item1, 121 Cy = tuple.Item2 122 }, 123 new DW.EffectExtent() 124 { 125 LeftEdge = 0L, 126 TopEdge = 0L, 127 RightEdge = 0L, 128 BottomEdge = 0L 129 }, 130 new DW.DocProperties() 131 { 132 Id = (UInt32Value)1U, 133 Name = "Picture 1" 134 }, 135 new DW.NonVisualGraphicFrameDrawingProperties( 136 new A.GraphicFrameLocks() { NoChangeAspect = true }), 137 new A.Graphic( 138 new A.GraphicData( 139 new PIC.Picture( 140 new PIC.NonVisualPictureProperties( 141 new PIC.NonVisualDrawingProperties() 142 { 143 Id = (UInt32Value)0U, 144 Name = $"New Bitmap Image.{System.IO.Path.GetExtension(imgPath)}" 145 }, 146 new PIC.NonVisualPictureDrawingProperties()), 147 new PIC.BlipFill( 148 new A.Blip( 149 new A.BlipExtensionList( 150 new A.BlipExtension() 151 { 152 Uri = 153 "{28A0092B-C50C-407E-A947-70E740481C1C}" 154 }) 155 ) 156 { 157 Embed = relationshipId, 158 CompressionState = 159 A.BlipCompressionValues.Print 160 } 161 , 162 new A.Stretch( 163 new A.FillRectangle()) 164 ) 165 , 166 new PIC.ShapeProperties( 167 new A.Transform2D( 168 new A.Offset() { X = 0L, Y = 0L }, 169 new A.Extents() { Cx = tuple.Item1, Cy = tuple.Item2 }), 170 new A.PresetGeometry( 171 new A.AdjustValueList() 172 ) 173 { Preset = A.ShapeTypeValues.Rectangle }) 174 ) 175 ) 176 { 177 Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" 178 }) 179 ) 180 { 181 DistanceFromTop = (UInt32Value)0U, 182 DistanceFromBottom = (UInt32Value)0U, 183 DistanceFromLeft = (UInt32Value)0U, 184 DistanceFromRight = (UInt32Value)0U, 185 EditId = "50D07946" 186 });; 187 188 if (wordDoc.MainDocumentPart is null || wordDoc.MainDocumentPart.Document.Body is null) 189 { 190 throw new ArgumentNullException("MainDocumentPart and/or Body is null."); 191 } 192 var run = new Run(element); 193 bookmarkStart?.Parent?.ReplaceChild(run, bookmarkStart); 194 run.NextSibling()?.Remove(); 195 } 196 /// <summary> 197 /// 根据文件路径 获取ImagePartType 198 /// </summary> 199 /// <param name="imgPath"></param> 200 /// <returns></returns> 201 public static PartTypeInfo GetImagePartType(this string imgPath) 202 { 203 var temp = new PartTypeInfo(); 204 switch (System.IO.Path.GetExtension(imgPath).ToLower()) 205 { 206 case "png":temp = ImagePartType.Png; 207 break; 208 case "jpeg":temp= ImagePartType.Jpeg; 209 break; 210 case "bmp":temp = ImagePartType.Bmp; 211 break; 212 case "gif":temp = ImagePartType.Gif; 213 break; 214 default: temp = ImagePartType.Png; 215 break; 216 } 217 return temp; 218 } 219 /// <summary> 220 /// 获取图片的Emus 221 /// </summary> 222 /// <param name="imgPath"></param> 223 /// <returns></returns> 224 public static Tuple<long,long> GetImageEmus(string imgPath) 225 { 226 long iWidth = 0; 227 long iHeight = 0; 228 229 using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(imgPath)) 230 { 231 iWidth = bmp.Width; 232 iHeight = bmp.Height; 233 } 234 iWidth = (long)Math.Round((decimal)iWidth * 9525); 235 iHeight = (long)Math.Round((decimal)iHeight * 9525); 236 double maxWidthCm = 17.4; // Our current margins gives us 17.4cm of space 237 const int emusPerCm = 360000; 238 long maxWidthEmus = (long)(maxWidthCm * emusPerCm); 239 if (iWidth > maxWidthEmus) 240 { 241 var ratio = (iHeight * 1.0m) / iWidth; 242 iWidth = maxWidthEmus; 243 iHeight = (long)(iWidth * ratio); 244 } 245 return Tuple.Create(iWidth, iHeight); 246 } 247 /// <summary> 248 /// 增加水印 249 /// </summary> 250 /// <param name="doc"></param> 251 /// <param name="watermarkText">水印文本</param> 252 public static void AddWatermark(this WordprocessingDocument doc, string watermarkText) 253 { 254 var watermarkFileName = GenerateWaterMarkImage(watermarkText); 255 if (doc.MainDocumentPart.HeaderParts.Count() == 0) 256 { 257 doc.MainDocumentPart.DeleteParts(doc.MainDocumentPart.HeaderParts); 258 var newHeaderPart = doc.MainDocumentPart.AddNewPart<HeaderPart>(); 259 var rId = doc.MainDocumentPart.GetIdOfPart(newHeaderPart); 260 var headerRef = new HeaderReference(); 261 headerRef.Id = rId; 262 var sectionProps = doc.MainDocumentPart.Document.Body.Elements<SectionProperties>().LastOrDefault(); 263 if (sectionProps == null) 264 { 265 sectionProps = new SectionProperties(); 266 doc.MainDocumentPart.Document.Body.Append(sectionProps); 267 } 268 sectionProps.RemoveAllChildren<HeaderReference>(); 269 sectionProps.Append(headerRef); 270 271 newHeaderPart.Header = MakeHeader(); 272 newHeaderPart.Header.Save(); 273 } 274 275 foreach (HeaderPart headerPart in doc.MainDocumentPart.HeaderParts) 276 { 277 var sdtBlock1 = new SdtBlock(); 278 var sdtProperties1 = new SdtProperties(); 279 var sdtId1 = new SdtId() { Val = 87908844 }; 280 var sdtContentDocPartObject1 = new SdtContentDocPartObject(); 281 var docPartGallery1 = new DocPartGallery() { Val = "Watermarks" }; 282 var docPartUnique1 = new DocPartUnique(); 283 sdtContentDocPartObject1.Append(docPartGallery1); 284 sdtContentDocPartObject1.Append(docPartUnique1); 285 sdtProperties1.Append(sdtId1); 286 sdtProperties1.Append(sdtContentDocPartObject1); 287 288 ImagePart imgPart = headerPart.AddImagePart(ImagePartType.Jpeg); 289 using (var fileStream = new FileStream(watermarkFileName, FileMode.Open, FileAccess.Read)) 290 { 291 imgPart.FeedData(fileStream); 292 fileStream.Close(); 293 fileStream.Dispose(); 294 } 295 string imgId = headerPart.GetIdOfPart(imgPart); 296 297 var sdtContentBlock1 = new SdtContentBlock(); 298 var paragraph2 = new Paragraph() 299 { 300 RsidParagraphAddition = "00656E18", 301 RsidRunAdditionDefault = "00656E18" 302 }; 303 var paragraphProperties2 = new ParagraphProperties(); 304 var paragraphStyleId2 = new ParagraphStyleId() { Val = "Header" }; 305 paragraphProperties2.Append(paragraphStyleId2); 306 var run1 = new Run(); 307 var runProperties1 = new RunProperties(); 308 var noProof1 = new NoProof(); 309 var languages1 = new Languages() { EastAsia = "zh-TW" }; 310 runProperties1.Append(noProof1); 311 runProperties1.Append(languages1); 312 var picture1 = new Picture(); 313 var shapetype1 = new Shapetype() 314 { 315 Id = "_x0000_t136", 316 CoordinateSize = "21600,21600", 317 OptionalNumber = 136, 318 Adjustment = "10800", 319 EdgePath = "m@7,l@8,m@5,21600l@6,21600e" 320 }; 321 var formulas1 = new Formulas(); 322 var formula1 = new Formula() { Equation = "sum #0 0 10800" }; 323 var formula2 = new Formula() { Equation = "prod #0 2 1" }; 324 var formula3 = new Formula() { Equation = "sum 21600 0 @1" }; 325 var formula4 = new Formula() { Equation = "sum 0 0 @2" }; 326 var formula5 = new Formula() { Equation = "sum 21600 0 @3" }; 327 var formula6 = new Formula() { Equation = "if @0 @3 0" }; 328 var formula7 = new Formula() { Equation = "if @0 21600 @1" }; 329 var formula8 = new Formula() { Equation = "if @0 0 @2" }; 330 var formula9 = new Formula() { Equation = "if @0 @4 21600" }; 331 var formula10 = new Formula() { Equation = "mid @5 @6" }; 332 var formula11 = new Formula() { Equation = "mid @8 @5" }; 333 var formula12 = new Formula() { Equation = "mid @7 @8" }; 334 var formula13 = new Formula() { Equation = "mid @6 @7" }; 335 var formula14 = new Formula() { Equation = "sum @6 0 @5" }; 336 337 formulas1.Append(formula1); 338 formulas1.Append(formula2); 339 formulas1.Append(formula3); 340 formulas1.Append(formula4); 341 formulas1.Append(formula5); 342 formulas1.Append(formula6); 343 formulas1.Append(formula7); 344 formulas1.Append(formula8); 345 formulas1.Append(formula9); 346 formulas1.Append(formula10); 347 formulas1.Append(formula11); 348 formulas1.Append(formula12); 349 formulas1.Append(formula13); 350 formulas1.Append(formula14); 351 var path1 = new DocumentFormat.OpenXml.Vml.Path() 352 { 353 AllowTextPath = TrueFalseValue.FromBoolean(true), 354 ConnectionPointType = ConnectValues.Custom, 355 ConnectionPoints = "@9,0;@10,10800;@11,21600;@12,10800", 356 ConnectAngles = "270,180,90,0" 357 }; 358 //var textPath1 = new TextPath() 359 //{ 360 // On = TrueFalseValue.FromBoolean(true), 361 // FitShape = TrueFalseValue.FromBoolean(true) 362 //}; 363 var shapeHandles1 = new ShapeHandles(); 364 365 var shapeHandle1 = new ShapeHandle() 366 { 367 Position = "#0,bottomRight", 368 XRange = "6629,14971" 369 }; 370 371 shapeHandles1.Append(shapeHandle1); 372 373 //var lock1 = new DocumentFormat.OpenXml.Vml.Office.Lock 374 //{ 375 // Extension = ExtensionHandlingBehaviorValues.Edit, 376 // TextLock = TrueFalseValue.FromBoolean(true), 377 // ShapeType = TrueFalseValue.FromBoolean(true) 378 //}; 379 380 shapetype1.Append(formulas1); 381 shapetype1.Append(path1); 382 shapetype1.Append(shapeHandles1); 383 for (var y = 0; y < 11; y++) 384 { 385 for (var x = 0; x < 6; x++) 386 { 387 var shape1 = new Shape() 388 { 389 Id = "WordPictureWatermark144925235", 390 Style = $"position:absolute;left:{(-200) + (x * 200)};top:{(-100) + (y * 100)};text-align:left;margin-left:0;margin-top:0;width:140pt;height:50pt;rotation:310;z-index:-251657216;mso-position-horizontal-relative:margin;mso-position-vertical-relative:margin",//mso-position-vertical:center;mso-position-horizontal:left; 391 OptionalString = "_x0000_s2050", 392 AllowInCell = TrueFalseValue.FromBoolean(false), 393 Type = "#_x0000_t75" 394 }; 395 396 var imgdata = new ImageData() 397 { 398 Title = "logo", 399 Gain = "19661f", 400 BlackLevel = "22938f", 401 RelId = imgId, 402 RelationshipId = imgId 403 }; 404 shape1.Append(imgdata); 405 if (y == 0 && x == 0) 406 { 407 picture1.Append(shapetype1); 408 } 409 picture1.Append(shape1); 410 } 411 412 } 413 414 415 416 417 418 run1.Append(runProperties1); 419 run1.Append(picture1); 420 paragraph2.Append(paragraphProperties2); 421 paragraph2.Append(run1); 422 sdtContentBlock1.Append(paragraph2); 423 sdtBlock1.Append(sdtProperties1); 424 sdtBlock1.Append(sdtContentBlock1); 425 headerPart.Header.Append(sdtBlock1); 426 headerPart.Header.Save(); 427 } 428 } 429 private static Header MakeHeader() 430 { 431 var header = new Header(); 432 var paragraph = new DocumentFormat.OpenXml.Wordprocessing.Paragraph(); 433 var run = new Run(); 434 var text = new Text(); 435 text.Text = ""; 436 run.Append(text); 437 paragraph.Append(run); 438 header.Append(paragraph); 439 return header; 440 } 441 /// <summary> 442 /// 生成水印图片 443 /// </summary> 444 private static string GenerateWaterMarkImage(string headerText) 445 { 446 string fileName = System.IO.Path.Combine("d:\\", string.Format("{0}_{1}.png", Guid.NewGuid().ToString(), headerText)); 447 int width = 200; 448 int height = 100; 449 using (Bitmap bitmap = new Bitmap(width, height)) 450 { 451 // 使用Graphics对象来绘制 452 using (Graphics graphics = Graphics.FromImage(bitmap)) 453 { 454 // 设置背景颜色 455 graphics.Clear(System.Drawing.Color.White); 456 457 // 创建字体 458 using (System.Drawing.Font font = new System.Drawing.Font("微软雅黑", 16)) 459 { 460 // 创建画刷 461 using (SolidBrush brush = new SolidBrush(System.Drawing.Color.Black)) 462 { 463 // 设置字符串格式 464 StringFormat stringFormat = new StringFormat(); 465 stringFormat.Alignment = StringAlignment.Center; 466 stringFormat.LineAlignment = StringAlignment.Center; 467 468 // 在图片上绘制文字 469 graphics.DrawString(headerText, font, brush, new System.Drawing.Rectangle(0, 0, width, height), stringFormat); 470 } 471 } 472 } 473 474 // 保存图片到文件 475 bitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Png); 476 } 477 return fileName; 478 } 479 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下