/src/gdal/frmts/mrf/LERCV1/Lerc1Image.h
Line | Count | Source |
1 | | /* |
2 | | Copyright 2015 - 2024 Esri |
3 | | Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | you may not use this file except in compliance with the License. |
5 | | You may obtain a copy of the License at |
6 | | http://www.apache.org/licenses/LICENSE-2.0 |
7 | | Unless required by applicable law or agreed to in writing, software |
8 | | distributed under the License is distributed on an "AS IS" BASIS, |
9 | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
10 | | See the License for the specific language governing permissions and |
11 | | limitations under the License. |
12 | | A local copy of the license and additional notices are located with the |
13 | | source distribution at: |
14 | | http://github.com/Esri/lerc/ |
15 | | Contributors: Thomas Maurer |
16 | | Lucian Plesea |
17 | | */ |
18 | | |
19 | | #ifndef LERC1IMAGE_H |
20 | | #define LERC1IMAGE_H |
21 | | |
22 | | #include <cstring> |
23 | | #include <vector> |
24 | | |
25 | | #ifndef NAMESPACE_LERC1_START |
26 | | #define NAMESPACE_LERC1_START \ |
27 | | namespace Lerc1NS \ |
28 | | { |
29 | | #define NAMESPACE_LERC1_END } |
30 | | #define USING_NAMESPACE_LERC1 using namespace Lerc1NS; |
31 | | #endif |
32 | | |
33 | | NAMESPACE_LERC1_START |
34 | | static_assert(sizeof(float) == 4, "lerc requires float to be exactly 4 bytes"); |
35 | | |
36 | | typedef unsigned char Byte; |
37 | | |
38 | | /** BitMaskV1 - Convenient and fast access to binary mask bits |
39 | | * includes RLE compression and decompression |
40 | | * |
41 | | */ |
42 | | |
43 | | class BitMaskV1 |
44 | | { |
45 | | public: |
46 | 2.20k | BitMaskV1() : m_nRows(0), m_nCols(0) |
47 | 2.20k | { |
48 | 2.20k | } |
49 | | |
50 | | int size() const |
51 | 603 | { |
52 | 603 | return 1 + (m_nCols * m_nRows - 1) / 8; |
53 | 603 | } |
54 | | |
55 | | void Set(int k, bool v) |
56 | 245M | { |
57 | 245M | if (v) |
58 | 0 | SetValid(k); |
59 | 245M | else |
60 | 245M | SetInvalid(k); |
61 | 245M | } |
62 | | |
63 | | Byte IsValid(int k) const |
64 | 33.6M | { |
65 | 33.6M | return (bits[k >> 3] & Bit(k)) != 0; |
66 | 33.6M | } |
67 | | |
68 | | void resize(int nCols, int nRows) |
69 | 428 | { |
70 | 428 | m_nRows = nRows; |
71 | 428 | m_nCols = nCols; |
72 | 428 | bits.resize(size()); |
73 | 428 | } |
74 | | |
75 | | // max RLE compressed size is n + 4 + 2 * (n - 1) / 32767 |
76 | | // Returns encoded size |
77 | | int RLEcompress(Byte *aRLE) const; |
78 | | // Encoded size, without doing the work |
79 | | int RLEsize() const; |
80 | | // Decompress a RLE bitmask, bitmask size should be already set |
81 | | // Returns false if input seems wrong |
82 | | bool RLEdecompress(const Byte *src, size_t sz); |
83 | | |
84 | | private: |
85 | | int m_nRows, m_nCols; |
86 | | std::vector<Byte> bits; |
87 | | |
88 | | static Byte Bit(int k) |
89 | 279M | { |
90 | 279M | return static_cast<Byte>(0x80 >> (k & 7)); |
91 | 279M | } |
92 | | |
93 | | void SetValid(int k) |
94 | 0 | { |
95 | 0 | bits[k >> 3] |= Bit(k); |
96 | 0 | } |
97 | | |
98 | | void SetInvalid(int k) |
99 | 245M | { |
100 | 245M | bits[k >> 3] &= ~Bit(k); |
101 | 245M | } |
102 | | }; |
103 | | |
104 | | template <typename T> class TImage |
105 | | { |
106 | | public: |
107 | 2.20k | TImage() : width_(0), height_(0) |
108 | 2.20k | { |
109 | 2.20k | } |
110 | | |
111 | | ~TImage() |
112 | 2.20k | { |
113 | 2.20k | } |
114 | | |
115 | | bool setsize(int width, int height) |
116 | 428 | { |
117 | 428 | width_ = width; |
118 | 428 | height_ = height; |
119 | 428 | values.resize(getSize()); |
120 | 428 | return true; |
121 | 428 | } |
122 | | |
123 | | int getWidth() const |
124 | 33.6M | { |
125 | 33.6M | return width_; |
126 | 33.6M | } |
127 | | |
128 | | int getHeight() const |
129 | 3.42k | { |
130 | 3.42k | return height_; |
131 | 3.42k | } |
132 | | |
133 | | int getSize() const |
134 | 245M | { |
135 | 245M | return width_ * height_; |
136 | 245M | } |
137 | | |
138 | | const T &operator()(int row, int col) const |
139 | 0 | { |
140 | 0 | return values[row * width_ + col]; |
141 | 0 | } |
142 | | |
143 | | T &operator()(int row, int col) |
144 | 1.38M | { |
145 | 1.38M | return values[row * width_ + col]; |
146 | 1.38M | } |
147 | | |
148 | | const T *data() const |
149 | | { |
150 | | return values.data(); |
151 | | } |
152 | | |
153 | | private: |
154 | | int width_, height_; |
155 | | std::vector<T> values; |
156 | | }; |
157 | | |
158 | | class Lerc1Image final : public TImage<float> |
159 | | { |
160 | | protected: |
161 | | struct InfoFromComputeNumBytes |
162 | | { |
163 | | double maxZError; |
164 | | int numTilesVertCnt; |
165 | | int numTilesHoriCnt; |
166 | | int numBytesCnt; |
167 | | float maxCntInImg; |
168 | | int numTilesVertZ; |
169 | | int numTilesHoriZ; |
170 | | int numBytesZ; |
171 | | float maxZInImg; |
172 | | |
173 | | InfoFromComputeNumBytes() |
174 | 0 | { |
175 | 0 | std::memset(this, 0, sizeof(*this)); |
176 | 0 | } |
177 | | }; |
178 | | |
179 | | bool findTiling(double maxZError, int &numTilesVert, int &numTilesHori, |
180 | | int &numBytesOpt, float &maxValInImg) const; |
181 | | |
182 | | bool writeTiles(double maxZError, int numTilesVert, int numTilesHori, |
183 | | Byte *bArr, int &numBytes, float &maxValInImg) const; |
184 | | |
185 | | bool readTiles(double maxZErrorInFile, int numTilesVert, int numTilesHori, |
186 | | float maxValInImg, Byte *bArr, size_t nRemainingBytes); |
187 | | |
188 | | bool computeZStats(int r0, int r1, int c0, int c1, float &zMin, float &zMax, |
189 | | int &numValidPixel, int &numFinite) const; |
190 | | |
191 | | // returns true if all floating point values in the region have the same |
192 | | // binary representation |
193 | | bool isallsameval(int r0, int r1, int c0, int c1) const; |
194 | | |
195 | | bool writeZTile(Byte **ppByte, int &numBytes, int r0, int r1, int c0, |
196 | | int c1, int numValidPixel, float zMin, float zMax, |
197 | | double maxZError) const; |
198 | | |
199 | | bool readZTile(Byte **ppByte, size_t &nRemainingBytes, int r0, int r1, |
200 | | int c0, int c1, double maxZErrorInFile, float maxZInImg); |
201 | | |
202 | | unsigned int |
203 | | computeNumBytesNeededToWrite(double maxZError, bool onlyZPart, |
204 | | InfoFromComputeNumBytes *info) const; |
205 | | |
206 | | std::vector<unsigned int> idataVec; // temporary buffer |
207 | | BitMaskV1 mask; |
208 | | |
209 | | public: |
210 | | /// binary file IO with optional compression |
211 | | /// (maxZError = 0 means no lossy compression for Z; the mask part is |
212 | | /// compressed lossless or not at all) read succeeds only if maxZError on |
213 | | /// file <= maxZError requested (!) |
214 | | |
215 | | Lerc1Image() |
216 | 2.20k | { |
217 | 2.20k | } |
218 | | |
219 | | ~Lerc1Image() |
220 | 2.20k | { |
221 | 2.20k | } |
222 | | |
223 | | static unsigned int computeNumBytesNeededToWriteVoidImage(); |
224 | | |
225 | | // Only initialize the size from the header, if LERC1 |
226 | | static bool getwh(const Byte *ppByte, size_t nBytes, int &w, int &h); |
227 | | |
228 | | void resize(int width, int height) |
229 | 428 | { |
230 | 428 | setsize(width, height); |
231 | 428 | mask.resize(getWidth(), getHeight()); |
232 | 428 | } |
233 | | |
234 | | bool IsValid(int row, int col) const |
235 | 33.6M | { |
236 | 33.6M | return mask.IsValid(row * getWidth() + col) != 0; |
237 | 33.6M | } |
238 | | |
239 | | void SetMask(int row, int col, bool v) |
240 | 0 | { |
241 | 0 | mask.Set(row * getWidth() + col, v); |
242 | 0 | } |
243 | | |
244 | | // Read and write into a memory buffer |
245 | | bool write(Byte **ppByte, double maxZError = 0, |
246 | | bool onlyZPart = false) const; |
247 | | bool read(Byte **ppByte, size_t &nRemainingBytes, double maxZError, |
248 | | bool onlyZPart = false); |
249 | | }; |
250 | | |
251 | | NAMESPACE_LERC1_END |
252 | | #endif |