/src/gdal/gcore/gdalnodatavaluesmaskband.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: GDAL Core |
4 | | * Purpose: Implementation of GDALNoDataValuesMaskBand, a class implementing |
5 | | * a default band mask based on the NODATA_VALUES metadata item. |
6 | | * A pixel is considered nodata in all bands if and only if all bands |
7 | | * match the corresponding value in the NODATA_VALUES tuple |
8 | | * Author: Even Rouault, <even dot rouault at spatialys.com> |
9 | | * |
10 | | ****************************************************************************** |
11 | | * Copyright (c) 2008-2009, Even Rouault <even dot rouault at spatialys.com> |
12 | | * |
13 | | * SPDX-License-Identifier: MIT |
14 | | ****************************************************************************/ |
15 | | |
16 | | #include "cpl_port.h" |
17 | | #include "gdal_priv.h" |
18 | | |
19 | | #include <cstring> |
20 | | |
21 | | #include "cpl_conv.h" |
22 | | #include "cpl_error.h" |
23 | | #include "cpl_string.h" |
24 | | #include "cpl_vsi.h" |
25 | | #include "gdal.h" |
26 | | |
27 | | //! @cond Doxygen_Suppress |
28 | | /************************************************************************/ |
29 | | /* GDALNoDataValuesMaskBand() */ |
30 | | /************************************************************************/ |
31 | | |
32 | | GDALNoDataValuesMaskBand::GDALNoDataValuesMaskBand(GDALDataset *poDSIn) |
33 | 0 | : padfNodataValues(nullptr) |
34 | 0 | { |
35 | 0 | const char *pszNoDataValues = poDSIn->GetMetadataItem("NODATA_VALUES"); |
36 | 0 | char **papszNoDataValues = |
37 | 0 | CSLTokenizeStringComplex(pszNoDataValues, " ", FALSE, FALSE); |
38 | |
|
39 | 0 | padfNodataValues = static_cast<double *>( |
40 | 0 | CPLMalloc(sizeof(double) * poDSIn->GetRasterCount())); |
41 | 0 | for (int i = 0; i < poDSIn->GetRasterCount(); ++i) |
42 | 0 | { |
43 | 0 | padfNodataValues[i] = CPLAtof(papszNoDataValues[i]); |
44 | 0 | } |
45 | |
|
46 | 0 | CSLDestroy(papszNoDataValues); |
47 | |
|
48 | 0 | poDS = poDSIn; |
49 | 0 | nBand = 0; |
50 | |
|
51 | 0 | nRasterXSize = poDS->GetRasterXSize(); |
52 | 0 | nRasterYSize = poDS->GetRasterYSize(); |
53 | |
|
54 | 0 | eDataType = GDT_Byte; |
55 | 0 | poDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize); |
56 | 0 | } |
57 | | |
58 | | /************************************************************************/ |
59 | | /* ~GDALNoDataValuesMaskBand() */ |
60 | | /************************************************************************/ |
61 | | |
62 | | GDALNoDataValuesMaskBand::~GDALNoDataValuesMaskBand() |
63 | | |
64 | 0 | { |
65 | 0 | CPLFree(padfNodataValues); |
66 | 0 | } |
67 | | |
68 | | /************************************************************************/ |
69 | | /* FillOutBuffer() */ |
70 | | /************************************************************************/ |
71 | | |
72 | | template <class T> |
73 | | static void FillOutBuffer(GPtrDiff_t nBlockOffsetPixels, int nBands, |
74 | | const void *pabySrc, const double *padfNodataValues, |
75 | | void *pImage) |
76 | 0 | { |
77 | 0 | T *paNoData = static_cast<T *>(CPLMalloc(nBands * sizeof(T))); |
78 | 0 | for (int iBand = 0; iBand < nBands; ++iBand) |
79 | 0 | { |
80 | 0 | paNoData[iBand] = static_cast<T>(padfNodataValues[iBand]); |
81 | 0 | } |
82 | |
|
83 | 0 | for (GPtrDiff_t i = 0; i < nBlockOffsetPixels; i++) |
84 | 0 | { |
85 | 0 | int nCountNoData = 0; |
86 | 0 | for (int iBand = 0; iBand < nBands; ++iBand) |
87 | 0 | { |
88 | 0 | if (static_cast<const T *>( |
89 | 0 | pabySrc)[i + iBand * nBlockOffsetPixels] == paNoData[iBand]) |
90 | 0 | ++nCountNoData; |
91 | 0 | } |
92 | 0 | static_cast<GByte *>(pImage)[i] = nCountNoData == nBands ? 0 : 255; |
93 | 0 | } |
94 | |
|
95 | 0 | CPLFree(paNoData); |
96 | 0 | } Unexecuted instantiation: gdalnodatavaluesmaskband.cpp:void FillOutBuffer<unsigned char>(long long, int, void const*, double const*, void*) Unexecuted instantiation: gdalnodatavaluesmaskband.cpp:void FillOutBuffer<unsigned int>(long long, int, void const*, double const*, void*) Unexecuted instantiation: gdalnodatavaluesmaskband.cpp:void FillOutBuffer<int>(long long, int, void const*, double const*, void*) Unexecuted instantiation: gdalnodatavaluesmaskband.cpp:void FillOutBuffer<float>(long long, int, void const*, double const*, void*) Unexecuted instantiation: gdalnodatavaluesmaskband.cpp:void FillOutBuffer<double>(long long, int, void const*, double const*, void*) |
97 | | |
98 | | /************************************************************************/ |
99 | | /* IReadBlock() */ |
100 | | /************************************************************************/ |
101 | | |
102 | | CPLErr GDALNoDataValuesMaskBand::IReadBlock(int nXBlockOff, int nYBlockOff, |
103 | | void *pImage) |
104 | | |
105 | 0 | { |
106 | 0 | GDALDataType eWrkDT = GDT_Unknown; |
107 | | |
108 | | /* -------------------------------------------------------------------- */ |
109 | | /* Decide on a working type. */ |
110 | | /* -------------------------------------------------------------------- */ |
111 | 0 | switch (poDS->GetRasterBand(1)->GetRasterDataType()) |
112 | 0 | { |
113 | 0 | case GDT_Byte: |
114 | 0 | eWrkDT = GDT_Byte; |
115 | 0 | break; |
116 | | |
117 | 0 | case GDT_UInt16: |
118 | 0 | case GDT_UInt32: |
119 | 0 | eWrkDT = GDT_UInt32; |
120 | 0 | break; |
121 | | |
122 | 0 | case GDT_Int8: |
123 | 0 | case GDT_Int16: |
124 | 0 | case GDT_Int32: |
125 | 0 | case GDT_CInt16: |
126 | 0 | case GDT_CInt32: |
127 | 0 | eWrkDT = GDT_Int32; |
128 | 0 | break; |
129 | | |
130 | 0 | case GDT_Float16: |
131 | 0 | case GDT_CFloat16: |
132 | 0 | case GDT_Float32: |
133 | 0 | case GDT_CFloat32: |
134 | 0 | eWrkDT = GDT_Float32; |
135 | 0 | break; |
136 | | |
137 | 0 | case GDT_Float64: |
138 | 0 | case GDT_CFloat64: |
139 | 0 | eWrkDT = GDT_Float64; |
140 | 0 | break; |
141 | | |
142 | 0 | case GDT_Int64: |
143 | 0 | case GDT_UInt64: |
144 | | // Lossy mapping... |
145 | 0 | eWrkDT = GDT_Float64; |
146 | 0 | break; |
147 | | |
148 | 0 | case GDT_Unknown: |
149 | 0 | case GDT_TypeCount: |
150 | 0 | CPLAssert(false); |
151 | 0 | eWrkDT = GDT_Float64; |
152 | 0 | break; |
153 | 0 | } |
154 | | |
155 | | /* -------------------------------------------------------------------- */ |
156 | | /* Read the image data. */ |
157 | | /* -------------------------------------------------------------------- */ |
158 | 0 | const int nBands = poDS->GetRasterCount(); |
159 | 0 | const int nWrkDTSize = GDALGetDataTypeSizeBytes(eWrkDT); |
160 | 0 | GByte *pabySrc = static_cast<GByte *>(VSI_MALLOC3_VERBOSE( |
161 | 0 | cpl::fits_on<int>(nBands * nWrkDTSize), nBlockXSize, nBlockYSize)); |
162 | 0 | if (pabySrc == nullptr) |
163 | 0 | { |
164 | 0 | return CE_Failure; |
165 | 0 | } |
166 | | |
167 | 0 | int nXSizeRequest = 0; |
168 | 0 | int nYSizeRequest = 0; |
169 | 0 | GetActualBlockSize(nXBlockOff, nYBlockOff, &nXSizeRequest, &nYSizeRequest); |
170 | |
|
171 | 0 | if (nXSizeRequest != nBlockXSize || nYSizeRequest != nBlockYSize) |
172 | 0 | { |
173 | | // memset the whole buffer to avoid Valgrind warnings in case we can't |
174 | | // fetch a full block. |
175 | 0 | memset(pabySrc, 0, |
176 | 0 | static_cast<size_t>(nBands) * nWrkDTSize * nBlockXSize * |
177 | 0 | nBlockYSize); |
178 | 0 | } |
179 | |
|
180 | 0 | const GPtrDiff_t nBlockOffsetPixels = |
181 | 0 | static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize; |
182 | 0 | const GPtrDiff_t nBandOffsetByte = nWrkDTSize * nBlockOffsetPixels; |
183 | 0 | for (int iBand = 0; iBand < nBands; ++iBand) |
184 | 0 | { |
185 | 0 | const CPLErr eErr = poDS->GetRasterBand(iBand + 1)->RasterIO( |
186 | 0 | GF_Read, nXBlockOff * nBlockXSize, nYBlockOff * nBlockYSize, |
187 | 0 | nXSizeRequest, nYSizeRequest, pabySrc + iBand * nBandOffsetByte, |
188 | 0 | nXSizeRequest, nYSizeRequest, eWrkDT, 0, |
189 | 0 | static_cast<GSpacing>(nBlockXSize) * nWrkDTSize, nullptr); |
190 | 0 | if (eErr != CE_None) |
191 | 0 | return eErr; |
192 | 0 | } |
193 | | |
194 | | /* -------------------------------------------------------------------- */ |
195 | | /* Process different cases. */ |
196 | | /* -------------------------------------------------------------------- */ |
197 | 0 | switch (eWrkDT) |
198 | 0 | { |
199 | 0 | case GDT_Byte: |
200 | 0 | { |
201 | 0 | FillOutBuffer<GByte>(nBlockOffsetPixels, nBands, pabySrc, |
202 | 0 | padfNodataValues, pImage); |
203 | 0 | } |
204 | 0 | break; |
205 | | |
206 | 0 | case GDT_UInt32: |
207 | 0 | { |
208 | 0 | FillOutBuffer<GUInt32>(nBlockOffsetPixels, nBands, pabySrc, |
209 | 0 | padfNodataValues, pImage); |
210 | 0 | } |
211 | 0 | break; |
212 | | |
213 | 0 | case GDT_Int32: |
214 | 0 | { |
215 | 0 | FillOutBuffer<GInt32>(nBlockOffsetPixels, nBands, pabySrc, |
216 | 0 | padfNodataValues, pImage); |
217 | 0 | } |
218 | 0 | break; |
219 | | |
220 | 0 | case GDT_Float32: |
221 | 0 | { |
222 | 0 | FillOutBuffer<float>(nBlockOffsetPixels, nBands, pabySrc, |
223 | 0 | padfNodataValues, pImage); |
224 | 0 | } |
225 | 0 | break; |
226 | | |
227 | 0 | case GDT_Float64: |
228 | 0 | { |
229 | 0 | FillOutBuffer<double>(nBlockOffsetPixels, nBands, pabySrc, |
230 | 0 | padfNodataValues, pImage); |
231 | 0 | } |
232 | 0 | break; |
233 | | |
234 | 0 | default: |
235 | 0 | CPLAssert(false); |
236 | 0 | break; |
237 | 0 | } |
238 | | |
239 | 0 | CPLFree(pabySrc); |
240 | |
|
241 | 0 | return CE_None; |
242 | 0 | } |
243 | | |
244 | | /************************************************************************/ |
245 | | /* EmitErrorMessageIfWriteNotSupported() */ |
246 | | /************************************************************************/ |
247 | | |
248 | | bool GDALNoDataValuesMaskBand::EmitErrorMessageIfWriteNotSupported( |
249 | | const char *pszCaller) const |
250 | 0 | { |
251 | 0 | ReportError(CE_Failure, CPLE_NoWriteAccess, |
252 | 0 | "%s: attempt to write to a nodata implicit mask band.", |
253 | 0 | pszCaller); |
254 | |
|
255 | 0 | return true; |
256 | 0 | } |
257 | | |
258 | | //! @endcond |