/src/gdal/frmts/mrf/JPEG_band.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2002-2012, California Institute of Technology. |
3 | | * All rights reserved. Based on Government Sponsored Research under contracts |
4 | | * NAS7-1407 and/or NAS7-03001. |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or without |
7 | | * modification, are permitted provided that the following conditions are met: |
8 | | * 1. Redistributions of source code must retain the above copyright notice, |
9 | | * this list of conditions and the following disclaimer. |
10 | | * 2. Redistributions in binary form must reproduce the above copyright |
11 | | * notice, this list of conditions and the following disclaimer in the |
12 | | * documentation and/or other materials provided with the distribution. |
13 | | * 3. Neither the name of the California Institute of Technology (Caltech), |
14 | | * its operating division the Jet Propulsion Laboratory (JPL), the National |
15 | | * Aeronautics and Space Administration (NASA), nor the names of its |
16 | | * contributors may be used to endorse or promote products derived from this |
17 | | * software without specific prior written permission. |
18 | | * |
19 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
20 | | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
21 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
22 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE CALIFORNIA INSTITUTE OF TECHNOLOGY BE |
23 | | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | | * POSSIBILITY OF SUCH DAMAGE. |
30 | | * |
31 | | * Copyright 2014-2021 Esri |
32 | | * |
33 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
34 | | * you may not use this file except in compliance with the License. |
35 | | * You may obtain a copy of the License at |
36 | | * |
37 | | * http://www.apache.org/licenses/LICENSE-2.0 |
38 | | * |
39 | | * Unless required by applicable law or agreed to in writing, software |
40 | | * distributed under the License is distributed on an "AS IS" BASIS, |
41 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
42 | | * See the License for the specific language governing permissions and |
43 | | * limitations under the License. |
44 | | * |
45 | | * Author: Lucian Plesea |
46 | | * |
47 | | * |
48 | | * JPEG band |
49 | | * JPEG page compression and decompression functions, file gets compiled twice |
50 | | * once directly and once through inclusion from JPEG12_band.cpp |
51 | | * JPEG12_SUPPORTED is defined if both 8 and 12 bit JPEG will be supported |
52 | | * JPEG12_ON is defined only for the 12 bit versions |
53 | | * |
54 | | * The MRF JPEG codec implements the Zen (Zero ENhanced) JPEG extension |
55 | | * This extension, when supported by the decompressor, preserves the zero or |
56 | | * non-zero state of all pixels which allows zero pixels to be used as a |
57 | | * non-data mask Clients which don't support the Zen extension will read it as a |
58 | | * normal JPEG |
59 | | * |
60 | | * On page writes, a mask of all fully zero pixels is built |
61 | | * If the mask has some zero pixels, it is written in a JPEG APP3 "Zen" marker |
62 | | * If the mask has no zero pixels, a zero length APP3 marker is inserted |
63 | | * |
64 | | * On page reads, after the JPEG decompression, if a mask or a zero length APP3 |
65 | | * marker is detected, the masked pixels with value of zero are set to 1 while |
66 | | * the non-masked ones are set to zero |
67 | | * |
68 | | */ |
69 | | |
70 | | #include "marfa.h" |
71 | | #include <setjmp.h> |
72 | | #include <vector> |
73 | | |
74 | | CPL_C_START |
75 | | #include "jpeglib.h" |
76 | | #include "jerror.h" |
77 | | CPL_C_END |
78 | | |
79 | | #define PACKER |
80 | | #include "BitMask2D.h" |
81 | | #include "Packer_RLE.h" |
82 | | |
83 | | #if defined(BRUNSLI) |
84 | | #include <brunsli/encode.h> |
85 | | #include <brunsli/decode.h> |
86 | | #endif |
87 | | |
88 | | #if defined(EXPECTED_JPEG_LIB_VERSION) && !defined(JPEG12_SUPPORTED) |
89 | | #if EXPECTED_JPEG_LIB_VERSION != JPEG_LIB_VERSION |
90 | | #error EXPECTED_JPEG_LIB_VERSION != JPEG_LIB_VERSION |
91 | | #endif |
92 | | #endif |
93 | | |
94 | | /* HAVE_JPEGTURBO_DUAL_MODE_8_12 is defined for libjpeg-turbo >= 2.2 which |
95 | | * adds a dual-mode 8/12 bit API in the same library. |
96 | | */ |
97 | | |
98 | | #if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12) |
99 | | /* Start by undefining BITS_IN_JSAMPLE which is always set to 8 in libjpeg-turbo |
100 | | * >= 2.2 Cf |
101 | | * https://github.com/libjpeg-turbo/libjpeg-turbo/commit/8b9bc4b9635a2a047fb23ebe70c9acd728d3f99b |
102 | | */ |
103 | | #undef BITS_IN_JSAMPLE |
104 | | /* libjpeg-turbo >= 2.2 adds J12xxxx datatypes for the 12-bit mode. */ |
105 | | #if defined(JPEG12_ON) |
106 | | #define BITS_IN_JSAMPLE 12 |
107 | | #define MRF_JSAMPLE J12SAMPLE |
108 | | #define MRF_JSAMPARRAY J12SAMPARRAY |
109 | | #define MRF_JSAMPIMAGE J12SAMPIMAGE |
110 | | #define MRF_JSAMPROW J12SAMPROW |
111 | | #else |
112 | | #define BITS_IN_JSAMPLE 8 |
113 | | #define MRF_JSAMPLE JSAMPLE |
114 | | #define MRF_JSAMPARRAY JSAMPARRAY |
115 | | #define MRF_JSAMPIMAGE JSAMPIMAGE |
116 | | #define MRF_JSAMPROW JSAMPROW |
117 | | #endif |
118 | | #else |
119 | | #define MRF_JSAMPLE JSAMPLE |
120 | 23.0k | #define MRF_JSAMPARRAY JSAMPARRAY |
121 | | #define MRF_JSAMPIMAGE JSAMPIMAGE |
122 | 0 | #define MRF_JSAMPROW JSAMPROW |
123 | | #endif |
124 | | |
125 | | NAMESPACE_MRF_START |
126 | | |
127 | | typedef BitMap2D<> BitMask; |
128 | | |
129 | | // Values for mask_state flag |
130 | | |
131 | | enum |
132 | | { |
133 | | NO_MASK = 0, |
134 | | MASK_LOADED, |
135 | | MASK_FULL |
136 | | }; |
137 | | |
138 | | extern char CHUNK_NAME[]; |
139 | | extern size_t CHUNK_NAME_SIZE; |
140 | | |
141 | | typedef struct MRFJPEGStruct |
142 | | { |
143 | | jmp_buf setjmpBuffer; |
144 | | BitMask *mask; |
145 | | int mask_state; |
146 | | |
147 | | MRFJPEGStruct() |
148 | 495 | { |
149 | 495 | memset(&setjmpBuffer, 0, sizeof(setjmpBuffer)); |
150 | 495 | mask = nullptr; |
151 | 495 | mask_state = NO_MASK; |
152 | 495 | } |
153 | | } MRFJPEGErrorStruct; |
154 | | |
155 | | /** |
156 | | *\brief Called when jpeg wants to report a warning |
157 | | * msgLevel can be: |
158 | | * -1 Corrupt data |
159 | | * 0 always display |
160 | | * 1... Trace level |
161 | | */ |
162 | | |
163 | | static void emitMessage(j_common_ptr cinfo, int msgLevel) |
164 | 259k | { |
165 | 259k | if (msgLevel > 0) |
166 | 19.1k | return; // No trace msgs |
167 | | // There can be many warnings, just print the first one |
168 | 239k | if (cinfo->err->num_warnings++ > 1) |
169 | 238k | return; |
170 | 913 | char buffer[JMSG_LENGTH_MAX]; |
171 | 913 | cinfo->err->format_message(cinfo, buffer); |
172 | 913 | CPLError(CE_Failure, CPLE_AppDefined, "%s", buffer); |
173 | 913 | } JPEG_band.cpp:GDAL_MRF::emitMessage(jpeg_common_struct*, int) Line | Count | Source | 164 | 259k | { | 165 | 259k | if (msgLevel > 0) | 166 | 19.1k | return; // No trace msgs | 167 | | // There can be many warnings, just print the first one | 168 | 239k | if (cinfo->err->num_warnings++ > 1) | 169 | 238k | return; | 170 | 913 | char buffer[JMSG_LENGTH_MAX]; | 171 | 913 | cinfo->err->format_message(cinfo, buffer); | 172 | 913 | CPLError(CE_Failure, CPLE_AppDefined, "%s", buffer); | 173 | 913 | } |
Unexecuted instantiation: JPEG12_band.cpp:GDAL_MRF::emitMessage(jpeg_common_struct12*, int) |
174 | | |
175 | | static void errorExit(j_common_ptr cinfo) |
176 | 408 | { |
177 | 408 | MRFJPEGStruct *psJPEGStruct = (MRFJPEGStruct *)cinfo->client_data; |
178 | | // format the warning message |
179 | 408 | char buffer[JMSG_LENGTH_MAX]; |
180 | | |
181 | 408 | cinfo->err->format_message(cinfo, buffer); |
182 | 408 | CPLError(CE_Failure, CPLE_AppDefined, "%s", buffer); |
183 | | // return control to the setjmp point |
184 | 408 | longjmp(psJPEGStruct->setjmpBuffer, 1); |
185 | 408 | } JPEG_band.cpp:GDAL_MRF::errorExit(jpeg_common_struct*) Line | Count | Source | 176 | 408 | { | 177 | 408 | MRFJPEGStruct *psJPEGStruct = (MRFJPEGStruct *)cinfo->client_data; | 178 | | // format the warning message | 179 | 408 | char buffer[JMSG_LENGTH_MAX]; | 180 | | | 181 | 408 | cinfo->err->format_message(cinfo, buffer); | 182 | 408 | CPLError(CE_Failure, CPLE_AppDefined, "%s", buffer); | 183 | | // return control to the setjmp point | 184 | 408 | longjmp(psJPEGStruct->setjmpBuffer, 1); | 185 | 408 | } |
Unexecuted instantiation: JPEG12_band.cpp:GDAL_MRF::errorExit(jpeg_common_struct12*) |
186 | | |
187 | | /** |
188 | | *\brief Do nothing stub function for JPEG library, called |
189 | | */ |
190 | | static void stub_source_dec(j_decompress_ptr /*cinfo*/) |
191 | 531 | { |
192 | 531 | } JPEG_band.cpp:GDAL_MRF::stub_source_dec(jpeg_decompress_struct*) Line | Count | Source | 191 | 531 | { | 192 | 531 | } |
Unexecuted instantiation: JPEG12_band.cpp:GDAL_MRF::stub_source_dec(jpeg_decompress_struct12*) |
193 | | |
194 | | /** |
195 | | *\brief: This function is supposed to do refilling of the input buffer, |
196 | | * but as we provided everything at the beginning, if it is called, then |
197 | | * we have an error. |
198 | | */ |
199 | | static boolean fill_input_buffer_dec(j_decompress_ptr cinfo) |
200 | 117 | { |
201 | 117 | CPLError(CE_Failure, CPLE_AppDefined, "Invalid JPEG stream"); |
202 | 117 | cinfo->err->msg_code = JERR_INPUT_EMPTY; |
203 | 117 | cinfo->err->error_exit((j_common_ptr)(cinfo)); |
204 | 117 | return FALSE; |
205 | 117 | } JPEG_band.cpp:GDAL_MRF::fill_input_buffer_dec(jpeg_decompress_struct*) Line | Count | Source | 200 | 117 | { | 201 | 117 | CPLError(CE_Failure, CPLE_AppDefined, "Invalid JPEG stream"); | 202 | 117 | cinfo->err->msg_code = JERR_INPUT_EMPTY; | 203 | 117 | cinfo->err->error_exit((j_common_ptr)(cinfo)); | 204 | 117 | return FALSE; | 205 | 117 | } |
Unexecuted instantiation: JPEG12_band.cpp:GDAL_MRF::fill_input_buffer_dec(jpeg_decompress_struct12*) |
206 | | |
207 | | /** |
208 | | *\brief: Skips unknown chunks |
209 | | */ |
210 | | static void skip_input_data_dec(j_decompress_ptr cinfo, long l) |
211 | 302 | { |
212 | 302 | struct jpeg_source_mgr *src = cinfo->src; |
213 | 302 | if (l > 0) |
214 | 302 | { |
215 | 302 | if (static_cast<size_t>(l) > src->bytes_in_buffer) |
216 | 31 | l = static_cast<long>(src->bytes_in_buffer); |
217 | 302 | src->bytes_in_buffer -= l; |
218 | 302 | src->next_input_byte += l; |
219 | 302 | } |
220 | 302 | } JPEG_band.cpp:GDAL_MRF::skip_input_data_dec(jpeg_decompress_struct*, long) Line | Count | Source | 211 | 302 | { | 212 | 302 | struct jpeg_source_mgr *src = cinfo->src; | 213 | 302 | if (l > 0) | 214 | 302 | { | 215 | 302 | if (static_cast<size_t>(l) > src->bytes_in_buffer) | 216 | 31 | l = static_cast<long>(src->bytes_in_buffer); | 217 | 302 | src->bytes_in_buffer -= l; | 218 | 302 | src->next_input_byte += l; | 219 | 302 | } | 220 | 302 | } |
Unexecuted instantiation: JPEG12_band.cpp:GDAL_MRF::skip_input_data_dec(jpeg_decompress_struct12*, long) |
221 | | |
222 | | // Destination should be already set up |
223 | | static void init_or_terminate_destination(j_compress_ptr /*cinfo*/) |
224 | 0 | { |
225 | 0 | } Unexecuted instantiation: JPEG_band.cpp:GDAL_MRF::init_or_terminate_destination(jpeg_compress_struct*) Unexecuted instantiation: JPEG12_band.cpp:GDAL_MRF::init_or_terminate_destination(jpeg_compress_struct12*) |
226 | | |
227 | | // Called if the buffer provided is too small |
228 | | static boolean empty_output_buffer(j_compress_ptr /*cinfo*/) |
229 | 0 | { |
230 | 0 | std::cerr << "JPEG Output buffer empty called\n"; |
231 | 0 | return FALSE; |
232 | 0 | } Unexecuted instantiation: JPEG_band.cpp:GDAL_MRF::empty_output_buffer(jpeg_compress_struct*) Unexecuted instantiation: JPEG12_band.cpp:GDAL_MRF::empty_output_buffer(jpeg_compress_struct12*) |
233 | | |
234 | | // Returns the number of zero pixels in the page, as well as clearing those bits |
235 | | // in the mask |
236 | | template <typename T> static int update_mask(BitMask &mask, T *src, int nc) |
237 | 0 | { |
238 | 0 | int zeros = 0; |
239 | 0 | int h = mask.getHeight(); |
240 | 0 | int w = mask.getWidth(); |
241 | 0 | for (int y = 0; y < h; y++) |
242 | 0 | for (int x = 0; x < w; x++) |
243 | 0 | { |
244 | 0 | bool is_zero = true; |
245 | 0 | for (int c = 0; c < nc; c++) |
246 | 0 | if (*src++ != 0) |
247 | 0 | is_zero = false; |
248 | 0 | if (is_zero) |
249 | 0 | { |
250 | 0 | zeros++; |
251 | 0 | mask.clear(x, y); |
252 | 0 | } |
253 | 0 | } |
254 | 0 | return zeros; |
255 | 0 | } Unexecuted instantiation: JPEG_band.cpp:int GDAL_MRF::update_mask<unsigned char>(GDAL_MRF::BitMap2D<unsigned long long>&, unsigned char*, int) Unexecuted instantiation: JPEG_band.cpp:int GDAL_MRF::update_mask<unsigned short>(GDAL_MRF::BitMap2D<unsigned long long>&, unsigned short*, int) Unexecuted instantiation: JPEG12_band.cpp:int GDAL_MRF::update_mask<unsigned char>(GDAL_MRF::BitMap2D<unsigned long long>&, unsigned char*, int) Unexecuted instantiation: JPEG12_band.cpp:int GDAL_MRF::update_mask<unsigned short>(GDAL_MRF::BitMap2D<unsigned long long>&, unsigned short*, int) |
256 | | |
257 | | /* |
258 | | *\brief Compress a JPEG page in memory |
259 | | * |
260 | | * It handles byte or 12 bit data, grayscale, RGB, YUV, and multispectral |
261 | | * |
262 | | * Returns the compressed size in dest.size |
263 | | */ |
264 | | #if defined(JPEG12_ON) |
265 | | CPLErr JPEG_Codec::CompressJPEG12(buf_mgr &dst, buf_mgr &src) |
266 | | #else |
267 | | CPLErr JPEG_Codec::CompressJPEG(buf_mgr &dst, buf_mgr &src) |
268 | | #endif |
269 | | |
270 | 0 | { |
271 | | // The cinfo should stay open and reside in the DS, since it can be left |
272 | | // initialized It saves some time because it has the tables initialized |
273 | 0 | struct jpeg_compress_struct cinfo; |
274 | 0 | MRFJPEGStruct sJPEGStruct; |
275 | 0 | struct jpeg_error_mgr sJErr; |
276 | 0 | ILSize sz = img.pagesize; |
277 | |
|
278 | 0 | jpeg_destination_mgr jmgr; |
279 | 0 | jmgr.next_output_byte = reinterpret_cast<JOCTET *>(dst.buffer); |
280 | 0 | jmgr.free_in_buffer = dst.size; |
281 | 0 | jmgr.init_destination = init_or_terminate_destination; |
282 | 0 | jmgr.empty_output_buffer = empty_output_buffer; |
283 | 0 | jmgr.term_destination = init_or_terminate_destination; |
284 | |
|
285 | 0 | memset(&cinfo, 0, sizeof(cinfo)); |
286 | | |
287 | | // Look at the source of this, some interesting tidbits |
288 | 0 | cinfo.err = jpeg_std_error(&sJErr); |
289 | 0 | sJErr.error_exit = errorExit; |
290 | 0 | sJErr.emit_message = emitMessage; |
291 | 0 | cinfo.client_data = (void *)&(sJPEGStruct); |
292 | 0 | jpeg_create_compress(&cinfo); |
293 | 0 | cinfo.dest = &jmgr; |
294 | | |
295 | | // The page specific info, size and color spaces |
296 | 0 | cinfo.image_width = sz.x; |
297 | 0 | cinfo.image_height = sz.y; |
298 | 0 | cinfo.input_components = sz.c; |
299 | 0 | switch (cinfo.input_components) |
300 | 0 | { |
301 | 0 | case 1: |
302 | 0 | cinfo.in_color_space = JCS_GRAYSCALE; |
303 | 0 | break; |
304 | 0 | case 3: |
305 | 0 | cinfo.in_color_space = JCS_RGB; |
306 | 0 | break; // Stored as YCbCr 4:2:0 by default |
307 | 0 | default: |
308 | 0 | cinfo.in_color_space = JCS_UNKNOWN; // 2, 4-10 bands |
309 | 0 | } |
310 | | |
311 | | #if defined(JPEG12_ON) |
312 | 0 | cinfo.data_precision = 12; |
313 | | #else |
314 | 0 | cinfo.data_precision = 8; |
315 | 0 | #endif |
316 | | |
317 | | // Set all required fields and overwrite the ones we want to change |
318 | 0 | jpeg_set_defaults(&cinfo); |
319 | | |
320 | | // Override certain settings |
321 | 0 | jpeg_set_quality(&cinfo, img.quality, TRUE); |
322 | 0 | cinfo.dct_method = JDCT_FLOAT; // Pretty fast and precise |
323 | 0 | cinfo.optimize_coding = |
324 | 0 | optimize; // Set "OPTIMIZE=TRUE" in OPTIONS, default for 12bit |
325 | | |
326 | | // Do we explicitly turn off the YCC color and downsampling? |
327 | |
|
328 | 0 | if (cinfo.in_color_space == JCS_RGB) |
329 | 0 | { |
330 | 0 | if (rgb) |
331 | 0 | { // Stored as RGB |
332 | 0 | jpeg_set_colorspace(&cinfo, JCS_RGB); // Huge files |
333 | 0 | } |
334 | 0 | else if (sameres) |
335 | 0 | { // YCC, somewhat larger files with improved color spatial detail |
336 | 0 | cinfo.comp_info[0].h_samp_factor = 1; |
337 | 0 | cinfo.comp_info[0].v_samp_factor = 1; |
338 | | |
339 | | // Enabling these lines will make the color components use the same |
340 | | // tables as Y, even larger file with slightly better color depth |
341 | | // detail cinfo.comp_info[1].quant_tbl_no = 0; |
342 | | // cinfo.comp_info[2].quant_tbl_no = 0; |
343 | | |
344 | | // cinfo.comp_info[1].dc_tbl_no = 0; |
345 | | // cinfo.comp_info[2].dc_tbl_no = 0; |
346 | | |
347 | | // cinfo.comp_info[1].ac_tbl_no = 0; |
348 | | // cinfo.comp_info[2].ac_tbl_no = 0; |
349 | 0 | } |
350 | 0 | } |
351 | |
|
352 | 0 | int linesize = cinfo.image_width * cinfo.input_components * |
353 | 0 | ((cinfo.data_precision == 8) ? 1 : 2); |
354 | 0 | MRF_JSAMPROW *rowp = (MRF_JSAMPROW *)CPLMalloc(sizeof(MRF_JSAMPROW) * sz.y); |
355 | 0 | if (!rowp) |
356 | 0 | { |
357 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "MRF: JPEG compression error"); |
358 | 0 | jpeg_destroy_compress(&cinfo); |
359 | 0 | return CE_Failure; |
360 | 0 | } |
361 | | |
362 | 0 | for (int i = 0; i < sz.y; i++) |
363 | 0 | { |
364 | 0 | rowp[i] = (MRF_JSAMPROW)(src.buffer + i * linesize); |
365 | | #if defined(JPEG12_ON) |
366 | 0 | for (int x = 0; x < sz.x; ++x) |
367 | 0 | { |
368 | 0 | if (static_cast<unsigned short>(rowp[i][x]) > 4095) |
369 | 0 | { |
370 | 0 | rowp[i][x] = (MRF_JSAMPLE)4095; |
371 | 0 | static bool bClipWarn = false; |
372 | 0 | if (!bClipWarn) |
373 | 0 | { |
374 | 0 | bClipWarn = true; |
375 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
376 | 0 | "One or more pixels clipped to fit 12bit domain " |
377 | 0 | "for jpeg output."); |
378 | 0 | } |
379 | 0 | } |
380 | 0 | } |
381 | | #endif |
382 | 0 | } |
383 | |
|
384 | 0 | if (setjmp(sJPEGStruct.setjmpBuffer)) |
385 | 0 | { |
386 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "MRF: JPEG compression error"); |
387 | 0 | jpeg_destroy_compress(&cinfo); |
388 | 0 | CPLFree(rowp); |
389 | 0 | return CE_Failure; |
390 | 0 | } |
391 | | |
392 | | // Build a bitmaps of the black pixels |
393 | | // If there are any black pixels, write a compressed mask in APP3 "Zen" |
394 | | // chunk |
395 | | |
396 | | // Mask is initialized to all pixels valid |
397 | 0 | BitMask mask(sz.x, sz.y); |
398 | 0 | storage_manager mbuffer = {CHUNK_NAME, CHUNK_NAME_SIZE}; |
399 | |
|
400 | 0 | int nzeros = |
401 | 0 | (cinfo.data_precision == 8) |
402 | 0 | ? update_mask(mask, reinterpret_cast<GByte *>(src.buffer), sz.c) |
403 | 0 | : update_mask(mask, reinterpret_cast<GUInt16 *>(src.buffer), sz.c); |
404 | | |
405 | | // In case we need to build a Zen chunk |
406 | 0 | char *buffer = nullptr; |
407 | |
|
408 | 0 | if (nzeros != 0) |
409 | 0 | { // build the Zen chunk |
410 | 0 | mbuffer.size = 2 * mask.size() + CHUNK_NAME_SIZE; |
411 | 0 | buffer = static_cast<char *>(CPLMalloc(mbuffer.size)); |
412 | 0 | if (!buffer) |
413 | 0 | { |
414 | 0 | jpeg_destroy_compress(&cinfo); |
415 | 0 | CPLFree(rowp); |
416 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, |
417 | 0 | "MRF: JPEG Zen mask compression"); |
418 | 0 | return CE_Failure; |
419 | 0 | } |
420 | | |
421 | 0 | memcpy(buffer, CHUNK_NAME, CHUNK_NAME_SIZE); |
422 | 0 | mbuffer.buffer = buffer + CHUNK_NAME_SIZE; |
423 | 0 | mbuffer.size -= CHUNK_NAME_SIZE; |
424 | |
|
425 | 0 | RLEC3Packer c3; |
426 | 0 | mask.set_packer(&c3); |
427 | 0 | if (!mask.store(&mbuffer)) |
428 | 0 | { |
429 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
430 | 0 | "MRF: JPEG Zen mask compression"); |
431 | 0 | CPLFree(rowp); |
432 | 0 | CPLFree(buffer); |
433 | 0 | return CE_Failure; |
434 | 0 | } |
435 | | |
436 | | // Change the buffer pointer to include the signature, on output the |
437 | | // size is the compressed size |
438 | 0 | mbuffer.buffer = buffer; |
439 | 0 | mbuffer.size += CHUNK_NAME_SIZE; |
440 | | |
441 | | // Check that the size fits in one JPEG chunk |
442 | 0 | if (mbuffer.size + 2 + CHUNK_NAME_SIZE > 65535) |
443 | 0 | { |
444 | | // Should split it in multiple chunks, for now mark this tile as all |
445 | | // data and emit a warning |
446 | 0 | CPLError(CE_Warning, CPLE_NotSupported, |
447 | 0 | "MRF: JPEG Zen mask too large"); |
448 | 0 | mbuffer.size = CHUNK_NAME_SIZE; // Write just the signature |
449 | 0 | } |
450 | 0 | } |
451 | | |
452 | | // Everything is ready |
453 | 0 | jpeg_start_compress(&cinfo, TRUE); |
454 | | |
455 | | // Always write the Zen app chunk, App3 |
456 | 0 | jpeg_write_marker(&cinfo, JPEG_APP0 + 3, |
457 | 0 | reinterpret_cast<JOCTET *>(mbuffer.buffer), |
458 | 0 | static_cast<unsigned int>(mbuffer.size)); |
459 | |
|
460 | | #if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12) && defined(JPEG12_ON) |
461 | | jpeg12_write_scanlines(&cinfo, rowp, sz.y); |
462 | | #else |
463 | 0 | jpeg_write_scanlines(&cinfo, rowp, sz.y); |
464 | 0 | #endif |
465 | 0 | jpeg_finish_compress(&cinfo); |
466 | 0 | jpeg_destroy_compress(&cinfo); |
467 | |
|
468 | 0 | CPLFree(rowp); |
469 | 0 | CPLFree(buffer); // Safe to call on null |
470 | | |
471 | | // Figure out the size of the JFIF |
472 | 0 | dst.size -= jmgr.free_in_buffer; |
473 | 0 | return CE_None; |
474 | 0 | } Unexecuted instantiation: GDAL_MRF::JPEG_Codec::CompressJPEG(GDAL_MRF::buf_mgr&, GDAL_MRF::buf_mgr&) Unexecuted instantiation: GDAL_MRF::JPEG_Codec::CompressJPEG12(GDAL_MRF::buf_mgr&, GDAL_MRF::buf_mgr&) |
475 | | |
476 | | /************************************************************************/ |
477 | | /* ProgressMonitor() */ |
478 | | /************************************************************************/ |
479 | | |
480 | | /* Avoid the risk of denial-of-service on crafted JPEGs with an insane */ |
481 | | /* number of scans. */ |
482 | | /* See |
483 | | * http://www.libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf |
484 | | */ |
485 | | static void ProgressMonitor(j_common_ptr cinfo) |
486 | 262k | { |
487 | 262k | if (cinfo->is_decompressor) |
488 | 262k | { |
489 | 262k | const int scan_no = |
490 | 262k | reinterpret_cast<j_decompress_ptr>(cinfo)->input_scan_number; |
491 | 262k | const int MAX_SCANS = 100; |
492 | 262k | if (scan_no >= MAX_SCANS) |
493 | 10 | { |
494 | 10 | CPLError(CE_Failure, CPLE_AppDefined, |
495 | 10 | "Scan number %d exceeds maximum scans (%d)", scan_no, |
496 | 10 | MAX_SCANS); |
497 | | |
498 | 10 | MRFJPEGStruct *psJPEGStruct = (MRFJPEGStruct *)cinfo->client_data; |
499 | | |
500 | | // return control to the setjmp point |
501 | 10 | longjmp(psJPEGStruct->setjmpBuffer, 1); |
502 | 10 | } |
503 | 262k | } |
504 | 262k | } JPEG_band.cpp:GDAL_MRF::ProgressMonitor(jpeg_common_struct*) Line | Count | Source | 486 | 262k | { | 487 | 262k | if (cinfo->is_decompressor) | 488 | 262k | { | 489 | 262k | const int scan_no = | 490 | 262k | reinterpret_cast<j_decompress_ptr>(cinfo)->input_scan_number; | 491 | 262k | const int MAX_SCANS = 100; | 492 | 262k | if (scan_no >= MAX_SCANS) | 493 | 10 | { | 494 | 10 | CPLError(CE_Failure, CPLE_AppDefined, | 495 | 10 | "Scan number %d exceeds maximum scans (%d)", scan_no, | 496 | 10 | MAX_SCANS); | 497 | | | 498 | 10 | MRFJPEGStruct *psJPEGStruct = (MRFJPEGStruct *)cinfo->client_data; | 499 | | | 500 | | // return control to the setjmp point | 501 | 10 | longjmp(psJPEGStruct->setjmpBuffer, 1); | 502 | 10 | } | 503 | 262k | } | 504 | 262k | } |
Unexecuted instantiation: JPEG12_band.cpp:GDAL_MRF::ProgressMonitor(jpeg_common_struct12*) |
505 | | |
506 | | // Returns the number of zero pixels, as well as clearing those bits int the |
507 | | // mask |
508 | | template <typename T> static void apply_mask(MRFJPEGStruct &sJ, T *s, int nc) |
509 | 36 | { |
510 | 36 | if (NO_MASK == sJ.mask_state) |
511 | 2 | return; |
512 | | |
513 | 34 | BitMask *mask = sJ.mask; |
514 | 34 | int w = mask->getWidth(); |
515 | 34 | int h = mask->getHeight(); |
516 | | |
517 | 34 | if (MASK_LOADED == sJ.mask_state) |
518 | 21 | { // Partial map |
519 | 10.5k | for (int y = 0; y < h; y++) |
520 | 3.71M | for (int x = 0; x < w; x++) |
521 | 3.69M | { |
522 | 3.69M | if (mask->isSet(x, y)) |
523 | 1.84M | { // Non zero pixel |
524 | 55.2M | for (int c = 0; c < nc; c++, s++) |
525 | 53.3M | { |
526 | 53.3M | if (*s == 0) |
527 | 8.58M | *s = 1; |
528 | 53.3M | } |
529 | 1.84M | } |
530 | 1.85M | else |
531 | 1.85M | { // Zero pixel |
532 | 55.7M | for (int c = 0; c < nc; c++) |
533 | 53.9M | *s++ = 0; |
534 | 1.85M | } |
535 | 3.69M | } |
536 | 21 | } |
537 | 13 | else if (MASK_FULL == sJ.mask_state) |
538 | 13 | { // All non-zero |
539 | 6.55k | for (int y = 0; y < h; y++) |
540 | 2.77M | for (int x = 0; x < w; x++) |
541 | 2.77M | { |
542 | 16.6M | for (int c = 0; c < nc; c++, s++) |
543 | 13.8M | { |
544 | 13.8M | if (*s == 0) |
545 | 6.73M | *s = 1; |
546 | 13.8M | } |
547 | 2.77M | } |
548 | 13 | } |
549 | 34 | } JPEG_band.cpp:void GDAL_MRF::apply_mask<char>(GDAL_MRF::MRFJPEGStruct&, char*, int) Line | Count | Source | 509 | 36 | { | 510 | 36 | if (NO_MASK == sJ.mask_state) | 511 | 2 | return; | 512 | | | 513 | 34 | BitMask *mask = sJ.mask; | 514 | 34 | int w = mask->getWidth(); | 515 | 34 | int h = mask->getHeight(); | 516 | | | 517 | 34 | if (MASK_LOADED == sJ.mask_state) | 518 | 21 | { // Partial map | 519 | 10.5k | for (int y = 0; y < h; y++) | 520 | 3.71M | for (int x = 0; x < w; x++) | 521 | 3.69M | { | 522 | 3.69M | if (mask->isSet(x, y)) | 523 | 1.84M | { // Non zero pixel | 524 | 55.2M | for (int c = 0; c < nc; c++, s++) | 525 | 53.3M | { | 526 | 53.3M | if (*s == 0) | 527 | 8.58M | *s = 1; | 528 | 53.3M | } | 529 | 1.84M | } | 530 | 1.85M | else | 531 | 1.85M | { // Zero pixel | 532 | 55.7M | for (int c = 0; c < nc; c++) | 533 | 53.9M | *s++ = 0; | 534 | 1.85M | } | 535 | 3.69M | } | 536 | 21 | } | 537 | 13 | else if (MASK_FULL == sJ.mask_state) | 538 | 13 | { // All non-zero | 539 | 6.55k | for (int y = 0; y < h; y++) | 540 | 2.77M | for (int x = 0; x < w; x++) | 541 | 2.77M | { | 542 | 16.6M | for (int c = 0; c < nc; c++, s++) | 543 | 13.8M | { | 544 | 13.8M | if (*s == 0) | 545 | 6.73M | *s = 1; | 546 | 13.8M | } | 547 | 2.77M | } | 548 | 13 | } | 549 | 34 | } |
Unexecuted instantiation: JPEG_band.cpp:void GDAL_MRF::apply_mask<unsigned short>(GDAL_MRF::MRFJPEGStruct&, unsigned short*, int) Unexecuted instantiation: JPEG12_band.cpp:void GDAL_MRF::apply_mask<char>(GDAL_MRF::MRFJPEGStruct&, char*, int) Unexecuted instantiation: JPEG12_band.cpp:void GDAL_MRF::apply_mask<unsigned short>(GDAL_MRF::MRFJPEGStruct&, unsigned short*, int) |
550 | | |
551 | | // JPEG marker processor, for the Zen app3 marker |
552 | | // Can't return error, only works if the JPEG mask is all in the buffer |
553 | | static boolean MaskProcessor(j_decompress_ptr pcinfo) |
554 | 3.95k | { |
555 | 3.95k | struct jpeg_source_mgr *src = pcinfo->src; |
556 | 3.95k | if (src->bytes_in_buffer < 2) |
557 | 3.95k | ERREXIT(pcinfo, JERR_CANT_SUSPEND); |
558 | | // Big endian length, two bytes |
559 | 3.95k | int len = (*src->next_input_byte++) << 8; |
560 | 3.95k | len += *src->next_input_byte++; |
561 | | // The length includes the two bytes we just read |
562 | 3.95k | src->bytes_in_buffer -= 2; |
563 | 3.95k | len -= 2; |
564 | | // Check that it is safe to read the rest |
565 | 3.95k | if (src->bytes_in_buffer < static_cast<size_t>(len)) |
566 | 3.95k | ERREXIT(pcinfo, JERR_CANT_SUSPEND); |
567 | 3.95k | MRFJPEGStruct *psJPEG = |
568 | 3.95k | reinterpret_cast<MRFJPEGStruct *>(pcinfo->client_data); |
569 | 3.95k | BitMask *mask = psJPEG->mask; |
570 | | // caller doesn't want a mask or wrong chunk, skip the chunk and return |
571 | 3.95k | if (!mask || static_cast<size_t>(len) < CHUNK_NAME_SIZE || |
572 | 2.41k | !EQUALN(reinterpret_cast<const char *>(src->next_input_byte), |
573 | 3.95k | CHUNK_NAME, CHUNK_NAME_SIZE)) |
574 | 2.54k | { |
575 | 2.54k | src->bytes_in_buffer -= len; |
576 | 2.54k | src->next_input_byte += len; |
577 | 2.54k | return true; |
578 | 2.54k | } |
579 | | |
580 | | // Skip the signature and load the mask |
581 | 1.41k | src->bytes_in_buffer -= CHUNK_NAME_SIZE; |
582 | 1.41k | src->next_input_byte += CHUNK_NAME_SIZE; |
583 | 1.41k | len -= static_cast<int>(CHUNK_NAME_SIZE); |
584 | 1.41k | if (len == 0) |
585 | 1.11k | { // No mask content means mask is all full, just return |
586 | 1.11k | psJPEG->mask_state = MASK_FULL; |
587 | 1.11k | return true; |
588 | 1.11k | } |
589 | | |
590 | | // It is OK to use const cast, the mask doesn't touch the buffer |
591 | 295 | storage_manager msrc = {const_cast<char *>(reinterpret_cast<const char *>( |
592 | 295 | src->next_input_byte)), |
593 | 295 | static_cast<size_t>(len)}; |
594 | | |
595 | 295 | if (!mask->load(&msrc)) |
596 | 194 | { // Fatal error return, mask is not valid |
597 | 194 | ERREXIT(pcinfo, JERR_CANT_SUSPEND); |
598 | 194 | } |
599 | | |
600 | 295 | src->bytes_in_buffer -= len; |
601 | 295 | src->next_input_byte += len; |
602 | 295 | psJPEG->mask_state = MASK_LOADED; |
603 | 295 | return true; |
604 | 1.41k | } JPEG_band.cpp:GDAL_MRF::MaskProcessor(jpeg_decompress_struct*) Line | Count | Source | 554 | 3.95k | { | 555 | 3.95k | struct jpeg_source_mgr *src = pcinfo->src; | 556 | 3.95k | if (src->bytes_in_buffer < 2) | 557 | 3.95k | ERREXIT(pcinfo, JERR_CANT_SUSPEND); | 558 | | // Big endian length, two bytes | 559 | 3.95k | int len = (*src->next_input_byte++) << 8; | 560 | 3.95k | len += *src->next_input_byte++; | 561 | | // The length includes the two bytes we just read | 562 | 3.95k | src->bytes_in_buffer -= 2; | 563 | 3.95k | len -= 2; | 564 | | // Check that it is safe to read the rest | 565 | 3.95k | if (src->bytes_in_buffer < static_cast<size_t>(len)) | 566 | 3.95k | ERREXIT(pcinfo, JERR_CANT_SUSPEND); | 567 | 3.95k | MRFJPEGStruct *psJPEG = | 568 | 3.95k | reinterpret_cast<MRFJPEGStruct *>(pcinfo->client_data); | 569 | 3.95k | BitMask *mask = psJPEG->mask; | 570 | | // caller doesn't want a mask or wrong chunk, skip the chunk and return | 571 | 3.95k | if (!mask || static_cast<size_t>(len) < CHUNK_NAME_SIZE || | 572 | 2.41k | !EQUALN(reinterpret_cast<const char *>(src->next_input_byte), | 573 | 3.95k | CHUNK_NAME, CHUNK_NAME_SIZE)) | 574 | 2.54k | { | 575 | 2.54k | src->bytes_in_buffer -= len; | 576 | 2.54k | src->next_input_byte += len; | 577 | 2.54k | return true; | 578 | 2.54k | } | 579 | | | 580 | | // Skip the signature and load the mask | 581 | 1.41k | src->bytes_in_buffer -= CHUNK_NAME_SIZE; | 582 | 1.41k | src->next_input_byte += CHUNK_NAME_SIZE; | 583 | 1.41k | len -= static_cast<int>(CHUNK_NAME_SIZE); | 584 | 1.41k | if (len == 0) | 585 | 1.11k | { // No mask content means mask is all full, just return | 586 | 1.11k | psJPEG->mask_state = MASK_FULL; | 587 | 1.11k | return true; | 588 | 1.11k | } | 589 | | | 590 | | // It is OK to use const cast, the mask doesn't touch the buffer | 591 | 295 | storage_manager msrc = {const_cast<char *>(reinterpret_cast<const char *>( | 592 | 295 | src->next_input_byte)), | 593 | 295 | static_cast<size_t>(len)}; | 594 | | | 595 | 295 | if (!mask->load(&msrc)) | 596 | 194 | { // Fatal error return, mask is not valid | 597 | 194 | ERREXIT(pcinfo, JERR_CANT_SUSPEND); | 598 | 194 | } | 599 | | | 600 | 295 | src->bytes_in_buffer -= len; | 601 | 295 | src->next_input_byte += len; | 602 | 295 | psJPEG->mask_state = MASK_LOADED; | 603 | 295 | return true; | 604 | 1.41k | } |
Unexecuted instantiation: JPEG12_band.cpp:GDAL_MRF::MaskProcessor(jpeg_decompress_struct12*) |
605 | | |
606 | | /** |
607 | | *\brief In memory decompression of JPEG file |
608 | | * |
609 | | * @param data pointer to output buffer |
610 | | * @param png pointer to PNG in memory |
611 | | * @param sz if non-zero, test that uncompressed data fits in the buffer. |
612 | | */ |
613 | | #if defined(JPEG12_ON) |
614 | | CPLErr JPEG_Codec::DecompressJPEG12(buf_mgr &dst, const buf_mgr &isrc) |
615 | | #else |
616 | | CPLErr JPEG_Codec::DecompressJPEG(buf_mgr &dst, const buf_mgr &isrc) |
617 | | #endif |
618 | | |
619 | 495 | { |
620 | 495 | int nbands = img.pagesize.c; |
621 | | // Locals, clean up after themselves |
622 | 495 | jpeg_decompress_struct cinfo; |
623 | 495 | MRFJPEGStruct sJPEGStruct; |
624 | 495 | struct jpeg_error_mgr sJErr; |
625 | 495 | BitMask mask(img.pagesize.x, img.pagesize.y); |
626 | 495 | RLEC3Packer packer; |
627 | 495 | mask.set_packer(&packer); |
628 | | |
629 | 495 | memset(&cinfo, 0, sizeof(cinfo)); |
630 | | // Pass the mask address to the decompressor |
631 | 495 | sJPEGStruct.mask = &mask; |
632 | | |
633 | 495 | struct jpeg_source_mgr src; |
634 | | |
635 | 495 | cinfo.err = jpeg_std_error(&sJErr); |
636 | 495 | sJErr.error_exit = errorExit; |
637 | 495 | sJErr.emit_message = emitMessage; |
638 | 495 | cinfo.client_data = &sJPEGStruct; |
639 | | |
640 | 495 | src.next_input_byte = reinterpret_cast<JOCTET *>(isrc.buffer); |
641 | 495 | src.bytes_in_buffer = isrc.size; |
642 | 495 | src.term_source = stub_source_dec; |
643 | 495 | src.init_source = stub_source_dec; |
644 | 495 | src.skip_input_data = skip_input_data_dec; |
645 | 495 | src.fill_input_buffer = fill_input_buffer_dec; |
646 | 495 | src.resync_to_restart = jpeg_resync_to_restart; |
647 | | |
648 | 495 | jpeg_create_decompress(&cinfo); |
649 | | |
650 | 495 | if (setjmp(sJPEGStruct.setjmpBuffer)) |
651 | 418 | { |
652 | 418 | CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error reading JPEG page"); |
653 | 418 | jpeg_destroy_decompress(&cinfo); |
654 | 418 | return CE_Failure; |
655 | 418 | } |
656 | | |
657 | 77 | cinfo.src = &src; |
658 | 77 | jpeg_set_marker_processor(&cinfo, JPEG_APP0 + 3, MaskProcessor); |
659 | 77 | jpeg_read_header(&cinfo, TRUE); |
660 | | |
661 | | /* In some cases, libjpeg needs to allocate a lot of memory */ |
662 | | /* http://www.libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf |
663 | | */ |
664 | 77 | if (jpeg_has_multiple_scans(&(cinfo))) |
665 | 163 | { |
666 | | /* In this case libjpeg will need to allocate memory or backing */ |
667 | | /* store for all coefficients */ |
668 | | /* See call to jinit_d_coef_controller() from master_selection() */ |
669 | | /* in libjpeg */ |
670 | 163 | vsi_l_offset nRequiredMemory = |
671 | 163 | static_cast<vsi_l_offset>(cinfo.image_width) * cinfo.image_height * |
672 | 163 | cinfo.num_components * ((cinfo.data_precision + 7) / 8); |
673 | | /* BLOCK_SMOOTHING_SUPPORTED is generally defined, so we need */ |
674 | | /* to replicate the logic of jinit_d_coef_controller() */ |
675 | 163 | if (cinfo.progressive_mode) |
676 | 163 | nRequiredMemory *= 3; |
677 | | |
678 | 163 | #ifndef GDAL_LIBJPEG_LARGEST_MEM_ALLOC |
679 | 326 | #define GDAL_LIBJPEG_LARGEST_MEM_ALLOC (100 * 1024 * 1024) |
680 | 163 | #endif |
681 | | |
682 | 163 | if (nRequiredMemory > GDAL_LIBJPEG_LARGEST_MEM_ALLOC && |
683 | 0 | CPLGetConfigOption("GDAL_ALLOW_LARGE_LIBJPEG_MEM_ALLOC", nullptr) == |
684 | 0 | nullptr) |
685 | 0 | { |
686 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
687 | 0 | "Reading this image would require libjpeg to allocate " |
688 | 0 | "at least " CPL_FRMT_GUIB " bytes. " |
689 | 0 | "This is disabled since above the " CPL_FRMT_GUIB |
690 | 0 | " threshold. " |
691 | 0 | "You may override this restriction by defining the " |
692 | 0 | "GDAL_ALLOW_LARGE_LIBJPEG_MEM_ALLOC environment variable, " |
693 | 0 | "or recompile GDAL by defining the " |
694 | 0 | "GDAL_LIBJPEG_LARGEST_MEM_ALLOC macro to a value greater " |
695 | 0 | "than " CPL_FRMT_GUIB, |
696 | 0 | static_cast<GUIntBig>(nRequiredMemory), |
697 | 0 | static_cast<GUIntBig>(GDAL_LIBJPEG_LARGEST_MEM_ALLOC), |
698 | 0 | static_cast<GUIntBig>(GDAL_LIBJPEG_LARGEST_MEM_ALLOC)); |
699 | 0 | jpeg_destroy_decompress(&cinfo); |
700 | 0 | return CE_Failure; |
701 | 0 | } |
702 | 163 | } |
703 | | |
704 | | // Use float, it is actually faster than the ISLOW method by a tiny bit |
705 | 77 | cinfo.dct_method = JDCT_FLOAT; |
706 | | |
707 | | // |
708 | | // Tolerate different input if we can do the conversion |
709 | | // Gray and RGB for example |
710 | | // This also means that a RGB MRF can be read as grayscale and vice versa |
711 | | // If libJPEG can't convert it will throw an error |
712 | | // |
713 | 77 | if (nbands == 3 && cinfo.num_components != nbands) |
714 | 12 | cinfo.out_color_space = JCS_RGB; |
715 | 77 | if (nbands == 1 && cinfo.num_components != nbands) |
716 | 0 | cinfo.out_color_space = JCS_GRAYSCALE; |
717 | | |
718 | 18.4E | const int datasize = ((cinfo.data_precision == 8) ? 1 : 2); |
719 | 77 | if (cinfo.image_width > |
720 | 77 | static_cast<unsigned>(INT_MAX / (nbands * datasize))) |
721 | 0 | { |
722 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
723 | 0 | "MRF: JPEG decompress buffer overflow"); |
724 | 0 | jpeg_destroy_decompress(&cinfo); |
725 | 0 | return CE_Failure; |
726 | 0 | } |
727 | 77 | int linesize = cinfo.image_width * nbands * datasize; |
728 | | |
729 | | // We have a mismatch between the real and the declared data format |
730 | | // warn and fail if output buffer is too small |
731 | 77 | if (linesize > static_cast<int>(INT_MAX / cinfo.image_height)) |
732 | 0 | { |
733 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
734 | 0 | "MRF: JPEG decompress buffer overflow"); |
735 | 0 | jpeg_destroy_decompress(&cinfo); |
736 | 0 | return CE_Failure; |
737 | 0 | } |
738 | 77 | if (static_cast<size_t>(linesize) * cinfo.image_height != dst.size) |
739 | 176 | { |
740 | 176 | CPLError(CE_Warning, CPLE_AppDefined, "MRF: read JPEG size is wrong"); |
741 | 176 | if (static_cast<size_t>(linesize) * cinfo.image_height > dst.size) |
742 | 41 | { |
743 | 41 | CPLError(CE_Failure, CPLE_AppDefined, |
744 | 41 | "MRF: JPEG decompress buffer overflow"); |
745 | 41 | jpeg_destroy_decompress(&cinfo); |
746 | 41 | return CE_Failure; |
747 | 41 | } |
748 | 176 | } |
749 | | |
750 | 36 | struct jpeg_progress_mgr sJProgress; |
751 | 36 | sJProgress.progress_monitor = ProgressMonitor; |
752 | 36 | cinfo.progress = &sJProgress; |
753 | | |
754 | 36 | jpeg_start_decompress(&cinfo); |
755 | | |
756 | | // Decompress, two lines at a time is what libjpeg does |
757 | 23.0k | while (cinfo.output_scanline < cinfo.image_height) |
758 | 23.0k | { |
759 | 23.0k | char *rp[2]; |
760 | 23.0k | rp[0] = (char *)dst.buffer + linesize * cinfo.output_scanline; |
761 | 23.0k | rp[1] = rp[0] + linesize; |
762 | | // if this fails, it calls the error handler |
763 | | // which will report an error |
764 | | #if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12) && defined(JPEG12_ON) |
765 | | if (jpeg12_read_scanlines(&cinfo, MRF_JSAMPARRAY(rp), 2) == 0) |
766 | | #else |
767 | 23.0k | if (jpeg_read_scanlines(&cinfo, MRF_JSAMPARRAY(rp), 2) == 0) |
768 | 0 | #endif |
769 | 0 | { |
770 | 0 | jpeg_destroy_decompress(&cinfo); |
771 | 0 | return CE_Failure; |
772 | 0 | } |
773 | 23.0k | } |
774 | 36 | jpeg_finish_decompress(&cinfo); |
775 | 0 | jpeg_destroy_decompress(&cinfo); |
776 | | |
777 | | // Apply the mask |
778 | 36 | if (datasize == 1) |
779 | 36 | apply_mask(sJPEGStruct, reinterpret_cast<char *>(dst.buffer), |
780 | 36 | img.pagesize.c); |
781 | 0 | else |
782 | 0 | apply_mask(sJPEGStruct, reinterpret_cast<GUInt16 *>(dst.buffer), |
783 | 0 | img.pagesize.c); |
784 | |
|
785 | 0 | return CE_None; |
786 | 36 | } GDAL_MRF::JPEG_Codec::DecompressJPEG(GDAL_MRF::buf_mgr&, GDAL_MRF::buf_mgr const&) Line | Count | Source | 619 | 495 | { | 620 | 495 | int nbands = img.pagesize.c; | 621 | | // Locals, clean up after themselves | 622 | 495 | jpeg_decompress_struct cinfo; | 623 | 495 | MRFJPEGStruct sJPEGStruct; | 624 | 495 | struct jpeg_error_mgr sJErr; | 625 | 495 | BitMask mask(img.pagesize.x, img.pagesize.y); | 626 | 495 | RLEC3Packer packer; | 627 | 495 | mask.set_packer(&packer); | 628 | | | 629 | 495 | memset(&cinfo, 0, sizeof(cinfo)); | 630 | | // Pass the mask address to the decompressor | 631 | 495 | sJPEGStruct.mask = &mask; | 632 | | | 633 | 495 | struct jpeg_source_mgr src; | 634 | | | 635 | 495 | cinfo.err = jpeg_std_error(&sJErr); | 636 | 495 | sJErr.error_exit = errorExit; | 637 | 495 | sJErr.emit_message = emitMessage; | 638 | 495 | cinfo.client_data = &sJPEGStruct; | 639 | | | 640 | 495 | src.next_input_byte = reinterpret_cast<JOCTET *>(isrc.buffer); | 641 | 495 | src.bytes_in_buffer = isrc.size; | 642 | 495 | src.term_source = stub_source_dec; | 643 | 495 | src.init_source = stub_source_dec; | 644 | 495 | src.skip_input_data = skip_input_data_dec; | 645 | 495 | src.fill_input_buffer = fill_input_buffer_dec; | 646 | 495 | src.resync_to_restart = jpeg_resync_to_restart; | 647 | | | 648 | 495 | jpeg_create_decompress(&cinfo); | 649 | | | 650 | 495 | if (setjmp(sJPEGStruct.setjmpBuffer)) | 651 | 418 | { | 652 | 418 | CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error reading JPEG page"); | 653 | 418 | jpeg_destroy_decompress(&cinfo); | 654 | 418 | return CE_Failure; | 655 | 418 | } | 656 | | | 657 | 77 | cinfo.src = &src; | 658 | 77 | jpeg_set_marker_processor(&cinfo, JPEG_APP0 + 3, MaskProcessor); | 659 | 77 | jpeg_read_header(&cinfo, TRUE); | 660 | | | 661 | | /* In some cases, libjpeg needs to allocate a lot of memory */ | 662 | | /* http://www.libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf | 663 | | */ | 664 | 77 | if (jpeg_has_multiple_scans(&(cinfo))) | 665 | 163 | { | 666 | | /* In this case libjpeg will need to allocate memory or backing */ | 667 | | /* store for all coefficients */ | 668 | | /* See call to jinit_d_coef_controller() from master_selection() */ | 669 | | /* in libjpeg */ | 670 | 163 | vsi_l_offset nRequiredMemory = | 671 | 163 | static_cast<vsi_l_offset>(cinfo.image_width) * cinfo.image_height * | 672 | 163 | cinfo.num_components * ((cinfo.data_precision + 7) / 8); | 673 | | /* BLOCK_SMOOTHING_SUPPORTED is generally defined, so we need */ | 674 | | /* to replicate the logic of jinit_d_coef_controller() */ | 675 | 163 | if (cinfo.progressive_mode) | 676 | 163 | nRequiredMemory *= 3; | 677 | | | 678 | 163 | #ifndef GDAL_LIBJPEG_LARGEST_MEM_ALLOC | 679 | 163 | #define GDAL_LIBJPEG_LARGEST_MEM_ALLOC (100 * 1024 * 1024) | 680 | 163 | #endif | 681 | | | 682 | 163 | if (nRequiredMemory > GDAL_LIBJPEG_LARGEST_MEM_ALLOC && | 683 | 0 | CPLGetConfigOption("GDAL_ALLOW_LARGE_LIBJPEG_MEM_ALLOC", nullptr) == | 684 | 0 | nullptr) | 685 | 0 | { | 686 | 0 | CPLError(CE_Failure, CPLE_NotSupported, | 687 | 0 | "Reading this image would require libjpeg to allocate " | 688 | 0 | "at least " CPL_FRMT_GUIB " bytes. " | 689 | 0 | "This is disabled since above the " CPL_FRMT_GUIB | 690 | 0 | " threshold. " | 691 | 0 | "You may override this restriction by defining the " | 692 | 0 | "GDAL_ALLOW_LARGE_LIBJPEG_MEM_ALLOC environment variable, " | 693 | 0 | "or recompile GDAL by defining the " | 694 | 0 | "GDAL_LIBJPEG_LARGEST_MEM_ALLOC macro to a value greater " | 695 | 0 | "than " CPL_FRMT_GUIB, | 696 | 0 | static_cast<GUIntBig>(nRequiredMemory), | 697 | 0 | static_cast<GUIntBig>(GDAL_LIBJPEG_LARGEST_MEM_ALLOC), | 698 | 0 | static_cast<GUIntBig>(GDAL_LIBJPEG_LARGEST_MEM_ALLOC)); | 699 | 0 | jpeg_destroy_decompress(&cinfo); | 700 | 0 | return CE_Failure; | 701 | 0 | } | 702 | 163 | } | 703 | | | 704 | | // Use float, it is actually faster than the ISLOW method by a tiny bit | 705 | 77 | cinfo.dct_method = JDCT_FLOAT; | 706 | | | 707 | | // | 708 | | // Tolerate different input if we can do the conversion | 709 | | // Gray and RGB for example | 710 | | // This also means that a RGB MRF can be read as grayscale and vice versa | 711 | | // If libJPEG can't convert it will throw an error | 712 | | // | 713 | 77 | if (nbands == 3 && cinfo.num_components != nbands) | 714 | 12 | cinfo.out_color_space = JCS_RGB; | 715 | 77 | if (nbands == 1 && cinfo.num_components != nbands) | 716 | 0 | cinfo.out_color_space = JCS_GRAYSCALE; | 717 | | | 718 | 18.4E | const int datasize = ((cinfo.data_precision == 8) ? 1 : 2); | 719 | 77 | if (cinfo.image_width > | 720 | 77 | static_cast<unsigned>(INT_MAX / (nbands * datasize))) | 721 | 0 | { | 722 | 0 | CPLError(CE_Failure, CPLE_AppDefined, | 723 | 0 | "MRF: JPEG decompress buffer overflow"); | 724 | 0 | jpeg_destroy_decompress(&cinfo); | 725 | 0 | return CE_Failure; | 726 | 0 | } | 727 | 77 | int linesize = cinfo.image_width * nbands * datasize; | 728 | | | 729 | | // We have a mismatch between the real and the declared data format | 730 | | // warn and fail if output buffer is too small | 731 | 77 | if (linesize > static_cast<int>(INT_MAX / cinfo.image_height)) | 732 | 0 | { | 733 | 0 | CPLError(CE_Failure, CPLE_AppDefined, | 734 | 0 | "MRF: JPEG decompress buffer overflow"); | 735 | 0 | jpeg_destroy_decompress(&cinfo); | 736 | 0 | return CE_Failure; | 737 | 0 | } | 738 | 77 | if (static_cast<size_t>(linesize) * cinfo.image_height != dst.size) | 739 | 176 | { | 740 | 176 | CPLError(CE_Warning, CPLE_AppDefined, "MRF: read JPEG size is wrong"); | 741 | 176 | if (static_cast<size_t>(linesize) * cinfo.image_height > dst.size) | 742 | 41 | { | 743 | 41 | CPLError(CE_Failure, CPLE_AppDefined, | 744 | 41 | "MRF: JPEG decompress buffer overflow"); | 745 | 41 | jpeg_destroy_decompress(&cinfo); | 746 | 41 | return CE_Failure; | 747 | 41 | } | 748 | 176 | } | 749 | | | 750 | 36 | struct jpeg_progress_mgr sJProgress; | 751 | 36 | sJProgress.progress_monitor = ProgressMonitor; | 752 | 36 | cinfo.progress = &sJProgress; | 753 | | | 754 | 36 | jpeg_start_decompress(&cinfo); | 755 | | | 756 | | // Decompress, two lines at a time is what libjpeg does | 757 | 23.0k | while (cinfo.output_scanline < cinfo.image_height) | 758 | 23.0k | { | 759 | 23.0k | char *rp[2]; | 760 | 23.0k | rp[0] = (char *)dst.buffer + linesize * cinfo.output_scanline; | 761 | 23.0k | rp[1] = rp[0] + linesize; | 762 | | // if this fails, it calls the error handler | 763 | | // which will report an error | 764 | | #if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12) && defined(JPEG12_ON) | 765 | | if (jpeg12_read_scanlines(&cinfo, MRF_JSAMPARRAY(rp), 2) == 0) | 766 | | #else | 767 | 23.0k | if (jpeg_read_scanlines(&cinfo, MRF_JSAMPARRAY(rp), 2) == 0) | 768 | 0 | #endif | 769 | 0 | { | 770 | 0 | jpeg_destroy_decompress(&cinfo); | 771 | 0 | return CE_Failure; | 772 | 0 | } | 773 | 23.0k | } | 774 | 36 | jpeg_finish_decompress(&cinfo); | 775 | 36 | jpeg_destroy_decompress(&cinfo); | 776 | | | 777 | | // Apply the mask | 778 | 36 | if (datasize == 1) | 779 | 36 | apply_mask(sJPEGStruct, reinterpret_cast<char *>(dst.buffer), | 780 | 36 | img.pagesize.c); | 781 | 0 | else | 782 | 0 | apply_mask(sJPEGStruct, reinterpret_cast<GUInt16 *>(dst.buffer), | 783 | 0 | img.pagesize.c); | 784 | | | 785 | 36 | return CE_None; | 786 | 36 | } |
Unexecuted instantiation: GDAL_MRF::JPEG_Codec::DecompressJPEG12(GDAL_MRF::buf_mgr&, GDAL_MRF::buf_mgr const&) |
787 | | |
788 | | // From here to end it gets compiled only once |
789 | | #if !defined(JPEG12_ON) |
790 | | |
791 | | // The Zen chunk signature |
792 | | char CHUNK_NAME[] = "Zen"; |
793 | | size_t CHUNK_NAME_SIZE = strlen(CHUNK_NAME) + 1; |
794 | | |
795 | | const static GUInt32 JPEG_SIG = 0xe0ffd8ff; // JPEG 4CC code |
796 | | const static GUInt32 BRUN_SIG = 0xd242040a; // Brunsli 4CC code, native |
797 | | |
798 | | static bool isbrunsli(const buf_mgr &src) |
799 | 495 | { |
800 | 495 | GUInt32 signature; |
801 | 495 | memcpy(&signature, src.buffer, sizeof(signature)); |
802 | 495 | if (BRUN_SIG == CPL_LSBWORD32(signature)) |
803 | 0 | return true; |
804 | 495 | return false; |
805 | 495 | } |
806 | | |
807 | | bool JPEG_Codec::IsJPEG(const buf_mgr &src) |
808 | 0 | { |
809 | 0 | if (isbrunsli(src)) |
810 | 0 | return true; |
811 | 0 | GUInt32 signature; |
812 | 0 | memcpy(&signature, src.buffer, sizeof(signature)); |
813 | 0 | if (JPEG_SIG == CPL_LSBWORD32(signature)) |
814 | 0 | return true; |
815 | 0 | return false; |
816 | 0 | } |
817 | | |
818 | | #if defined(BRUNSLI) |
819 | | // Append to end of out vector |
820 | | static size_t brunsli_fun_callback(void *out, const GByte *data, size_t size) |
821 | | { |
822 | | auto outv = static_cast<std::vector<GByte> *>(out); |
823 | | outv->insert(outv->end(), data, data + size); |
824 | | return size; |
825 | | } |
826 | | #endif |
827 | | |
828 | | // Type dependent dispatchers |
829 | | CPLErr JPEG_Band::Decompress(buf_mgr &dst, buf_mgr &src) |
830 | 495 | { |
831 | 495 | #if defined(JPEG12_SUPPORTED) |
832 | 495 | if (GDT_UInt8 != img.dt) |
833 | 0 | return codec.DecompressJPEG12(dst, src); |
834 | 495 | #endif |
835 | 495 | if (!isbrunsli(src)) |
836 | 495 | return codec.DecompressJPEG(dst, src); |
837 | | |
838 | | // Need conversion to JFIF first |
839 | 0 | #if !defined(BRUNSLI) |
840 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
841 | 0 | "MRF: JPEG-XL content, yet this GDAL was not compiled with " |
842 | 0 | "BRUNSLI support"); |
843 | 0 | return CE_Failure; |
844 | | #else |
845 | | std::vector<GByte> out; |
846 | | // Returns 0 on failure |
847 | | if (!DecodeBrunsli(src.size, reinterpret_cast<uint8_t *>(src.buffer), &out, |
848 | | brunsli_fun_callback)) |
849 | | { |
850 | | CPLError(CE_Failure, CPLE_AppDefined, |
851 | | "MRF: JPEG-XL (brunsli) tile decode failed"); |
852 | | return CE_Failure; |
853 | | } |
854 | | |
855 | | buf_mgr jfif_src; |
856 | | jfif_src.buffer = reinterpret_cast<char *>(out.data()); |
857 | | jfif_src.size = out.size(); |
858 | | return Decompress(dst, jfif_src); // Call itself with JFIF JPEG source |
859 | | #endif // BRUNSLI |
860 | 495 | } |
861 | | |
862 | | CPLErr JPEG_Band::Compress(buf_mgr &dst, buf_mgr &src) |
863 | 0 | { |
864 | 0 | #if defined(JPEG12_SUPPORTED) |
865 | 0 | if (GDT_UInt8 != img.dt) |
866 | 0 | return codec.CompressJPEG12(dst, src); |
867 | 0 | #endif |
868 | 0 | #if !defined(BRUNSLI) |
869 | 0 | return codec.CompressJPEG(dst, src); |
870 | | #else |
871 | | auto dst_size = dst.size; // Save the original size |
872 | | auto err_code = codec.CompressJPEG(dst, src); |
873 | | if (codec.JFIF || err_code != CE_None) |
874 | | return err_code; |
875 | | |
876 | | // The JFIF is in dst buffer |
877 | | std::vector<GByte> out; |
878 | | if (!EncodeBrunsli(dst.size, reinterpret_cast<uint8_t *>(dst.buffer), &out, |
879 | | brunsli_fun_callback)) |
880 | | { |
881 | | CPLError(CE_Failure, CPLE_AppDefined, |
882 | | "MRF: JPEG-XL (brunsli) tile encode failed"); |
883 | | return CE_Failure; |
884 | | } |
885 | | // Copy the brunsli to the dst buffer |
886 | | if (out.size() > dst_size) |
887 | | { |
888 | | CPLError(CE_Failure, CPLE_AppDefined, |
889 | | "MRF: JPEG-XL (brunsli) encoded tile too large"); |
890 | | return CE_Failure; |
891 | | } |
892 | | memcpy(dst.buffer, out.data(), out.size()); |
893 | | dst.size = out.size(); |
894 | | return CE_None; |
895 | | #endif // BRUNSLI |
896 | 0 | } |
897 | | |
898 | | // PHOTOMETRIC == MULTISPECTRAL turns off YCbCr conversion and downsampling |
899 | | JPEG_Band::JPEG_Band(MRFDataset *pDS, const ILImage &image, int b, int level) |
900 | 7.44k | : MRFRasterBand(pDS, image, b, int(level)), codec(image) |
901 | 7.44k | { |
902 | 7.44k | const int nbands = image.pagesize.c; |
903 | | // Check behavior on signed 16bit. Does the libjpeg sign extend? |
904 | 7.44k | #if defined(JPEG12_SUPPORTED) |
905 | 7.44k | if (GDT_UInt8 != image.dt && GDT_UInt16 != image.dt) |
906 | | #else |
907 | | if (GDT_UInt8 != image.dt) |
908 | | #endif |
909 | 0 | { |
910 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
911 | 0 | "Data type not supported by MRF JPEG"); |
912 | 0 | return; |
913 | 0 | } |
914 | | |
915 | 7.44k | if (nbands == 3) |
916 | 48 | { // Only the 3 band JPEG has storage flavors |
917 | 48 | CPLString const &pm = pDS->GetPhotometricInterpretation(); |
918 | 48 | if (pm == "RGB" || pm == "MULTISPECTRAL") |
919 | 0 | { // Explicit RGB or MS |
920 | 0 | codec.rgb = TRUE; |
921 | 0 | codec.sameres = TRUE; |
922 | 0 | } |
923 | 48 | if (pm == "YCC") |
924 | 0 | codec.sameres = TRUE; |
925 | 48 | } |
926 | | |
927 | 7.44k | if (GDT_UInt8 == image.dt) |
928 | 7.44k | { |
929 | 7.44k | codec.optimize = GetOptlist().FetchBoolean("OPTIMIZE", FALSE) != FALSE; |
930 | 7.44k | codec.JFIF = GetOptlist().FetchBoolean("JFIF", FALSE) != FALSE; |
931 | 7.44k | } |
932 | 0 | else |
933 | 0 | { |
934 | 0 | codec.optimize = true; // Required for 12bit |
935 | 0 | } |
936 | | // For high Q, no downsampling and multispectral, output can be larger than the input |
937 | | // This is just a guess, 20% larger plus some space for the headers and mask |
938 | | // If too small, the empty_output_buffer() above will be called and an |
939 | | // error will be generated |
940 | 7.44k | poMRFDS->SetPBufferSize(int(1.2 * image.pageSizeBytes + 4000)); |
941 | 7.44k | } |
942 | | #endif |
943 | | |
944 | | NAMESPACE_MRF_END |