2008-10-21 5 views
9

Background: Je travaille sur une application silverlight (1.0) qui construit dynamiquement une carte des États-Unis avec des icônes et du texte superposés à des endroits spécifiques. La carte fonctionne très bien dans le navigateur et maintenant je dois obtenir une copie statique (imprimable et insérable dans les documents/powerpoints) d'une carte affichée.Mise à l'échelle du contenu WPF avant le rendu en bitmap

Objectif: Afin d'obtenir une copie imprimable de la carte qui peut également être utilisée dans les diapositives Powerpoint, Word, etc. WPF et ensuite rendre le WPF à une image bitmap qui est retournée en tant que fichier png, généré à 300 dpi pour une meilleure qualité d'impression.

Problème: Cela fonctionne très bien avec un problème, je ne peux pas obtenir l'image à l'échelle à une taille spécifiée. J'ai essayé plusieurs choses différentes, dont certaines peuvent être vues dans les lignes commentées. Je dois être en mesure de spécifier une hauteur et une largeur de l'image, soit en pouces ou en pixels, je ne me soucie pas nécessairement de qui, et avoir l'échelle xaml à cette taille pour le bitmap généré. Actuellement, si je rends la taille supérieure à la toile racine, le canevas est rendu à sa taille d'origine dans le coin supérieur gauche de l'image générée à la taille spécifiée. Voici la partie importante de mon httphandler. La toile racine stockée sous la forme "MyImage" a une hauteur de 600 et une largeur de 800. Que dois-je faire pour que le contenu s'adapte à la taille spécifiée?

Je ne comprends pas parfaitement ce que les dimensions passées dans Arrange() et Measure() font car une partie de ce code provient d'exemples en ligne. Je ne comprends pas complètement le truc de RenderTargetBitmap. Toute orientation serait appréciée.

Public Sub Capture(ByVal MyImage As Canvas) 
    ' Determine the constraining scale to maintain the aspect ratio and the bounds of the image size 
    Dim scale As Double = Math.Min(Width/MyImage.Width, Height/MyImage.Height) 

    'Dim vbox As New Viewbox() 
    'vbox.Stretch = Stretch.Uniform 
    'vbox.StretchDirection = StretchDirection.Both 
    'vbox.Height = Height * scale * 300/96.0 
    'vbox.Width = Width * scale * 300/96.0 
    'vbox.Child = MyImage 

    Dim bounds As Rect = New Rect(0, 0, MyImage.Width * scale, MyImage.Height * scale) 
    MyImage.Measure(New Size(Width * scale, Height * scale)) 
    MyImage.Arrange(bounds) 
    'MyImage.UpdateLayout() 

    ' Create the target bitmap 
    Dim rtb As RenderTargetBitmap = New RenderTargetBitmap(CInt(Width * scale * 300/96.0), CInt(Height * scale * 300/96.0), 300, 300, PixelFormats.Pbgra32) 

    ' Render the image to the target bitmap 
    Dim dv As DrawingVisual = New DrawingVisual() 
    Using ctx As DrawingContext = dv.RenderOpen() 
     Dim vb As New VisualBrush(MyImage) 
     'Dim vb As New VisualBrush(vbox) 
     ctx.DrawRectangle(vb, Nothing, New Rect(New System.Windows.Point(), bounds.Size)) 
    End Using 
    rtb.Render(dv) 

    ' Encode the image in the format selected 
    Dim encoder As System.Windows.Media.Imaging.BitmapEncoder 
    Select Case Encoding.ToLower 
     Case "jpg" 
      encoder = New System.Windows.Media.Imaging.JpegBitmapEncoder() 
     Case "png" 
      encoder = New System.Windows.Media.Imaging.PngBitmapEncoder() 
     Case "gif" 
      encoder = New System.Windows.Media.Imaging.GifBitmapEncoder() 
     Case "bmp" 
      encoder = New System.Windows.Media.Imaging.BmpBitmapEncoder() 
     Case "tif" 
      encoder = New System.Windows.Media.Imaging.TiffBitmapEncoder() 
     Case "wmp" 
      encoder = New System.Windows.Media.Imaging.WmpBitmapEncoder() 
    End Select 
    encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(rtb)) 

    ' Create the memory stream to save the encoded image. 
    retImageStream = New System.IO.MemoryStream() 
    encoder.Save(retImageStream) 
    retImageStream.Flush() 
    retImageStream.Seek(0, System.IO.SeekOrigin.Begin) 
    MyImage = Nothing 
End Sub 

Répondre

13

Cela devrait être suffisant pour vous lancer:


private void ExportCanvas(int width, int height) 
{ 
    string path = @"c:\temp\Test.tif"; 
    FileStream fs = new FileStream(path, FileMode.Create); 


    RenderTargetBitmap renderBitmap = new RenderTargetBitmap(width, 
                  height, 1/300, 1/300, PixelFormats.Pbgra32); 

    DrawingVisual visual = new DrawingVisual(); 
    using (DrawingContext context = visual.RenderOpen()) 
    { 
     VisualBrush brush = new VisualBrush(MyCanvas); 
     context.DrawRectangle(brush, 
           null, 
           new Rect(new Point(), new Size(MyCanvas.Width, MyCanvas.Height))); 
    } 

    visual.Transform = new ScaleTransform(width/MyCanvas.ActualWidth, height/MyCanvas.ActualHeight); 

    renderBitmap.Render(visual); 

    BitmapEncoder encoder = new TiffBitmapEncoder(); 
    encoder.Frames.Add(BitmapFrame.Create(renderBitmap)); 
    encoder.Save(fs); 
    fs.Close(); 
} 
+0

Cela a fini par me inspirer pour trouver la bonne solution si je l'ai marqué comme la réponse mais ci-dessous est le code qui a vraiment travaillé pour moi. –

1

C'est ce qui a fini par travailler pour moi:

Public Sub Capture(ByVal MyImage As Canvas) 
     ' Normally we would obtain a user's configured DPI setting to account for the possibilty of a high DPI setting. 
     ' However, this code is running server side so the client's DPI is not obtainable. 
     Const SCREEN_DPI As Double = 96.0 ' Screen DPI 
     Const TARGET_DPI As Double = 300.0 ' Print Quality DPI 

     ' Determine the constraining scale to maintain the aspect ratio and the bounds of the image size 
     Dim scale As Double = Math.Min(Width * SCREEN_DPI/MyImage.Width, Height * SCREEN_DPI/MyImage.Height) 

     ' Setup the bounds of the image 
     Dim bounds As Rect = New Rect(0, 0, MyImage.Width * scale, MyImage.Height * scale) 
     MyImage.Measure(New Size(MyImage.Width * scale, MyImage.Height * scale)) 
     MyImage.Arrange(bounds) 

     ' Create the target bitmap 
     Dim rtb As RenderTargetBitmap = New RenderTargetBitmap(CDbl(MyImage.Width * scale/SCREEN_DPI * TARGET_DPI), CDbl(MyImage.Height * scale/SCREEN_DPI * TARGET_DPI), TARGET_DPI, TARGET_DPI, PixelFormats.Pbgra32) 

     ' Render the image to the target bitmap 
     Dim dv As DrawingVisual = New DrawingVisual() 
     Using ctx As DrawingContext = dv.RenderOpen() 
      Dim vb As New VisualBrush(MyImage) 
      ctx.DrawRectangle(vb, Nothing, New Rect(New System.Windows.Point(), bounds.Size)) 
     End Using 
     ' Transform the visual to scale the image to our desired size. 
     'dv.Transform = New ScaleTransform(scale, scale) 

     ' Render the visual to the bitmap. 
     rtb.Render(dv) 

     ' Encode the image in the format selected. If no valid format was selected, default to png. 
     Dim encoder As System.Windows.Media.Imaging.BitmapEncoder 
     Select Case Encoding.ToLower 
      Case "jpg" 
       encoder = New System.Windows.Media.Imaging.JpegBitmapEncoder() 
      Case "png" 
       encoder = New System.Windows.Media.Imaging.PngBitmapEncoder() 
      Case "gif" 
       encoder = New System.Windows.Media.Imaging.GifBitmapEncoder() 
      Case "bmp" 
       encoder = New System.Windows.Media.Imaging.BmpBitmapEncoder() 
      Case "tif" 
       encoder = New System.Windows.Media.Imaging.TiffBitmapEncoder() 
      Case "wmp" 
       encoder = New System.Windows.Media.Imaging.WmpBitmapEncoder() 
      Case Else 
       encoder = New System.Windows.Media.Imaging.PngBitmapEncoder() 
     End Select 
     encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(rtb)) 

     ' Create the memory stream to save the encoded image. 
     retImageStream = New System.IO.MemoryStream() 
     encoder.Save(retImageStream) 
     retImageStream.Flush() 
     retImageStream.Seek(0, System.IO.SeekOrigin.Begin) 
     MyImage = Nothing 
    End Sub 
+0

Je pense que vous pourriez manquer la ligne qui insère le cadre dans l'encodeur. – bryanbcook

Questions connexes