Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

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;

    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;


    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))

            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);

        bitmap.Save("c:\\image.bmp", ImageFormat.Bmp);
    map.MapScale = originalScale;

    if (mapSurround != null)

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? Any help and ideas are greatly appreciated.

share|improve this question
Did you try calling IActiveView.Activate using a window handle from GetDesktopWindow ? rantincsharp.wordpress.com/2010/10/29/… I'm not even sure what the desktop window should be when running as a gp service on a virtual server (which is what I was dealing with) but this worked. Maybe someday I'll figure out why. –  Kirk Kuykendall Feb 7 '11 at 23:09
I am actually working within an ArcMap session, so all the objects are properly initialized. Changes to scale etc. are working. –  Petr Krebs Feb 7 '11 at 23:21
add comment

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.