/src/gdal/frmts/nitf/nitfaridpcm.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: NITF Read/Write Library |
4 | | * Purpose: ARIDPCM reading code. |
5 | | * Author: Frank Warmerdam, warmerdam@pobox.com |
6 | | * |
7 | | ********************************************************************** |
8 | | * Copyright (c) 2007, Frank Warmerdam |
9 | | * Copyright (c) 2009, Even Rouault <even dot rouault at spatialys.com> |
10 | | * |
11 | | * SPDX-License-Identifier: MIT |
12 | | ****************************************************************************/ |
13 | | |
14 | | #include "cpl_port.h" |
15 | | #include "nitflib.h" |
16 | | |
17 | | #include <algorithm> |
18 | | #include <cstring> |
19 | | |
20 | | #include "gdal.h" |
21 | | #include "cpl_conv.h" |
22 | | #include "cpl_error.h" |
23 | | |
24 | | constexpr int neighbourhood_size_75[4] = {23, 47, 74, 173}; |
25 | | constexpr int bits_per_level_by_busycode_75[4 /*busy code*/][4 /*level*/] = { |
26 | | {8, 5, 0, 0}, // BC = 00 |
27 | | {8, 5, 2, 0}, // BC = 01 |
28 | | {8, 6, 4, 0}, // BC = 10 |
29 | | {8, 7, 4, 2}}; // BC = 11 |
30 | | |
31 | | constexpr int CR075 = 1; |
32 | | |
33 | | // Level for each index value. |
34 | | constexpr int level_index_table[64] = { |
35 | | 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, |
36 | | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
37 | | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}; |
38 | | |
39 | | // List of i,j to linear index macros mappings. |
40 | | // Note that i is vertical and j is horizontal and progression is |
41 | | // right to left, bottom to top. |
42 | | |
43 | 0 | #define IND(i, j) (ij_index[i + j * 8] - 1) |
44 | | |
45 | | constexpr int ij_index[64] = { |
46 | | |
47 | | 1, // 0, 0 |
48 | | 18, // 1, 0 |
49 | | 6, // 2, 0 |
50 | | 30, // 3, 0 |
51 | | 3, // 4, 0 |
52 | | 42, // 5, 0 |
53 | | 12, // 6, 0 |
54 | | 54, // 7, 0 |
55 | | |
56 | | 17, // 0, 1 |
57 | | 19, // 1, 1 |
58 | | 29, // 2, 1 |
59 | | 31, // 3, 1 |
60 | | 41, // 4, 1 |
61 | | 43, // 5, 1 |
62 | | 53, // 6, 1 |
63 | | 55, // 7, 1 |
64 | | |
65 | | 5, // 0, 2 |
66 | | 21, // 1, 2 |
67 | | 7, // 2, 2 |
68 | | 33, // 3, 2 |
69 | | 11, // 4, 2 |
70 | | 45, // 5, 2 |
71 | | 13, // 6, 2 |
72 | | 57, // 7, 2 |
73 | | |
74 | | 20, // 0, 3 |
75 | | 22, // 1, 3 |
76 | | 32, // 2, 3 |
77 | | 34, // 3, 3 |
78 | | 44, // 4, 3 |
79 | | 46, // 5, 3 |
80 | | 56, // 6, 3 |
81 | | 58, // 7, 3 |
82 | | |
83 | | 2, // 0, 4 |
84 | | 24, // 1, 4 |
85 | | 9, // 2, 4 |
86 | | 36, // 3, 4 |
87 | | 4, // 4, 4 |
88 | | 48, // 5, 4 |
89 | | 15, // 6, 4 |
90 | | 60, // 7, 4 |
91 | | |
92 | | 23, // 0, 5 |
93 | | 25, // 1, 5 |
94 | | 35, // 2, 5 |
95 | | 37, // 3, 5 |
96 | | 47, // 4, 5 |
97 | | 49, // 5, 5 |
98 | | 59, // 6, 5 |
99 | | 61, // 7, 5 |
100 | | |
101 | | 8, // 0, 6 |
102 | | 27, // 1, 6 |
103 | | 10, // 2, 6 |
104 | | 39, // 3, 6 |
105 | | 14, // 4, 6 |
106 | | 51, // 5, 6 |
107 | | 16, // 6, 6 |
108 | | 63, // 7, 6 |
109 | | |
110 | | 26, // 0, 7 |
111 | | 28, // 1, 7 |
112 | | 38, // 2, 7 |
113 | | 40, // 3, 7 |
114 | | 50, // 4, 7 |
115 | | 52, // 5, 7 |
116 | | 62, // 6, 7 |
117 | | 64}; // 7, 7 |
118 | | |
119 | | constexpr int delta_075_level_2_bc_0[32] = { |
120 | | -71, -49, -38, -32, -27, -23, -20, -17, -14, -12, -10, -8, -6, -4, -3, -1, |
121 | | 1, 2, 4, 6, 8, 12, 14, 16, 19, 22, 26, 31, 37, 46, 72}; |
122 | | constexpr int delta_075_level_2_bc_1[32] = { |
123 | | -71, -49, -38, -32, -27, -23, -20, -17, -14, -12, -10, -8, -6, -4, -3, -1, |
124 | | 1, 2, 4, 6, 8, 12, 14, 16, 19, 22, 26, 31, 37, 46, 72}; |
125 | | constexpr int delta_075_level_2_bc_2[64] = { |
126 | | -109, -82, -68, -59, -52, -46, -41, -37, -33, -30, -27, -25, -22, |
127 | | -20, -18, -16, -15, -13, -11, -10, -9, -8, -7, -6, -5, -4, |
128 | | -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |
129 | | 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, |
130 | | 26, 28, 31, 35, 38, 42, 47, 52, 60, 69, 85, 118}; |
131 | | constexpr int delta_075_level_2_bc_3[128] = { |
132 | | -159, -134, -122, -113, -106, -100, -94, -88, -83, -79, -76, -72, -69, |
133 | | -66, -63, -61, -58, -56, -54, -52, -50, -48, -47, -45, -43, -42, |
134 | | -40, -39, -37, -36, -35, -33, -32, -31, -30, -29, -28, -27, -25, |
135 | | -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, |
136 | | -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, |
137 | | 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
138 | | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, |
139 | | 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, |
140 | | 41, 42, 43, 45, 48, 52, 56, 60, 64, 68, 73, 79, 85, |
141 | | 92, 100, 109, 118, 130, 144, 159, 177, 196, 217, 236}; |
142 | | static const int *const delta_075_level_2[4] = { |
143 | | delta_075_level_2_bc_0, delta_075_level_2_bc_1, delta_075_level_2_bc_2, |
144 | | delta_075_level_2_bc_3}; |
145 | | |
146 | | constexpr int delta_075_level_3_bc_1[4] = {-24, -6, 6, 24}; |
147 | | constexpr int delta_075_level_3_bc_2[16] = {-68, -37, -23, -15, -9, -6, -3, -1, |
148 | | 1, 4, 7, 10, 16, 24, 37, 70}; |
149 | | constexpr int delta_075_level_3_bc_3[16] = { |
150 | | -117, -72, -50, -36, -25, -17, -10, -5, -1, 3, 7, 14, 25, 45, 82, 166}; |
151 | | static const int *const delta_075_level_3[4] = {nullptr, delta_075_level_3_bc_1, |
152 | | delta_075_level_3_bc_2, |
153 | | delta_075_level_3_bc_3}; |
154 | | |
155 | | constexpr int delta_075_level_4_bc_3[4] = {-47, -8, 4, 43}; |
156 | | static const int *const delta_075_level_4[4] = {nullptr, nullptr, nullptr, |
157 | | delta_075_level_4_bc_3}; |
158 | | |
159 | | static const int *const *const delta_075_by_level_by_bc[4] = { |
160 | | nullptr, delta_075_level_2, delta_075_level_3, delta_075_level_4}; |
161 | | |
162 | | /************************************************************************/ |
163 | | /* get_bits() */ |
164 | | /************************************************************************/ |
165 | | |
166 | | static int get_bits(unsigned char *buffer, int first_bit, int num_bits) |
167 | | |
168 | 0 | { |
169 | 0 | int total = 0; |
170 | |
|
171 | 0 | for (int i = first_bit; i < first_bit + num_bits; i++) |
172 | 0 | { |
173 | 0 | total *= 2; |
174 | 0 | if (buffer[i >> 3] & (0x80 >> (i & 7))) |
175 | 0 | total++; |
176 | 0 | } |
177 | |
|
178 | 0 | return total; |
179 | 0 | } |
180 | | |
181 | | /************************************************************************/ |
182 | | /* get_delta() */ |
183 | | /* */ |
184 | | /* Compute the delta value for a particular (i,j) location. */ |
185 | | /************************************************************************/ |
186 | | static int get_delta(unsigned char *srcdata, int nInputBytes, int busy_code, |
187 | | CPL_UNUSED int comrat, int block_offset, |
188 | | CPL_UNUSED int block_size, int i, int j, int *pbError) |
189 | | |
190 | 0 | { |
191 | 0 | CPLAssert(comrat == CR075); |
192 | 0 | const int pixel_index = IND(i, j); |
193 | 0 | const int level_index = level_index_table[pixel_index]; |
194 | 0 | const int *bits_per_level = bits_per_level_by_busycode_75[busy_code]; |
195 | 0 | const int delta_bits = bits_per_level[level_index]; |
196 | 0 | int delta_offset = 0; |
197 | |
|
198 | 0 | *pbError = FALSE; |
199 | |
|
200 | 0 | if (delta_bits == 0) |
201 | 0 | return 0; |
202 | | |
203 | 0 | if (level_index == 3) |
204 | 0 | delta_offset = bits_per_level[0] + bits_per_level[1] * 3 + |
205 | 0 | bits_per_level[2] * 12 + |
206 | 0 | (pixel_index - 16) * bits_per_level[3]; |
207 | 0 | else if (level_index == 2) |
208 | 0 | delta_offset = bits_per_level[0] + bits_per_level[1] * 3 + |
209 | 0 | (pixel_index - 4) * bits_per_level[2]; |
210 | 0 | else if (level_index == 1) |
211 | 0 | delta_offset = |
212 | 0 | bits_per_level[0] + (pixel_index - 1) * bits_per_level[1]; |
213 | |
|
214 | 0 | if (nInputBytes * 8 < block_offset + delta_offset + delta_bits) |
215 | 0 | { |
216 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Input buffer too small"); |
217 | 0 | *pbError = TRUE; |
218 | 0 | return 0; |
219 | 0 | } |
220 | | |
221 | 0 | const int delta_raw = |
222 | 0 | get_bits(srcdata, block_offset + delta_offset, delta_bits); |
223 | | |
224 | | /* Should not happen as delta_075_by_level_by_bc[level_index] == NULL if and |
225 | | only if level_index == 0, which means that pixel_index == 0, which means |
226 | | (i, j) = (0, 0). That cannot happen as we are never called with those |
227 | | values |
228 | | */ |
229 | 0 | CPLAssert(delta_075_by_level_by_bc[level_index] != nullptr); |
230 | 0 | const int *lookup_table = delta_075_by_level_by_bc[level_index][busy_code]; |
231 | |
|
232 | 0 | CPLAssert(lookup_table != nullptr); |
233 | 0 | int delta = lookup_table[delta_raw]; |
234 | |
|
235 | 0 | return delta; |
236 | 0 | } |
237 | | |
238 | | /************************************************************************/ |
239 | | /* decode_block() */ |
240 | | /* */ |
241 | | /* Decode one 8x8 block. The 9x9 L buffer is pre-loaded with */ |
242 | | /* the left and top values from previous blocks. */ |
243 | | /************************************************************************/ |
244 | | static int decode_block(unsigned char *srcdata, int nInputBytes, int busy_code, |
245 | | int comrat, int block_offset, int block_size, |
246 | | int left_side, int top_side, int L[9][9]) |
247 | | |
248 | 0 | { |
249 | 0 | int bError; |
250 | | |
251 | | // Level 2 |
252 | 0 | L[0][4] = (L[0][0] + L[0][8]) / 2 + |
253 | 0 | get_delta(srcdata, nInputBytes, busy_code, comrat, block_offset, |
254 | 0 | block_size, 0, 4, &bError); |
255 | 0 | if (bError) |
256 | 0 | return FALSE; |
257 | 0 | L[4][0] = (L[0][0] + L[8][0]) / 2 + |
258 | 0 | get_delta(srcdata, nInputBytes, busy_code, comrat, block_offset, |
259 | 0 | block_size, 4, 0, &bError); |
260 | 0 | if (bError) |
261 | 0 | return FALSE; |
262 | 0 | L[4][4] = (L[0][0] + L[8][0] + L[0][8] + L[8][8]) / 4 + |
263 | 0 | get_delta(srcdata, nInputBytes, busy_code, comrat, block_offset, |
264 | 0 | block_size, 4, 4, &bError); |
265 | 0 | if (bError) |
266 | 0 | return FALSE; |
267 | | |
268 | 0 | if (left_side) |
269 | 0 | L[4][8] = L[4][0]; |
270 | 0 | if (top_side) |
271 | 0 | L[8][4] = L[0][4]; |
272 | | |
273 | | // Level 3 |
274 | 0 | for (int i = 0; i < 8; i += 4) |
275 | 0 | { |
276 | 0 | for (int j = 0; j < 8; j += 4) |
277 | 0 | { |
278 | | // above |
279 | 0 | L[i + 2][j] = |
280 | 0 | (L[i][j] + L[i + 4][j]) / 2 + |
281 | 0 | get_delta(srcdata, nInputBytes, busy_code, comrat, block_offset, |
282 | 0 | block_size, i + 2, j, &bError); |
283 | 0 | if (bError) |
284 | 0 | return FALSE; |
285 | | // left |
286 | 0 | L[i][j + 2] = |
287 | 0 | (L[i][j] + L[i][j + 4]) / 2 + |
288 | 0 | get_delta(srcdata, nInputBytes, busy_code, comrat, block_offset, |
289 | 0 | block_size, i, j + 2, &bError); |
290 | 0 | if (bError) |
291 | 0 | return FALSE; |
292 | | // up-left |
293 | 0 | L[i + 2][j + 2] = |
294 | 0 | (L[i][j] + L[i][j + 4] + L[i + 4][j] + L[i + 4][j + 4]) / 4 + |
295 | 0 | get_delta(srcdata, nInputBytes, busy_code, comrat, block_offset, |
296 | 0 | block_size, i + 2, j + 2, &bError); |
297 | 0 | if (bError) |
298 | 0 | return FALSE; |
299 | 0 | } |
300 | 0 | } |
301 | | |
302 | 0 | if (left_side) |
303 | 0 | { |
304 | 0 | L[2][8] = L[2][0]; |
305 | 0 | L[6][8] = L[6][0]; |
306 | 0 | } |
307 | 0 | if (top_side) |
308 | 0 | { |
309 | 0 | L[8][2] = L[0][2]; |
310 | 0 | L[8][6] = L[0][6]; |
311 | 0 | } |
312 | | |
313 | | // Level 4 |
314 | 0 | for (int i = 0; i < 8; i += 2) |
315 | 0 | { |
316 | 0 | for (int j = 0; j < 8; j += 2) |
317 | 0 | { |
318 | | // above |
319 | 0 | L[i + 1][j] = |
320 | 0 | (L[i][j] + L[i + 2][j]) / 2 + |
321 | 0 | get_delta(srcdata, nInputBytes, busy_code, comrat, block_offset, |
322 | 0 | block_size, i + 1, j, &bError); |
323 | 0 | if (bError) |
324 | 0 | return FALSE; |
325 | | // left |
326 | 0 | L[i][j + 1] = |
327 | 0 | (L[i][j] + L[i][j + 2]) / 2 + |
328 | 0 | get_delta(srcdata, nInputBytes, busy_code, comrat, block_offset, |
329 | 0 | block_size, i, j + 1, &bError); |
330 | 0 | if (bError) |
331 | 0 | return FALSE; |
332 | | // up-left |
333 | 0 | L[i + 1][j + 1] = |
334 | 0 | (L[i][j] + L[i][j + 2] + L[i + 2][j] + L[i + 2][j + 2]) / 4 + |
335 | 0 | get_delta(srcdata, nInputBytes, busy_code, comrat, block_offset, |
336 | 0 | block_size, i + 1, j + 1, &bError); |
337 | 0 | if (bError) |
338 | 0 | return FALSE; |
339 | 0 | } |
340 | 0 | } |
341 | | |
342 | 0 | return TRUE; |
343 | 0 | } |
344 | | |
345 | | /************************************************************************/ |
346 | | /* NITFUncompressARIDPCM() */ |
347 | | /************************************************************************/ |
348 | | |
349 | | int NITFUncompressARIDPCM(NITFImage *psImage, GByte *pabyInputData, |
350 | | int nInputBytes, GByte *pabyOutputImage) |
351 | | |
352 | 0 | { |
353 | | /* -------------------------------------------------------------------- */ |
354 | | /* First, verify that we are a COMRAT 0.75 image, which is all */ |
355 | | /* we currently support. */ |
356 | | /* -------------------------------------------------------------------- */ |
357 | 0 | if (!EQUAL(psImage->szCOMRAT, "0.75")) |
358 | 0 | { |
359 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
360 | 0 | "COMRAT=%s ARIDPCM is not supported.\n" |
361 | 0 | "Currently only 0.75 is supported.", |
362 | 0 | psImage->szCOMRAT); |
363 | 0 | return FALSE; |
364 | 0 | } |
365 | | |
366 | | /* -------------------------------------------------------------------- */ |
367 | | /* Setup up the various info we need for each 8x8 neighbourhood */ |
368 | | /* (which we call blocks in this context). */ |
369 | | /* -------------------------------------------------------------------- */ |
370 | 0 | const int blocks_x = (psImage->nBlockWidth + 7) / 8; |
371 | 0 | const int blocks_y = (psImage->nBlockHeight + 7) / 8; |
372 | 0 | const int block_count = blocks_x * blocks_y; |
373 | 0 | const int rowlen = blocks_x * 8; |
374 | |
|
375 | 0 | if (psImage->nBlockWidth > 1000 || /* to detect int overflow above */ |
376 | 0 | psImage->nBlockHeight > 1000 || block_count > 1000) |
377 | 0 | { |
378 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Block too large to be decoded"); |
379 | 0 | return FALSE; |
380 | 0 | } |
381 | | |
382 | 0 | int block_offset[1000]; |
383 | 0 | int block_size[1000]; |
384 | 0 | int busy_code[1000]; |
385 | 0 | const int busy_code_table_size = blocks_x * blocks_y * 2; |
386 | 0 | unsigned char L00[1000]; |
387 | | |
388 | | /* to make clang static analyzer happy */ |
389 | 0 | block_offset[0] = 0; |
390 | 0 | block_size[0] = 0; |
391 | 0 | busy_code[0] = 0; |
392 | 0 | L00[0] = 0; |
393 | 0 | CPL_IGNORE_RET_VAL(busy_code[0]); |
394 | 0 | CPL_IGNORE_RET_VAL(block_size[0]); |
395 | 0 | CPL_IGNORE_RET_VAL(busy_code[0]); |
396 | 0 | CPL_IGNORE_RET_VAL(L00[0]); |
397 | | |
398 | | /* -------------------------------------------------------------------- */ |
399 | | /* We allocate a working copy of the full image that may be a */ |
400 | | /* bit larger than the output buffer if the width or height is */ |
401 | | /* not divisible by 8. */ |
402 | | /* -------------------------------------------------------------------- */ |
403 | 0 | GByte *full_image = reinterpret_cast<GByte *>( |
404 | 0 | CPLMalloc(static_cast<size_t>(blocks_x) * blocks_y * 8 * 8)); |
405 | | |
406 | | /* -------------------------------------------------------------------- */ |
407 | | /* Scan through all the neighbourhoods determining the busyness */ |
408 | | /* code, and the offset to each's data as well as the L00 value. */ |
409 | | /* -------------------------------------------------------------------- */ |
410 | 0 | int total = busy_code_table_size; |
411 | |
|
412 | 0 | for (int i = 0; i < blocks_x * blocks_y; i++) |
413 | 0 | { |
414 | 0 | if (nInputBytes * 8 < i * 2 + 2) |
415 | 0 | { |
416 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Input buffer too small"); |
417 | 0 | CPLFree(full_image); |
418 | 0 | return FALSE; |
419 | 0 | } |
420 | 0 | busy_code[i] = get_bits(pabyInputData, i * 2, 2); |
421 | |
|
422 | 0 | block_offset[i] = total; |
423 | 0 | block_size[i] = neighbourhood_size_75[busy_code[i]]; |
424 | |
|
425 | 0 | if (nInputBytes * 8 < block_offset[i] + 8) |
426 | 0 | { |
427 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Input buffer too small"); |
428 | 0 | CPLFree(full_image); |
429 | 0 | return FALSE; |
430 | 0 | } |
431 | 0 | L00[i] = static_cast<unsigned char>( |
432 | 0 | get_bits(pabyInputData, block_offset[i], 8)); |
433 | |
|
434 | 0 | total += block_size[i]; |
435 | 0 | } |
436 | | |
437 | | /* -------------------------------------------------------------------- */ |
438 | | /* Process all the blocks, forming into a final image. */ |
439 | | /* -------------------------------------------------------------------- */ |
440 | 0 | for (int iY = 0; iY < blocks_y; iY++) |
441 | 0 | { |
442 | 0 | for (int iX = 0; iX < blocks_x; iX++) |
443 | 0 | { |
444 | 0 | int iBlock = iX + iY * blocks_x; |
445 | 0 | int L[9][9]; |
446 | 0 | unsigned char *full_tl = full_image + iX * 8 + iY * 8 * rowlen; |
447 | |
|
448 | 0 | L[0][0] = L00[iBlock]; |
449 | 0 | if (iX > 0) |
450 | 0 | { |
451 | 0 | L[0][8] = full_tl[rowlen * 7 - 1]; |
452 | 0 | L[2][8] = full_tl[rowlen * 5 - 1]; |
453 | 0 | L[4][8] = full_tl[rowlen * 3 - 1]; |
454 | 0 | L[6][8] = full_tl[rowlen * 1 - 1]; |
455 | 0 | } |
456 | 0 | else |
457 | 0 | { |
458 | 0 | L[0][8] = L[0][0]; |
459 | 0 | L[2][8] = L[0][8]; // need to reconstruct the rest! |
460 | 0 | L[4][8] = L[0][8]; |
461 | 0 | L[6][8] = L[0][8]; |
462 | 0 | } |
463 | |
|
464 | 0 | if (iY > 0) |
465 | 0 | { |
466 | 0 | L[8][0] = full_tl[7 - rowlen]; |
467 | 0 | L[8][2] = full_tl[5 - rowlen]; |
468 | 0 | L[8][4] = full_tl[3 - rowlen]; |
469 | 0 | L[8][6] = full_tl[1 - rowlen]; |
470 | 0 | } |
471 | 0 | else |
472 | 0 | { |
473 | 0 | L[8][0] = L[0][0]; |
474 | 0 | L[8][2] = L[0][0]; // Need to reconstruct the rest! |
475 | 0 | L[8][4] = L[0][0]; |
476 | 0 | L[8][5] = L[0][0]; |
477 | 0 | } |
478 | |
|
479 | 0 | if (iX == 0 || iY == 0) |
480 | 0 | L[8][8] = L[0][0]; |
481 | 0 | else |
482 | 0 | L[8][8] = full_tl[-1 - rowlen]; |
483 | |
|
484 | 0 | if (!(decode_block(pabyInputData, nInputBytes, busy_code[iBlock], |
485 | 0 | CR075, block_offset[iBlock], block_size[iBlock], |
486 | 0 | iX == 0, iY == 0, L))) |
487 | 0 | { |
488 | 0 | CPLFree(full_image); |
489 | 0 | return FALSE; |
490 | 0 | } |
491 | | |
492 | | // Assign to output matrix. |
493 | 0 | for (int i = 0; i < 8; i++) |
494 | 0 | { |
495 | 0 | for (int j = 0; j < 8; j++) |
496 | 0 | { |
497 | 0 | const unsigned char value = |
498 | 0 | static_cast<unsigned char>(std::clamp(L[i][j], 0, 255)); |
499 | 0 | full_tl[8 - j - 1 + (8 - i - 1) * rowlen] = value; |
500 | 0 | } |
501 | 0 | } |
502 | 0 | } |
503 | 0 | } |
504 | | |
505 | | /* -------------------------------------------------------------------- */ |
506 | | /* Copy full image back into target buffer, and free. */ |
507 | | /* -------------------------------------------------------------------- */ |
508 | 0 | for (int iY = 0; iY < psImage->nBlockHeight; iY++) |
509 | 0 | { |
510 | 0 | memcpy(pabyOutputImage + iY * psImage->nBlockWidth, |
511 | 0 | full_image + iY * rowlen, psImage->nBlockWidth); |
512 | 0 | } |
513 | |
|
514 | 0 | CPLFree(full_image); |
515 | |
|
516 | 0 | return TRUE; |
517 | 0 | } |