Grdimage and GeoTIFF with alpha?

When using grdimage with a GeoTIFF, it appears in my testing that the alpha channel is ignored - transparent pixels just show up as white. I can work around this by setting the -Q option to "white" (-Qwhite), such that the now-white pixels are now made transparent, but this is less than ideal as there could be white pixels that are not transparent - and the user would have to know that with this GeoTIFF, transparent pixels are white, which doesn’t seem to be default (NaN or “black” being the “standard”, apparently).

Is there a way to get grdimage to recognize/use the alpha channel?

Alternately, the GoTIFFs in question are being created by converting a PNG with transparency to GeoTIFF format using gdal_translate. While it isn’t really a GMT question, would anyone know of there is a way to convert transparent pixels to NaN, such that one could just use the -Q option “normally”, as part of the conversion process?

Thanks.

EDIT: replaced PyGMT option names with equivalent command-line GMT options.

This is not a GMT option. Are you referring to a PyGMT option? Then you should post this under the PyGMT target.

Sigh…I’m always doing that! Sorry! Let me re-phrase this to be “plain” GMT, as it is not a PyGMT specific question:

“… I can work around this by setting the -Q option to "white" (-Qwhite)…”

I believe the rest of the question still stands though?

Yes, it should apply. But we need some examples to reproduce. Transparency is tricky but I’m sure we got some variations working (though maybe not all cases). Anyway, if you are converting from png to Geotiff, you can’t use the NaNs as a fall back. NaNs are floats and images are integers (8 bits unsigned integers). The distinction between grids and images is important in GMT.

Ok, here’s a random GeoTIFF with an alpha channel:
https://www.dropbox.com/scl/fi/i222ewkvubhpceoxgo7i2/RandomGeoTIFFWithAlpha.tiff?rlkey=iov32h9pqht8y873amzpgi14z&dl=0

And some GMT code that uses grdimage to add that GeoTIFF to a map:

(env) israel@ijbrewster MapGen % gmt begin                                                              
(env) israel@ijbrewster MapGen % gmt basemap -JM8i -R-169.765/-165.3272/52.3948/54.6188 -Bnsew -Baf                     
(env) israel@ijbrewster MapGen % gmt grdimage '@earth_relief_01s' -Q -I                                      
(env) israel@ijbrewster MapGen % gmt grdimage '/Path/to/random/GeoTIFF/with/alpha.tiff' -Q
(env) israel@ijbrewster MapGen % gmt end 

As is, the alpha channel is ignored, making the transparent pixels solid white. As mentioned, adding white to the -Q argument can make them transparent again, with the caveat that a) whoever got this GeoTIFF would need to know to do that, and b) any other pixels in the image that may be white (not many, if any, in this case) would also be made transparent.

It is transparent to me

julia> I = gmtread("RandomGeoTIFFWithAlpha.tiff")
A GMTimage object with 4 bands of type UInt8
Pixel node registration used
x_min: -169.765 x_max :-165.3727        x_inc :0.002144677734374989     n_columns :2048
y_min: 52.3948  y_max :54.6188  y_inc :0.0021446480231436874    n_rows :1037
z_min: 0.0      z_max :255.0
Mem layout:     BRPA
PROJ: +proj=longlat +datum=WGS84 +no_defs

julia> viz(I, fmt=:jpg, Vd=1)
        grdimage  -R-169.765/-165.3727/52.3948/54.6188 -JX15c/0 -Baf -BWSen -n+a -D -P -K > c:\TMP/GMTjl_j.ps

Note, you can reproduce this in CLI with

gmt grdimage RandomGeoTIFFWithAlpha.tiff -R-169.765/-165.3727/52.3948/54.6188 -JX15c/0 -Baf -BWSen -n+a -D -jpg lixo

1 Like

Huh?
If you only do the GeoTIFF - as appears to be the case here - you would have no way of knowing if it was drawn with transparency or not, as the transparent areas would just look white regardless.

Just for kicks, I changed your CLI command to save as a png (which supports transparency) instead of a jpg, and opened it in an image editor, which showed that the white areas are just that - white, not transparent.

What am I missing here?

I’m afraid you are right. The image is correctly read as with transparency. The Mem layout: BRPA means it is a pixel interleaved with an alpha layer (the A) and indeed

julia> I[1:4]
4-element Vector{UInt8}:
 0x00
 0x00
 0x00
 0x00

first pixel is black but shows up as white. The -Q option of grdimage should work for images too in GMT6.5. Man says

-Q[+z value][color]
Make grid nodes with NaN values transparent, using the color-masking feature in PostScript Level 3 (the PS device must support PS Level 3). If the input is a grid, use +z to select another grid value than NaN. If input is instead an image, append an alternate color to select another pixel value to be transparent [Default is black].

but the result image still has transparent pixels as white. And oddly, the PNG (the one that supports the transparency) seems to apply it to the outside of the image. i.e., no annotations are visible with

gmt grdimage RandomGeoTIFFWithAlpha.tiff -R-169.765/-165.3727/52.3948/54.6188 -JX15c/0 -Baf -BWSen -n+a -D -Q -PNG lixo

Not shown because file size is 2.3 MB

No matter how I try to download that tiff is saves it as a HTML file…

After a couple of emails with Paul, we found that transparency is in fact working. The trick is to use -Qwhite. Confess that this part puzzles me and may indicate some issue, but it works

gmt begin t png
    gmt grdimage @earth_relief_06m -R-169.765/-165.3727/52.3948/54.6188 -JX15c/0 -Baf -BWSen
    gmt grdimage RandomGeoTIFFWithAlpha.tiff -Qwhite
gmt end show

Oddly, using gmt begin t PNG extends the transparency to the outside of the frame

P.S. GMT6.5 is probably needed for this

Why do you say it "extends the transparency to the outside of the frame? No can do I think. I dont see it.

with PNG and in “edit mode” that shows the light chessboard typical of transparencies.
image

No “edit mode”. Annotations barely visible
image

Ummmm…yeah. I said that in my first post??? :smile:

I’m thinking the best path forward at this point is to load the image, change any black pixels to almost black, then change the transparent pixels to solid black and drop the Alpha channel.

In theory then the default of “black” with images should kick in and make things work as desired without any workarounds.

Clearly something isn’t behaving as expected when the Alpha channel is present, and that’s not something my end users should have to deal with (or with having to remember that with my GeoTIFFs they have to use -Qwhite rather than just -Q). So this might be an ugly solution, but at least it should work (in theory).

Yeah, DropBox is being weird about it. The link goes to an HTML page which then has a download option. Sorry about that!

I have a vague recollection that I’ve run into that before. Don’t recall what I did to fix it though - Perhaps it has to do with plotting the earth_relief and frame in the same command, rather than using basemap first to get the frame/bounds/etc and then plotting grdimage on top of that? Dunno.

Looking at your RGBA image I found that all 731894 A values are 0. So what is it you expect to happen? Every pixel shall be transparent at 0 (opaque) or 255 (see through)?

I’m not sure where you are getting your information, but:

  1. If what you say was true, the image would be fully transparent (when opened normally). It is not.
  2. In an RGBA image, for the A channel, 0 is transparent, and 255 is opaque. This is reversed from the GMT definition of -t (transparency) which sets the transparency percentage.
  3. If I look at the various pixels of the image, I find that MANY A values are NOT zero. For example, using the following python code:
>>> from PIL import Image
>>> img = Image.open('/Users/israel/Downloads/RandomGeoTIFFWithAlpha.tiff')
>>> img.getpixel((0, 0))
(0, 0, 0, 0)
>>> img.getpixel((1024, 500))
(70, 49, 75, 255)

We can see that while the pixel at (0,0) is transparent (A value of 0), the pixel at (1024,500) -roughly the center of the image - is fully opaque (A value of 255)

Also, the GeoTIFF image is 2048x1037, which gives 2,123,776 A values, not 731,894

I expect that the pixels with an Alpha value of 0 (transparent) will be transparent (allow the previous layers to be visible), while the pixels with an Alpha value of 255 (opaque) will cover the previous layers.

Yep, I just confirmed that setting all the transparent pixels to black and dropping the Alpha channel does the trick - simply specifying -Q at that point works as expected. So I guess this can be considered “solved”, unless someone wanted to look into why the Alpha channel isn’t behaving as one would expect. :man_shrugging:

Sorry, too quick coding error. Yes, not all are 0, either 0 or 255. So seems to me there are many different ways to consider transparency and GMT should be enhanced to do any of them:

  1. Like your image, the alpha is either 0 or 255, where you say 0 should be transparent. OK, but that means it stores opacity (0 is no opacity but 100% transparency).
  2. If alpha has a distribution from 0-255 then that is a continuously changing transparency. Or opacity?

Perhaps -Q can take a modifier +t for alpha = transparency while the default is alpha = opacity. Alternatively we do +o for opacity instead.

Need @Joaquim to get back from dinner since he coded the current decision.

1 Like

Yes, technically Alpha is “Opacity”. This is a standard, in case there was any confusion on that front. From Difference between RGB vs RGBA color format - GeeksforGeeks for example: “…alpha channel that specifies the opacity of the color” (Note that that page specifically mentions CSS, where the value is 0 to 1, but in an 8bit image it is 0-255)

The either 0 or 255 distribution is specific to this image, as you mention here:

This statement is correct, in that alpha can be any value from 0-255 (in a standard 8 bit image, of course).