1+ import . ArchGDAL: RasterDataset, AbstractRasterBand,
2+ getgeotransform, width, height, getname, getcolorinterp,
3+ getband, nraster, getdataset, ArchGDAL
4+ using . ArchGDAL. DiskArrays: GridChunks, DiskArrays, eachchunk
15const AG = ArchGDAL
26
3- struct GDALBand{T} <: AbstractDiskArray{T,2}
7+ struct GDALBand{T} <: AG.DiskArrays. AbstractDiskArray{T,2}
48 filename:: String
59 band:: Int
610 size:: Tuple{Int,Int}
711 attrs:: Dict{String,Any}
812 cs:: GridChunks{2}
913end
10- function GDALBand (b,filename,i)
14+ function GDALBand (b, filename, i)
1115 s = size (b)
1216 atts = getbandattributes (b)
1317 GDALBand {AG.pixeltype(b)} (filename, i, s, atts, eachchunk (b))
1418end
1519Base. size (b:: GDALBand ) = b. size
1620DiskArrays. eachchunk (b:: GDALBand ) = b. cs
1721DiskArrays. haschunks (:: GDALBand ) = DiskArrays. Chunked ()
18- function DiskArrays. readblock! (b:: GDALBand ,aout,r:: AbstractUnitRange... )
22+ function DiskArrays. readblock! (b:: GDALBand , aout, r:: AbstractUnitRange... )
1923 AG. read (b. filename) do ds
20- AG. getband (ds,b. band) do bh
21- DiskArrays. readblock! (bh,aout,r... )
24+ AG. getband (ds, b. band) do bh
25+ DiskArrays. readblock! (bh, aout, r... )
26+ end
27+ end
28+ end
29+ function DiskArrays. writeblock! (b:: GDALBand , ain, r:: AbstractUnitRange... )
30+ AG. read (b. filename, flags= AG. OF_Update) do ds
31+ AG. getband (ds, b. band) do bh
32+ DiskArrays. writeblock! (bh, ain, r... )
2233 end
2334 end
2435end
@@ -27,47 +38,167 @@ struct GDALDataset
2738 filename:: String
2839 bandsize:: Tuple{Int,Int}
2940 projection:: String
30- trans:: NTuple{6, Float64}
41+ trans:: Vector{ Float64}
3142 bands:: OrderedDict{String}
3243end
3344
3445function GDALDataset (filename)
3546 AG. read (filename) do r
3647 nb = AG. nraster (r)
3748 allbands = map (1 : nb) do iband
38- b = AG. getband (r,iband)
39- gb = GDALBand (b, filename,iband)
49+ b = AG. getband (r, iband)
50+ gb = GDALBand (b, filename, iband)
4051 name = AG. getname (AG. getcolorinterp (b))
41- isempty (name) && (name = string (" Band" ,iband))
4252 name => gb
4353 end
4454 proj = AG. getproj (r)
45- trans = ( AG. getgeotransform (r) ... , )
55+ trans = AG. getgeotransform (r)
4656 s = AG. _common_size (r)
57+ allnames = first .(allbands)
58+ if ! allunique (allnames)
59+ allbands = [" Band$i " => last (v) for (i,v) in enumerate (allbands)]
60+ end
4761 GDALDataset (filename, s[1 : end - 1 ], proj, trans, OrderedDict (allbands))
4862 end
4963end
50- Base. haskey (ds:: GDALDataset , k) = in (k,(" X" ," Y" )) || haskey (ds. bands,k)
64+ Base. haskey (ds:: GDALDataset , k) = in (k, (" X" , " Y" )) || haskey (ds. bands, k)
5165# Implement Dataset interface
52- function get_var_handle (ds:: GDALDataset , name)
66+ function get_var_handle (ds:: GDALDataset , name)
5367 if name == " X"
54- range (ds. trans[1 ],length= ds. bandsize[1 ], step= ds. trans[2 ])
68+ range (ds. trans[1 ], length = ds. bandsize[1 ], step = ds. trans[2 ])
5569 elseif name == " Y"
56- range (ds. trans[4 ],length= ds. bandsize[2 ], step= ds. trans[6 ])
70+ range (ds. trans[4 ], length = ds. bandsize[2 ], step = ds. trans[6 ])
5771 else
5872 ds. bands[name]
5973 end
6074end
61-
75+
6276
6377get_varnames (ds:: GDALDataset ) = collect (keys (ds. bands))
6478
6579get_var_dims (ds:: GDALDataset , _) = (" X" , " Y" )
6680
67- function get_var_attrs (ds:: GDALDataset ,name)
68- if name in (" Y" ," X" )
81+ function get_var_attrs (ds:: GDALDataset , name)
82+ if name in (" Y" , " X" )
6983 Dict {String,Any} ()
7084 else
7185 ds. bands[name]. attrs
7286 end
73- end
87+ end
88+
89+ const colornames = AG. getname .(AG. GDAL. GDALColorInterp .(0 : 16 ))
90+
91+ islat (s) = startswith (uppercase (s), " LAT" )
92+ islon (s) = startswith (uppercase (s), " LON" )
93+ isx (s) = uppercase (s) == " X"
94+ isy (s) = uppercase (s) == " Y"
95+
96+ function totransform (x, y)
97+ xstep = diff (x)
98+ ystep = diff (y)
99+ if ! all (isapprox (first (xstep)), xstep) && ! all (isapprox (first (ystep)), ystep)
100+ throw (ArgumentError (" Grid must have regular spacing" ))
101+ end
102+ Float64[first (x), first (xstep), 0.0 , first (y), 0.0 , first (ystep)]
103+ end
104+ totransform (x:: AbstractRange , y:: AbstractRange ) =
105+ Float64[first (x), step (x), 0.0 , first (y), 0.0 , step (y)]
106+ getproj (userproj:: String , attrs) = AG. importPROJ4 (userproj)
107+ getproj (userproj:: AG.AbstractSpatialRef , attrs) = userproj
108+ function getproj (userproj:: Nothing , attrs)
109+ if haskey (attr, " projection_PROJ4" )
110+ return AG. importPROJ4 (attr[" projection_PROJ4" ])
111+ elseif haskey (attr, " projection_WKT" )
112+ return AG. importWKT (attr[" projection_WKT" ])
113+ else
114+ error (
115+ " Could not determine output projection from attributes, please specify userproj" ,
116+ )
117+ end
118+ end
119+
120+
121+ function create_dataset (
122+ :: Type{<:GDALDataset} ,
123+ outpath,
124+ gatts,
125+ dimnames,
126+ dimvals,
127+ dimattrs,
128+ vartypes,
129+ varnames,
130+ vardims,
131+ varattrs,
132+ varchunks;
133+ userproj = nothing ,
134+ kwargs... ,
135+ )
136+ @assert length (dimnames) == 2
137+ proj, trans = if islon (dimnames[1 ]) && islat (dimnames[2 ])
138+ # Lets set srs to EPSG:4326
139+ proj = AG. importEPSG (4326 )
140+ trans = totransform (dimvals[1 ], dimvals[2 ])
141+ proj, trans
142+ elseif isx (dimnames[1 ]) && isy (dimnames[2 ])
143+ # Try to find out srs
144+ proj = getproj (userproj, gatts)
145+ trans = totransform (dimvals[1 ], dimvals[2 ])
146+ proj, trans
147+ else
148+ error (" Did not find x, y or lon, lat dimensions in dataset" )
149+ end
150+ cs = first (varchunks)
151+ @assert all (isequal (varchunks[1 ]), varchunks)
152+
153+ driver = AG. getdriver (AG. extensiondriver (outpath))
154+
155+ nbands = length (varnames)
156+ dtype = promote_type (vartypes... )
157+ s = (length .(dimvals)... ,)
158+ bands = AG. create (
159+ outpath;
160+ driver = driver,
161+ width = length (dimvals[1 ]),
162+ height = length (dimvals[2 ]),
163+ nbands = nbands,
164+ dtype = dtype,
165+ options = [" BLOCKXSIZE=$(cs[1 ]) " , " BLOCKYSIZE=$(cs[2 ]) " ]
166+ ) do ds
167+ AG. setgeotransform! (ds, trans)
168+ bands = map (1 : length (varnames)) do i
169+ b = AG. getband (ds, i)
170+ icol = findfirst (isequal (varnames[i]), colornames)
171+ if isnothing (icol)
172+ AG. setcolorinterp! (b, AG. GDAL. GDALColorInterp (0 ))
173+ else
174+ AG. setcolorinterp! (b, AG. GDAL. GDALColorInterp (icol - 1 ))
175+ end
176+ atts = varattrs[i]
177+ haskey (atts, " missing_value" ) && AG. setnodatavalue! (b, atts[" missing_value" ])
178+ if haskey (atts, " labels" )
179+ labeldict = atts[labels]
180+ maxlabel = maximum (keys (labeldict))
181+ kt = keytype (labeldict)
182+ labelvec = [haskey (labeldict, et (i)) ? labeldict[et (i)] : " " for i = 0 : maxlabel]
183+ AG. setcategorynames! (b, labelvec)
184+ end
185+ haskey (atts, " units" ) && AG. setunittype! (b, atts[" units" ])
186+ haskey (atts, " scale_factor" ) && AG. setscale! (b, atts[" scale_factor" ])
187+ haskey (atts, " add_offset" ) && AG. setoffset! (b, atts[" add_offset" ])
188+ GDALBand {dtype} (outpath, i, s, atts, AG. DiskArrays. GridChunks (s,cs))
189+ end
190+ end
191+ return GDALDataset (outpath, s, AG. toPROJ4 (proj), trans, OrderedDict (vn=> b for (vn,b) in zip (varnames, bands)))
192+ end
193+
194+ allow_parallel_write (:: Type{<:GDALDataset} ) = false
195+ allow_parallel_write (:: GDALDataset ) = false
196+
197+ allow_missings (:: Type{<:GDALDataset} ) = false
198+ allow_missings (:: GDALDataset ) = false
199+
200+ backendlist[:gdal ] = GDALDataset
201+ push! (backendregex,r" .tif$" => GDALDataset)
202+ push! (backendregex,r" .gtif$" => GDALDataset)
203+ push! (backendregex,r" .tiff$" => GDALDataset)
204+ push! (backendregex,r" .gtiff$" => GDALDataset)
0 commit comments