Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Purpose: Implementation of the JPEG compression/decompression based 4 : * on libjpeg. This implements functions suitable for use 5 : * as jpeg interfaces in the PCIDSKInterfaces class. 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2009 9 : * PCI Geomatics, 90 Allstate Parkway, Markham, Ontario, Canada. 10 : * 11 : * SPDX-License-Identifier: MIT 12 : ****************************************************************************/ 13 : 14 : #include "pcidsk_config.h" 15 : #include "pcidsk_types.h" 16 : #include "core/pcidsk_utils.h" 17 : #include "pcidsk_exception.h" 18 : #include <cassert> 19 : #include <cstdio> 20 : 21 : using namespace PCIDSK; 22 : 23 : #if defined(HAVE_LIBJPEG) 24 : 25 : extern "C" { 26 : #include "jpeglib.h" 27 : } 28 : 29 2 : static void _DummyMgrMethod( j_compress_ptr /*pUnused*/ ) {} 30 2 : static void _DummySrcMgrMethod( j_decompress_ptr /*pUnused*/ ) {} 31 0 : static boolean _DummyFillInputBuffer(j_decompress_ptr) { return 0; } 32 0 : static void _DummySkipInputData(j_decompress_ptr, long) {} 33 0 : static boolean _DummyEmptyOutputBuffer(j_compress_ptr) { return 0; } 34 : 35 : /************************************************************************/ 36 : /* JpegError() */ 37 : /* */ 38 : /* Handle errors generated by the IJG library. We treat all */ 39 : /* errors as fatal at this point. Future handling may be */ 40 : /* improved by overriding other methods. */ 41 : /************************************************************************/ 42 : 43 0 : static void JpegError(j_common_ptr cinfo) 44 : { 45 : char buf[256]; 46 : 47 0 : cinfo->err->format_message(cinfo, buf); 48 : 49 : // Make sure we destroy the context before throwing an exception. 50 0 : if (cinfo->is_decompressor) 51 0 : jpeg_destroy_decompress((j_decompress_ptr) cinfo); 52 : else 53 0 : jpeg_destroy_compress((j_compress_ptr) cinfo); 54 : 55 0 : return ThrowPCIDSKException( "%s", buf ); 56 : } 57 : 58 : /************************************************************************/ 59 : /* LibJPEG_DecompressBlock() */ 60 : /************************************************************************/ 61 : 62 1 : void PCIDSK::LibJPEG_DecompressBlock( 63 : uint8 *src_data, int src_bytes, uint8 *dst_data, CPL_UNUSED int dst_bytes, 64 : int xsize, int ysize, eChanType CPL_UNUSED pixel_type ) 65 : { 66 : struct jpeg_decompress_struct sJCompInfo; 67 : struct jpeg_source_mgr sSrcMgr; 68 : struct jpeg_error_mgr sErrMgr; 69 : 70 : int i; 71 : 72 : /* -------------------------------------------------------------------- */ 73 : /* Setup the buffer we will compress into. We make it pretty */ 74 : /* big to ensure there is space. The calling function will */ 75 : /* free it as soon as it is done so this should not hurt much. */ 76 : /* -------------------------------------------------------------------- */ 77 1 : sSrcMgr.init_source = _DummySrcMgrMethod; 78 1 : sSrcMgr.fill_input_buffer = _DummyFillInputBuffer; 79 1 : sSrcMgr.skip_input_data = _DummySkipInputData; 80 1 : sSrcMgr.resync_to_restart = jpeg_resync_to_restart; 81 1 : sSrcMgr.term_source = _DummySrcMgrMethod; 82 : 83 1 : sSrcMgr.next_input_byte = src_data; 84 1 : sSrcMgr.bytes_in_buffer = src_bytes; 85 : 86 : /* -------------------------------------------------------------------- */ 87 : /* Setup JPEG Decompression */ 88 : /* -------------------------------------------------------------------- */ 89 1 : jpeg_create_decompress(&sJCompInfo); 90 : 91 1 : sJCompInfo.src = &sSrcMgr; 92 1 : sJCompInfo.err = jpeg_std_error(&sErrMgr); 93 1 : sJCompInfo.err->output_message = JpegError; 94 : 95 : /* -------------------------------------------------------------------- */ 96 : /* Read the header. */ 97 : /* -------------------------------------------------------------------- */ 98 1 : jpeg_read_header( &sJCompInfo, TRUE ); 99 1 : if (sJCompInfo.image_width != (unsigned int)xsize || 100 1 : sJCompInfo.image_height != (unsigned int)ysize) 101 : { 102 0 : jpeg_destroy_decompress( &sJCompInfo ); 103 : 104 0 : return ThrowPCIDSKException("Tile Size wrong in LibJPEG_DecompressTile(), got %dx%d, expected %dx%d.", 105 : sJCompInfo.image_width, 106 : sJCompInfo.image_height, 107 0 : xsize, ysize ); 108 : } 109 : 110 1 : sJCompInfo.out_color_space = JCS_GRAYSCALE; 111 1 : jpeg_start_decompress(&sJCompInfo); 112 : 113 : /* -------------------------------------------------------------------- */ 114 : /* Read each of the scanlines. */ 115 : /* -------------------------------------------------------------------- */ 116 257 : for( i = 0; i < ysize; i++ ) 117 : { 118 256 : uint8 *line_data = dst_data + i*xsize; 119 256 : jpeg_read_scanlines( &sJCompInfo, (JSAMPARRAY) &line_data, 1 ); 120 : } 121 : 122 : /* -------------------------------------------------------------------- */ 123 : /* Cleanup. */ 124 : /* -------------------------------------------------------------------- */ 125 1 : jpeg_finish_decompress( &sJCompInfo ); 126 1 : jpeg_destroy_decompress( &sJCompInfo ); 127 : } 128 : 129 : /************************************************************************/ 130 : /* LibJPEG_CompressBlock() */ 131 : /************************************************************************/ 132 : 133 1 : void PCIDSK::LibJPEG_CompressBlock( 134 : uint8 *src_data, CPL_UNUSED int src_bytes, uint8 *dst_data, int &dst_bytes, 135 : int xsize, int ysize, CPL_UNUSED eChanType pixel_type, int quality ) 136 : { 137 : struct jpeg_compress_struct sJCompInfo; 138 : struct jpeg_destination_mgr sDstMgr; 139 : struct jpeg_error_mgr sErrMgr; 140 : 141 : int i; 142 : 143 : /* -------------------------------------------------------------------- */ 144 : /* Setup the buffer we will compress into. */ 145 : /* -------------------------------------------------------------------- */ 146 1 : sDstMgr.next_output_byte = dst_data; 147 1 : sDstMgr.free_in_buffer = dst_bytes; 148 1 : sDstMgr.init_destination = _DummyMgrMethod; 149 1 : sDstMgr.empty_output_buffer = _DummyEmptyOutputBuffer; 150 1 : sDstMgr.term_destination = _DummyMgrMethod; 151 : 152 : /* -------------------------------------------------------------------- */ 153 : /* Setup JPEG Compression */ 154 : /* -------------------------------------------------------------------- */ 155 1 : jpeg_create_compress(&sJCompInfo); 156 : 157 1 : sJCompInfo.dest = &sDstMgr; 158 1 : sJCompInfo.err = jpeg_std_error(&sErrMgr); 159 1 : sJCompInfo.err->output_message = JpegError; 160 : 161 1 : sJCompInfo.image_width = xsize; 162 1 : sJCompInfo.image_height = ysize; 163 1 : sJCompInfo.input_components = 1; 164 1 : sJCompInfo.in_color_space = JCS_GRAYSCALE; 165 : 166 1 : jpeg_set_defaults(&sJCompInfo); 167 1 : jpeg_set_quality(&sJCompInfo, quality, TRUE ); 168 1 : jpeg_start_compress(&sJCompInfo, TRUE ); 169 : 170 : /* -------------------------------------------------------------------- */ 171 : /* Write all the scanlines at once. */ 172 : /* -------------------------------------------------------------------- */ 173 257 : for( i = 0; i < ysize; i++ ) 174 : { 175 256 : uint8 *pabyLine = src_data + i*xsize; 176 : 177 256 : jpeg_write_scanlines( &sJCompInfo, (JSAMPARRAY)&pabyLine, 1 ); 178 : } 179 : 180 : /* -------------------------------------------------------------------- */ 181 : /* Cleanup. */ 182 : /* -------------------------------------------------------------------- */ 183 1 : jpeg_finish_compress( &sJCompInfo ); 184 : 185 1 : dst_bytes = static_cast<int>(dst_bytes - sDstMgr.free_in_buffer); 186 : 187 1 : jpeg_destroy_compress( &sJCompInfo ); 188 1 : } 189 : 190 : #endif /* defined(HAVE_LIBJPEG) */