ThinkGeo.com    |     Documentation    |     Premium Support

Pdf Extension

Hi ThinkGeo team,


I am using simpleMarkerOverlay to plot my points on the map. Now I want to export that map to Pdf file but I am getting stack because it seems Pdf extesions work with staticOverlays of the map control only. I am using CustomOverlay of the map control. In this case how can I get my map exported to Pdf file?


Best Regards,


Vincent



 


Hi Vincent,
Exporting the PDF canvas works on server side, it’s very similar to the scenario that we create a Graphics and get the data to draw. However, the client side overlay, such as MarkerOverlay, popup, just get the data from server side and are rendered on client side. To get around it, we can create an InMemoryFeatureLayer to replace the SimpleMarkerOverlay when printing the map into PDF.
Hope everything works with you. Thanks,
Johnny   

Hi Johnny


Thank you for the reply. Basically I am implementing simpleMarkerOverlay for the purpose of maintaining markers that are using my own custom images. Now I have failed to figure out how to implement InmemoryFeatureLayer on one hand, while maintaining markers with custom images and popups on the other hand.


Can you give me a simple sample code showing how to go about this.


Best Regards,


Vincent



Hi Vincent,  
  
 Before the source code provided, I have two items to show you: 
 1.Do all the markers share the same custom images or different ones? If the same one, we just need to create one InMemoryFeatureLayer to present the markerOverlay, otherwise, we need several ones. 
 2.Do you want to export the markers with Popup shown? Maybe we are unable to print the Popups to the PDF canvas. 
  
 Thanks, 
 Johnny 


Hi Vincent,


Here is a simple demo code about creating InMemoryFeatureLayer based on SimpleMarkerOlverlay:




InMemoryFeatureLayer markerRepresentLayer = new InMemoryFeatureLayer();

markerRepresentLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = new PointStyle(new GeoImage("Your custom Image path"));

markerRepresentLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

// Add the markers as points into InMemoryFeatureLayer

markerRepresentLayer.Open();

foreach (Marker marker in markerOverlay.Markers)

{

  Feature feature = new Feature(marker.Position);

  markerRepresentLayer.FeatureSource.AddFeature(feature);

}




Thanks,


Johnny  



Hi Johnny


Thank you for the reply. I have encountered one challenge when implementing the code you have provided. In my scenario I put marker images of different color based on particular criteria met by an individual feature as shown in the code below.


 


for (int i = 0; i < datatable.Rows.Count; i++)
            {
                DataRow rw = datatable.Rows[i]; ;
                String x = rw["X"].ToString();
                String y = rw["Y"].ToString();
                Int16 indicator = Int16.Parse(rw["Indicator"].ToString());

              
                String CustomerRefNo = rw["CustomerRefNo"].ToString();

                String Remarks = rw["Remarks"].ToString();

                Vertex projectedVertex = projction.ConvertToExternalProjection(double.Parse(x), double.Parse(y));

                if (indicator == 1)
                {
                    pushpin = "./theme/default/img/marker_blue.gif";
                    
                }
                else if (indicator == 2)
                {
                    pushpin = "./theme/default/img/marker_gold.gif";
                  
                }
               

                Marker marker = new Marker(projectedVertex.X, projectedVertex.Y, new WebImage(pushpin, 21, 25, -10.5f, -10f));
               
                marker.Popup.ContentHtml = Remarks;
                marker.Popup.AutoSize = true;                
                markerOverlay.Markers.Add(marker);

               
            }

Is there any way we can modify the code you have provided to meet this need?


Best Regards,


Vincent



 


Hi, Vincent
Here is one workaround for you.
First off, call the method of GetBitMap of Map control and then you will get the returned image with feature data of FeatureLayer and Makers.
And then draw this image on the PdfDocument using PdfGeoCanvas.
We made one simple sample depend on the “UsePdfExtension” installed sample for you. Please refer to it.
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Web.UI;
using PdfSharp;
using PdfSharp.Pdf;
using ThinkGeo.MapSuite.Core;
using ThinkGeo.MapSuite.WebEdition;
 
namespace CSSamples.Samples.Extending_MapSuite
{
    public partial class UsePdfExtension : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                Map1.MapUnit = GeographyUnit.DecimalDegree;
                Map1.CurrentExtent = new RectangleShape(-111.7875, 92.0859375, 148.36875, -93.5390625);
                Map1.MapBackground.BackgroundBrush = new GeoSolidBrush(GeoColor.GeographicColors.ShallowOcean);
 
                EcwRasterLayer worldImageLayer = new EcwRasterLayer(MapPath("~/SampleData/world/World.ecw"));
 
                ShapeFileFeatureLayer worldLayer = new ShapeFileFeatureLayer(MapPath("~/SampleData/world/cntry02.shp"));
                worldLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.Country1;
                worldLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle.OutlinePen.StartCap = DrawingLineCap.Round;
                worldLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle.OutlinePen.EndCap = DrawingLineCap.Round;
                worldLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
 
                ShapeFileFeatureLayer usStatesLayer = new ShapeFileFeatureLayer(MapPath("~/SampleData/USA/STATES.SHP"));
                usStatesLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.State2;
                usStatesLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle.OutlinePen.StartCap = DrawingLineCap.Round;
                usStatesLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
 
                ShapeFileFeatureLayer worldCapitalsLayer = new ShapeFileFeatureLayer(MapPath("~/SampleData/world/capital.shp"));
                worldCapitalsLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyles.City4;
                worldCapitalsLayer.DrawingMarginPercentage = 80;
                worldCapitalsLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
 
                ShapeFileFeatureLayer worldCapitalsLabelsLayer = new ShapeFileFeatureLayer(MapPath("~/SampleData/world/capital.shp"));
                worldCapitalsLabelsLayer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle = TextStyles.Capital1("city_name");
                worldCapitalsLabelsLayer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle.HaloPen = new GeoPen(GeoColor.StandardColors.White, 2);
                worldCapitalsLabelsLayer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle.HaloPen.StartCap = DrawingLineCap.Round;
                worldCapitalsLabelsLayer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle.HaloPen.EndCap = DrawingLineCap.Round;
                worldCapitalsLabelsLayer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle.SuppressPartialLabels = true;
                worldCapitalsLabelsLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
 
                Map1.StaticOverlay.Layers.Add("WorldImageLayer", worldImageLayer);
                Map1.StaticOverlay.Layers.Add("WorldLayer", worldLayer);
                Map1.StaticOverlay.Layers.Add("USStatesLayer", usStatesLayer);
                Map1.StaticOverlay.Layers.Add("WorldCapitals", worldCapitalsLayer);
                Map1.StaticOverlay.Layers.Add("WorldCapitalsLabels", worldCapitalsLabelsLayer);
 
                SimpleMarkerOverlay markerOverlay = new SimpleMarkerOverlay("MarkerOverlay");
                Marker marker = new Marker(-94.558, 39.078, new WebImage("../../theme/default/img/marker_gold.gif", 21, 25, -10.5f, -25f));
                marker.Popup.ContentHtml = "ContentHTML";
                marker.Popup.AutoSize = true;
                marker.IsVisible = true;
                markerOverlay.Markers.Add(marker);
 
                Map1.CustomOverlays.Add(markerOverlay);
            }
        }
 
        protected void btnToPdf_Click(object sender, EventArgs e)
        {
            PdfDocument document = new PdfDocument();
            PdfPage page = document.AddPage();
            if (rdlOptions.SelectedItem.Text == "Landscape")
            {
                page.Orientation = PageOrientation.Landscape;
            }
 
            PdfGeoCanvas pdfGeoCanvas = new PdfGeoCanvas();
 
            RectangleShape printExtent = ExtentHelper.GetDrawingExtent(Map1.CurrentExtent, (float)Map1.WidthInPixels, (float)Map1.HeightInPixels);
            pdfGeoCanvas.BeginDrawing(page, printExtent, GeographyUnit.DecimalDegree);
            
            Bitmap bitmap = Map1.GetBitmap();
            MemoryStream stream = new MemoryStream();
            bitmap.Save(stream, ImageFormat.Png);
            PointShape centerPoint = pdfGeoCanvas.CurrentWorldExtent.GetCenterPoint();
            
            pdfGeoCanvas.DrawWorldImageWithoutScaling(new GeoImage(stream), centerPoint.X, centerPoint.Y, DrawingLevel.LabelLevel);
            
            pdfGeoCanvas.EndDrawing();
 
            string filename = @"c:\temp\MapSuite PDF Map.pdf";
            document.Save(filename);
            OpenPdfFile(filename);
       }
 
        private static void OpenPdfFile(string filename)
        {
            try
            {
                Process.Start(filename);
            }
            catch (Win32Exception ex)
            {
                if (ex.Message == "No application is associated with the specified file for this operation")
                {
                    //string message = "You can't open Pdf file, the reason maybe you don't install Adobe Reader\r\n\r\n" + ex.ToString();
                    //MessageBox.Show(message, "Open Pdf file failed", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, (MessageBoxOptions)0);
                    ProcessStartInfo psi = new ProcessStartInfo(@"C:\WINDOWS\system32\rundll32.exe");
                    psi.Arguments = @" C:\WINDOWS\system32\shell32.dll, OpenAs_RunDLL " + filename;
                    Process.Start(psi);
                }
            }
        }
    }
}
 
 
For the text on the marker, and I remember that you used the InMemoryFeatureLayer to display the text of marker, so you just need to put it in the StaticOverlay or other overlays on the top of other FeatureLayers.
Thanks,
Khalil

Hi Khalil


Thank you for the solution. It has worked but I am still facing some challenges as follows


1. The map on the Pdf file is extremely faint that one can hardly see it


2. My legend that describes the features on the map has been left out


3. When I set page size to A0, alot of space is left unused on the Pdf file and the resulting map draw is not actually A0


 


Best Regards,


Vincent



 


Hi, Vincent
What do you mean by saying that “The map on the Pdf file is extremely faint that one can hardly see it”, please attach one screenshot or sample code to clarify your problem.
How do you use your legend? With InMemoryFeatureLayer or AdornmentLayer?
For your third question, I have tried to set the page size as A0, and it works as I expected. The size of A0 is 33.1 × 46.8 in, so I am sure that there are a lot of space is left unused, and the image or feature data will be drawn on the PdfGeoCanvas depends on the extent or position you have specified.
Thanks,
Khalil 

 



Hi Khalil


Thank you for the reply. When I say a map on the Pdf file I mean how the map looks like when open on the pdf file. I have attached an image showing how the map looks like on the pdf file. Observe how faint it is and how big the empty space left unfilled is. Also can you give me means of making it fill the entire page (e.g. A1) as well as making map legend visible on the resulting open pdf file. I am using a float description panel for creating legend. Below is the code that I have used to generate the file.


 


 


 public void ToPdf(object sender, EventArgs e)
        {
            
            string pageSize = this.PageSise.SelectedValue;


            PdfDocument document = new PdfDocument();
            PdfPage page = document.AddPage();
            page.Size = GetPageSize(pageSize);
           
                page.Orientation = PageOrientation.Landscape;
            

            PdfGeoCanvas pdfGeoCanvas = new PdfGeoCanvas();

            RectangleShape printExtent = ExtentHelper.GetDrawingExtent(Map1.CurrentExtent, (float)Map1.WidthInPixels, (float)Map1.HeightInPixels);
            pdfGeoCanvas.BeginDrawing(page, printExtent, GeographyUnit.DecimalDegree);

            Bitmap bitmap = Map1.GetBitmap();
            MemoryStream stream = new MemoryStream();
            bitmap.Save(stream, ImageFormat.Png);
            PointShape centerPoint = pdfGeoCanvas.CurrentWorldExtent.GetCenterPoint();

            pdfGeoCanvas.DrawWorldImageWithoutScaling(new GeoImage(stream), centerPoint.X, centerPoint.Y, DrawingLevel.LabelLevel);

            pdfGeoCanvas.EndDrawing();

            string filename = "MapSuite PDF Map.pdf";
            document.Save(filename);           
            Process.Start(filename);
        }


        private PageSize GetPageSize(string pageSize)
        {
            switch (pageSize)
            {
                case "A1":
                    return PageSize.A1;
                case "A2":
                    return PageSize.A2;
                case "A4":
                    return PageSize.A4;
                default:
                    return PageSize.A4;
            }
        }


FaintImage.JPG (6.02 KB)

 


Hi, Vincent
I doubted that whether you have set the page size of the PDF file to 100 percent or actual size on the Adobe Reader or other PDF Reader software? By default it’s a value less than its actual size so that you will see lots of space left. Another reason is that your map size is two small compared with the size of pdf file, so that you draw it on the pdf file and then the blank space will be lfet unfilled. 
Another thing is that if you have set the page size to A1 (23.4 × 33.1in) and you want to make it full the entire page, the alternate solution is to set the same width and height with the page size. That means you need to set the map width as 33.1 * DPI, and the height as 23.4 * DPI, the DPI you can choose to 96.
I have tested it and it works as we expected.
Thanks,
Khalil

Hi Khalil


Thank you for the reply. In fact I do not understand when you say "set the map width as 33.1 * DPI". Can you please elaborate a bit and if possible with a single line of code.


Best Regards,


Vincent



 


Hi, Vincent
The DPI is the dots per inch for your screen, so you need it to set the same width and height  with the PDF file.
Please see the attached sample for detailed information.
Thanks,
Khalil

Extending_MapSuite.zip (3.11 KB)

Hi Khalil


Thank you for the solution. What can I do to get my legend drawn on the resulting pdf file? I am using float description panel to create legend.


Best regards,


Vincent



 


Hi, Vincent
No, we can’t render the float description panel in the PDF file, which is composed with html tag of client-side.
But from the sample I provided for you, and you can see that we can render any images on the PDF file, so maybe this is the better choice for you.
Thanks,
Khalil

Hi Khalil


Thank you for the replay


I looked at the sample you provided but I could not figure out how to render a float description panel in pdf file.


Best Regards,


Vinvent



 


Hi, Vincent
We can’t render the description panel using PDF extension on the server-side. Here is one workaround for you temporarily. If the legend is static and doesn’t change very frequently and I suggest that you replace it with one legend image and then you can utilize the LogoAdornmentLayer to render it on the map. 
Because it’s an image so that we can render it in the PDF file.
Thanks,
Khalil

Hi Khalil


Thank you for the reply


Actually I have not used LogoAdornmentLayer and to help me, could you please give me a simple sample code showing how to use LogoAdornmentLayer or resource location where I can get it.


Best Regards,


Vincent



 


Hi, Vincent
We have a code project named “Graphic Logo for Web” to show users how to use the LogoAdornmentLayer. Please download it from the link below:
wiki.thinkgeo.com/wiki/Map_Suite_Web_Edition_All_Samples#Graphic_Logo_for_Web
Thanks,
Khalil

Hi Khalil


Thank you for the solution. It has worked. But I have a problem. When I export to pdf a Map overlayed with image, the image is not as clearly seen as it should. I have attached two images 


1. FaintImage - It is not clearly seen


2. ClearImage - This is how the image should appear on pdf file


Best Regards,


Vincent


 



001_FaintImage.JPG (36.1 KB)
ClearImage.JPG (92.2 KB)