C# insert pictures into word via OpenXML if exceeds max width and height,adjust proportially

Install-Package DocumentFormat.OpenXml;
Install-Package System.Drawing.Common;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.ExtendedProperties;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System.IO;
using A = DocumentFormat.OpenXml.Drawing;
using DW = DocumentFormat.OpenXml.Drawing.Wordprocessing;
using PIC = DocumentFormat.OpenXml.Drawing.Pictures;

namespace ConsoleApp26
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string docFile = $"Picture_{DateTime.Now.ToString("yyyyMMddHHmmssffff")}.docx";
            var imgsList = Directory.GetFiles(@"../../../Images").ToList();
            AdvancedWordImageInserter imageInserter = new AdvancedWordImageInserter();
            imageInserter.CreateWordWithImages(docFile, imgsList);
            Console.WriteLine($"Exported in {docFile} successfully!");
        }
    }

    public class AdvancedWordImageInserter
    {
        // A0 dimensions in twips
        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;

        public void CreateWordWithImages(string outputPath, List<string> imagePaths)
        {
            // Create a new Word document
            using (WordprocessingDocument doc = WordprocessingDocument.Create(
                outputPath, WordprocessingDocumentType.Document))
            {
                // Add main document part
                MainDocumentPart mainPart = doc.AddMainDocumentPart();
                Body body = new Body();
                mainPart.Document = new Document(body); 

                // Add styles part for better formatting
                AddStylesPart(mainPart);

                // Add title
                AddTitle(mainPart, "Document with Images");

                // Insert each image
                foreach (var imagePath in imagePaths)
                {
                    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.Append(sectionProps);
                mainPart.Document.Save();
            }
        }

        private 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 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 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 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 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 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 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" })));
        }
    }
}

 

 

 

image

 

posted @ 2025-09-03 11:36  FredGrit  阅读(14)  评论(0)    收藏  举报