ThinkGeo.com    |     Documentation    |     Premium Support

Printing using PrinterGeoCanvas

Do you guys have a sample on how to use the PrinterGeoCanvas to print the map?


TIA.



Hi Klaus, 



Here is a related post to use PrinterGeoCanvas to print the map. But not everything on the map can be printed except layers. Please check this post and let me know if you have more queries. 

gis.thinkgeo.com/Support/Dis...fault.aspx



Thanks, 

Howard



Let me give it  a try Howard, thanks.



Howard,  two quick questions regarding the post :


- How to i get map canvas to pass to getImageFromControl


Does PrinterGeoCanvas.BeginDrawing accept a FlowDocument as nativeImage.  I want to use System.Windows.Controls.PrintDialog instead.Thanks again.



Hi Klaus, 
  
 You don’t need get the canvas to pass; here you can change the canvas type to UIElement directly to pass map directly. I think that’s what you want. 
  
 For the other issue, PrinterGeoCanvas doesn’t support FlowDocument as nativeImage; if it’s needed, you can rewrite your own GeoCanvas to support it if possible. Sorry for the inconvenience. 
  
 Thanks, 
 Howard

  Hi - I have been trying to follow this example, with the exception that I would like to just write the map image as an image file to the system (mymap.bmp).  I've been trying to get the printerGeoCanvas to give me the native image, but that is always null.  The correct image does go to the printer, but I really don't need it to do that directly.  I've also tried turning on the printToFile = true and setting a path name there, but that just generates a 0 byte image.  


The API seems to be somewhat confusing to me in regards to what is a native image vs. a geo image, etc.  Are there any examples that will walk through saving the map display to an image file in bmp or png?  (I've also seen a forum example on PDF creation, but my users want images that they can combine/manipulate rather than PDFs.)


 


Thanks,


Mikkel



Mikkel,


  GeoImage is something like an object, you can inherit and rewrite it, so your graphic object will become a GeoImage, then the GeoCanvas could transform GeoImage into a steam and draw it.

  

I will write a sample as soon as i can, please let me know if you have more questions.

  

Thanks


James



 Still having no luck with this.  My print method is as follows:  THe code blows up on the bitmap save method, whether I keep it as a bitmap and just pass a filename or if I try to convert to a jpg as below.  It appears as though the NativeImage property is null - any ideas on why that would be?


 



 private void PrintButton_Click(object sender, RoutedEventArgs e)


        {


            PrinterGeoCanvas printerGeoCanvas = new PrinterGeoCanvas();


            //PrintDialog Dialog1 = new PrintDialog();


 


            Collection<SimpleCandidate> labelsInLayers = new Collection<SimpleCandidate>();


            string imgFilename = @"c:\temp\ltmoMapImage" + DateTime.Now.Millisecond.ToString() + ".jpg";


            PrintDocument document = new PrintDocument();


            printerGeoCanvas.DrawingArea = new Rectangle(0, 0, (int)wpfMap1.Width, (int)wpfMap1.Height);


            printerGeoCanvas.BeginDrawing(document, wpfMap1.CurrentExtent, wpfMap1.MapUnit);


            foreach (LayerOverlay layeroverlay in wpfMap1.Overlays)


            {


                foreach (Layer layer in layeroverlay.Layers)


                {


                    layer.Open();


                    layer.Draw(printerGeoCanvas, labelsInLayers);


                    layer.Close();


                    printerGeoCanvas.Flush();


          }


            }


            printerGeoCanvas.EndDrawing();


            FileStream fs = File.OpenWrite(imgFilename);


            Bitmap myBmp = (Bitmap)(printerGeoCanvas.NativeImage);


            myBmp.Save(fs, System.Drawing.Imaging.ImageFormat.Jpeg);


            fs.Flush();


            fs.Close();


        }




Mikkel, 
  
 Thanks for your sample code. 
  
 If you call EndDrawing() method, the NativeImage of GeoCanvas will be set to null, so you can try to get NativeImage before EndDrawing(). 
  
 Thanks, 
 James

Do you have an example of printing using the WPF PrintDialog? 
  
 Thanks, 
 .Ryan.

Hi Ryan, 
  
 Printing the map by using the PrintDialog control in WPF is very convenient, especially when the scenario is not very complicated. 
 For example, if you want to print the whole map, you just need to create an instance of PrintDialog, call its PrintVisual method and pass the map in as a parameter. 
 If your scenario is more complicated than just printing the whole map, then please let us know, we do have some advanced approaches that might be of help. 
  
 Regards, 
 Tsui

Hi Tsui, 
  
 Thanks for the reply.  I have done that but have run into a couple issues. 
  
 1) I’ve set in the print options to scale my image, but when the map prints, it is off-center (If I have the entire US centered on my screen, when it prints it is on the right side, however my upper-left location seems to be correct.  This may be an issue with something I’m doing wrong or not setting, unsure. 
  
 2) This isn’t really an issue, more a question.  How does this scale if I say print to a plotter?  Will it keep all my lines looking crisp when the map is printed larger than it is in my application?  Or does it even scale? 
  
 Thanks for your time and help, 
  
 .Ryan.

Hi Ryan, 
  
 The approach I mentioned is only suitable for simple scenarios. What you need seems to be more complicated. 
 Unlike most built-in wpf controls in the .net framework that are rendered by drawing visual, WpfMap is composed of multiple bitmaps by default, which means it can’t automatically scale when being printed. 
 We do have a drawing visual mode in the wpf edition, and it’s scalable when being printed. But it still has some issues so we don’t recommend you to use it by now. 
  
 We’d suggest you to follow these steps when printing map: 
 1. Show the PrintDialog. 
 2. If the user clicks “ok” on the PrintDialog, save the PrintableAreaWidth and PrintableAreaHeight properties of PrintDialog. These two properties indicate the size of the paper. 
 3. Use those two values to construct a bitmap, use GeoCanvas to draw all overlays in the map to this bitmap. 
 4. Wrap this bitmap into a WPF Image control, and then use PrintDialog.PrintVisual to print this image. 
  
 This approach is not very easy to use, but it makes sure the printing result is not distorted. 
  
 Please let us know if you have any further question. 
  
 Regards, 
 Tsui

Is it possible to draw MarkerOverlay’s to a GeoCanvas?  Looking at the API, I don’t see a way to do this easily? 
  
 Thanks, 
  
 .Ryan.

Hi Ryan, 
  
 MakerOverlay is different from other overlays; it’s not using GDI+ to render its contents, all its contents are native wpf controls. 
 If you want to make sure the printing result of a MarkerOverlay is not distorted, we’d suggest you to create an InMemoryFeatureLayer on the fly and draw the layer to the bitmap. The InMemoryFeatureLayer should have a similar style to the MarkerOverlay. 
  
 Regards, 
 Tsui

This works great except none of my labels print.  Any ideas on how to get layers with labels printing? 
  
 Thanks, 
 .Ryan.

Note my last post was regarding ShapeFileFeatureLayers, not anything to do with MarkerOverlay, I got that to work fine.

Actually it seems like its a bug on my end… maybe something to do w/ scale changing, although I’m using the map extent to do the drawing… will have to do more research tomorrow to figure out exactly what is happening.

Hi Ryan, 
  
 I don’t know the details of your program, but I guess you can try to call the EndDrawing method of GeoCanvas after all layers are drawn. 
 Please let us know if this works. We’ll figure something else out if it doesn’t work. 
  
 Regards, 
 Tsui

I've uploaded 2 pdf files of my map at the exact same zoom printed to pdf.  One is portrait and one is landscape.  As you can see, the one that is portrait has no labels.  I didn't want my image to look squished or stretched, so I used the following code to scale the map image to be best fit to the page


PrintDialog Dialog1 = new PrintDialog();



            if (Dialog1.ShowDialog().Value)

            {

                GdiPlusGeoCanvas canvas = new GdiPlusGeoCanvas();

                double wsc = (double)Dialog1.PrintableAreaWidth / (double)this.Map.ActualWidth;

                double hsc = (double)Dialog1.PrintableAreaHeight / (double)this.Map.ActualHeight;



                double sc = Math.Min(wsc, hsc);



                Bitmap b = new Bitmap((int)(Map.ActualWidth * sc), (int)(Map.ActualHeight * sc));

                canvas.BeginDrawing(b, this.Map.CurrentExtent, this.Map.MapUnit);


                ...


 


This keeps the proper ratios, but I'm guessing is what makes the labels show and not.  Ideally, I'd like to have what prints be in the same style as what is displayed to the user in the application, which in this case, has labels.


Any ideas would be appreciated.  Thanks so much for your help.


.Ryan.



portrait.pdf (45 KB)
landscape.pdf (67.6 KB)