ffi-gdal 0.0.4 → 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +7 -1
  3. data/Rakefile +12 -1
  4. data/TODO.md +11 -0
  5. data/ffi-gdal.gemspec +2 -2
  6. data/lib/ext/error_symbols.rb +59 -0
  7. data/lib/ext/float_ext.rb +15 -0
  8. data/lib/ext/narray_ext.rb +16 -0
  9. data/lib/ext/to_bool.rb +2 -0
  10. data/lib/ffi-gdal.rb +139 -4
  11. data/lib/ffi/{gdal/cpl_conv.rb → cpl/conv_h.rb} +2 -3
  12. data/lib/ffi/{gdal/cpl_error.rb → cpl/error_h.rb} +1 -25
  13. data/lib/ffi/cpl/minixml_h.rb +14 -0
  14. data/lib/ffi/{gdal/cpl_string.rb → cpl/string_h.rb} +0 -25
  15. data/lib/ffi/{gdal/cpl_vsi.rb → cpl/vsi_h.rb} +0 -0
  16. data/lib/ffi/cpl/xml_node.rb +13 -0
  17. data/lib/ffi/gdal.rb +57 -593
  18. data/lib/ffi/gdal/alg_h.rb +127 -0
  19. data/lib/ffi/gdal/gdal_grid_data_metrics_options.rb +14 -0
  20. data/lib/ffi/gdal/gdal_grid_inverse_distance_to_a_power_options.rb +19 -0
  21. data/lib/ffi/gdal/gdal_grid_moving_average_options.rb +14 -0
  22. data/lib/ffi/gdal/gdal_grid_nearest_neighbor_options.rb +13 -0
  23. data/lib/ffi/gdal/gdal_h.rb +683 -0
  24. data/lib/ffi/gdal/gdal_rpc_info.rb +27 -0
  25. data/lib/ffi/gdal/gdal_transformer_info.rb +14 -0
  26. data/lib/ffi/gdal/gdal_warp_options.rb +43 -0
  27. data/lib/ffi/gdal/grid_h.rb +51 -0
  28. data/lib/ffi/gdal/version.rb +1 -1
  29. data/lib/ffi/gdal/warper_h.rb +48 -0
  30. data/lib/ffi/ogr.rb +12 -0
  31. data/lib/ffi/ogr/api_h.rb +553 -0
  32. data/lib/ffi/ogr/core_h.rb +148 -0
  33. data/lib/ffi/ogr/featurestyle_h.rb +22 -0
  34. data/lib/ffi/ogr/geocoding_h.rb +21 -0
  35. data/lib/ffi/ogr/ogr_contour_writer_info.rb +14 -0
  36. data/lib/ffi/ogr/ogr_envelope.rb +12 -0
  37. data/lib/ffi/ogr/ogr_envelope_3d.rb +14 -0
  38. data/lib/ffi/ogr/ogr_field.rb +50 -0
  39. data/lib/ffi/ogr/ogr_style_param.rb +12 -0
  40. data/lib/ffi/ogr/ogr_style_value.rb +13 -0
  41. data/lib/ffi/ogr/srs_api_h.rb +325 -0
  42. data/lib/gdal/color_entry.rb +47 -0
  43. data/lib/gdal/color_entry_extensions.rb +30 -0
  44. data/lib/gdal/color_interpretation.rb +15 -0
  45. data/lib/gdal/color_table.rb +146 -0
  46. data/lib/gdal/color_table_extensions.rb +47 -0
  47. data/lib/gdal/color_table_types/cmyk.rb +25 -0
  48. data/lib/gdal/color_table_types/gray.rb +9 -0
  49. data/lib/gdal/color_table_types/hls.rb +21 -0
  50. data/lib/gdal/color_table_types/rgb.rb +25 -0
  51. data/lib/gdal/data_type.rb +38 -0
  52. data/lib/gdal/dataset.rb +437 -0
  53. data/lib/gdal/dataset_extensions.rb +496 -0
  54. data/lib/gdal/driver.rb +244 -0
  55. data/lib/gdal/driver_extensions.rb +56 -0
  56. data/lib/gdal/environment_methods.rb +43 -0
  57. data/lib/{ffi-gdal → gdal}/exceptions.rb +4 -1
  58. data/lib/gdal/geo_transform.rb +188 -0
  59. data/lib/gdal/geo_transform_extensions.rb +90 -0
  60. data/lib/gdal/logger.rb +7 -0
  61. data/lib/{ffi-gdal → gdal}/major_object.rb +15 -14
  62. data/lib/gdal/options.rb +49 -0
  63. data/lib/gdal/raster_attribute_table.rb +185 -0
  64. data/lib/gdal/raster_attribute_table_extensions.rb +40 -0
  65. data/lib/{ffi-gdal → gdal}/raster_band.rb +227 -99
  66. data/lib/gdal/raster_band_extensions.rb +198 -0
  67. data/lib/{ffi-gdal → gdal}/version_info.rb +8 -0
  68. data/lib/gdal/warp_operation.rb +96 -0
  69. data/lib/ogr/coordinate_transformation.rb +108 -0
  70. data/lib/ogr/data_source.rb +172 -0
  71. data/lib/ogr/data_source_extensions.rb +32 -0
  72. data/lib/ogr/driver.rb +119 -0
  73. data/lib/ogr/envelope.rb +80 -0
  74. data/lib/ogr/envelope_extensions.rb +92 -0
  75. data/lib/ogr/exceptions.rb +35 -0
  76. data/lib/ogr/feature.rb +212 -0
  77. data/lib/ogr/feature_definition.rb +120 -0
  78. data/lib/ogr/feature_definition_extensions.rb +36 -0
  79. data/lib/ogr/feature_extensions.rb +31 -0
  80. data/lib/ogr/field.rb +91 -0
  81. data/lib/ogr/field_extensions.rb +23 -0
  82. data/lib/ogr/geocoding_session.rb +84 -0
  83. data/lib/ogr/geometry.rb +617 -0
  84. data/lib/ogr/geometry_extensions.rb +60 -0
  85. data/lib/ogr/geometry_types/collection.rb +45 -0
  86. data/lib/ogr/geometry_types/curve.rb +120 -0
  87. data/lib/ogr/geometry_types/surface.rb +20 -0
  88. data/lib/ogr/layer.rb +226 -0
  89. data/lib/ogr/layer_extensions.rb +55 -0
  90. data/lib/ogr/line_string.rb +7 -0
  91. data/lib/ogr/linear_ring.rb +6 -0
  92. data/lib/ogr/multi_line_string.rb +9 -0
  93. data/lib/ogr/multi_point.rb +7 -0
  94. data/lib/ogr/multi_polygon.rb +14 -0
  95. data/lib/ogr/point.rb +89 -0
  96. data/lib/ogr/polygon.rb +9 -0
  97. data/lib/ogr/spatial_reference.rb +723 -0
  98. data/lib/ogr/spatial_reference_extensions.rb +32 -0
  99. data/lib/ogr/style_table.rb +17 -0
  100. data/lib/ogr/style_table_extensions.rb +16 -0
  101. data/spec/{ffi-gdal/integration → integration}/color_table_info_spec.rb +1 -1
  102. data/spec/{ffi-gdal/integration → integration}/dataset_info_spec.rb +0 -0
  103. data/spec/{ffi-gdal/integration → integration}/driver_info_spec.rb +1 -1
  104. data/spec/{ffi-gdal/integration → integration}/geo_transform_info_spec.rb +0 -0
  105. data/spec/{ffi-gdal/integration → integration}/raster_attribute_table_info_spec.rb +1 -1
  106. data/spec/{ffi-gdal/integration → integration}/raster_band_info_spec.rb +5 -5
  107. data/spec/spec_helper.rb +4 -1
  108. data/spec/support/shapefiles/states_21basic/states.prj +1 -0
  109. data/spec/support/shapefiles/states_21basic/states.sbn +0 -0
  110. data/spec/support/shapefiles/states_21basic/states.sbx +0 -0
  111. data/spec/support/shapefiles/states_21basic/states.shp +0 -0
  112. data/spec/support/worldfiles/SR_50M/SR_50M.VERSION.txt +1 -0
  113. data/spec/support/worldfiles/SR_50M/SR_50M.prj +1 -0
  114. data/spec/support/worldfiles/SR_50M/SR_50M.tfw +6 -0
  115. data/spec/{ext/cpl_error_symbols_spec.rb → unit/ext/error_symbols_spec.rb} +1 -1
  116. data/spec/unit/gdal/color_table_spec.rb +146 -0
  117. data/spec/unit/ogr/layer_spec.rb +97 -0
  118. data/spec/unit/ogr/linear_ring_spec.rb +111 -0
  119. data/spec/unit/ogr/point_spec.rb +321 -0
  120. data/spec/{ffi-gdal/unit → unit}/version_info_spec.rb +1 -1
  121. data/testing_gdal.rb +168 -0
  122. data/testing_gdalwarp.rb +91 -0
  123. data/testing_layer_to_layer.rb +35 -0
  124. data/testing_ndvi.rb +76 -0
  125. data/testing_nir.rb +77 -0
  126. data/testing_ogr.rb +63 -0
  127. metadata +167 -59
  128. data/lib/ext/cpl_error_symbols.rb +0 -37
  129. data/lib/ffi-gdal/color_table.rb +0 -59
  130. data/lib/ffi-gdal/dataset.rb +0 -359
  131. data/lib/ffi-gdal/driver.rb +0 -151
  132. data/lib/ffi-gdal/geo_transform.rb +0 -137
  133. data/lib/ffi-gdal/raster_attribute_table.rb +0 -78
  134. data/lib/ffi/gdal/ogr_api.rb +0 -21
  135. data/lib/ffi/gdal/ogr_core.rb +0 -195
  136. data/lib/ffi/gdal/ogr_srs_api.rb +0 -44
  137. data/meow.rb +0 -144
  138. data/rubby.rb +0 -224
@@ -1,37 +0,0 @@
1
- require_relative '../ffi-gdal/exceptions'
2
-
3
-
4
- class ::Symbol
5
-
6
- # When FFI interfaces with a GDAL CPLError, it returns a Symbol that
7
- # maps to the CPLErr enum (see GDAL's cpl_error.h or cpl_error.rb docs). Since
8
- # many of the GDAL C API's functions return these symbols _and_ because the
9
- # symbols have some functional implications, this wrapping here is simply for
10
- # returning Ruby-esque values when the GDAL API returns one of these symbols.
11
- #
12
- # The optional params let you override behavior. Passing in a block instead
13
- # will call the block. Ex.
14
- #
15
- # cpl_err = GDALCopyDatasetFiles(@gdal_driver_handle, new_name, old_name)
16
- # cpl_err.to_ruby # returns the default value
17
- # cpl_err.to_ruby { raise 'Crap!' }
18
- def to_ruby(none: :none, debug: :debug, warning: :warning, failure: :failure, fatal: :fatal)
19
- case self
20
- when :CE_None then none
21
- when :CE_Debug then debug
22
- when :CE_Warning then warning
23
- when :CE_Failure then failure
24
- when :CE_Fatal then fatal
25
- end
26
- end
27
-
28
- def to_bool
29
- case self
30
- when :CE_None then true
31
- when :CE_Debug then true
32
- when :CE_Warning then false
33
- when :CE_Failure then raise GDAL::CPLErrFailure
34
- when :CE_Fatal then raise GDAL::CPLErrFailure
35
- end
36
- end
37
- end
@@ -1,59 +0,0 @@
1
- require_relative '../ffi/gdal'
2
-
3
-
4
- module GDAL
5
- class ColorTable
6
- include FFI::GDAL
7
-
8
- def initialize(gdal_raster_band, color_table_pointer: nil)
9
- @gdal_raster_band = if gdal_raster_band.is_a? GDAL::RasterBand
10
- gdal_raster_band.c_pointer
11
- else
12
- gdal_raster_band
13
- end
14
-
15
- @gdal_color_table = color_table_pointer
16
- end
17
-
18
- def c_pointer
19
- @gdal_color_table ||= GDALGetRasterColorTable(@gdal_raster_band)
20
- end
21
-
22
- def null?
23
- c_pointer.nil? || c_pointer.null?
24
- end
25
-
26
- # Usually :GPI_RGB.
27
- #
28
- # @return [Symbol] One of FFI::GDAL::GDALPaletteInterp.
29
- def palette_interpretation
30
- GDALGetPaletteInterpretation(c_pointer)
31
- end
32
-
33
- # @return [Fixnum]
34
- def color_entry_count
35
- return 0 if null?
36
-
37
- GDALGetColorEntryCount(c_pointer)
38
- end
39
-
40
- # @param index [Fixnum]
41
- # @return [FFI::GDAL::GDALColorEntry]
42
- def color_entry(index)
43
- return nil if null?
44
-
45
- GDALGetColorEntry(c_pointer, index)
46
- end
47
-
48
- # @param index [Fixnum]
49
- # @return [GGI::GDAL::GDALColorEntry]
50
- def color_entry_as_rgb(index)
51
- return nil if null?
52
-
53
- entry = GDALColorEntry.new
54
- GDALGetColorEntryAsRGB(c_pointer, index, entry)
55
-
56
- entry
57
- end
58
- end
59
- end
@@ -1,359 +0,0 @@
1
- require 'uri'
2
- require_relative '../ffi/gdal'
3
- require_relative '../ffi-gdal'
4
- require_relative 'driver'
5
- require_relative 'geo_transform'
6
- require_relative 'raster_band'
7
- require_relative 'exceptions'
8
- require_relative 'major_object'
9
-
10
-
11
- module GDAL
12
-
13
- # A set of associated raster bands and info common to them all. It's also
14
- # responsible for the georeferencing transform and coordinate system
15
- # definition of all bands.
16
- class Dataset
17
- include FFI::GDAL
18
- include MajorObject
19
-
20
- ACCESS_FLAGS = {
21
- 'r' => :GA_ReadOnly,
22
- 'w' => :GA_Update
23
- }
24
-
25
- # @param path [String] Path to the file that contains the dataset. Can be
26
- # a local file or a URL.
27
- # @param access_flag [String] 'r' or 'w'.
28
- def self.open(path, access_flag)
29
- uri = URI.parse(path)
30
- file_path = uri.scheme.nil? ? ::File.expand_path(path) : path
31
-
32
- pointer = FFI::GDAL.GDALOpen(file_path, ACCESS_FLAGS[access_flag])
33
- raise OpenFailure.new(file_path) if pointer.null?
34
-
35
- new(pointer)
36
- end
37
-
38
- # Computes NDVI from the red and near-infrared bands in the dataset. Raises
39
- # a GDAL::RequiredBandNotFound if one of those band types isn't found.
40
- #
41
- # @param source [String] Path to the dataset that contains the red and NIR
42
- # bands.
43
- # @param destination [String] Path to output the new dataset to.
44
- # @param driver_name [String] The type of dataset to create.
45
- def self.extract_ndvi(source, destination, driver_name: 'GTiff')
46
- extract_8bit(source, destination, driver_name) do |original, ndvi_dataset|
47
- red = original.red_band
48
- nir = original.undefined_band
49
-
50
- if red.nil?
51
- fail RequiredBandNotFound, 'Red band not found.'
52
- elsif nir.nil?
53
- fail RequiredBandNotFound, 'Near-infrared'
54
- end
55
-
56
- the_array = calculate_ndvi(red.to_a, nir.to_a)
57
-
58
- ndvi_band = ndvi_dataset.raster_band(1)
59
- ndvi_band.write_array(the_array)
60
- end
61
- end
62
-
63
- def self.extract_gndvi(source, destination, driver_name: 'GTiff')
64
- extract_8bit(source, destination, driver_name) do |original, gndvi_dataset|
65
- green = original.green_band
66
- nir = original.undefined_band
67
-
68
- if green.nil?
69
- fail RequiredBandNotFound, 'Green band not found.'
70
- elsif nir.nil?
71
- fail RequiredBandNotFound, 'Near-infrared'
72
- end
73
-
74
- the_array = calculate_ndvi(green.to_a, nir.to_a)
75
-
76
- gndvi_band = gndvi_dataset.raster_band(1)
77
- gndvi_band.write_array(the_array)
78
- end
79
- end
80
-
81
- def self.extract_nir(source, destination, driver_name: 'GTiff')
82
- extract_8bit(source, destination, driver_name) do |original, nir_dataset|
83
- nir = original.undefined_band
84
- fail RequiredBandNotFound, 'Near-infrared' if nir.nil?
85
-
86
- nir_band = nir_dataset.raster_band(1)
87
- nir_band.write_array(nir.to_a)
88
- end
89
- end
90
-
91
- def self.extract_natural_color(source, destination, driver_name: 'GTiff')
92
- original_dataset = open(source, 'r')
93
- geo_transform = original_dataset.geo_transform
94
- projection = original_dataset.projection
95
- rows = original_dataset.raster_y_size
96
- columns = original_dataset.raster_x_size
97
-
98
- driver = GDAL::Driver.by_name(driver_name)
99
- driver.create_dataset(destination, columns, rows, bands: 3) do |new_dataset|
100
- new_dataset.geo_transform = geo_transform
101
- new_dataset.projection = projection
102
- original_red_band = original_dataset.red_band
103
- original_green_band = original_dataset.green_band
104
- original_blue_band = original_dataset.blue_band
105
-
106
- new_red_band = new_dataset.raster_band(1)
107
- new_red_band.write_array(original_red_band.to_a)
108
-
109
- new_green_band = new_dataset.raster_band(2)
110
- new_green_band.write_array(original_green_band.to_a)
111
-
112
- new_blue_band = new_dataset.raster_band(3)
113
- new_blue_band.write_array(original_blue_band.to_a)
114
- end
115
- end
116
-
117
- # @param red_band_array [NArray]
118
- # @param nir_band_array [NArray]
119
- # @return [NArray]
120
- def self.calculate_ndvi(red_band_array, nir_band_array)
121
- (nir_band_array - red_band_array) / (nir_band_array + red_band_array)
122
- end
123
-
124
- def self.extract_8bit(source, destination, driver_name)
125
- dataset = open(source, 'r')
126
- geo_transform = dataset.geo_transform
127
- projection = dataset.projection
128
- rows = dataset.raster_y_size
129
- columns = dataset.raster_x_size
130
-
131
- driver = GDAL::Driver.by_name(driver_name)
132
- driver.create_dataset(destination, columns, rows) do |new_dataset|
133
- new_dataset.geo_transform = geo_transform
134
- new_dataset.projection = projection
135
-
136
- yield dataset, new_dataset
137
- end
138
- end
139
- private_class_method :extract_8bit
140
-
141
- # @param dataset_pointer [FFI::Pointer] Pointer to the dataset in memory.
142
- def initialize(dataset_pointer)
143
- @gdal_dataset = dataset_pointer
144
- @last_known_file_list = []
145
- @open = true
146
- close_me = -> { self.close }
147
- ObjectSpace.define_finalizer self, close_me
148
- end
149
-
150
- # @return [FFI::Pointer] Pointer to the GDALDatasetH that's represented by
151
- # this Ruby object.
152
- def c_pointer
153
- @gdal_dataset
154
- end
155
-
156
- # Close the dataset.
157
- def close
158
- @last_known_file_list = file_list
159
- GDALClose(@gdal_dataset)
160
- @open = false
161
- end
162
-
163
- # Tries to reopen the dataset using the first item from #file_list before
164
- # the dataset was closed.
165
- #
166
- # @param access_flag [String]
167
- # @return [Boolean]
168
- def reopen(access_flag)
169
- @gdal_dataset = GDALOpen(@last_known_file_list.first, access_flag)
170
-
171
- @open = true unless @gdal_dataset.null?
172
- end
173
-
174
- # @return [Boolean]
175
- def open?
176
- @open
177
- end
178
-
179
- # @return [GDAL::Driver] The driver to be used for working with this
180
- # dataset.
181
- def driver
182
- return @driver if @driver
183
-
184
- @driver = if @gdal_dataset && !null?
185
- Driver.new(dataset: @gdal_dataset)
186
- else
187
- Driver.new
188
- end
189
- end
190
-
191
- # Fetches all files that form the dataset.
192
- # @return [Array<String>]
193
- def file_list
194
- list_pointer = GDALGetFileList(c_pointer)
195
- file_list = list_pointer.get_array_of_string(0)
196
- CSLDestroy(list_pointer)
197
-
198
- file_list
199
- end
200
-
201
- # @return [Fixnum]
202
- def raster_x_size
203
- return nil if null?
204
-
205
- GDALGetRasterXSize(@gdal_dataset)
206
- end
207
-
208
- # @return [Fixnum]
209
- def raster_y_size
210
- return nil if null?
211
-
212
- GDALGetRasterYSize(@gdal_dataset)
213
- end
214
-
215
- # @return [Fixnum]
216
- def raster_count
217
- return 0 if null?
218
-
219
- GDALGetRasterCount(@gdal_dataset)
220
- end
221
-
222
- # @param raster_index [Fixnum]
223
- # @return [GDAL::RasterBand]
224
- def raster_band(raster_index)
225
- @raster_bands ||= Array.new(raster_count)
226
-
227
- if @raster_bands[raster_index] && !@raster_bands[raster_index].null?
228
- return @raster_bands[raster_index]
229
- end
230
-
231
- @raster_bands[raster_index] =
232
- GDAL::RasterBand.new(@gdal_dataset, band_id: raster_index)
233
- end
234
-
235
- # @return [String]
236
- def projection
237
- return '' if null?
238
-
239
- GDALGetProjectionRef(@gdal_dataset)
240
- end
241
-
242
- # @param new_projection [String]
243
- # @return [Boolean]
244
- def projection=(new_projection)
245
- cpl_err = GDALSetProjection(@gdal_dataset, new_projection)
246
-
247
- cpl_err.to_bool
248
- end
249
-
250
- # @return [Symbol]
251
- def access_flag
252
- return nil if null?
253
-
254
- flag = GDALGetAccess(@gdal_dataset)
255
-
256
- GDALAccess[flag]
257
- end
258
-
259
- # @return [GDAL::GeoTransform]
260
- def geo_transform
261
- @geo_transform ||= GeoTransform.new(@gdal_dataset)
262
- end
263
-
264
- # @param new_transform [GDAL::GeoTransform]
265
- # @return [GDAL::GeoTransform]
266
- def geo_transform=(new_transform)
267
- new_pointer = new_transform.c_pointer.dup
268
- cpl_err = GDALSetGeoTransform(@gdal_dataset, new_pointer)
269
- cpl_err.to_bool
270
-
271
- @geo_transform = GeoTransform.new(@gdal_dataset, geo_transform_pointer: new_pointer)
272
- end
273
-
274
- # @return [Fixnum]
275
- def gcp_count
276
- return 0 if null?
277
-
278
- GDALGetGCPCount(@gdal_dataset)
279
- end
280
-
281
- # @return [String]
282
- def gcp_projection
283
- return '' if null?
284
-
285
- GDALGetGCPProjection(@gdal_dataset)
286
- end
287
-
288
- # @return [FFI::GDAL::GDALGCP]
289
- def gcps
290
- return GDALGCP.new if null?
291
-
292
- gcp_array_pointer = GDALGetGCPs(@gdal_dataset)
293
-
294
- if gcp_array_pointer.null?
295
- GDALGCP.new
296
- else
297
- GDALGCP.new(gcp_array_pointer)
298
- end
299
- end
300
-
301
- # Iterates raster bands from 1 to #raster_count and yields them to the given
302
- # block.
303
- def each_band
304
- 1.upto(raster_count) do |i|
305
- yield(raster_band(i))
306
- end
307
- end
308
-
309
- # Returns the first raster band for which the block returns true. Ex.
310
- #
311
- # dataset.find_band do |band|
312
- # band.color_interpretation == :GCI_RedBand
313
- # end
314
- #
315
- # @return [GDAL::RasterBand]
316
- def find_band
317
- each_band do |band|
318
- result = yield(band)
319
- return band if result
320
- end
321
- end
322
-
323
- # @return [GDAL::RasterBand]
324
- def red_band
325
- band = find_band do |band|
326
- band.color_interpretation == :GCI_RedBand
327
- end
328
-
329
- band.is_a?(GDAL::RasterBand) ? band : nil
330
- end
331
-
332
- # @return [GDAL::RasterBand]
333
- def green_band
334
- band = find_band do |band|
335
- band.color_interpretation == :GCI_GreenBand
336
- end
337
-
338
- band.is_a?(GDAL::RasterBand) ? band : nil
339
- end
340
-
341
- # @return [GDAL::RasterBand]
342
- def blue_band
343
- band = find_band do |band|
344
- band.color_interpretation == :GCI_BlueBand
345
- end
346
-
347
- band.is_a?(GDAL::RasterBand) ? band : nil
348
- end
349
-
350
- # @return [GDAL::RasterBand]
351
- def undefined_band
352
- band = find_band do |band|
353
- band.color_interpretation == :GCI_Undefined
354
- end
355
-
356
- band.is_a?(GDAL::RasterBand) ? band : nil
357
- end
358
- end
359
- end