Does anyone know a good alternative to the IMapServer2.ExportScaleBar function?
I want to do essentialy the same task, but outside the ArcGIS Server environment. For a given map scale, predefined scale bar style, scale bar size and image resolution, I'd like to generate a scale bar image.
I know I could add a scale bar to the page layout and then export the whole layout, but I do not want to clutter and/or modify the page layout if at all possible.
This is the closest I was able to get, but works only if the resolution used is 96 DPI (screen resolution).
IMapSurround mapSurround = null;
IMap map = GetMap(); // returns the map
var originalScale = map.MapScale;
try
{
var scaleBar = DefaultSymbols.ScaleBar; // returns a scalebar with some predefined properties
var scaleBarUid = new UIDClass() {Value = scaleBar.GetType().GUID.ToString("B")};
mapSurround = map.CreateMapSurround(scaleBarUid, scaleBar);
var resolution = 300;
map.MapScale = 1000;
mapSurround.Refresh();
((IScaleBar)mapSurround).UseMapSettings();
var querySize = (IQuerySize)mapSurround;
double widthPoints = 0;
double heightPoints = 0;
querySize.QuerySize(ref widthPoints, ref heightPoints);
var widthInches = 3.0; // scale bar is 3 inches wide
var heightInches = widthInches * (heightPoints / widthPoints); // determine height by respecting the aspect ratio
var pixelsWidth = (int)(widthInches * resolution);
var pixelsHeight = (int)(heightInches * resolution);
using (var bitmap = new Bitmap(pixelsWidth, pixelsHeight, PixelFormat.Format32bppRgb))
{
bitmap.SetResolution(resolution, resolution);
using (var graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(Color.White);
var simpleDisplay = new SimpleDisplayClass();
simpleDisplay.DisplayTransformation.Resolution = resolution;
simpleDisplay.DisplayTransformation.Units = esriUnits.esriInches;
simpleDisplay.DisplayTransformation.Bounds = new EnvelopeClass
{
XMin = 0,
YMin = 0,
XMax = widthInches,
YMax = heightInches
};
simpleDisplay.DisplayTransformation.VisibleBounds = simpleDisplay.DisplayTransformation.Bounds;
var tagRect = new tagRECT {left = 0, top = 0, right = pixelsWidth, bottom = pixelsHeight};
simpleDisplay.DisplayTransformation.set_DeviceFrame(ref tagRect);
simpleDisplay.StartDrawing(graphics.GetHdc().ToInt32(), 0);
var drawBounds = new EnvelopeClass
{
XMin = 0,
YMin = 0,
XMax = widthInches,
YMax = heightInches
};
mapSurround.Draw(simpleDisplay, null, drawBounds);
simpleDisplay.FinishDrawing();
}
bitmap.Save("c:\\image.bmp", ImageFormat.Bmp);
}
}
finally
{
map.MapScale = originalScale;
if (mapSurround != null)
{
map.DeleteMapSurround(mapSurround);
}
}
For resolutions other than 96 DPI this does not work correctly, the scale bar IS drawn to the bitmap, but the measurements it shows are not correct.
Is there a way to do this?