I'm trying to create images from symbols so that I can create a custom symbol dialog. Found this sample code on the ESRI forums and it workes great on almost all symbols. I'm having problems with a IMultiLayerFillSymbol that has a IPictureFillSymbol on one of it's layers. It's throwing an exception on symbol.Draw(geometry);

Does anyone know if there is any additional steps that has to taken to get it to work with a IMultiLayerFillSymbol?

static public Image ImageFromSymbol(ISymbol symbol, Int32 width, Int32 height)
        Bitmap bitmap = new Bitmap(width, height);
        Graphics g = Graphics.FromImage(bitmap);
        IntPtr hdc = g.GetHdc();

        IGeometry geometry = null;
        if (symbol is IMarkerSymbol)
            IPoint point = new PointClass();
            point.X = (width / 2);
            point.Y = (height / 2);
            geometry = point;
        else if (symbol is ILineSymbol)
            IPolyline line = new PolylineClass();
            IPoint ptFrom = new PointClass();
            IPoint ptTo = new PointClass();
            ptFrom.X = 3; ptFrom.Y = (height / 2);
            ptTo.X = (width - 3); ptTo.Y = ptFrom.Y;
            line.FromPoint = ptFrom;
            line.ToPoint = ptTo;
            geometry = line;
            IEnvelope bounds = new EnvelopeClass();
            bounds.XMin = 1; bounds.XMax = width - 1;
            bounds.YMin = 1; bounds.YMax = height - 1;
            geometry = bounds;

        symbol.SetupDC(hdc.ToInt32(), null);

        return bitmap as Image;
    catch (Exception ex)
        return null;

Update, Added the following code to make it work:

Updated the ImageFromSymbol metod with:

ITransformation pTransformation = CreateTransFromDC(
                       hDC, size.Width, size.Height);
pSymbol.SetupDC(hDC.ToInt32(), pTransformation);


 private const int LOGPIXELSY = 90;

[DllImport("GDI32.dll", EntryPoint = "GetDeviceCaps",
           ExactSpelling = true, SetLastError = true)]
       private static extern int GetDeviceCaps(IntPtr hdc, int nIndex);

private static ITransformation CreateTransFromDC(IntPtr hDC,
           int lWidth, int lHeight) {
           // Calculate the parameters for the new transformation,
           // based on the dimensions passed to this function.
           try {
               IEnvelope pBoundsEnvelope = new EnvelopeClass();
               pBoundsEnvelope.PutCoords(0.0, 0.0, (double)lWidth,

               tagRECT deviceRect;
               deviceRect.left = 0;
               deviceRect.top = 0;
               deviceRect.right = lWidth;
               deviceRect.bottom = lHeight;

               int dpi = GetDeviceCaps(hDC, LOGPIXELSY);
               if (dpi == 0) {
                   throw new Exception(
                     "Could not retrieve Resolution from device context.");

               // Create a new display transformation and set its properties
               IDisplayTransformation newTrans =
                   new DisplayTransformationClass();
               newTrans.VisibleBounds = pBoundsEnvelope;
               newTrans.Bounds = pBoundsEnvelope;
               newTrans.set_DeviceFrame(ref deviceRect);
               newTrans.Resolution = dpi;

               return newTrans;
           catch {
               return null;
  • Yes, when I tried to loop through layers of the IMultiLayerFillSymbol and drawing the individual IPictureFillSymbol it throws the same exception. Oct 6 '10 at 14:54

I'd try creating a new DisplayTransformation class and passing it to SetupDC (instead of null). I think you'll need to set the device frame to match the pixel extent, along with visible extent. Then pass an envelope to Draw that matches the visible extent.

Update: try Richie Carmichael's SymbolToBitmap function here.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.