2011-11-10 101 views
25

Estoy usando OpenXML para insertar una imagen en mi documento. El código proporcionado por Microsoft funciona, pero hace que la imagen sea mucho más pequeña:Insertar imagen en DocX usando OpenXML y configurar el tamaño

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

Necesito hacer que la imagen tenga su tamaño original. ¿Cómo puedo hacer esto? (He buscado en Google cómo hacer esto fuera de este proceso, pero eso no es lo que estoy buscando. Tengo que asumir que hay algún tipo de propiedades de tamaño dentro del código dado).

Editar: Actualización de código (aún no funciona)

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

Respuesta

37

Los tamaños, en EMU (English Metric Unit -- read this for a good explanation), están situados en la extensión (la CX y CY). Con el fin de conseguir una foto en un DOCX Usualmente lo hago de esta manera:

  1. Get dimensiones y la resolución
  2. Calcular el ancho de la imagen en EMU de la imagen: WEMU = imgWidthPixels/imgHorizontalDpi * emuPerInch
  3. Compute la altura de la imagen en EMU: el Mu = imgHeightPixels/imgVerticalDpi * emuPerInch
  4. Calcular el ancho de página máximo en EMU (he descubierto que si la imagen es demasiado ancha, no se mostrará)
  5. Si el ancho de la imagen en UEM es mayor que el máximo ancho de página, escala el ancho y alto de la imagen para que el ancho de la imagen sea igual al de la página (cuando digo página, me refiero a la página "utilizable", que es menos los márgenes):

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

  6. entonces utilizo el ancho como el valor de Cx y altura que el valor de Cy, tanto en el DW.Extent y en el A.Extents (de la A.Transform2D de la PIC.ShapeProperties) .

Tenga en cuenta que el valor emuPerInch es 914400.
tengo esta en funcionamiento (en servicio), pero no tengo el código conmigo en este momento.

ACTUALIZACIÓN

Este es el código que utilizo:

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

En mi caso, las medidas de mi página en cm, de ahí el emusPerCm que ves arriba.

ACTUALIZACIÓN 2 (para responder @andw)

Para que el archivo bloqueado durante el mínimo tiempo posible, abrirlo con un FileStream y pasar la corriente resultante a la propiedad de la StreamSourceBitmapImage:

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

¿La imagen ppp es constante tanto para el ancho como para la altura? ¿Cómo calculo esto? –

+0

Los trato como no constantes, pero todavía no he encontrado uno donde no estén. Si abre la imagen con la clase [BitmapImage] (http://msdn.microsoft.com/en-us/library/ms619218.aspx) (System.Windows.Media.Imaging namespace), tiene las siguientes propiedades que puede use: 'PixelWidth',' PixelHeight', 'DpiX',' DpiY'. – ssarabando

+0

He agregado una muestra de código a mi respuesta. – ssarabando

2

Este código funciona para mí.

Fuente: 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

¿Desea agregar la fuente donde encuentra esto? Como no es tu propio "hallazgo". – Styxxy

+0

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

2

Usted puede dar a la imagen de su tamaño original de esta manera:

En primer lugar se obtiene la anchura y la altura del archivo:

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

Entonces Conviertapíxeles a EMUs de esta manera:

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

Y finalmente dar los valores al abrir su archivo, quiero decir en esta línea de código:

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

reemplazar Cx y Cy con los valores calculados por lo se parece a esto:

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

cuenta de que hay dos líneas en años Tu código donde tienes que dar los valores calculados.

Luego tiene su imagen en su tamaño original, espero que esto ayude a alguien.

Cuestiones relacionadas