1 : /******************************************************************************
2 : * $Id: nitfwritejpeg.cpp 21951 2011-03-12 22:02:07Z warmerdam $
3 : *
4 : * Project: NITF Read/Write Translator
5 : * Purpose: GDALDataset/GDALRasterBand implementation on top of "nitflib".
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2002, Frank Warmerdam
10 : *
11 : * Portions Copyright (c) Her majesty the Queen in right of Canada as
12 : * represented by the Minister of National Defence, 2006.
13 : *
14 : * Permission is hereby granted, free of charge, to any person obtaining a
15 : * copy of this software and associated documentation files (the "Software"),
16 : * to deal in the Software without restriction, including without limitation
17 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 : * and/or sell copies of the Software, and to permit persons to whom the
19 : * Software is furnished to do so, subject to the following conditions:
20 : *
21 : * The above copyright notice and this permission notice shall be included
22 : * in all copies or substantial portions of the Software.
23 : *
24 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 : * DEALINGS IN THE SOFTWARE.
31 : ****************************************************************************/
32 :
33 : #ifdef JPEG_SUPPORTED
34 :
35 : #include "cpl_port.h"
36 : #include "gdal_pam.h"
37 :
38 : CPL_C_START
39 : #ifdef LIBJPEG_12_PATH
40 : # include LIBJPEG_12_PATH
41 : #else
42 : # include "jpeglib.h"
43 : #endif
44 : CPL_C_END
45 :
46 : /*
47 : * Do we want to do special processing suitable for when JSAMPLE is a
48 : * 16bit value?
49 : */
50 : #if defined(JPEG_LIB_MK1)
51 : # define JPEG_LIB_MK1_OR_12BIT 1
52 : #elif BITS_IN_JSAMPLE == 12
53 : # define JPEG_LIB_MK1_OR_12BIT 1
54 : #endif
55 :
56 : #if defined(JPEG_DUAL_MODE_8_12) && !defined(NITFWriteJPEGBlock)
57 : int
58 : NITFWriteJPEGBlock_12( GDALDataset *poSrcDS, VSILFILE *fp,
59 : int nBlockXOff, int nBlockYOff,
60 : int nBlockXSize, int nBlockYSize,
61 : int bProgressive, int nQuality,
62 : const GByte* pabyAPP6, int nRestartInterval,
63 : GDALProgressFunc pfnProgress, void * pProgressData );
64 : #endif
65 :
66 : void jpeg_vsiio_src (j_decompress_ptr cinfo, VSILFILE * infile);
67 : void jpeg_vsiio_dest (j_compress_ptr cinfo, VSILFILE * outfile);
68 :
69 : /************************************************************************/
70 : /* NITFWriteJPEGBlock() */
71 : /************************************************************************/
72 :
73 : int
74 11 : NITFWriteJPEGBlock( GDALDataset *poSrcDS, VSILFILE *fp,
75 : int nBlockXOff, int nBlockYOff,
76 : int nBlockXSize, int nBlockYSize,
77 : int bProgressive, int nQuality,
78 : const GByte* pabyAPP6, int nRestartInterval,
79 : GDALProgressFunc pfnProgress, void * pProgressData )
80 : {
81 11 : GDALDataType eDT = poSrcDS->GetRasterBand(1)->GetRasterDataType();
82 : #if defined(JPEG_DUAL_MODE_8_12) && !defined(NITFWriteJPEGBlock)
83 10 : if( eDT == GDT_UInt16 )
84 : {
85 : return NITFWriteJPEGBlock_12(poSrcDS, fp,
86 : nBlockXOff, nBlockYOff,
87 : nBlockXSize, nBlockYSize,
88 : bProgressive, nQuality,
89 : pabyAPP6, nRestartInterval,
90 1 : pfnProgress, pProgressData );
91 : }
92 : #endif
93 :
94 10 : int nBands = poSrcDS->GetRasterCount();
95 10 : int nXSize = poSrcDS->GetRasterXSize();
96 10 : int nYSize = poSrcDS->GetRasterYSize();
97 10 : int anBandList[3] = {1,2,3};
98 :
99 : /* -------------------------------------------------------------------- */
100 : /* Initialize JPG access to the file. */
101 : /* -------------------------------------------------------------------- */
102 : struct jpeg_compress_struct sCInfo;
103 : struct jpeg_error_mgr sJErr;
104 :
105 10 : sCInfo.err = jpeg_std_error( &sJErr );
106 10 : jpeg_create_compress( &sCInfo );
107 :
108 10 : jpeg_vsiio_dest( &sCInfo, fp );
109 :
110 10 : sCInfo.image_width = nBlockXSize;
111 10 : sCInfo.image_height = nBlockYSize;
112 10 : sCInfo.input_components = nBands;
113 :
114 10 : if( nBands == 1 )
115 : {
116 1 : sCInfo.in_color_space = JCS_GRAYSCALE;
117 : }
118 : else
119 : {
120 9 : sCInfo.in_color_space = JCS_RGB;
121 : }
122 :
123 10 : jpeg_set_defaults( &sCInfo );
124 :
125 : #if defined(JPEG_LIB_MK1_OR_12BIT)
126 1 : if( eDT == GDT_UInt16 )
127 : {
128 1 : sCInfo.data_precision = 12;
129 : }
130 : else
131 : {
132 0 : sCInfo.data_precision = 8;
133 : }
134 : #endif
135 :
136 : GDALDataType eWorkDT;
137 : #ifdef JPEG_LIB_MK1
138 : sCInfo.bits_in_jsample = sCInfo.data_precision;
139 : eWorkDT = GDT_UInt16; /* Always force to 16 bit for JPEG_LIB_MK1 */
140 : #else
141 10 : eWorkDT = eDT;
142 : #endif
143 :
144 10 : sCInfo.write_JFIF_header = FALSE;
145 :
146 : /* Set the restart interval */
147 10 : if (nRestartInterval < 0)
148 : {
149 : /* nRestartInterval < 0 means that we will guess the value */
150 : /* so we set it at the maximum allowed by MIL-STD-188-198 */
151 : /* that is to say the number of MCU per row-block */
152 10 : nRestartInterval = nBlockXSize / 8;
153 : }
154 :
155 10 : if (nRestartInterval > 0)
156 10 : sCInfo.restart_interval = nRestartInterval;
157 :
158 10 : jpeg_set_quality( &sCInfo, nQuality, TRUE );
159 :
160 10 : if( bProgressive )
161 0 : jpeg_simple_progression( &sCInfo );
162 :
163 10 : jpeg_start_compress( &sCInfo, TRUE );
164 :
165 : /* -------------------------------------------------------------------- */
166 : /* Emits APP6 NITF application segment (required by MIL-STD-188-198) */
167 : /* -------------------------------------------------------------------- */
168 10 : if (pabyAPP6)
169 : {
170 : /* 0xe6 = APP6 marker */
171 4 : jpeg_write_marker( &sCInfo, 0xe6, (const JOCTET*) pabyAPP6, 23);
172 : }
173 :
174 : /* -------------------------------------------------------------------- */
175 : /* Loop over image, copying image data. */
176 : /* -------------------------------------------------------------------- */
177 : GByte *pabyScanline;
178 10 : CPLErr eErr = CE_None;
179 10 : int nWorkDTSize = GDALGetDataTypeSize(eWorkDT) / 8;
180 :
181 10 : pabyScanline = (GByte *) CPLMalloc( nBands * nBlockXSize * nWorkDTSize );
182 :
183 10 : double nTotalPixels = (double)nXSize * nYSize;
184 :
185 10 : int nBlockXSizeToRead = nBlockXSize;
186 10 : if (nBlockXSize * nBlockXOff + nBlockXSize > nXSize)
187 : {
188 4 : nBlockXSizeToRead = nXSize - nBlockXSize * nBlockXOff;
189 : }
190 10 : int nBlockYSizeToRead = nBlockYSize;
191 10 : if (nBlockYSize * nBlockYOff + nBlockYSize > nYSize)
192 : {
193 4 : nBlockYSizeToRead = nYSize - nBlockYSize * nBlockYOff;
194 : }
195 :
196 10 : bool bClipWarn = false;
197 380 : for( int iLine = 0; iLine < nBlockYSize && eErr == CE_None; iLine++ )
198 : {
199 : JSAMPLE *ppSamples;
200 :
201 370 : if (iLine < nBlockYSizeToRead)
202 : {
203 : eErr = poSrcDS->RasterIO( GF_Read, nBlockXSize * nBlockXOff, iLine + nBlockYSize * nBlockYOff, nBlockXSizeToRead, 1,
204 : pabyScanline, nBlockXSizeToRead, 1, eWorkDT,
205 : nBands, anBandList,
206 314 : nBands*nWorkDTSize, nBands * nBlockXSize * nWorkDTSize, nWorkDTSize );
207 :
208 : #if !defined(JPEG_LIB_MK1_OR_12BIT)
209 : /* Repeat the last pixel till the end of the line */
210 : /* to minimize discontinuity */
211 250 : if (nBlockXSizeToRead < nBlockXSize)
212 : {
213 400 : for (int iBand = 0; iBand < nBands; iBand++)
214 : {
215 300 : GByte bVal = pabyScanline[nBands * (nBlockXSizeToRead - 1) + iBand];
216 4500 : for(int iX = nBlockXSizeToRead; iX < nBlockXSize; iX ++)
217 : {
218 4200 : pabyScanline[nBands * iX + iBand ] = bVal;
219 : }
220 : }
221 : }
222 : #endif
223 : }
224 :
225 : // clamp 16bit values to 12bit.
226 370 : if( eDT == GDT_UInt16 )
227 : {
228 64 : GUInt16 *panScanline = (GUInt16 *) pabyScanline;
229 : int iPixel;
230 :
231 4160 : for( iPixel = 0; iPixel < nXSize*nBands; iPixel++ )
232 : {
233 4096 : if( panScanline[iPixel] > 4095 )
234 : {
235 0 : panScanline[iPixel] = 4095;
236 0 : if( !bClipWarn )
237 : {
238 0 : bClipWarn = true;
239 : CPLError( CE_Warning, CPLE_AppDefined,
240 0 : "One or more pixels clipped to fit 12bit domain for jpeg output." );
241 : }
242 : }
243 : }
244 : }
245 :
246 370 : ppSamples = (JSAMPLE *) pabyScanline;
247 :
248 370 : if( eErr == CE_None )
249 370 : jpeg_write_scanlines( &sCInfo, &ppSamples, 1 );
250 :
251 : double nCurPixels = (double)nBlockYOff * nBlockYSize * nXSize +
252 370 : (double)nBlockXOff * nBlockYSize * nBlockXSize + (iLine + 1) * nBlockXSizeToRead;
253 370 : if( eErr == CE_None
254 : && !pfnProgress( nCurPixels / nTotalPixels, NULL, pProgressData ) )
255 : {
256 0 : eErr = CE_Failure;
257 : CPLError( CE_Failure, CPLE_UserInterrupt,
258 0 : "User terminated CreateCopy()" );
259 : }
260 : }
261 :
262 : /* -------------------------------------------------------------------- */
263 : /* Cleanup and close. */
264 : /* -------------------------------------------------------------------- */
265 10 : CPLFree( pabyScanline );
266 :
267 10 : if( eErr == CE_None )
268 10 : jpeg_finish_compress( &sCInfo );
269 10 : jpeg_destroy_compress( &sCInfo );
270 :
271 10 : return eErr == CE_None;
272 : }
273 : #endif /* def JPEG_SUPPORTED */
|