Skip to content

Commit 129de2b

Browse files
committed
featuer : support image
1 parent 3520cc1 commit 129de2b

5 files changed

Lines changed: 169 additions & 14 deletions

File tree

samples/docx/TestBasicImage.docx

12.9 KB
Binary file not shown.

src/MiniWord/Helpers.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace MiniSoftware
2+
{
3+
using System.IO;
4+
5+
internal static partial class Helpers
6+
{
7+
public static FileStream OpenSharedRead(string path) => File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
8+
}
9+
}

src/MiniWord/MiniWord.cs

Lines changed: 122 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,142 @@
11
namespace MiniSoftware
22
{
3-
using DocumentFormat.OpenXml;
4-
using DocumentFormat.OpenXml.Packaging;
5-
using DocumentFormat.OpenXml.Wordprocessing;
3+
using DocumentFormat.OpenXml;
4+
using DocumentFormat.OpenXml.Packaging;
5+
using DocumentFormat.OpenXml.Wordprocessing;
6+
using System;
67
using System.Collections.Generic;
78
using System.IO;
89
using System.Linq;
910
using System.Text.RegularExpressions;
11+
using A = DocumentFormat.OpenXml.Drawing;
12+
using DW = DocumentFormat.OpenXml.Drawing.Wordprocessing;
13+
using PIC = DocumentFormat.OpenXml.Drawing.Pictures;
1014

1115
public static class MiniWord
1216
{
1317
static void ReplaceTag(this OpenXmlElement xmlElement, WordprocessingDocument docx, Dictionary<string, object> tags)
1418
{
1519
var paragraphs = xmlElement.Descendants<Paragraph>();
20+
// Avoid not standard string format e.g. {{<t>tag</t>}}
21+
foreach (var tag in tags)
22+
{
23+
var regexStr = string.Concat(@"((\{\{(?:(?!\{\{|}}).)*>)|\{\{)", tag.Key, @"(}}|<.*?}})");
24+
25+
xmlElement.InnerXml = Regex.Replace(xmlElement.InnerXml, regexStr, $"{{{{{tag.Key?.ToString()}}}}}", RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | RegexOptions.CultureInvariant);
26+
}
27+
//return;
1628
foreach (var p in paragraphs)
1729
{
18-
var innerXmlSb = p.InnerXml;
19-
foreach (var tag in tags)
30+
var runs = p.Descendants<Run>();
31+
foreach (var run in runs)
2032
{
21-
innerXmlSb = Regex.Replace(innerXmlSb, @"((\{\{(?:(?!\{\{|}}).)*>)|\{\{)" + tag.Key + @"(}}|<.*?}})", tags[tag.Key]?.ToString(), RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | RegexOptions.CultureInvariant);
33+
foreach (Text t in run.Descendants<Text>())
34+
{
35+
foreach (var tag in tags)
36+
{
37+
var isMatch = t.Text.Contains($"{{{{{tag.Key}}}}}");
38+
if (isMatch)
39+
{
40+
if (tag.Value is MiniWordPicture)
41+
{
42+
var pic = (MiniWordPicture)tag.Value;
43+
byte[] l_Data = null;
44+
if (pic.Path != null)
45+
{
46+
l_Data = File.ReadAllBytes(pic.Path);
47+
}
48+
if (pic.Bytes != null)
49+
{
50+
l_Data = pic.Bytes;
51+
}
52+
53+
var mainPart = docx.MainDocumentPart;
54+
var imagePart = mainPart.AddImagePart(ImagePartType.Png);//TODO: jpg..
55+
using (var stream = new MemoryStream(l_Data))
56+
{
57+
imagePart.FeedData(stream);
58+
AddPicture(run, mainPart.GetIdOfPart(imagePart), pic);
59+
}
60+
t.Remove();
61+
}
62+
else
63+
{
64+
t.Text = t.Text.Replace($"{{{{{tag.Key}}}}}", tag.Value?.ToString());
65+
}
66+
}
67+
}
68+
}
2269
}
23-
p.InnerXml = innerXmlSb;
2470
}
2571
}
72+
73+
private static void AddPicture(OpenXmlElement appendElement, string relationshipId, MiniWordPicture pic)
74+
{
75+
// Define the reference of the image.
76+
var element =
77+
new Drawing(
78+
new DW.Inline(
79+
new DW.Extent() { Cx = pic.Width, Cy = pic.Height },
80+
new DW.EffectExtent()
81+
{
82+
LeftEdge = 0L,
83+
TopEdge = 0L,
84+
RightEdge = 0L,
85+
BottomEdge = 0L
86+
},
87+
new DW.DocProperties()
88+
{
89+
Id = (UInt32Value)1U,
90+
Name = $"Picture {Guid.NewGuid().ToString()}"
91+
},
92+
new DW.NonVisualGraphicFrameDrawingProperties(
93+
new A.GraphicFrameLocks() { NoChangeAspect = true }),
94+
new A.Graphic(
95+
new A.GraphicData(
96+
new PIC.Picture(
97+
new PIC.NonVisualPictureProperties(
98+
new PIC.NonVisualDrawingProperties()
99+
{
100+
Id = (UInt32Value)0U,
101+
Name = $"New Bitmap Image{Guid.NewGuid().ToString()}.png"
102+
},
103+
new PIC.NonVisualPictureDrawingProperties()),
104+
new PIC.BlipFill(
105+
new A.Blip(
106+
new A.BlipExtensionList(
107+
new A.BlipExtension()
108+
{
109+
Uri =
110+
$"{{{ Guid.NewGuid().ToString("n")}}}"
111+
})
112+
)
113+
{
114+
Embed = relationshipId,
115+
CompressionState =
116+
A.BlipCompressionValues.Print
117+
},
118+
new A.Stretch(
119+
new A.FillRectangle())),
120+
new PIC.ShapeProperties(
121+
new A.Transform2D(
122+
new A.Offset() { X = 0L, Y = 0L },
123+
new A.Extents() { Cx = pic.Width, Cy = pic.Height }),
124+
new A.PresetGeometry(
125+
new A.AdjustValueList()
126+
)
127+
{ Preset = A.ShapeTypeValues.Rectangle }))
128+
)
129+
{ Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" })
130+
)
131+
{
132+
DistanceFromTop = (UInt32Value)0U,
133+
DistanceFromBottom = (UInt32Value)0U,
134+
DistanceFromLeft = (UInt32Value)0U,
135+
DistanceFromRight = (UInt32Value)0U,
136+
EditId = "50D07946"
137+
});
138+
appendElement.Append((element));
139+
}
26140
public static void SaveAsByTemplate(string path, string templatePath, object value)
27141
{
28142
using (var stream = File.Create(path))
@@ -46,7 +160,7 @@ public static void SaveAsByTemplate(this Stream stream, byte[] templateBytes, ob
46160
}
47161
private static byte[] GetBytes(string path)
48162
{
49-
using (var st = FileHelper.OpenSharedRead(path))
163+
using (var st = Helpers.OpenSharedRead(path))
50164
using (var ms = new MemoryStream())
51165
{
52166
st.CopyTo(ms);
@@ -75,9 +189,4 @@ private static void SaveAsByTemplateImpl(Stream stream, byte[] template, object
75189
stream.Write(bytes,0, bytes.Length);
76190
}
77191
}
78-
79-
internal static partial class FileHelper
80-
{
81-
public static FileStream OpenSharedRead(string path) => File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
82-
}
83192
}

src/MiniWord/MiniWordPicture.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace MiniSoftware
2+
{
3+
using DocumentFormat.OpenXml;
4+
5+
public class MiniWordPicture
6+
{
7+
public string Path { get; set; }
8+
public byte[] Bytes { get; set; }
9+
public Int64Value Width { get; set; } = 990000L;
10+
11+
public Int64Value Height { get; set; } = 792000L;
12+
}
13+
}

tests/MiniWordTests/IssueTests.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,37 @@ namespace MiniWordTests
1313
{
1414
public class IssueTests
1515
{
16+
/// <summary>
17+
/// [Support image · Issue #3 · mini-software/MiniWord](https://github.com/mini-software/MiniWord/issues/3)
18+
/// </summary>
19+
[Fact]
20+
public void TestIssue3()
21+
{
22+
var path = PathHelper.GetTempFilePath();
23+
var templatePath = PathHelper.GetFile("TestBasicImage.docx");
24+
var value = new Dictionary<string, object>()
25+
{
26+
["Name"] = "Jack",
27+
["Company_Name"] = "MiniSofteware",
28+
["CreateDate"] = new DateTime(2021, 01, 01),
29+
["VIP"] = true,
30+
["Points"] = 123,
31+
["APP"] = "Demo APP",
32+
["Logo"] = new MiniWordPicture() { Path= @"D:\git\MiniWord\src\MiniWord\icon.png" ,Width= 392000L, Height= 392000L }
33+
};
34+
MiniWord.SaveAsByTemplate(path, templatePath, value);
35+
//Console.WriteLine(path);
36+
var xml = Helpers.GetZipFileContent(path, "word/document.xml");
37+
Assert.Contains("<w:drawing>", xml);
38+
}
39+
1640
/// <summary>
1741
/// [Fuzzy Regex replace similar key · Issue #5 · mini-software/MiniWord](https://github.com/mini-software/MiniWord/issues/5)
1842
/// </summary>
1943
[Fact]
2044
public void TestIssue5()
2145
{
22-
var path = PathHelper.GetTempPath();
46+
var path = PathHelper.GetTempFilePath();
2347
var templatePath = PathHelper.GetFile("TestBasicFill.docx");
2448
var value = new Dictionary<string, object>()
2549
{

0 commit comments

Comments
 (0)