2011-11-10 38 views
25

Używam OpenXML do wstawienia obrazu do mojego dokumentu. Kod dostarczony przez firmę Microsoft działa, ale powoduje, że obraz jest znacznie mniejszy:Wstawianie obrazu do DocX za pomocą OpenXML i ustawianie rozmiaru

public static void InsertAPicture(string document, string fileName) 
     { 
      using (WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(document, true)) 
      { 
       MainDocumentPart mainPart = wordprocessingDocument.MainDocumentPart; 

       ImagePart imagePart = mainPart.AddImagePart(ImagePartType.Jpeg); 

       using (FileStream stream = new FileStream(fileName, FileMode.Open)) 
       { 
        imagePart.FeedData(stream); 
       } 

       AddImageToBody(wordprocessingDocument, mainPart.GetIdOfPart(imagePart)); 
      } 
     } 
     private static void AddImageToBody(WordprocessingDocument wordDoc, string relationshipId) 
     { 
      // Define the reference of the image. 
      var element = 
       new Drawing(
        new DW.Inline(
         new DW.Extent() { Cx = 990000L, Cy = 792000L }, 
         new DW.EffectExtent() 
         { 
          LeftEdge = 0L, 
          TopEdge = 0L, 
          RightEdge = 0L, 
          BottomEdge = 0L 
         }, 
         new DW.DocProperties() 
         { 
          Id = (UInt32Value)1U, 
          Name = "Picture 1" 
         }, 
         new DW.NonVisualGraphicFrameDrawingProperties(
          new A.GraphicFrameLocks() { NoChangeAspect = true }), 
         new A.Graphic(
          new A.GraphicData(
           new PIC.Picture(
            new PIC.NonVisualPictureProperties(
             new PIC.NonVisualDrawingProperties() 
             { 
              Id = (UInt32Value)0U, 
              Name = "New Bitmap Image.jpg" 
             }, 
             new PIC.NonVisualPictureDrawingProperties()), 
            new PIC.BlipFill(
             new A.Blip(
              new A.BlipExtensionList(
               new A.BlipExtension() 
               { 
                Uri = 
                 "{28A0092B-C50C-407E-A947-70E740481C1C}" 
               }) 
             ) 
             { 
              Embed = relationshipId, 
              CompressionState = A.BlipCompressionValues.Print 
             }, 
             new A.Stretch(
              new A.FillRectangle())), 
            new PIC.ShapeProperties(
             new A.Transform2D(
              new A.Offset() { X = 0L, Y = 0L }, 
              new A.Extents() { Cx = 990000L, Cy = 792000L }), 
             new A.PresetGeometry(
              new A.AdjustValueList() 
             ) { Preset = A.ShapeTypeValues.Rectangle })) 
          ) { Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" }) 
        ) 
        { 
         DistanceFromTop = (UInt32Value)0U, 
         DistanceFromBottom = (UInt32Value)0U, 
         DistanceFromLeft = (UInt32Value)0U, 
         DistanceFromRight = (UInt32Value)0U, 
         EditId = "50D07946" 
        }); 

      // Append the reference to body, the element should be in a Run. 
      wordDoc.MainDocumentPart.Document.Body.AppendChild(new Paragraph(new Run(element))); 
     } 

Potrzebuję zrobić obraz o jego pierwotnym rozmiarze. Jak mogę to zrobić? (Mam google'a, jak to zrobić poza tym procesem, ale to nie jest to, czego szukam.Muszę założyć, że istnieją pewne właściwości rozmiaru wewnątrz danego kodu).

Edycja: Aktualizacja Code (jeszcze nie działa)

public static void InsertAPicture(string document, string fileName) 
{ 
    using (WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(document, true)) 
    { 
     MainDocumentPart mainPart = wordprocessingDocument.MainDocumentPart; 

     ImagePart imagePart = mainPart.AddImagePart(ImagePartType.Jpeg); 

     using (FileStream stream = new FileStream(fileName, FileMode.Open)) 
     { 
      imagePart.FeedData(stream); 
     } 

     AddImageToBody(wordprocessingDocument, mainPart.GetIdOfPart(imagePart), fileName); 
    } 
} 
private static void AddImageToBody(WordprocessingDocument wordDoc, string relationshipId, string fileName) 
{ 

    var img = new BitmapImage(new Uri(fileName, UriKind.RelativeOrAbsolute)); 
    var widthPx = img.PixelWidth; 
    var heightPx = img.PixelHeight; 
    var horzRezDpi = img.DpiX; 
    var vertRezDpi = img.DpiY; 
    const int emusPerInch = 914400; 
    const int emusPerCm = 360000; 
    var maxWidthCm = 16.51; 
    var widthEmus = (long)(widthPx/horzRezDpi * emusPerInch); 
    var heightEmus = (long)(heightPx/vertRezDpi * emusPerInch); 
    var maxWidthEmus = (long)(maxWidthCm * emusPerCm); 
    if (widthEmus > maxWidthEmus) 
    { 
     var ratio = (heightEmus * 1.0m)/widthEmus; 
     widthEmus = maxWidthEmus; 
     heightEmus = (long)(widthEmus * ratio); 
    } 

    // Define the reference of the image. 
    var element = 
     new Drawing(
      new DW.Inline(
       new DW.Extent() { Cx = 990000L, Cy = 792000L }, 
       new DW.EffectExtent() 
       { 
        LeftEdge = 0L, 
        TopEdge = 0L, 
        RightEdge = 0L, 
        BottomEdge = 0L 
       }, 
       new DW.DocProperties() 
       { 
        Id = (UInt32Value)1U, 
        Name = "Picture 1" 
       }, 
       new DW.NonVisualGraphicFrameDrawingProperties(
        new A.GraphicFrameLocks() { NoChangeAspect = true }), 
       new A.Graphic(
        new A.GraphicData(
         new PIC.Picture(
          new PIC.NonVisualPictureProperties(
           new PIC.NonVisualDrawingProperties() 
           { 
            Id = (UInt32Value)0U, 
            Name = "New Bitmap Image.jpg" 
           }, 
           new PIC.NonVisualPictureDrawingProperties()), 
          new PIC.BlipFill(
           new A.Blip(
            new A.BlipExtensionList(
             new A.BlipExtension() 
             { 
              Uri = 
               "{28A0092B-C50C-407E-A947-70E740481C1C}" 
             }) 
           ) 
           { 
            Embed = relationshipId, 
            CompressionState = A.BlipCompressionValues.Print 
           }, 
           new A.Stretch(
            new A.FillRectangle())), 
          new PIC.ShapeProperties(
           new A.Transform2D(
            new A.Offset() { X = 0L, Y = 0L }, 
            new A.Extents() { Cx = widthEmus, Cy = heightEmus }), 
           new A.PresetGeometry(
            new A.AdjustValueList() 
           ) { Preset = A.ShapeTypeValues.Rectangle })) 
        ) { Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" }) 
      ) 
      { 
       DistanceFromTop = (UInt32Value)0U, 
       DistanceFromBottom = (UInt32Value)0U, 
       DistanceFromLeft = (UInt32Value)0U, 
       DistanceFromRight = (UInt32Value)0U, 
       EditId = "50D07946" 
      }); 

    // Append the reference to body, the element should be in a Run. 
    wordDoc.MainDocumentPart.Document.Body.AppendChild(new Paragraph(new Run(element))); 
} 

Odpowiedz

37

Wielkości w EMU (English Metric Unit -- read this for a good explanation), są ustawione w stopniu (CX i CY). W celu uzyskania pic na docx zwykle zrobić to tak:

  1. Uzyskaj wymiary i rozdzielczość
  2. Compute szerokość obrazem w EMU obrazka: wEmu = imgWidthPixels/imgHorizontalDpi * emuPerInch
  3. Compute wysokość obrazem w EMU: hemu = imgHeightPixels/imgVerticalDpi * emuPerInch
  4. obliczyć max szerokość strony w EMU (odkryłem, że jeśli obraz jest zbyt szeroki, to nie pokaże)
  5. If szerokości obrazu w EMU jest większa niż maksymalna szerokość strony, przeskalowuję szerokość i wysokość obrazu tak, aby szerokość obrazu była równa szerokości strony (gdy mówię o stronie, mam na myśli stronę "użyteczną", czyli minus marginesy):

    var ratio = hEmu/wEmu;
    wEmu = maxPageWidthEmu;
    hEmu = wEmu * ratio;

  6. następnie używać szerokość jako wartość Cx i wysokość jako wartość Cy, zarówno w DW.Extent aw A.Extents (z A.Transform2D z PIC.ShapeProperties) .

pamiętać, że wartość emuPerInch jest 914400.
mam to działa (w eksploatacji) ale nie mam kodu ze mną teraz.

UPDATE

Jest to kod używam:

var img = new BitmapImage(new Uri(fileName, UriKind.RelativeOrAbsolute)); 
var widthPx = img.PixelWidth; 
var heightPx = img.PixelHeight; 
var horzRezDpi = img.DpiX; 
var vertRezDpi = img.DpiY; 
const int emusPerInch = 914400; 
const int emusPerCm = 360000; 
var widthEmus = (long)(widthPx/horzRezDpi * emusPerInch); 
var heightEmus = (long)(heightPx/vertRezDpi * emusPerInch); 
var maxWidthEmus = (long)(maxWidthCm * emusPerCm); 
if (widthEmus > maxWidthEmus) { 
    var ratio = (heightEmus * 1.0m)/widthEmus; 
    widthEmus = maxWidthEmus; 
    heightEmus = (long)(widthEmus * ratio); 
} 

W moim przypadku, środki mojej stronie są w cm, stąd emusPerCm widać powyżej.

UPDATE 2 (na odpowiedź @andw)

Aby plik zamknięte w minimalnym możliwym czasie, należy go otworzyć w FileStream i przechodzą wynikowy strumień właściwości StreamSource z BitmapImage:

var img = new BitmapImage(); 
using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { 
    img.BeginInit(); 
    img.StreamSource = fs; 
    img.EndInit(); 
} 
// The file is now unlocked 
var widthPx = img.PixelWidth; 
... 
+0

Czy rozdzielczość dpi jest stała zarówno dla szerokości, jak i wysokości? jak to obliczyć? –

+0

Traktuję je jako nietrwałe, ale jeszcze nie znalazłem takiego, gdzie one nie są. Jeśli otworzysz obraz przy użyciu klasy [BitmapImage] (http://msdn.microsoft.com/en-us/library/ms619218.aspx) (obszar nazw System.Windows.Media.Imaging), ma on następujące właściwości: użyj: 'PixelWidth',' PixelHeight', 'DpiX',' DpiY'. – ssarabando

+0

Dodałem próbkę kodu do mojej odpowiedzi. – ssarabando

2

Ten kod działa dla mnie.

Źródło: http://msdn.microsoft.com/en-us/library/office/bb497430(v=office.15).aspx

public static void Do() 
    { 
     string filename = @"c:\temp\m.docx"; 
     byte[] reportData = GetWordReport(); 
     // File.WriteAllBytes(filename, reportData); 
     //MessageBox.Show("File " + filename + " created"); 
    } 

    private static byte[] GetWordReport() 
    { 
     // using (MemoryStream stream = new MemoryStream()) 
     // { 
      //var template = GetTemplateData(); 
      //stream.Write(template, 0, template.Length); 
      using (WordprocessingDocument docx = WordprocessingDocument.Open(@"c:\temp\m.docx", true)) 
      { 
       // Some changes on docx 
       docx.MainDocumentPart.Document = GenerateMainDocumentPart(6,4); 

       var imagePart = docx.MainDocumentPart.AddNewPart<ImagePart>("image/jpeg", "rIdImagePart1"); 
       GenerateImagePart(imagePart); 
      } 
      // stream.Seek(0, SeekOrigin.Begin); 
      // return stream.ToArray(); 
     // } 
     return null; 
    } 

    private static byte[] GetTemplateData() 
    { 
     using (MemoryStream targetStream = new MemoryStream()) 
     using (BinaryReader sourceReader = new BinaryReader(File.Open(@"c:\temp\m_2.docx", FileMode.Open))) 
     { 
      byte[] buffer = new byte[4096]; 

      int num = 0; 
      do 
      { 
       num = sourceReader.Read(buffer, 0, 4096); 
       if (num > 0) 
        targetStream.Write(buffer, 0, num); 
      } 
      while (num > 0); 
      targetStream.Seek(0, SeekOrigin.Begin); 
      return targetStream.ToArray(); 
     } 
    } 

    private static void GenerateImagePart(OpenXmlPart part) 
    { 
     using (Stream imageStream = File.Open(@"c:\temp\image002.jpg", FileMode.Open)) 
     { 
      part.FeedData(imageStream); 
     } 
    } 

    private static Document GenerateMainDocumentPart(int cx,int cy) 
    { 
     long LCX = cx*261257L; 
     long LCY = cy*261257L; 




     var element = 
      new Document(
       new Body(
        new Paragraph(
         new Run(
          new RunProperties(
           new NoProof()), 
          new Drawing(
           new wp.Inline(
            new wp.Extent() { Cx = LCX, Cy = LCY }, 
            new wp.EffectExtent() { LeftEdge = 0L, TopEdge = 19050L, RightEdge = 0L, BottomEdge = 0L }, 
            new wp.DocProperties() { Id = (UInt32Value)1U, Name = "Picture 0", Description = "Forest Flowers.jpg" }, 
            new wp.NonVisualGraphicFrameDrawingProperties(
             new a.GraphicFrameLocks() { NoChangeAspect = true }), 
            new a.Graphic(
             new a.GraphicData(
              new pic.Picture(
               new pic.NonVisualPictureProperties(
                new pic.NonVisualDrawingProperties() { Id = (UInt32Value)0U, Name = "Forest Flowers.jpg" }, 
                new pic.NonVisualPictureDrawingProperties()), 
               new pic.BlipFill(
                new a.Blip() { Embed = "rIdImagePart1", CompressionState = a.BlipCompressionValues.Print }, 
                new a.Stretch(
                 new a.FillRectangle())), 
               new pic.ShapeProperties(
                new a.Transform2D(
                 new a.Offset() { X = 0L, Y = 0L }, 
                 new a.Extents() { Cx = LCX, Cy = LCY }), 
                new a.PresetGeometry(
                 new a.AdjustValueList() 
                ) { Preset = a.ShapeTypeValues.Rectangle })) 
             ) { Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" }) 
           ) { DistanceFromTop = (UInt32Value)0U, DistanceFromBottom = (UInt32Value)0U, DistanceFromLeft = (UInt32Value)0U, DistanceFromRight = (UInt32Value)0U })) 
        ) { RsidParagraphAddition = "00A2180E", RsidRunAdditionDefault = "00EC4DA7" }, 
        new SectionProperties(
         new PageSize() { Width = (UInt32Value)11906U, Height = (UInt32Value)16838U }, 
         new PageMargin() { Top = 1440, Right = (UInt32Value)1800U, Bottom = 1440, Left = (UInt32Value)1800U, Header = (UInt32Value)851U, Footer = (UInt32Value)992U, Gutter = (UInt32Value)0U }, 
         new Columns() { Space = ((UInt32Value)425U).ToString() }, 
         new DocGrid() { Type = DocGridValues.Lines, LinePitch = 312 } 
        ) { RsidR = "00A2180E", RsidSect = "00A2180E" })); 
     return element; 
    } 
+1

Chcesz dodać źródło, w którym to znajdujesz? Ponieważ to nie jest twoje własne "odkrycie". – Styxxy

+0

http://msdn.microsoft.com/en-us/library/office/bb497430(v=office.15).aspx –

2

można dać do obrazu jego oryginalnym rozmiarze w ten sposób:

Najpierw trzeba uzyskać szerokość i wysokość pliku:

int iWidth = 0; 
int iHeight = 0; 
using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap("yourFilePath")) 
{ 
    iWidth = bmp.Width; 
    iHeight = bmp.Height; 
} 

Następnie przelicz na pikseli na EMU w ten sposób:

iWidth = (int)Math.Round((decimal)iWidth * 9525); 
iHeight = (int)Math.Round((decimal)iHeight * 9525); 

I wreszcie podają wartości podczas otwierania pliku, to znaczy w tej linii kodu:

new DW.Extent() { Cx = 990000L, Cy = 792000L }, 

zastąpić Cx i Cy ze swoimi obliczone wartości tak Wygląda to tak:

new DW.Extent() { Cx = iWidth, Cy = iHeight }, 

Zauważ, że są dwie linie w yo kod ur, w którym musisz podać obliczone wartości.

Następnie masz obraz w oryginalnym rozmiarze, mam nadzieję, że to pomaga komuś.

Powiązane problemy