4

I have a georeferenced IRasterLayer which is displaying data from a PPM file with no alpha channel. I am trying to specify a color which should be treated as transparent. In ArcMap it is possible to set a specific color to be transparent, but I have yet to find a working C++ example for ArcObjects 10.x .NET.

I am using the C++ COM interface and have been trying to achieve this by creating a RasterRGBRenderer as per this post. The claimed-working VB.NET sample passes an array of doubles into IRasterStretch.BackgroundValues which is not compatible with the documented 10.1 interface.
Unfortunately documentation in this area is poor, and these samples are very dated. The documentation does not even specify what type of COM VARIANT is needed when VARIANTS are expected.

Please advise how to specify background transparency using C++ in ArcObjects 10.x .NET

Edit: As a test I have attempted to set the BackgroundValue white to display as red using the following, this did not work (This does work on a test PNG with a white background, but not my PPM file):

esri::IRasterRGBRenderer2Ptr rgbRenderer;
rgbRenderer.CreateInstance(__uuidof(esri::RasterRGBRenderer));
IRasterRendererPtr rasterRenderer(rgbRenderer);
rasterRenderer->Raster = rasterLayer->Raster;
hr = rasterLayer->putref_Renderer(rasterRenderer);

IRgbColorPtr backgroundColor;
backgroundColor.CreateInstance(__uuidof(esri::RgbColor));
backgroundColor->put_RGB(RGB(255, 0, 0)); // Bright red for testing

CComSafeArray<double> backgroundValue;
backgroundValue.Create(3);
backgroundValue.SetAt(0, 255.0);
backgroundValue.SetAt(1, 255.0);
backgroundValue.SetAt(2, 255.0);
CComVariant varBackgroundValue(backgroundValue);

IRasterStretch2Ptr stretch(rasterRenderer);
hr = stretch->put_Background(VARIANT_TRUE);
hr = stretch->putref_BackgroundColor(backgroundColor);
hr = stretch->put_BackgroundValue(varBackgroundValue);
rasterRenderer->Update();

I can confirm that BackgroundValue is being set correctly. Calling get_BackgroundValue always returns a VARIANT array of doubles and these include the correct values if I get after I call put. The renderer is also confirmed to be set correctly as if I disable one of the bands using the renderer pointer that is clearly visible

0

I faced the problem last year and had to learn: The proof of the pudding is in the eating :-o For every renderer the type of the value is different, in c# you have to create an type of object and put there the value as double or array of double... this is a very worst thing... byt maybe my code snippet helps a bit.

if (catLyrRenderer is IRasterRGBRenderer)
    {
      object ob = null;
      double[] colVals = new double[bands.Count];
      for (int i = 0; i < bands.Count; i++)
      {
        ob = raster2.GetPixelValue(i, col, row);
        if (ob != null) colVals[i] = (double)(byte)ob;
      }
      (catLyrRenderer as IRasterStretch2).Background = true;
      (catLyrRenderer as IRasterStretch2).BackgroundColor = ((IRasterDisplayProps)catLyrRenderer).NoDataColor;
      (catLyrRenderer as IRasterStretch2).BackgroundValue = colVals;
      catLyrRenderer.Update();
}   else if (catLyrRenderer is IRasterStretchColorRampRenderer)
            {
                object ob = null;
                ob = raster2.GetPixelValue(0, col, row);

                (catLyrRenderer as IRasterStretch2).Background = true;
                (catLyrRenderer as IRasterStretch2).BackgroundColor = ((IRasterDisplayProps)catLyrRenderer).NoDataColor;
                (catLyrRenderer as IRasterStretch2).BackgroundValue = ob;
                catLyrRenderer.Update();
            }
  • Reading a value out from the image is a nice idea. Unfortunately this merely identified that the colour I am attempting to set to transparent is indeed understood by ESRI to be [255,255,255]. Original post updated – gisHermit Sep 2 '15 at 10:08
  • Out of curiosity I created a new PNG file with a white background and tried that. Unfortunately, it worked, so my issue is only evident for rasters generated from the PPM format. Is there an alternative color indexing scheme RGBRenderer may be using? Is there a way to see what value an RGBRenderer believes a pixel to be, rather than reading it directly from the raster? – gisHermit Sep 2 '15 at 10:30
  • Solution found, see other post. Thank you for spurring me to try again – gisHermit Sep 2 '15 at 11:02
0

It seems that this was caused by a rounding issue within ESRI, as although the COM interface will always return an array of doubles no matter what you send it (and setting an array of doubles worked for a hand-made PNG), the background of my PPM file would only change if the BackgroundValue was set to an array of int. In this format the RGB scaling was in the normal 0-255 range and setting transparency was as trivial as generating an IColor with transparency set, or alternatively re-using the NoDataColor value as per schmiddor's post. Working solution:

esri::IRasterRGBRenderer2Ptr rgbRenderer;
rgbRenderer.CreateInstance(__uuidof(esri::RasterRGBRenderer));
IRasterRendererPtr rasterRenderer(rgbRenderer);
rasterRenderer->Raster = rasterLayer->Raster;
hr = rasterLayer->putref_Renderer(rasterRenderer);

esri::IRasterDisplayPropsPtr displayProps(rasterRenderer);
esri::IColorPtr noDataColor;
hr = displayProps->get_NoDataColor(&noDataColor);

CComSafeArray<int> backgroundValue;
backgroundValue.Create(3);
backgroundValue.SetAt(0, 255);
backgroundValue.SetAt(1, 255);
backgroundValue.SetAt(2, 255);
CComVariant varBackgroundValue(backgroundValue);

IRasterStretch2Ptr stretch(rasterRenderer);
hr = stretch->put_Background(VARIANT_TRUE);
hr = stretch->putref_BackgroundColor(noDataColor);
hr = stretch->put_BackgroundValue(varBackgroundValue);
rasterRenderer->Update();

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.