using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System.Diagnostics;
using A = DocumentFormat.OpenXml.Drawing;
using DW = DocumentFormat.OpenXml.Drawing.Wordprocessing;
using PIC = DocumentFormat.OpenXml.Drawing.Pictures;
namespace ConsoleApp29
{
internal class Program
{
static Random rnd;
private const UInt32 WordMaxPage = 31680;
// Clamp A0 dimensions to Word's maximum supported
private const UInt32 A0Width = WordMaxPage;
private const UInt32 A0Height = WordMaxPage;
// Margins in twips (1 inch = 1440 twips)
private const int Margin = 1440;
// EMU conversion (1 inch = 914400 EMU)
private const long EmusPerInch = 914400;
static void Main(string[] args)
{
string wordFile = $"DOC_{DateTime.Now.ToString("yyyyMMddHHmmssffff")}.docx";
InsertStringToWordFile(wordFile);
InsertImagesToWordFile(wordFile);
var proc = new Process()
{
StartInfo=new ProcessStartInfo()
{
FileName = wordFile,
UseShellExecute = true
}
};
proc.Start();
}
private static void InsertImagesToWordFile(string wordFile)
{
var imgDir = @"../../../Images";
if (Directory.Exists(imgDir))
{
var imgsList = Directory.GetFiles(imgDir).ToList();
InsertImagesListIntoWord(wordFile, imgsList);
}
}
private static void InsertStringToWordFile(string wordFile)
{
rnd=new Random();
CreateOrOrOpenWordFileInsertString(wordFile, "SMOOTHTECH", 50, "center", true);
CreateOrOrOpenWordFileInsertString(wordFile, "Focus", 50, "left", true);
CreateOrOrOpenWordFileInsertString(wordFile, "Laser Focus", 50, "left", true);
CreateOrOrOpenWordFileInsertString(wordFile, "Laser Beam Focus", 50, "left", true);
for (int i = 1; i<101; i++)
{
System.Drawing.Color color = System.Drawing.Color.FromArgb(255, rnd.Next(0, 255), rnd.Next(0, 255), rnd.Next(0, 255));
string hexColorStr = ColorToHexString(color);
CreateOrOrOpenWordFileInsertString(wordFile, $"{i}_{Guid.NewGuid().ToString("N")}"
, rnd.Next(20, 50), "left", rnd.Next(0, 10)/2==0, hexColorStr);
}
}
static void CreateOrOrOpenWordFileInsertString(string wordFile, string str, int fontSize = 20,
string alignment = "left", bool isBold = false, string color = "000000")
{
if (!File.Exists(wordFile))
{
using (WordprocessingDocument doc = WordprocessingDocument.Create(wordFile, WordprocessingDocumentType.Document))
{
MainDocumentPart mainPart = doc.AddMainDocumentPart();
mainPart.Document = new Document(new Body());
WriteStringToDoc(mainPart, str, fontSize, alignment, isBold, color);
SetWordPageMaximize(mainPart);
SetWordPageSize(mainPart);
}
}
else
{
using (WordprocessingDocument doc = WordprocessingDocument.Open(wordFile, true))
{
MainDocumentPart mainPart = doc.MainDocumentPart;
if (mainPart?.Document?.Body==null)
{
mainPart.Document=new Document(new Body());
}
WriteStringToDoc(mainPart, str, fontSize, alignment, isBold, color);
SetWordPageMaximize(mainPart);
SetWordPageSize(mainPart);
}
}
}
private static void SetWordPageSize(MainDocumentPart mainPart)
{
SectionProperties sectionProps = new SectionProperties(
new PageSize()
{
Width = A0Width, // A0 width in twips
Height = A0Height, // A0 height in twips
Orient = PageOrientationValues.Landscape
},
new PageMargin()
{
Top = 1440, // 1 inch
Bottom = 1440,
Left = 1440,
Right = 1440
}
);
Body body = mainPart.Document.Body;
body.Append(sectionProps);
mainPart.Document.Save();
}
private static void SetWordPageMaximize(MainDocumentPart mainPart)
{
var settingsPart = mainPart.DocumentSettingsPart ?? mainPart.AddNewPart<DocumentSettingsPart>();
if (settingsPart.Settings == null)
settingsPart.Settings = new Settings();
// Remove old zoom/view if exist
settingsPart.Settings.RemoveAllChildren<Zoom>();
settingsPart.Settings.RemoveAllChildren<View>();
// Add new
settingsPart.Settings.Append(new View() { Val = ViewValues.Print });
settingsPart.Settings.Append(new Zoom() { Percent = "100" });
settingsPart.Settings.Save();
}
static void WriteStringToDoc(MainDocumentPart mainPart, string str, int fontSize = 20,
string alignment = "left", bool isBold = false, string color = "000000",
string fontFamily = "Arial", bool isItalic = false, bool isUnderline = false)
{
Body body = mainPart.Document.Body;
Run run = new Run();
RunProperties runProperties = new RunProperties();
// Set font properties
SetRunProperties(runProperties, fontSize, isBold, isItalic, isUnderline, fontFamily, color);
// Add properties to run
if (runProperties.HasChildren)
{
run.RunProperties = runProperties;
}
// Add text to run
run.Append(new Text(str));
run.Append(new Break());
Paragraph para = new Paragraph(run);
SetParagraphAlignment(para, alignment);
// Add run to paragraph
body.Append(para);
mainPart.Document.Save();
}
private static void SetRunProperties(RunProperties runProperties, int fontSize,
bool isBold, bool isItalic, bool isUnderline, string fontFamily, string color)
{
runProperties.Append(new FontSize()
{
Val = (fontSize * 2).ToString()
});
if (isBold)
{
runProperties.Append(new Bold());
}
if (isItalic)
{
runProperties.Append(new Italic());
}
if (isUnderline)
{
runProperties.Append(new Underline()
{
Val = UnderlineValues.Single
});
}
runProperties.Append(new RunFonts()
{
Ascii = fontFamily,
HighAnsi = fontFamily
});
runProperties.Append(new DocumentFormat.OpenXml.Wordprocessing.Color()
{
Val = color
});
}
private static void SetParagraphAlignment(Paragraph paragraph, string alignment)
{
ParagraphProperties paragraphProps = new ParagraphProperties();
switch (alignment.ToLower())
{
case "center":
paragraphProps.Append(new Justification()
{
Val = JustificationValues.Center
});
break;
case "right":
paragraphProps.Append(new Justification()
{
Val = JustificationValues.Right
});
break;
case "both":
paragraphProps.Append(new Justification()
{
Val = JustificationValues.Both
});
break;
default:
paragraphProps.Append(new Justification()
{
Val = JustificationValues.Left
});
break;
}
paragraph.ParagraphProperties = paragraphProps;
}
private static string ColorToHexString(System.Drawing.Color color)
{
// Convert to 6-digit hex string (without alpha)
return $"{color.R:X2}{color.G:X2}{color.B:X2}";
}
public static void InsertImagesListIntoWord(string wordFile, List<string> imagePathsList)
{
if (!File.Exists(wordFile))
{
// Create a new Word document
using (WordprocessingDocument doc = WordprocessingDocument.Create(
wordFile, WordprocessingDocumentType.Document))
{
// Add main document part
MainDocumentPart mainPart = doc.AddMainDocumentPart();
Body body = new Body();
mainPart.Document = new Document(body);
InsertImagesInWord(mainPart, imagePathsList);
}
}
else
{
using (WordprocessingDocument doc = WordprocessingDocument.Open(wordFile, true))
{
MainDocumentPart mainPart = doc.MainDocumentPart;
if (mainPart?.Document?.Body==null)
{
mainPart.Document=new Document(new Body());
}
InsertImagesInWord(mainPart, imagePathsList);
}
}
}
private static void InsertImagesInWord(MainDocumentPart mainPart, List<string> imagePathsList)
{
// Add styles part for better formatting
AddStylesPart(mainPart);
// Add title
AddTitle(mainPart, "Document with Images");
// Insert each image
foreach (var imagePath in imagePathsList)
{
AddImageWithCaption(mainPart, imagePath);
Console.WriteLine(imagePath);
}
//Word’s page size units are in twips(1/20th of a point).
//A0 = 841 × 1189 mm = 33.1 × 46.8 inches
//1 inch = 1440 twips
//So:
//Width = 33.1 × 1440 ≈ 47664 twips
//Height = 46.8 × 1440 ≈ 67456 twips
// Add required SectionProperties with A0 page size
SectionProperties sectionProps = new SectionProperties(
new PageSize()
{
Width = A0Width, // A0 width in twips
Height = A0Height, // A0 height in twips
Orient = PageOrientationValues.Landscape
},
new PageMargin()
{
Top = 1440, // 1 inch
Bottom = 1440,
Left = 1440,
Right = 1440
}
);
Body body = mainPart.Document.Body;
body.Append(sectionProps);
mainPart.Document.Save();
}
private static void AddStylesPart(MainDocumentPart mainPart)
{
StyleDefinitionsPart stylePart = mainPart.AddNewPart<StyleDefinitionsPart>();
Styles styles = new Styles();
// Add some basic styles
styles.Append(CreateParagraphStyle("Title", "Title", "36"));
styles.Append(CreateParagraphStyle("Heading1", "Heading 1", "24"));
styles.Append(CreateParagraphStyle("Normal", "Normal", "12"));
stylePart.Styles = styles;
}
private static Style CreateParagraphStyle(string styleId, string styleName, string fontSize)
{
return new Style()
{
Type = StyleValues.Paragraph,
StyleId = styleId,
CustomStyle = true,
StyleName = new StyleName() { Val = styleName },
StyleParagraphProperties = new StyleParagraphProperties(
new SpacingBetweenLines() { After = "200" }),
StyleRunProperties = new StyleRunProperties(
new FontSize() { Val = fontSize })
};
}
private static void AddTitle(MainDocumentPart mainPart, string titleText)
{
Paragraph titleParagraph = new Paragraph(
new ParagraphProperties(
new ParagraphStyleId() { Val = "Title" }),
new Run(
new RunProperties(
new FontSize() { Val="100" }),
new Text(titleText)));
mainPart.Document.Body.AppendChild(titleParagraph);
}
private static void AddImageWithCaption(MainDocumentPart mainPart, string imagePath)
{
long widthEmu, heightEmu;
using (var image = System.Drawing.Image.FromFile(imagePath))
{
const int emusPerInch = 914400;
double widthInches = image.Width/image.HorizontalResolution;
double heightInches = image.Height/image.VerticalResolution;
widthEmu=(long)(widthInches*emusPerInch);
heightEmu= (long)(heightInches*emusPerInch);
}
long maxWidth = A0Width * EmusPerInch / 1440;
long maxHeight = A0Height * EmusPerInch / 1440;
if (widthEmu > maxWidth || heightEmu > maxHeight)
{
double ratio = Math.Min((double)maxWidth / widthEmu,
(double)maxHeight / heightEmu);
widthEmu = (long)(widthEmu * ratio);
heightEmu = (long)(heightEmu * ratio);
}
// Add image part
ImagePart imagePart = mainPart.AddImagePart(GetImagePartType(imagePath));
using (FileStream stream = new FileStream(imagePath, FileMode.Open,
FileAccess.Read, FileShare.Read))
{
imagePart.FeedData(stream);
}
string relationshipId = mainPart.GetIdOfPart(imagePart);
// Create image drawing
var drawing = CreateImageDrawing(relationshipId, widthEmu, heightEmu,
Path.GetFileName(imagePath));
// Add image paragraph
Paragraph imageParagraph = new Paragraph(
new ParagraphProperties(
new Justification() { Val = JustificationValues.Center }),
new Run(drawing));
mainPart.Document.Body.AppendChild(imageParagraph);
// Add caption
AddCaption(mainPart, $"Image: {Path.GetFileName(imagePath)}");
}
private static PartTypeInfo GetImagePartType(string imagePath)
{
string extension = Path.GetExtension(imagePath).ToLower();
return extension switch
{
".jpg" or ".jpeg" => ImagePartType.Jpeg,
".png" => ImagePartType.Png,
".bmp" => ImagePartType.Bmp,
".gif" => ImagePartType.Gif,
".tiff" => ImagePartType.Tiff,
_ => ImagePartType.Jpeg
};
}
private static Drawing CreateImageDrawing(string relationshipId, long width, long height, string imageName)
{
return new Drawing(
new DW.Inline(
new DW.Extent() { Cx = width, Cy = height },
new DW.EffectExtent()
{
LeftEdge = 0L,
TopEdge = 0L,
RightEdge = 0L,
BottomEdge = 0L
},
new DW.DocProperties() { Id = 1U, Name = imageName },
new DW.NonVisualGraphicFrameDrawingProperties(
new A.GraphicFrameLocks() { NoChangeAspect = true }),
new A.Graphic(
new A.GraphicData(
new PIC.Picture(
new PIC.NonVisualPictureProperties(
new PIC.NonVisualDrawingProperties()
{
Id = 0U,
Name = imageName
},
new PIC.NonVisualPictureDrawingProperties()),
new PIC.BlipFill(
new A.Blip(
new A.BlipExtensionList(
new A.BlipExtension()
{
Uri = "{28A0092B-C50C-407E-A947-70E740481C1C}"
})
)
{
Embed = relationshipId
},
new A.Stretch(
new A.FillRectangle())),
new PIC.ShapeProperties(
new A.Transform2D(
new A.Offset() { X = 0L, Y = 0L },
new A.Extents() { Cx = width, Cy = height }),
new A.PresetGeometry(
new A.AdjustValueList()
)
{ Preset = A.ShapeTypeValues.Rectangle }))
)
{ Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" })
)
{
DistanceFromTop = 0U,
DistanceFromBottom = 0U,
DistanceFromLeft = 0U,
DistanceFromRight = 0U
});
}
private static void AddCaption(MainDocumentPart mainPart, string captionText)
{
Paragraph captionParagraph = new Paragraph(
new ParagraphProperties(
new ParagraphStyleId() { Val = "Normal" },
new Justification() { Val = JustificationValues.Center }),
new Run(
new Text(captionText)));
mainPart.Document.Body.AppendChild(captionParagraph);
// Add some space after caption
mainPart.Document.Body.AppendChild(
new Paragraph(
new ParagraphProperties(
new SpacingBetweenLines() { After = "400" })));
}
}
}