ThinkGeo.com    |     Documentation    |     Premium Support

Questions on export as image?

I am looking at the example of exporting map as image and pdf, and have two questions:



The documents are REALLY bad! basically no document. help pls!


        
  1. In the function SetupMapWithBlankPage(), why do we need to set up a PrinterZoomLevleSet to Map? I already have a customized ZoomLevelSet. Does it overwrite my map configuration?
        

              
    1. the code is Map1.ZoomLevelSet = new PrinterZoomLevelSet(Map1.MapUnit, PrinterHelper.GetPointsPerGeographyUnit(Map1.MapUnit))

    2.     

        

  2.     
  3. Does this function require map unit to be in feet or meters? I see in the function AddMapLayer(), the codes re-project the worldMapLayer from DecimalDegree to meter. Is this just for Printing? The codes are like:


ShapeFileFeatureLayer worldMapLayer = new ShapeFileFeatureLayer(MapPath(@"~\SampleData\Countries02.shp"));


 worldMapLayer.FeatureSource.Projection = new Proj4Projection(Proj4Projection.GetDecimalDegreesParametersString(), Proj4Projection.GetGoogleMapParametersString());


 worldMapLayer.FeatureSource.Projection.Open();


 worldMapLayer.Open();



thanks,



Guangming


 



Hi Guangming,



The printer sample you are looking for does look a bit complex, I will try to explain it and your issues below:

In the printer sample, actually, we don’t need to care about the map instance, if we only want to print some layers, then we don’t need this map but only the MapPrinterLayer and some other adornment PrinterLayer is enough. The MapPrinterLayer will include all the layers like worldlayer, shape file layer etc and we need to set its mapunit and map extent based on those layers. (please see method AddMapLayer around line 53)



As for the other adornment  PrinterLayer like ScaleLinePrinterLayer,labelPrinterLayer,DataGridPrinterLayer,ImagePrinterLayer, we can still draw them on GdiPlusGeoCanvas if exporting bitmap or PdfGeoCanvas if pdf. (see method btnToBitmap_Click or btnToPDF_Click)



So, as for your questions:

#1: the sample map is only used to see what we will print, but not related with the real map in your application map. So, we don’t need to care its zoomlevelset or other things on this map. I think we can treat there are two map instance, one is yours to show to end-users and the other one is for printing preview show.

#2: yes, those layers and its map unit is only used for printing and not related with its original map unit. The key is we add those layers into the  MapPrinterLayer and its MapUnit and MapExtent is very important to set.



Hope it helps and any questions, please feel free to let us know.

Thanks,

Troy

cool, this helps! 
  
 do I care that blank page: added in the function SetupMapWithBlankPage()? 
  
 because all my layers are in decimaldegree, so I should re-project all into feet/meter as in the example, before adding to MapPrinterLayer? 
  
 Thanks,

guangming,



No, we don’t need to care about the blankpage if you don’t want to add.

As for the decimal degree, yes, we still can use the decimal degree without converting to meter. You can try to modify the print sample as :

            ShapeFileFeatureLayer worldMapLayer = new ShapeFileFeatureLayer(MapPath(@"~\SampleData\Countries02.shp"));
            //worldMapLayer.FeatureSource.Projection = new Proj4Projection(Proj4Projection.GetDecimalDegreesParametersString(), Proj4Projection.GetGoogleMapParametersString());
            //worldMapLayer.FeatureSource.Projection.Open();


            worldMapLayer.Open();
            mapPrinterLayer.MapUnit = GeographyUnit.DecimalDegree;
            mapPrinterLayer.MapExtent = worldMapLayer.GetBoundingBox();



mapPrinterLayer.Layers.Add(worldMapLayer);



From the above code, we can see we commented out the projection and change the map unit as decimal degree.

Any questions ,please feel free to let us know.

Thanks,

Troy

worldMapLayer.GetBoundingBox();  -> returns that this layer does not have bounding box. 
  
 Seems weird. Any ideas? my layer is saved in sql server database: possibly converted from shp to sql layer without bounding box inserted? 
  
 Also,i still got the unit error: not in feet or meter. 
  
 Here are my codes: 
                 // myMapImage = map.GetBitmap();
                if(!myMainMapLayer.IsOpen) myMainMapLayer.Open();
                myMapImage = new Bitmap(800, 700);//(int)myMainMapLayer.GetBoundingBox().Width, (int)myMainMapLayer.GetBoundingBox().Height
                GdiPlusGeoCanvas gdiPgc = new GdiPlusGeoCanvas();
                gdiPgc.BeginDrawing(myMapImage, map.CurrentExtent, GeographyUnit.DecimalDegree);


                // draw each map layer throug MapPrinterLayer
                Collection<SimpleCandidate> labelsInAllLayers = new Collection<SimpleCandidate>();
                MapPrinterLayer mpl = new MapPrinterLayer();
                foreach (Layer l in mapOverlay.Layers)
                {
                    if (l.IsVisible)
                    {
                        MsSql2008FeatureLayer theLayer2 = (MsSql2008FeatureLayer)l;
                        if(!theLayer2.IsOpen) theLayer2.Open();
                        mpl.MapUnit = GeographyUnit.DecimalDegree;
                        mpl.MapExtent = map.CurrentExtent;  //theLayer2.GetBoundingBox()
                        if (theLayer2.IsOpen) theLayer2.Close();
                        // mpl.SetPosition(8, 7, theLayer2.GetCenterPoint().X, theLayer2.GetCenterPoint().Y + 1, PrintingUnit.Inch);

                        mpl.Layers.Add(l);
                    }
                }
                if (myMainMapLayer.IsOpen) myMainMapLayer.Close();

                // draw this map PrinterLayer to GeoCanvas
                mpl.Open();
                mpl.IsDrawing = true;
                mpl.Draw(gdiPgc, labelsInAllLayers);
                mpl.IsDrawing = false;
                mpl.Close(); 


Hi guangming,



#1 issue: So your worldmaplayer is a sql server layer? shall we do a simple test with only one function to getboundingbox to see if it works? like:



              string connectString = "User ID=userid;Password=password;Data Source=192.168.0.178/orcl;";
              MsSql2008FeatureLayer sql2008Layer = new MsSql2008FeatureLayer(connectString, "states", "recid");

              sql2008Layer.open();

              sql2008Layer.getboundingbox();

Or you can run the T-SQL in sql server management studio:


DECLARE @polygon01 geometry;
select Top @polygon01 = geom from cntry02 WHERE geom is not null;
Select @polygon01 = @polygon01.STUnion(geom.STEnvelope()).STEnvelope() from cntry02 WHERE geom is not null;
select @polygon01.STAsText()



#2 issue: The error is happened on "gdiPgc.BeginDrawing(myMapImage, map.CurrentExtent, GeographyUnit.DecimalDegree);" please give a meter value for boundingbox and GeographyUnit as meter, you can follow the printer sample on line 395 "btnToPrinter_Click"method.



If the issue persists, please let us know.

Thanks,

Troy




my spatial column is type of Geography, not geometry. 
  
 I believe that is the  problem: that is why I asked if this printing module requires re-projection as in your example. 
  


I did reprojection: still an empty map: 
  
 what is the purpose of this line: (I did not include this line yet) 
 mpl.SetPosition(8, 7, theLayer2.GetCenterPoint().X, theLayer2.GetCenterPoint().Y + 1, PrintingUnit.Inch); 
  
 myMainMapLayer.FeatureSource.Projection = new Proj4Projection(
                    Proj4Projection.GetDecimalDegreesParametersString(), Proj4Projection.GetGoogleMapParametersString());
                myMainMapLayer.FeatureSource.Projection.Open();
                if(!myMainMapLayer.IsOpen) myMainMapLayer.Open();
                Collection<Feature> features = myMainMapLayer.QueryTools.GetAllFeatures(ReturningColumnsType.AllColumns);
                myMapImage = new Bitmap(800, 700);//(int)myMainMapLayer.GetBoundingBox().Width, (int)myMainMapLayer.GetBoundingBox().Height
                GdiPlusGeoCanvas gdiPgc = new GdiPlusGeoCanvas();
                gdiPgc.BeginDrawing(myMapImage, myMainMapLayer.FeatureSource.Projection.ConvertToExternalProjection(map.CurrentExtent), GeographyUnit.Meter); 


Hi guangming,



Mssql2008Feature layer still supports “Geography” type and it would use the below statement to get boundingbox(replace the “MajorCities with your table name”):


DECLARE @polygon01 geometry;
SELECT TOP @polygon01 = geometry::STGeomFromWKB(geom.STAsBinary(),4326) FROM MajorCities WHERE geom IS NOT NULL;
SELECT @polygon01 = @polygon01.STUnion(geometry::STGeomFromWKB(geom.STAsBinary(),4326).STEnvelope()).STEnvelope() FROM MajorCities WHERE geom IS NOT NULL;
SELECT @polygon01.STAsText();

Btw, please make sure the layer’s SRID is 4326 or we need to set its Srid property for this layer.

I also attached our majorcities database, you can have a check if you need. If the layer still doesn’t show on the map, would you mind sending us your sql database as scripts text, several records data would be fine?



Also, I think the sql server layer doesn’t show on the map is not related with printing, so in order to make sure the topic purely and the others can read easier, shall we open a new thread to solve this issue?



SetPosition means which area you want to draw the layers which are in MapPrinterLayer on a paper. The code from you should not be correct as you are using the world position as its center point, the center point should be the paper center point from your PagePrinterLayer. I think you can check our sample code in AddMapLayer method.



Thanks,

Troy







MajorCities.sql.zip (6.51 KB)

sorry for the confusing: everything is working when just showing the map. 
  
 What I meant is that the layer did not show up on map when printing! 
  
 I tried the sql query, it did work: I set srid 4326, and I used similar query to return bounding box of a certain set of features. 
  
 My issue here is purely related to printing. Could you give me a simple example working for my situation: 
  
 My spatial layer is in DecimalDegree; I want to print out one layer within current map extent; please also give some necessary documentation so that I can extend the codes later. 
  
 I do not think my case is unique - should be many people printing MVC maps? I really appreciate you have detailed documents on each function telling us the purpose/parameters.  
  
 It wastes you and me (many developers) a lot of time on this forum for this kind of very basic questions. 
  
 thanks, 
  
  


now it seems that I figured it out partially my case, at least I got layers printed. 
  
 it does need an empty PagePrinterLayer; it does require my layer to reproject to unit meter. 
  
 Now I have two questions: 
  
 1, how to just print spatial features: line/polygon/…, in the current view? I set mapPrinterLayer.MapExtent to my current map extent: map1.CurrentExtent. this did not work 
 2, still not clear what this does: mpl.SetPosition(8, 7, PagePrinterLayer.GetCenterPoint().X, PagePrinterLayer.GetCenterPoint().Y + 1, PrintingUnit.Inch); how to set the first two parameters? arbitrary? 
  
  
 Thanks, 
  
 Guangming

Hi,



A detailed description can be accessed at youtube.com/watch?v=qaJzo04VsAE, also please check the attached sample which prints map in decimal degree in MVC version. The regular map and printer map are 2 separate systems but shares some same configurations. To do the printer, I guess the MapPrinterLayer is required, which should have the same configuration of the regular map, also you can add it to regular map for display as well. Thus, for your first question, I think making mapPrinterLayer.MapExtent to the same as regular map extent is ok, if it doesn’t work, could you please share something here?



For the 2nd question, the value of first 2 parameters is based on the layout of the content what you would like to printer, in the attached, you can try changing the following 2 line codes to see what happened.







Thanks,

Johnny

MvcPrintMap.zip (460 KB)

are you sure that the zip project is a working solution? 
  
 the project did not even include a reference to MapSuiteCore.dll, and all other ThinkGeo stuff: mvcedition.dll. 
 the sample shp not included neither. 


Hi Guangming,



We always won’t include map suite dlls in project, we need to re-refer them with your dlls instead. One is for safe considering, another one is to make the sample minimize for uploading.



The first two parameters of SetPosition method means the current printer layer canvas size with and height inch unit. you can change them to see how it affects the result.



Thanks,

Troy