What is the recommended way to print an InMemoryMarkerOverlay along with the LayerOverlays contained in my map? I have been using Map.GetBitmap() to retrieve a bitmap of the current view and then sending that to a printer process. My issue with that method currently is I am getting a black background instead of my transparent one that I would expect. I have attached a saved bitmap using that method to show a little better what I am getting.
InMemoryMarkerOverlay printing
Hi Jake,
Have you set your wpfMap1.BackgroundOverlay.BackgroundBrush to black?
And I think if you can sent us your code for reproduce that is better for looks the reason.
Regards,
Don
Don,
I don't set the background at all, when I set it to white it does better, it has some issues still getting the sizes to work right though. What I would really be interested in is using the new MapPrinterLayer and printing functionality added recently. What I am struggling with that though is getting my InMemoryMarkerOverlay added to the printer layer. I have seen where others are asking about different Overlays (Google, Bing, etc) but haven't seen InMemoryMarkerOverlay in any of the forum posts. Is that a type that is supported currently and if it is, how do I get that added to the printer layers collection?
Here is my current Printing class:
using System;
using System.Collections.Generic;
using System.Linq;
using ThinkGeo.MapSuite.WpfDesktopEdition;
using System.Windows.Controls;
using ThinkGeo.MapSuite.Core;
using System.Drawing;
using System.IO;
using System.Drawing.Imaging;
using System.Windows.Media.Imaging;
using System.Windows;
using System.Collections.ObjectModel;
namespace UtilityClasses
{
class Printing
{
public Bitmap GetMapBitmap(WpfMap Map, double dWidth, double dHeight)
{
GdiPlusGeoCanvas canvas = new GdiPlusGeoCanvas();
double wsc = dWidth / (double)Map.ActualWidth;
double hsc = dHeight / (double)Map.ActualHeight;
double sc = Math.Min(wsc, hsc);
Bitmap b = new Bitmap((int)(Map.ActualWidth * sc), (int)(Map.ActualHeight * sc));
canvas.BeginDrawing(b, Map.CurrentExtent, Map.MapUnit);
for (int i = 0; i < Map.Overlays.Count; i++)
{
Type tp = Map.Overlays[i].GetType();
if (tp.Name == "LayerOverlay")
{
LayerOverlay lo = (LayerOverlay)Map.Overlays[i];
if (lo.IsVisible)
DrawLayerOverlay(lo, canvas);
}
else if (tp.Name == "InMemoryMarkerOverlay")
{
InMemoryMarkerOverlay im = (InMemoryMarkerOverlay)Map.Overlays[i];
if (im.IsVisible)
{
//add to the canvas if possible
}
}
}
//foreach (LayerOverlay lo in Map.Overlays)
//{
// if (lo.IsVisible)
// DrawLayerOverlay(lo, canvas);
//}
canvas.EndDrawing();
return b;
}
public void Print(WpfMap Map)
{
PrintDialog Dialog1 = new PrintDialog();
if (Dialog1.ShowDialog().Value)
{
float wid = (float)Dialog1.PrintableAreaWidth;
float hig = (float)Dialog1.PrintableAreaHeight;
Bitmap b = Map.GetBitmap(wid, hig);// GetMapBitmap(Map, (double)Dialog1.PrintableAreaWidth, (double)Dialog1.PrintableAreaHeight);
System.Windows.Controls.Image img = WrapBitmap(b);
Dialog1.PrintVisual(img, "test printing");
}
}
private System.Windows.Controls.Image WrapBitmap(Bitmap bitmap)
{
MemoryStream stream = new MemoryStream();
bitmap.Save(stream, ImageFormat.Png);
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
System.Windows.Controls.Image image = new System.Windows.Controls.Image { Source = bitmapImage };
image.Measure(new System.Windows.Size(bitmap.Width, bitmap.Height));
image.Arrange(new Rect(0, 0, bitmap.Width, bitmap.Height));
return image;
}
private void DrawLayerOverlay(LayerOverlay layerOverlay, GeoCanvas geoCanvas)
{
Collection<SimpleCandidate> simpleCandidates = new Collection<SimpleCandidate>();
foreach (Layer layer in layerOverlay.Layers)
{
lock (layer)
{
bool isLayerClosed = false;
if (!layer.IsOpen)
{
isLayerClosed = true;
layer.Open();
}
layer.Draw(geoCanvas, simpleCandidates);
if (isLayerClosed) layer.Close();
}
}
}
}
}
Couple of notes, when using the Map.GetBitmap and passing in the width and height it will not expand the map control to fit the measurements, it will simply fill in the extra space with a background color, in my case it is using black. When I try to use the GetMapBitmap function instead, I run into an issue trying to draw the InMemoryMarkerOverlay features to the canvas, it will draw the base map layers fine though.
Not sure if it helps, but here are 2 sample images.
This one is using the GetMapBitmap function to print the layers, notice there are no markers on this one. (It is really hard to tell in a picture, but this does scale to the size of the paper being used).
This one is using Map.GetBitmap function. It has the markers, but in addition it has filled out the rest of the width and height with black background. I figure I can simply pass in the width/height of the user control to counter that, but that risks losing portions of the image if the control is larger than the printer area, I would really like it to scale.
Hi Jake,
I think our new MapPrinterLayer only can print layers but not overlay, and the layer should be vector type.
If you want to print InMemoryMarkerOverlay, why not directly code like this: Dialog1.PrintVisual(Map, "test printing");
Regards,
Don
Don,
Doing that won’t scale the image to fit the paper size selected for the printer.
Jake
Hi Jake,
The Map.GetBitmap function directly draw the control by RenderTargetBitmap and BmpBitmapEncoder class, so that’s not helpful for us.
In render logic of InMemoryMarkerOverlay class, we add marker as children control of canvas and directly draw it.
So the only try I can do is like this:
else if (tp.Name == “InMemoryMarkerOverlay”)
{
InMemoryMarkerOverlay im = (InMemoryMarkerOverlay)Map.Overlays[i];
if (im.IsVisible)
{
GeoCollection<Marker> drawingMarkers = im.GetMarkersForDrawing(Map.CurrentExtent);
foreach (Marker marker in drawingMarkers)
{
if (Map.CurrentExtent.Contains(new PointShape(marker.Position.X, marker.Position.Y)))
{
ImageSource source = marker.ImageSource;
GeoImage img = new GeoImage(((System.Windows.Media.Imaging.BitmapImage)(source)).StreamSource);
canvas.DrawWorldImage(img, marker.Position.X, marker.Position.Y, img.GetWidth(), img.GetHeight(), DrawingLevel.LevelOne);
}
}
//add to the canvas if possible
}
}
But unlucky that don’t works well.
I think if you think this print function is important to you, you would like to vote for it on our enhancement tracker at: helpdesk.thinkgeo.com/EnhancementTracker
Regards,
Don