none
Como obtener Imagenes de un FlowDocument RRS feed

  • Pregunta

  •  

    Hola, me gustaria a partir de un FlowDocument que contiene imagenes, obtener esas imagenes.

    He encontrado una forma de hacerlo, pero las imagenes que consigo son del tipo System.Windows.Controls.Image.

    Yo necesito obtener imagenes del tipo System.Drawing.Image.

    ¿Alguin conoce una forma de obtenerlas? ¿O alguna forma de hacer una conversión entre tipos de images?

    Gracias,

    Un saludo

     

    martes, 7 de junio de 2011 13:59

Respuestas

  • Hola jcloquell.

    ¿si no te importa, puedes comentar como has obtenido las imagenes del flowDocument?, asi se implementa toda la solucion al problema.

    Bien, yo pongo la parte que necesitas. En un principio, existiria otra forma que posiblemente sea mas facil que es guardar la imagen y abrirla con el tipo que quieras.

    Pero te pongo la mas elegante, se trata de hacer la conversion:

     

    Codigo .cs

     //---------------------------------------------------------------------
       // Pasar de un 'System.Drawing.Bitmap' a un Windows.Controls.Image
       System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(@"Montanejos.jpg");   
       
       // puntero manejado para usar en el proceso
       IntPtr handle = IntPtr.Zero;
       try
       {
        // obtener el handle del bitmap
        handle = bmp.GetHbitmap();
        // establecer la fuente en System.windows.image
        image1.Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty,
         BitmapSizeOptions.FromEmptyOptions());
       }
       finally
       {
        // eliminar el manejador del GDI
        DeleteObject(handle);
       }
    
    
       // ------------------------------------------------------------------
       // Pasar de un Windows.Controls.Image a un System.Drawing.Image
       BitmapSource bitmapSource = (BitmapSource)image1.Source;
    
       // stride es el numero de bits del formato de pixel multiplicado por el ancho del bitmap
       // http://msdn.microsoft.com/es-es/library/zy1a2d14(v=vs.80).aspx
       var stride = bitmapSource.PixelWidth * bitmapSource.Format.BitsPerPixel;
       // todos los bytes de la imagen = alto por stride
       byte[] imageBits = new byte[bitmapSource.PixelHeight * stride];
       // copiar los bits al array creado
       bitmapSource.CopyPixels(imageBits, stride, 0);
    
       try
       {
        // codigo no manejado para manejar punteros al estilo c++
        unsafe   
        {
         // fijar la variable administrada (para que no la use el recolector)
         fixed (byte* pImageBits = imageBits)    
         {
          // crear un puntero manejado
          handle = new IntPtr(pImageBits);
          // crear el Bitmap con los datos del bitmapsource
          bmp = new System.Drawing.Bitmap(bitmapSource.PixelWidth, bitmapSource.PixelHeight, stride,
           System.Drawing.Imaging.PixelFormat.Format32bppArgb, handle);    
         }   
        }
       }
       finally
       {
        // eliminar el manejador del GDI
        DeleteObject(handle);
       }
    
       //--------------------------------------------------------------------------------------------------
       // volver Pasar del 'System.Drawing.Bitmap' convertido a un Windows.Controls.Image para visualizarlo
       System.Drawing.Image image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
          
       handle = IntPtr.Zero;
       try
       {
        // obtener el manejador
        handle = ((System.Drawing.Bitmap)image).GetHbitmap();
        // establecer la fuente en System.windows.image
        image2.Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty,
         BitmapSizeOptions.FromEmptyOptions());
       }
       finally
       {
        // eliminar el manejador del GDI
        DeleteObject(handle);
       }
    

     

    En este codigo estan las dos alternativas de Controls.Image a Drawing.Image y viceversa. la ultima vuelve a convertir el Drawing.Image para poder visualizar el resultado en otro control de imagen.

    NOTA: como para la conversion es necesario acceder al puntero del array manejado, se necesita habilitar el codigo no seguro /unsafe (se puede realizar desde las propiedades del proyecto, pestaña general->permitir codigo no seguro) y fijar la variable para que no la mueva el recolector (aunque es posible que no haga falta, es lo ideal).

    Ademas, se hace uso de la funcion DeleteObject del GDI para eliminar el handle del bitmap, con lo que se tiene que declarar una funcion como esta:

      /// <summary>
      /// Libreria de WIN32 para hacer uso de funciones del GDI
      /// </summary>
      [System.Runtime.InteropServices.DllImport("gdi32.dll")]
      static extern bool DeleteObject(IntPtr hObject);
    

    Y con esto es todo, creo que no me he dejado ninguna fuga de memoria, de todas formas tendras que coger solo el codigo que te interese y lo optimizas mejor.

    Pruebalo y cuentas que tal.

     


    Saludos
    David González
    MCP, MCTS
    Visita mi Blog en: http://www.dgzornoza.com/

    • Marcado como respuesta jcloquell martes, 14 de junio de 2011 15:08
    viernes, 10 de junio de 2011 19:16

Todas las respuestas

  • Hola jcloquell.

    ¿si no te importa, puedes comentar como has obtenido las imagenes del flowDocument?, asi se implementa toda la solucion al problema.

    Bien, yo pongo la parte que necesitas. En un principio, existiria otra forma que posiblemente sea mas facil que es guardar la imagen y abrirla con el tipo que quieras.

    Pero te pongo la mas elegante, se trata de hacer la conversion:

     

    Codigo .cs

     //---------------------------------------------------------------------
       // Pasar de un 'System.Drawing.Bitmap' a un Windows.Controls.Image
       System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(@"Montanejos.jpg");   
       
       // puntero manejado para usar en el proceso
       IntPtr handle = IntPtr.Zero;
       try
       {
        // obtener el handle del bitmap
        handle = bmp.GetHbitmap();
        // establecer la fuente en System.windows.image
        image1.Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty,
         BitmapSizeOptions.FromEmptyOptions());
       }
       finally
       {
        // eliminar el manejador del GDI
        DeleteObject(handle);
       }
    
    
       // ------------------------------------------------------------------
       // Pasar de un Windows.Controls.Image a un System.Drawing.Image
       BitmapSource bitmapSource = (BitmapSource)image1.Source;
    
       // stride es el numero de bits del formato de pixel multiplicado por el ancho del bitmap
       // http://msdn.microsoft.com/es-es/library/zy1a2d14(v=vs.80).aspx
       var stride = bitmapSource.PixelWidth * bitmapSource.Format.BitsPerPixel;
       // todos los bytes de la imagen = alto por stride
       byte[] imageBits = new byte[bitmapSource.PixelHeight * stride];
       // copiar los bits al array creado
       bitmapSource.CopyPixels(imageBits, stride, 0);
    
       try
       {
        // codigo no manejado para manejar punteros al estilo c++
        unsafe   
        {
         // fijar la variable administrada (para que no la use el recolector)
         fixed (byte* pImageBits = imageBits)    
         {
          // crear un puntero manejado
          handle = new IntPtr(pImageBits);
          // crear el Bitmap con los datos del bitmapsource
          bmp = new System.Drawing.Bitmap(bitmapSource.PixelWidth, bitmapSource.PixelHeight, stride,
           System.Drawing.Imaging.PixelFormat.Format32bppArgb, handle);    
         }   
        }
       }
       finally
       {
        // eliminar el manejador del GDI
        DeleteObject(handle);
       }
    
       //--------------------------------------------------------------------------------------------------
       // volver Pasar del 'System.Drawing.Bitmap' convertido a un Windows.Controls.Image para visualizarlo
       System.Drawing.Image image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
          
       handle = IntPtr.Zero;
       try
       {
        // obtener el manejador
        handle = ((System.Drawing.Bitmap)image).GetHbitmap();
        // establecer la fuente en System.windows.image
        image2.Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty,
         BitmapSizeOptions.FromEmptyOptions());
       }
       finally
       {
        // eliminar el manejador del GDI
        DeleteObject(handle);
       }
    

     

    En este codigo estan las dos alternativas de Controls.Image a Drawing.Image y viceversa. la ultima vuelve a convertir el Drawing.Image para poder visualizar el resultado en otro control de imagen.

    NOTA: como para la conversion es necesario acceder al puntero del array manejado, se necesita habilitar el codigo no seguro /unsafe (se puede realizar desde las propiedades del proyecto, pestaña general->permitir codigo no seguro) y fijar la variable para que no la mueva el recolector (aunque es posible que no haga falta, es lo ideal).

    Ademas, se hace uso de la funcion DeleteObject del GDI para eliminar el handle del bitmap, con lo que se tiene que declarar una funcion como esta:

      /// <summary>
      /// Libreria de WIN32 para hacer uso de funciones del GDI
      /// </summary>
      [System.Runtime.InteropServices.DllImport("gdi32.dll")]
      static extern bool DeleteObject(IntPtr hObject);
    

    Y con esto es todo, creo que no me he dejado ninguna fuga de memoria, de todas formas tendras que coger solo el codigo que te interese y lo optimizas mejor.

    Pruebalo y cuentas que tal.

     


    Saludos
    David González
    MCP, MCTS
    Visita mi Blog en: http://www.dgzornoza.com/

    • Marcado como respuesta jcloquell martes, 14 de junio de 2011 15:08
    viernes, 10 de junio de 2011 19:16
  • Hola, muchas gracias!

    Pongo aqui mi parte de la solución:

    List<Image> FindAllImagesInParagraph(Paragraph paragraph)
    {
      List<Image> result = null;
    
      foreach (var inline in paragraph.Inlines)
      {
        var inlineUIContainer = inline as InlineUIContainer;
        if (inlineUIContainer != null)
        {
          var image = inlineUIContainer.Child as Image;
    
          if (image != null)
          {
            if (result == null)
              result = new List<Image>();
    
            result.Add(image);
          }
        }
      }
    
      return result;
    }
    
    private List<Image> FindAllImagesInDocument(FlowDocument Document)
    {
      List<Image> result = new List<Image>();
    
      foreach (var block in Document.Blocks)
      {
        if (block is Table)
        {
          var table = block as Table;
    
          foreach (TableRowGroup rowGroup in table.RowGroups)
          {
            foreach (TableRow row in rowGroup.Rows)
            {
              foreach (TableCell cell in row.Cells)
              {
                foreach (var block2 in cell.Blocks)
                {
                  if (block2 is Paragraph)
                  {
                    var paragraph = block2 as Paragraph;
                    var images = FindAllImagesInParagraph(paragraph);
                    if (images != null)
                      result.AddRange(images);
                  }
    
                  else if (block2 is BlockUIContainer)
                  {
                    var container = block as BlockUIContainer;
                    if (container.Child is Image)
                    {
                      var image = container.Child as Image;
                      result.Add(image);
                    }
                  }
                }
              }
            }
          }
        }
    
        else if (block is Paragraph)
        {
          var paragraph = block as Paragraph;
          var images = FindAllImagesInParagraph(paragraph);
          if (images != null)
            result.AddRange(images);
        }
    
        else if (block is BlockUIContainer)
        {
          var container = block as BlockUIContainer;
          if(container.Child is Image)
          {
            var image = container.Child as Image;
            result.Add(image);
          }
        }
      }
    
      return result.Count > 0 ? result : null;
    }
    

     

    Gracias por la ayuda
    martes, 14 de junio de 2011 15:11