Skip to content

Commit b4d8414

Browse files
authored
Let flatfv() deal with RGBA images. Either band or pixel interleaved. (#1588)
* Docstrings tweaks * Add option 'logo' to 'pagebg'. Also add a under the hood -T option. * Docstrings * Let flatfv() deal with RGBA images. Either band or pixel interleaved.
1 parent 9c25c6b commit b4d8414

File tree

4 files changed

+71
-31
lines changed

4 files changed

+71
-31
lines changed

src/gdal_tools.jl

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,12 @@ end
3131
3232
Image/Grid reprojection and warping function.
3333
34-
### Parameters
34+
### Args
3535
- `indata`: Input data. It can be a file name, a GMTgrid or GMTimage object or a GDAL dataset
3636
- `options`: List of options. The accepted options are the ones of the gdal_translate utility.
3737
This list can be in the form of a vector of strings, or joined in a single string.
3838
The accepted options are the ones of the gdalwarp utility.
39+
3940
- `kwargs`: Besides what was mentioned above one can also use `meta=metadata`, where `metadata`
4041
is a string vector with the form "NAME=...." for each of its elements. This data
4142
will be recognized by GDAL as Metadata.
@@ -54,14 +55,15 @@ end
5455
5556
Fill selected raster regions by interpolation from the edges.
5657
57-
### Parameters
58+
### Args
5859
- `data`: Input data. It can be a file name, a GMTgrid or GMTimage object.
60+
61+
### Kwargs
5962
- `nodata`: The nodata value that will be used to fill the regions. Otherwise use the `nodata` attribute of `indata`
6063
if it exists, or NaN if none of the above were set.
61-
- `kwargs`:
62-
- band: the band number. Default is first layer in `indata`
63-
- maxdist: the maximum number of cels to search in all directions to find values to interpolate from. Default, fills all.
64-
- nsmooth: the number of 3x3 smoothing filter passes to run (0 or more).
64+
- band: the band number. Default is first layer in `indata`
65+
- maxdist: the maximum number of cels to search in all directions to find values to interpolate from. Default, fills all.
66+
- nsmooth: the number of 3x3 smoothing filter passes to run (0 or more).
6567
6668
### Returns
6769
The modified input `data`

src/psxy.jl

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ function common_plot_xyz(cmd0::String, arg1, caller::String, first::Bool, is3D::
108108
cmd, = parse_common_opts(d, cmd, [:a :e :f :g :t :w :margin :params]; first=first)
109109
cmd, opt_l = parse_l(d, cmd) # Parse this one (legend) aside so we can use it in classic mode
110110
cmd, opt_f = parse_f(d, cmd) # Parse this one (-f) aside so we can check against D.attrib
111-
cmd = parse_these_opts(cmd, d, [[:D :shift :offset], [:I :intens], [:N :no_clip :noclip]])
111+
cmd = parse_these_opts(cmd, d, [[:D :shift :offset], [:I :intens], [:N :no_clip :noclip], [:T]])
112112
parse_ls_code!(d::Dict) # Check for linestyle codes (must be before the GMTsyntax_opt() call)
113113
cmd = GMTsyntax_opt(d, cmd)[1] # See if an hardcore GMT syntax string has been passed by mk_styled_line!
114114
(is_ternary) && (cmd = add_opt(d, cmd, "M", [:M :dump]))
@@ -591,13 +591,14 @@ end
591591
Check if using a background image to replace the page color.
592592
593593
This function checks for the presence of a `pagebg` option that sets the page background image.
594-
Note that this different from the `background` or `bg` option that sets the plotting canvas background color.
594+
Note that this is different from the `background` or `bg` option that sets the plotting canvas background color.
595595
596596
- `pagebg`: a NamedTuple with the following members
597-
- `image`: the image name or a GMTimage/GMTgrid object
598-
- `width`: the width of the background image in percentage of the page width (default: 0.8)
599-
- `offset`: the offset of the background image in percentage of the page width (default: (0.0,0.0))
600-
If only one value is provided it is used for the X offset only.
597+
- `image`: the image name or a GMTimage/GMTgrid object
598+
- `logo`: To plot the GMT logo (from the global ``timestamp`` option) at the lower left corner.
599+
- `width`: the width of the background image in percentage of the page width (default: 0.8)
600+
- `offset`: the offset in paper units (cm prefrably) with respect to the center of the background
601+
image (default: (0.0,0.0)). If only one value is provided it is used for the X offset only.
601602
602603
OR
603604
@@ -607,6 +608,7 @@ OR
607608
function fish_pagebg(d::Dict, cmd::Vector{String}; autoJZ::Bool=true)::Vector{String}
608609
((val = find_in_dict(d, [:pagebg])[1]) === nothing) && return cmd
609610
width::Float64 = 0.8; off_X::Float64 = 0.0; off_Y::Float64 = 0.0 # The off's are offsets from the center
611+
opt_U = ""
610612
if isa(val, NamedTuple)
611613
!haskey(val, :image) && error("pagebg: NamedTuple must contain the member 'image'")
612614
fname = helper_fish_bgs(val[:image]) # Get the image name or set it under the hood if input is a GMTimage
@@ -617,6 +619,7 @@ function fish_pagebg(d::Dict, cmd::Vector{String}; autoJZ::Bool=true)::Vector{St
617619
isa(off, Real) ? (off_X = off) : length(off) == 2 ? (off_X = off[1]; off_Y = off[2]) :
618620
error("pagebg: offset must be a Real or a two elements Array/Tuple")
619621
end
622+
haskey(val, :logo) && (opt_U = " -U+o0+t")
620623
else # Here, val is just the file name or a GMTimage
621624
fname = helper_fish_bgs(val) # Get the image name or set it under the hood if input is a GMTimage
622625
end
@@ -647,7 +650,7 @@ function fish_pagebg(d::Dict, cmd::Vector{String}; autoJZ::Bool=true)::Vector{St
647650
cmd[ind_cmd] = replace(cmd[ind_cmd], opt_JZ => CTRL.pocket_J[3])
648651
end
649652
proggy = IamModern[1] ? "image " : "psimage "
650-
[proggy * fname * CTRL.pocket_J[1] * CTRL.pocket_R[1] * " -Dx0/0+w"*Wt*cw, cmd...]
653+
[proggy * fname * CTRL.pocket_J[1] * CTRL.pocket_R[1] * opt_U * " -Dx0/0+w"*Wt*cw, cmd...]
651654
end
652655

653656
# ---------------------------------------------------------------------------------------------------

src/solids.jl

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -683,10 +683,13 @@ end
683683
"""
684684
FV = flatfv(I::Union{GMTimage, AbstractString}; shape=nothing, level=0.0) ->GMTfv
685685
686-
Create a flat 3D surface from an image and a set of xyz or just xy coordinates.
686+
Create a flat 3D surface from an image and a set of xyz or xy coordinates.
687687
688-
This function creates face for each pixel in the image that is inside the `shape` and assigns the
689-
face's color from that of the image. So be careful that the image is not too large.
688+
This function creates a face for each pixel in the image that is inside the `shape` and assigns the
689+
face's color from that of the image. So be careful that the image is not too large. As explained below,
690+
this function creates flat surfaces in any of the xy, xz or yz planes. While this may seam a big
691+
limitation, it can be circumvented by a posterior rotation of the image with the help of a rotation
692+
matrix created with the `eulermat` function.
690693
691694
### Args
692695
- `I`: A `GMTimage` object or a file name of an image.
@@ -717,7 +720,16 @@ function flatfv(I::Union{GMTimage, AbstractString}; shape=:n, level=0.0)::GMTfv
717720
end
718721

719722
_I = forceRGB(I)
720-
n_rows::Int, n_cols::Int = size(_I.image)
723+
n_cols::Int, n_rows::Int = getsize(_I) # Works for both 'regular' and GDAL transposed images
724+
725+
hasAlphaMask = (length(_I.layout) == 4 && _I.layout[4] == 'A')
726+
if hasAlphaMask
727+
if (_I.layout[3] == 'B') # Band interleaved
728+
_masca = (_I.image[:, :, 4] .== 255)'
729+
else # Pixel interleaved
730+
_masca = reshape((_I.image[4:4:end] .== 255), n_cols, n_rows)'
731+
end
732+
end
721733

722734
if (shape == :circle || shape == :circ || shape == :ellipse)
723735
X,Y = meshgrid(linspace(0, 1, n_cols+1), linspace(1, 0, n_rows+1))
@@ -754,15 +766,30 @@ function flatfv(I::Union{GMTimage, AbstractString}; shape=:n, level=0.0)::GMTfv
754766
end
755767
doMask = !isempty(masca)
756768

769+
if (hasAlphaMask)
770+
masca = doMask ? masca .& _masca : _masca
771+
doMask = true
772+
end
773+
757774
FV = surf2fv(X, Y, Z, type=:quad, mask=masca)
758775
n_colors = doMask ? sum(masca) : (n_rows * n_cols)
759776
cor = Vector{String}(undef, n_colors)
760777

761778
kk = 0
762-
@inbounds for n = 1:n_cols, m = 1:n_rows
763-
doMask && !masca[m,n] && continue
764-
k = (m-1) * n_cols * 3 + (n-1) * 3
765-
cor[kk+=1] = @sprintf("-G#%.2x%.2x%.2x", _I[k+=1], _I[k+=1], _I[k+=1])
779+
if (_I.layout[3] == 'P') # Pixel interleaved
780+
n_interleaved = (length(_I.layout) == 4 && _I.layout[4] == 'A') ? 4 : 3
781+
@inbounds for n = 1:n_cols, m = 1:n_rows
782+
doMask && !masca[m,n] && continue
783+
k = (m-1) * n_cols * n_interleaved + (n-1) * n_interleaved
784+
cor[kk+=1] = @sprintf("-G#%.2x%.2x%.2x", _I[k+=1], _I[k+=1], _I[k+=1])
785+
end
786+
else # Band interleaved
787+
nxy, nxy2 = n_rows * n_cols, n_rows * n_cols * 2
788+
@inbounds for n = 1:n_cols, m = 1:n_rows
789+
doMask && !masca[m,n] && continue
790+
k = (m-1) * n_cols + n
791+
cor[kk+=1] = @sprintf("-G#%.2x%.2x%.2x", _I[k], _I[k+nxy], _I[k+nxy2])
792+
end
766793
end
767794

768795
FV.color, FV.isflat = [cor], true

src/utils.jl

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -987,8 +987,10 @@ getbb(D::GDtype) = isa(D, Vector) ? D[1].ds_bbox : D.ds_bbox
987987
"""
988988
width, height = getsize(GI::GItype) -> Tuple(Int, Int)
989989
990-
Return the width and height of the grid or image. The grid case is simple but images are more complicated
991-
due to the memory layout. To disambiguate this, we are not relying in 'size(GI)' but on the length of the
990+
Return the width and height of the grid or image.
991+
992+
The grid case is simple but images are more complicated due to the memory layout.
993+
To disambiguate this, we are not relying in 'size(GI)' but on the length of the
992994
x,y coordinates vectors, that are assumed to always be correct.
993995
"""
994996
function getsize(GI::GItype)
@@ -1039,8 +1041,9 @@ end
10391041
"""
10401042
settimecol!(D::GDtype, Tcol)
10411043
1042-
Set the time column in the dataset D (or vector of them). `Tcol` is either an Int scalar or vector
1043-
of Ints with the column number(s) that hold the time columns.
1044+
Set the time column in the dataset D (or vector of them).
1045+
1046+
`Tcol` is either an Int scalar or vector of Ints with the column number(s) that hold the time columns.
10441047
"""
10451048
settimecol!(D::GDtype, Tc::Int) = isa(D, Vector) ? (D[1].attrib["Timecol"] = string(Tc)) : (D.attrib["Timecol"] = string(Tc))
10461049
settimecol!(D::GDtype, Tc::VecOrMat{<:Int}) = isa(D, Vector) ? (D[1].attrib["Timecol"] = join(Tc, ",")) : (D.attrib["Timecol"] = join(Tc, ","))
@@ -1052,10 +1055,13 @@ const set_timecol! = settimecol!
10521055
10531056
Changes the geometry of the dataset `D` (or vector of them). The keyword version takes precedence.
10541057
1055-
### Parameters
1058+
### Args
10561059
- `D`: A GMTdataset, or a vector of them.
10571060
- `geom` | `gm`: the new geometry to apply to D. These are alternatives ways of seting the geometry
10581061
but the keyword version takes precedence.
1062+
1063+
### Kwargs
1064+
- `geom`: the new geometry to apply to D.
10591065
"""
10601066
function setgeom!(D::GMTdataset, gm::Integer=0; geom::Integer=0)
10611067
D.geom = (geom != 0) ? geom : gm # The keyword version takes precedenceg
@@ -1067,11 +1073,13 @@ end
10671073

10681074
# ---------------------------------------------------------------------------------------------------
10691075
"""
1070-
refsystem_A2B!(A, B)
1076+
refsystem_A2B!(A, B) -> nothing
1077+
1078+
Copy the referencing information in object `A` to object `B`.
10711079
1072-
Copy the referencing information in object `A` to object `B`. Both `A` and `B` can be either a GMTgrid or
1073-
GMTimage or GMTdataset or vectors of GMTdataset objects. Attention that any previous referencing information
1074-
stored in object `A` will be lost (replaced by that on object `B`).
1080+
Both `A` and `B` can be either a GMTgrid or GMTimage or GMTdataset or vectors of GMTdataset objects.
1081+
Attention that any previous referencing information stored in object `A` will be lost
1082+
(replaced by that on object `B`).
10751083
"""
10761084
function refsystem_A2B!(A, B)
10771085
prj, wkt, epsg = isa(A, Vector) ? (A[1].proj4, A[1].wkt, A[1].epsg) : (A.proj4, A.wkt, A.epsg)
@@ -1118,7 +1126,7 @@ end
11181126
"""
11191127
overlap, value = rect_overlap(xc_1, yc_1, xc_2, yc_2, width1, height1, width2, height2) -> Bool, Float64
11201128
1121-
Check if two rectangles, aligned with the axes, overlap.
1129+
Check if two rectangles, aligned with the axes (non-rotated), overlap.
11221130
11231131
- `xc_1, yc_1`: Center of the first rectangle
11241132
- `xc_2, yc_2`: Center of the second rectangle

0 commit comments

Comments
 (0)