File: | libs/tiff-4.0.2/contrib/addtiffo/tif_overview.c |
Location: | line 526, column 71 |
Description: | Division by zero |
1 | /****************************************************************************** | |||
2 | * tif_overview.c,v 1.9 2005/05/25 09:03:16 dron Exp | |||
3 | * | |||
4 | * Project: TIFF Overview Builder | |||
5 | * Purpose: Library function for building overviews in a TIFF file. | |||
6 | * Author: Frank Warmerdam, warmerdam@pobox.com | |||
7 | * | |||
8 | * Notes: | |||
9 | * o Currently only images with bits_per_sample of a multiple of eight | |||
10 | * will work. | |||
11 | * | |||
12 | * o The downsampler currently just takes the top left pixel from the | |||
13 | * source rectangle. Eventually sampling options of averaging, mode, and | |||
14 | * ``center pixel'' should be offered. | |||
15 | * | |||
16 | * o The code will attempt to use the same kind of compression, | |||
17 | * photometric interpretation, and organization as the source image, but | |||
18 | * it doesn't copy geotiff tags to the reduced resolution images. | |||
19 | * | |||
20 | * o Reduced resolution overviews for multi-sample files will currently | |||
21 | * always be generated as PLANARCONFIG_SEPARATE. This could be fixed | |||
22 | * reasonable easily if needed to improve compatibility with other | |||
23 | * packages. Many don't properly support PLANARCONFIG_SEPARATE. | |||
24 | * | |||
25 | ****************************************************************************** | |||
26 | * Copyright (c) 1999, Frank Warmerdam | |||
27 | * | |||
28 | * Permission is hereby granted, free of charge, to any person obtaining a | |||
29 | * copy of this software and associated documentation files (the "Software"), | |||
30 | * to deal in the Software without restriction, including without limitation | |||
31 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |||
32 | * and/or sell copies of the Software, and to permit persons to whom the | |||
33 | * Software is furnished to do so, subject to the following conditions: | |||
34 | * | |||
35 | * The above copyright notice and this permission notice shall be included | |||
36 | * in all copies or substantial portions of the Software. | |||
37 | * | |||
38 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
39 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
40 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
41 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
42 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
43 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
44 | * DEALINGS IN THE SOFTWARE. | |||
45 | ****************************************************************************** | |||
46 | */ | |||
47 | ||||
48 | /* TODO: update notes in header above */ | |||
49 | ||||
50 | #include <stdio.h> | |||
51 | #include <assert.h> | |||
52 | #include <stdlib.h> | |||
53 | #include <string.h> | |||
54 | ||||
55 | #include "tiffio.h" | |||
56 | #include "tif_ovrcache.h" | |||
57 | ||||
58 | #ifndef FALSE0 | |||
59 | # define FALSE0 0 | |||
60 | # define TRUE1 1 | |||
61 | #endif | |||
62 | ||||
63 | #ifndef MAX | |||
64 | # define MIN(a,b)((a<b) ? a : b) ((a<b) ? a : b) | |||
65 | # define MAX(a,b)((a>b) ? a : b) ((a>b) ? a : b) | |||
66 | #endif | |||
67 | ||||
68 | void TIFFBuildOverviews( TIFF *, int, int *, int, const char *, | |||
69 | int (*)(double,void*), void * ); | |||
70 | ||||
71 | /************************************************************************/ | |||
72 | /* TIFF_WriteOverview() */ | |||
73 | /* */ | |||
74 | /* Create a new directory, without any image data for an overview. */ | |||
75 | /* Returns offset of newly created overview directory, but the */ | |||
76 | /* current directory is reset to be the one in used when this */ | |||
77 | /* function is called. */ | |||
78 | /************************************************************************/ | |||
79 | ||||
80 | uint32 TIFF_WriteOverview( TIFF *hTIFF, uint32 nXSize, uint32 nYSize, | |||
81 | int nBitsPerPixel, int nPlanarConfig, int nSamples, | |||
82 | int nBlockXSize, int nBlockYSize, | |||
83 | int bTiled, int nCompressFlag, int nPhotometric, | |||
84 | int nSampleFormat, | |||
85 | unsigned short *panRed, | |||
86 | unsigned short *panGreen, | |||
87 | unsigned short *panBlue, | |||
88 | int bUseSubIFDs, | |||
89 | int nHorSubsampling, int nVerSubsampling ) | |||
90 | ||||
91 | { | |||
92 | toff_t nBaseDirOffset; | |||
93 | toff_t nOffset; | |||
94 | ||||
95 | (void) bUseSubIFDs; | |||
96 | ||||
97 | nBaseDirOffset = TIFFCurrentDirOffset( hTIFF ); | |||
98 | ||||
99 | TIFFCreateDirectory( hTIFF ); | |||
100 | ||||
101 | /* -------------------------------------------------------------------- */ | |||
102 | /* Setup TIFF fields. */ | |||
103 | /* -------------------------------------------------------------------- */ | |||
104 | TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH256, nXSize ); | |||
105 | TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH257, nYSize ); | |||
106 | if( nSamples == 1 ) | |||
107 | TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG284, PLANARCONFIG_CONTIG1 ); | |||
108 | else | |||
109 | TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG284, nPlanarConfig ); | |||
110 | ||||
111 | TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE258, nBitsPerPixel ); | |||
112 | TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL277, nSamples ); | |||
113 | TIFFSetField( hTIFF, TIFFTAG_COMPRESSION259, nCompressFlag ); | |||
114 | TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC262, nPhotometric ); | |||
115 | TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT339, nSampleFormat ); | |||
116 | ||||
117 | if( bTiled ) | |||
118 | { | |||
119 | TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH322, nBlockXSize ); | |||
120 | TIFFSetField( hTIFF, TIFFTAG_TILELENGTH323, nBlockYSize ); | |||
121 | } | |||
122 | else | |||
123 | TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP278, nBlockYSize ); | |||
124 | ||||
125 | TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE254, FILETYPE_REDUCEDIMAGE0x1 ); | |||
126 | ||||
127 | if( nPhotometric == PHOTOMETRIC_YCBCR6 || nPhotometric == PHOTOMETRIC_ITULAB10 ) | |||
128 | { | |||
129 | TIFFSetField( hTIFF, TIFFTAG_YCBCRSUBSAMPLING530, nHorSubsampling, nVerSubsampling); | |||
130 | /* TODO: also write YCbCrPositioning and YCbCrCoefficients tag identical to source IFD */ | |||
131 | } | |||
132 | /* TODO: add command-line parameter for selecting jpeg compression quality | |||
133 | * that gets ignored when compression isn't jpeg */ | |||
134 | ||||
135 | /* -------------------------------------------------------------------- */ | |||
136 | /* Write color table if one is present. */ | |||
137 | /* -------------------------------------------------------------------- */ | |||
138 | if( panRed != NULL((void*)0) ) | |||
139 | { | |||
140 | TIFFSetField( hTIFF, TIFFTAG_COLORMAP320, panRed, panGreen, panBlue ); | |||
141 | } | |||
142 | ||||
143 | /* -------------------------------------------------------------------- */ | |||
144 | /* Write directory, and return byte offset. */ | |||
145 | /* -------------------------------------------------------------------- */ | |||
146 | if( TIFFWriteCheck( hTIFF, bTiled, "TIFFBuildOverviews" ) == 0 ) | |||
147 | return 0; | |||
148 | ||||
149 | TIFFWriteDirectory( hTIFF ); | |||
150 | TIFFSetDirectory( hTIFF, (tdir_t) (TIFFNumberOfDirectories(hTIFF)-1) ); | |||
151 | ||||
152 | nOffset = TIFFCurrentDirOffset( hTIFF ); | |||
153 | ||||
154 | TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); | |||
155 | ||||
156 | return nOffset; | |||
157 | } | |||
158 | ||||
159 | /************************************************************************/ | |||
160 | /* TIFF_GetSourceSamples() */ | |||
161 | /************************************************************************/ | |||
162 | ||||
163 | static void | |||
164 | TIFF_GetSourceSamples( double * padfSamples, unsigned char *pabySrc, | |||
165 | int nPixelBytes, int nSampleFormat, | |||
166 | uint32 nXSize, uint32 nYSize, | |||
167 | int nPixelOffset, int nLineOffset ) | |||
168 | { | |||
169 | uint32 iXOff, iYOff; | |||
170 | int iSample; | |||
171 | ||||
172 | iSample = 0; | |||
173 | ||||
174 | for( iYOff = 0; iYOff < nYSize; iYOff++ ) | |||
175 | { | |||
176 | for( iXOff = 0; iXOff < nXSize; iXOff++ ) | |||
177 | { | |||
178 | unsigned char *pabyData; | |||
179 | ||||
180 | pabyData = pabySrc + iYOff * nLineOffset + iXOff * nPixelOffset; | |||
181 | ||||
182 | if( nSampleFormat == SAMPLEFORMAT_UINT1 && nPixelBytes == 1 ) | |||
183 | { | |||
184 | padfSamples[iSample++] = *pabyData; | |||
185 | } | |||
186 | else if( nSampleFormat == SAMPLEFORMAT_UINT1 && nPixelBytes == 2 ) | |||
187 | { | |||
188 | padfSamples[iSample++] = ((uint16 *) pabyData)[0]; | |||
189 | } | |||
190 | else if( nSampleFormat == SAMPLEFORMAT_UINT1 && nPixelBytes == 4 ) | |||
191 | { | |||
192 | padfSamples[iSample++] = ((uint32 *) pabyData)[0]; | |||
193 | } | |||
194 | else if( nSampleFormat == SAMPLEFORMAT_INT2 && nPixelBytes == 2 ) | |||
195 | { | |||
196 | padfSamples[iSample++] = ((int16 *) pabyData)[0]; | |||
197 | } | |||
198 | else if( nSampleFormat == SAMPLEFORMAT_INT2 && nPixelBytes == 32 ) | |||
199 | { | |||
200 | padfSamples[iSample++] = ((int32 *) pabyData)[0]; | |||
201 | } | |||
202 | else if( nSampleFormat == SAMPLEFORMAT_IEEEFP3 && nPixelBytes == 4 ) | |||
203 | { | |||
204 | padfSamples[iSample++] = ((float *) pabyData)[0]; | |||
205 | } | |||
206 | else if( nSampleFormat == SAMPLEFORMAT_IEEEFP3 && nPixelBytes == 8 ) | |||
207 | { | |||
208 | padfSamples[iSample++] = ((double *) pabyData)[0]; | |||
209 | } | |||
210 | } | |||
211 | } | |||
212 | } | |||
213 | ||||
214 | /************************************************************************/ | |||
215 | /* TIFF_SetSample() */ | |||
216 | /************************************************************************/ | |||
217 | ||||
218 | static void | |||
219 | TIFF_SetSample( unsigned char * pabyData, int nPixelBytes, int nSampleFormat, | |||
220 | double dfValue ) | |||
221 | ||||
222 | { | |||
223 | if( nSampleFormat == SAMPLEFORMAT_UINT1 && nPixelBytes == 1 ) | |||
224 | { | |||
225 | *pabyData = (unsigned char) MAX(0,MIN(255,dfValue))((0>((255<dfValue) ? 255 : dfValue)) ? 0 : ((255<dfValue ) ? 255 : dfValue)); | |||
226 | } | |||
227 | else if( nSampleFormat == SAMPLEFORMAT_UINT1 && nPixelBytes == 2 ) | |||
228 | { | |||
229 | *((uint16 *)pabyData) = (uint16) MAX(0,MIN(65535,dfValue))((0>((65535<dfValue) ? 65535 : dfValue)) ? 0 : ((65535< dfValue) ? 65535 : dfValue)); | |||
230 | } | |||
231 | else if( nSampleFormat == SAMPLEFORMAT_UINT1 && nPixelBytes == 4 ) | |||
232 | { | |||
233 | *((uint32 *)pabyData) = (uint32) dfValue; | |||
234 | } | |||
235 | else if( nSampleFormat == SAMPLEFORMAT_INT2 && nPixelBytes == 2 ) | |||
236 | { | |||
237 | *((int16 *)pabyData) = (int16) MAX(-32768,MIN(32767,dfValue))((-32768>((32767<dfValue) ? 32767 : dfValue)) ? -32768 : ((32767<dfValue) ? 32767 : dfValue)); | |||
238 | } | |||
239 | else if( nSampleFormat == SAMPLEFORMAT_INT2 && nPixelBytes == 32 ) | |||
240 | { | |||
241 | *((int32 *)pabyData) = (int32) dfValue; | |||
242 | } | |||
243 | else if( nSampleFormat == SAMPLEFORMAT_IEEEFP3 && nPixelBytes == 4 ) | |||
244 | { | |||
245 | *((float *)pabyData) = (float) dfValue; | |||
246 | } | |||
247 | else if( nSampleFormat == SAMPLEFORMAT_IEEEFP3 && nPixelBytes == 8 ) | |||
248 | { | |||
249 | *((double *)pabyData) = dfValue; | |||
250 | } | |||
251 | } | |||
252 | ||||
253 | /************************************************************************/ | |||
254 | /* TIFF_DownSample() */ | |||
255 | /* */ | |||
256 | /* Down sample a tile of full res data into a window of a tile */ | |||
257 | /* of downsampled data. */ | |||
258 | /************************************************************************/ | |||
259 | ||||
260 | static | |||
261 | void TIFF_DownSample( unsigned char *pabySrcTile, | |||
262 | uint32 nBlockXSize, uint32 nBlockYSize, | |||
263 | int nPixelSkewBits, int nBitsPerPixel, | |||
264 | unsigned char * pabyOTile, | |||
265 | uint32 nOBlockXSize, uint32 nOBlockYSize, | |||
266 | uint32 nTXOff, uint32 nTYOff, int nOMult, | |||
267 | int nSampleFormat, const char * pszResampling ) | |||
268 | ||||
269 | { | |||
270 | uint32 i, j; | |||
271 | int k, nPixelBytes = (nBitsPerPixel) / 8; | |||
272 | int nPixelGroupBytes = (nBitsPerPixel+nPixelSkewBits)/8; | |||
273 | unsigned char *pabySrc, *pabyDst; | |||
274 | double *padfSamples; | |||
275 | ||||
276 | assert( nBitsPerPixel >= 8 )((nBitsPerPixel >= 8) ? (void) (0) : __assert_fail ("nBitsPerPixel >= 8" , "tif_overview.c", 276, __PRETTY_FUNCTION__)); | |||
277 | ||||
278 | padfSamples = (double *) malloc(sizeof(double) * nOMult * nOMult); | |||
279 | ||||
280 | /* ==================================================================== */ | |||
281 | /* Loop over scanline chunks to process, establishing where the */ | |||
282 | /* data is going. */ | |||
283 | /* ==================================================================== */ | |||
284 | for( j = 0; j*nOMult < nBlockYSize; j++ ) | |||
285 | { | |||
286 | if( j + nTYOff >= nOBlockYSize ) | |||
287 | break; | |||
288 | ||||
289 | pabyDst = pabyOTile + ((j+nTYOff)*nOBlockXSize + nTXOff) | |||
290 | * nPixelBytes * nPixelGroupBytes; | |||
291 | ||||
292 | /* -------------------------------------------------------------------- */ | |||
293 | /* Handler nearest resampling ... we don't even care about the */ | |||
294 | /* data type, we just do a bytewise copy. */ | |||
295 | /* -------------------------------------------------------------------- */ | |||
296 | if( strncmp(pszResampling,"nearest",4)(__extension__ (__builtin_constant_p (4) && ((__builtin_constant_p (pszResampling) && strlen (pszResampling) < ((size_t ) (4))) || (__builtin_constant_p ("nearest") && strlen ("nearest") < ((size_t) (4)))) ? __extension__ ({ size_t __s1_len , __s2_len; (__builtin_constant_p (pszResampling) && __builtin_constant_p ("nearest") && (__s1_len = __builtin_strlen (pszResampling ), __s2_len = __builtin_strlen ("nearest"), (!((size_t)(const void *)((pszResampling) + 1) - (size_t)(const void *)(pszResampling ) == 1) || __s1_len >= 4) && (!((size_t)(const void *)(("nearest") + 1) - (size_t)(const void *)("nearest") == 1 ) || __s2_len >= 4)) ? __builtin_strcmp (pszResampling, "nearest" ) : (__builtin_constant_p (pszResampling) && ((size_t )(const void *)((pszResampling) + 1) - (size_t)(const void *) (pszResampling) == 1) && (__s1_len = __builtin_strlen (pszResampling), __s1_len < 4) ? (__builtin_constant_p ("nearest" ) && ((size_t)(const void *)(("nearest") + 1) - (size_t )(const void *)("nearest") == 1) ? __builtin_strcmp (pszResampling , "nearest") : (__extension__ ({ const unsigned char *__s2 = ( const unsigned char *) (const char *) ("nearest"); int __result = (((const unsigned char *) (const char *) (pszResampling))[ 0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (pszResampling ))[1] - __s2[1]); if (__s1_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) (pszResampling ))[2] - __s2[2]); if (__s1_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) (pszResampling ))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ( "nearest") && ((size_t)(const void *)(("nearest") + 1 ) - (size_t)(const void *)("nearest") == 1) && (__s2_len = __builtin_strlen ("nearest"), __s2_len < 4) ? (__builtin_constant_p (pszResampling) && ((size_t)(const void *)((pszResampling ) + 1) - (size_t)(const void *)(pszResampling) == 1) ? __builtin_strcmp (pszResampling, "nearest") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (pszResampling ); int __result = (((const unsigned char *) (const char *) ("nearest" ))[0] - __s2[0]); if (__s2_len > 0 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("nearest" ))[1] - __s2[1]); if (__s2_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("nearest" ))[2] - __s2[2]); if (__s2_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) ("nearest" ))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (pszResampling , "nearest")))); }) : strncmp (pszResampling, "nearest", 4))) == 0 | |||
297 | || strncmp(pszResampling,"NEAR",4)(__extension__ (__builtin_constant_p (4) && ((__builtin_constant_p (pszResampling) && strlen (pszResampling) < ((size_t ) (4))) || (__builtin_constant_p ("NEAR") && strlen ( "NEAR") < ((size_t) (4)))) ? __extension__ ({ size_t __s1_len , __s2_len; (__builtin_constant_p (pszResampling) && __builtin_constant_p ("NEAR") && (__s1_len = __builtin_strlen (pszResampling ), __s2_len = __builtin_strlen ("NEAR"), (!((size_t)(const void *)((pszResampling) + 1) - (size_t)(const void *)(pszResampling ) == 1) || __s1_len >= 4) && (!((size_t)(const void *)(("NEAR") + 1) - (size_t)(const void *)("NEAR") == 1) || __s2_len >= 4)) ? __builtin_strcmp (pszResampling, "NEAR") : (__builtin_constant_p (pszResampling) && ((size_t)(const void *)((pszResampling ) + 1) - (size_t)(const void *)(pszResampling) == 1) && (__s1_len = __builtin_strlen (pszResampling), __s1_len < 4 ) ? (__builtin_constant_p ("NEAR") && ((size_t)(const void *)(("NEAR") + 1) - (size_t)(const void *)("NEAR") == 1) ? __builtin_strcmp (pszResampling, "NEAR") : (__extension__ ( { const unsigned char *__s2 = (const unsigned char *) (const char *) ("NEAR"); int __result = (((const unsigned char *) (const char *) (pszResampling))[0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (pszResampling))[1] - __s2[1]); if (__s1_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) (pszResampling))[2] - __s2[2]); if (__s1_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) (pszResampling))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ("NEAR") && ((size_t)(const void *)(("NEAR") + 1) - ( size_t)(const void *)("NEAR") == 1) && (__s2_len = __builtin_strlen ("NEAR"), __s2_len < 4) ? (__builtin_constant_p (pszResampling ) && ((size_t)(const void *)((pszResampling) + 1) - ( size_t)(const void *)(pszResampling) == 1) ? __builtin_strcmp (pszResampling, "NEAR") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (pszResampling ); int __result = (((const unsigned char *) (const char *) ("NEAR" ))[0] - __s2[0]); if (__s2_len > 0 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("NEAR" ))[1] - __s2[1]); if (__s2_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("NEAR" ))[2] - __s2[2]); if (__s2_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) ("NEAR" ))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (pszResampling , "NEAR")))); }) : strncmp (pszResampling, "NEAR", 4))) == 0 ) | |||
298 | { | |||
299 | pabySrc = pabySrcTile + j*nOMult*nBlockXSize * nPixelGroupBytes; | |||
300 | ||||
301 | for( i = 0; i*nOMult < nBlockXSize; i++ ) | |||
302 | { | |||
303 | if( i + nTXOff >= nOBlockXSize ) | |||
304 | break; | |||
305 | ||||
306 | /* | |||
307 | * For now use simple subsampling, from the top left corner | |||
308 | * of the source block of pixels. | |||
309 | */ | |||
310 | ||||
311 | for( k = 0; k < nPixelBytes; k++ ) | |||
312 | pabyDst[k] = pabySrc[k]; | |||
313 | ||||
314 | pabyDst += nPixelBytes * nPixelGroupBytes; | |||
315 | pabySrc += nOMult * nPixelGroupBytes; | |||
316 | } | |||
317 | } | |||
318 | ||||
319 | /* -------------------------------------------------------------------- */ | |||
320 | /* Handle the case of averaging. For this we also have to */ | |||
321 | /* handle each sample format we are concerned with. */ | |||
322 | /* -------------------------------------------------------------------- */ | |||
323 | else if( strncmp(pszResampling,"averag",6)(__extension__ (__builtin_constant_p (6) && ((__builtin_constant_p (pszResampling) && strlen (pszResampling) < ((size_t ) (6))) || (__builtin_constant_p ("averag") && strlen ("averag") < ((size_t) (6)))) ? __extension__ ({ size_t __s1_len , __s2_len; (__builtin_constant_p (pszResampling) && __builtin_constant_p ("averag") && (__s1_len = __builtin_strlen (pszResampling ), __s2_len = __builtin_strlen ("averag"), (!((size_t)(const void *)((pszResampling) + 1) - (size_t)(const void *)(pszResampling ) == 1) || __s1_len >= 4) && (!((size_t)(const void *)(("averag") + 1) - (size_t)(const void *)("averag") == 1) || __s2_len >= 4)) ? __builtin_strcmp (pszResampling, "averag" ) : (__builtin_constant_p (pszResampling) && ((size_t )(const void *)((pszResampling) + 1) - (size_t)(const void *) (pszResampling) == 1) && (__s1_len = __builtin_strlen (pszResampling), __s1_len < 4) ? (__builtin_constant_p ("averag" ) && ((size_t)(const void *)(("averag") + 1) - (size_t )(const void *)("averag") == 1) ? __builtin_strcmp (pszResampling , "averag") : (__extension__ ({ const unsigned char *__s2 = ( const unsigned char *) (const char *) ("averag"); int __result = (((const unsigned char *) (const char *) (pszResampling))[ 0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (pszResampling ))[1] - __s2[1]); if (__s1_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) (pszResampling ))[2] - __s2[2]); if (__s1_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) (pszResampling ))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ( "averag") && ((size_t)(const void *)(("averag") + 1) - (size_t)(const void *)("averag") == 1) && (__s2_len = __builtin_strlen ("averag"), __s2_len < 4) ? (__builtin_constant_p (pszResampling) && ((size_t)(const void *)((pszResampling ) + 1) - (size_t)(const void *)(pszResampling) == 1) ? __builtin_strcmp (pszResampling, "averag") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (pszResampling ); int __result = (((const unsigned char *) (const char *) ("averag" ))[0] - __s2[0]); if (__s2_len > 0 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("averag" ))[1] - __s2[1]); if (__s2_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("averag" ))[2] - __s2[2]); if (__s2_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) ("averag" ))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (pszResampling , "averag")))); }) : strncmp (pszResampling, "averag", 6))) == 0 | |||
324 | || strncmp(pszResampling,"AVERAG",6)(__extension__ (__builtin_constant_p (6) && ((__builtin_constant_p (pszResampling) && strlen (pszResampling) < ((size_t ) (6))) || (__builtin_constant_p ("AVERAG") && strlen ("AVERAG") < ((size_t) (6)))) ? __extension__ ({ size_t __s1_len , __s2_len; (__builtin_constant_p (pszResampling) && __builtin_constant_p ("AVERAG") && (__s1_len = __builtin_strlen (pszResampling ), __s2_len = __builtin_strlen ("AVERAG"), (!((size_t)(const void *)((pszResampling) + 1) - (size_t)(const void *)(pszResampling ) == 1) || __s1_len >= 4) && (!((size_t)(const void *)(("AVERAG") + 1) - (size_t)(const void *)("AVERAG") == 1) || __s2_len >= 4)) ? __builtin_strcmp (pszResampling, "AVERAG" ) : (__builtin_constant_p (pszResampling) && ((size_t )(const void *)((pszResampling) + 1) - (size_t)(const void *) (pszResampling) == 1) && (__s1_len = __builtin_strlen (pszResampling), __s1_len < 4) ? (__builtin_constant_p ("AVERAG" ) && ((size_t)(const void *)(("AVERAG") + 1) - (size_t )(const void *)("AVERAG") == 1) ? __builtin_strcmp (pszResampling , "AVERAG") : (__extension__ ({ const unsigned char *__s2 = ( const unsigned char *) (const char *) ("AVERAG"); int __result = (((const unsigned char *) (const char *) (pszResampling))[ 0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (pszResampling ))[1] - __s2[1]); if (__s1_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) (pszResampling ))[2] - __s2[2]); if (__s1_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) (pszResampling ))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ( "AVERAG") && ((size_t)(const void *)(("AVERAG") + 1) - (size_t)(const void *)("AVERAG") == 1) && (__s2_len = __builtin_strlen ("AVERAG"), __s2_len < 4) ? (__builtin_constant_p (pszResampling) && ((size_t)(const void *)((pszResampling ) + 1) - (size_t)(const void *)(pszResampling) == 1) ? __builtin_strcmp (pszResampling, "AVERAG") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (pszResampling ); int __result = (((const unsigned char *) (const char *) ("AVERAG" ))[0] - __s2[0]); if (__s2_len > 0 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("AVERAG" ))[1] - __s2[1]); if (__s2_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("AVERAG" ))[2] - __s2[2]); if (__s2_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) ("AVERAG" ))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (pszResampling , "AVERAG")))); }) : strncmp (pszResampling, "AVERAG", 6))) == 0 ) | |||
325 | { | |||
326 | pabySrc = pabySrcTile + j*nOMult*nBlockXSize * nPixelGroupBytes; | |||
327 | ||||
328 | for( i = 0; i*nOMult < nBlockXSize; i++ ) | |||
329 | { | |||
330 | double dfTotal; | |||
331 | uint32 nXSize, nYSize, iSample; | |||
332 | ||||
333 | if( i + nTXOff >= nOBlockXSize ) | |||
334 | break; | |||
335 | ||||
336 | nXSize = MIN((uint32)nOMult,nBlockXSize-i)(((uint32)nOMult<nBlockXSize-i) ? (uint32)nOMult : nBlockXSize -i); | |||
337 | nYSize = MIN((uint32)nOMult,nBlockYSize-j)(((uint32)nOMult<nBlockYSize-j) ? (uint32)nOMult : nBlockYSize -j); | |||
338 | ||||
339 | TIFF_GetSourceSamples( padfSamples, pabySrc, | |||
340 | nPixelBytes, nSampleFormat, | |||
341 | nXSize, nYSize, | |||
342 | nPixelGroupBytes, | |||
343 | nPixelGroupBytes * nBlockXSize ); | |||
344 | ||||
345 | dfTotal = 0; | |||
346 | for( iSample = 0; iSample < nXSize*nYSize; iSample++ ) | |||
347 | { | |||
348 | dfTotal += padfSamples[iSample]; | |||
349 | } | |||
350 | ||||
351 | TIFF_SetSample( pabyDst, nPixelBytes, nSampleFormat, | |||
352 | dfTotal / (nXSize*nYSize) ); | |||
353 | ||||
354 | pabySrc += nOMult * nPixelGroupBytes; | |||
355 | pabyDst += nPixelBytes; | |||
356 | } | |||
357 | } | |||
358 | } | |||
359 | ||||
360 | free( padfSamples ); | |||
361 | } | |||
362 | ||||
363 | /************************************************************************/ | |||
364 | /* TIFF_DownSample_Subsampled() */ | |||
365 | /************************************************************************/ | |||
366 | static | |||
367 | void TIFF_DownSample_Subsampled( unsigned char *pabySrcTile, int nSample, | |||
368 | uint32 nBlockXSize, uint32 nBlockYSize, | |||
369 | unsigned char * pabyOTile, | |||
370 | uint32 nOBlockXSize, uint32 nOBlockYSize, | |||
371 | uint32 nTXOff, uint32 nTYOff, int nOMult, | |||
372 | const char *pszResampling, | |||
373 | int nHorSubsampling, int nVerSubsampling ) | |||
374 | { | |||
375 | /* TODO: test with variety of subsampling values, and incovinient tile/strip sizes */ | |||
376 | int nSampleBlockSize; | |||
377 | int nSourceSampleRowSize; | |||
378 | int nDestSampleRowSize; | |||
379 | uint32 nSourceX, nSourceY; | |||
380 | uint32 nSourceXSec, nSourceYSec; | |||
381 | uint32 nSourceXSecEnd, nSourceYSecEnd; | |||
382 | uint32 nDestX, nDestY; | |||
383 | int nSampleOffsetInSampleBlock; | |||
384 | unsigned int nCummulator; | |||
385 | unsigned int nCummulatorCount; | |||
386 | ||||
387 | nSampleBlockSize = nHorSubsampling * nVerSubsampling + 2; | |||
388 | nSourceSampleRowSize = | |||
389 | ( ( nBlockXSize + nHorSubsampling - 1 ) / nHorSubsampling ) * nSampleBlockSize; | |||
390 | nDestSampleRowSize = | |||
391 | ( ( nOBlockXSize + nHorSubsampling - 1 ) / nHorSubsampling ) * nSampleBlockSize; | |||
392 | ||||
393 | if( strncmp(pszResampling,"nearest",4)(__extension__ (__builtin_constant_p (4) && ((__builtin_constant_p (pszResampling) && strlen (pszResampling) < ((size_t ) (4))) || (__builtin_constant_p ("nearest") && strlen ("nearest") < ((size_t) (4)))) ? __extension__ ({ size_t __s1_len , __s2_len; (__builtin_constant_p (pszResampling) && __builtin_constant_p ("nearest") && (__s1_len = __builtin_strlen (pszResampling ), __s2_len = __builtin_strlen ("nearest"), (!((size_t)(const void *)((pszResampling) + 1) - (size_t)(const void *)(pszResampling ) == 1) || __s1_len >= 4) && (!((size_t)(const void *)(("nearest") + 1) - (size_t)(const void *)("nearest") == 1 ) || __s2_len >= 4)) ? __builtin_strcmp (pszResampling, "nearest" ) : (__builtin_constant_p (pszResampling) && ((size_t )(const void *)((pszResampling) + 1) - (size_t)(const void *) (pszResampling) == 1) && (__s1_len = __builtin_strlen (pszResampling), __s1_len < 4) ? (__builtin_constant_p ("nearest" ) && ((size_t)(const void *)(("nearest") + 1) - (size_t )(const void *)("nearest") == 1) ? __builtin_strcmp (pszResampling , "nearest") : (__extension__ ({ const unsigned char *__s2 = ( const unsigned char *) (const char *) ("nearest"); int __result = (((const unsigned char *) (const char *) (pszResampling))[ 0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (pszResampling ))[1] - __s2[1]); if (__s1_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) (pszResampling ))[2] - __s2[2]); if (__s1_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) (pszResampling ))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ( "nearest") && ((size_t)(const void *)(("nearest") + 1 ) - (size_t)(const void *)("nearest") == 1) && (__s2_len = __builtin_strlen ("nearest"), __s2_len < 4) ? (__builtin_constant_p (pszResampling) && ((size_t)(const void *)((pszResampling ) + 1) - (size_t)(const void *)(pszResampling) == 1) ? __builtin_strcmp (pszResampling, "nearest") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (pszResampling ); int __result = (((const unsigned char *) (const char *) ("nearest" ))[0] - __s2[0]); if (__s2_len > 0 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("nearest" ))[1] - __s2[1]); if (__s2_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("nearest" ))[2] - __s2[2]); if (__s2_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) ("nearest" ))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (pszResampling , "nearest")))); }) : strncmp (pszResampling, "nearest", 4))) == 0 | |||
| ||||
394 | || strncmp(pszResampling,"NEAR",4)(__extension__ (__builtin_constant_p (4) && ((__builtin_constant_p (pszResampling) && strlen (pszResampling) < ((size_t ) (4))) || (__builtin_constant_p ("NEAR") && strlen ( "NEAR") < ((size_t) (4)))) ? __extension__ ({ size_t __s1_len , __s2_len; (__builtin_constant_p (pszResampling) && __builtin_constant_p ("NEAR") && (__s1_len = __builtin_strlen (pszResampling ), __s2_len = __builtin_strlen ("NEAR"), (!((size_t)(const void *)((pszResampling) + 1) - (size_t)(const void *)(pszResampling ) == 1) || __s1_len >= 4) && (!((size_t)(const void *)(("NEAR") + 1) - (size_t)(const void *)("NEAR") == 1) || __s2_len >= 4)) ? __builtin_strcmp (pszResampling, "NEAR") : (__builtin_constant_p (pszResampling) && ((size_t)(const void *)((pszResampling ) + 1) - (size_t)(const void *)(pszResampling) == 1) && (__s1_len = __builtin_strlen (pszResampling), __s1_len < 4 ) ? (__builtin_constant_p ("NEAR") && ((size_t)(const void *)(("NEAR") + 1) - (size_t)(const void *)("NEAR") == 1) ? __builtin_strcmp (pszResampling, "NEAR") : (__extension__ ( { const unsigned char *__s2 = (const unsigned char *) (const char *) ("NEAR"); int __result = (((const unsigned char *) (const char *) (pszResampling))[0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (pszResampling))[1] - __s2[1]); if (__s1_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) (pszResampling))[2] - __s2[2]); if (__s1_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) (pszResampling))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ("NEAR") && ((size_t)(const void *)(("NEAR") + 1) - ( size_t)(const void *)("NEAR") == 1) && (__s2_len = __builtin_strlen ("NEAR"), __s2_len < 4) ? (__builtin_constant_p (pszResampling ) && ((size_t)(const void *)((pszResampling) + 1) - ( size_t)(const void *)(pszResampling) == 1) ? __builtin_strcmp (pszResampling, "NEAR") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (pszResampling ); int __result = (((const unsigned char *) (const char *) ("NEAR" ))[0] - __s2[0]); if (__s2_len > 0 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("NEAR" ))[1] - __s2[1]); if (__s2_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("NEAR" ))[2] - __s2[2]); if (__s2_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) ("NEAR" ))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (pszResampling , "NEAR")))); }) : strncmp (pszResampling, "NEAR", 4))) == 0 ) | |||
395 | { | |||
396 | if( nSample == 0 ) | |||
397 | { | |||
398 | for( nSourceY = 0, nDestY = nTYOff; | |||
399 | nSourceY < nBlockYSize; | |||
400 | nSourceY += nOMult, nDestY ++) | |||
401 | { | |||
402 | if( nDestY >= nOBlockYSize ) | |||
403 | break; | |||
404 | ||||
405 | for( nSourceX = 0, nDestX = nTXOff; | |||
406 | nSourceX < nBlockXSize; | |||
407 | nSourceX += nOMult, nDestX ++) | |||
408 | { | |||
409 | if( nDestX >= nOBlockXSize ) | |||
410 | break; | |||
411 | ||||
412 | * ( pabyOTile + ( nDestY / nVerSubsampling ) * nDestSampleRowSize | |||
413 | + ( nDestY % nVerSubsampling ) * nHorSubsampling | |||
414 | + ( nDestX / nHorSubsampling ) * nSampleBlockSize | |||
415 | + ( nDestX % nHorSubsampling ) ) = | |||
416 | * ( pabySrcTile + ( nSourceY / nVerSubsampling ) * nSourceSampleRowSize | |||
417 | + ( nSourceY % nVerSubsampling ) * nHorSubsampling | |||
418 | + ( nSourceX / nHorSubsampling ) * nSampleBlockSize | |||
419 | + ( nSourceX % nHorSubsampling ) ); | |||
420 | } | |||
421 | } | |||
422 | } | |||
423 | else | |||
424 | { | |||
425 | nSampleOffsetInSampleBlock = nHorSubsampling * nVerSubsampling + nSample - 1; | |||
426 | for( nSourceY = 0, nDestY = ( nTYOff / nVerSubsampling ); | |||
427 | nSourceY < ( nBlockYSize / nVerSubsampling ); | |||
428 | nSourceY += nOMult, nDestY ++) | |||
429 | { | |||
430 | if( nDestY*nVerSubsampling >= nOBlockYSize ) | |||
431 | break; | |||
432 | ||||
433 | for( nSourceX = 0, nDestX = ( nTXOff / nHorSubsampling ); | |||
434 | nSourceX < ( nBlockXSize / nHorSubsampling ); | |||
435 | nSourceX += nOMult, nDestX ++) | |||
436 | { | |||
437 | if( nDestX*nHorSubsampling >= nOBlockXSize ) | |||
438 | break; | |||
439 | ||||
440 | * ( pabyOTile + nDestY * nDestSampleRowSize | |||
441 | + nDestX * nSampleBlockSize | |||
442 | + nSampleOffsetInSampleBlock ) = | |||
443 | * ( pabySrcTile + nSourceY * nSourceSampleRowSize | |||
444 | + nSourceX * nSampleBlockSize | |||
445 | + nSampleOffsetInSampleBlock ); | |||
446 | } | |||
447 | } | |||
448 | } | |||
449 | } | |||
450 | else if( strncmp(pszResampling,"averag",6)(__extension__ (__builtin_constant_p (6) && ((__builtin_constant_p (pszResampling) && strlen (pszResampling) < ((size_t ) (6))) || (__builtin_constant_p ("averag") && strlen ("averag") < ((size_t) (6)))) ? __extension__ ({ size_t __s1_len , __s2_len; (__builtin_constant_p (pszResampling) && __builtin_constant_p ("averag") && (__s1_len = __builtin_strlen (pszResampling ), __s2_len = __builtin_strlen ("averag"), (!((size_t)(const void *)((pszResampling) + 1) - (size_t)(const void *)(pszResampling ) == 1) || __s1_len >= 4) && (!((size_t)(const void *)(("averag") + 1) - (size_t)(const void *)("averag") == 1) || __s2_len >= 4)) ? __builtin_strcmp (pszResampling, "averag" ) : (__builtin_constant_p (pszResampling) && ((size_t )(const void *)((pszResampling) + 1) - (size_t)(const void *) (pszResampling) == 1) && (__s1_len = __builtin_strlen (pszResampling), __s1_len < 4) ? (__builtin_constant_p ("averag" ) && ((size_t)(const void *)(("averag") + 1) - (size_t )(const void *)("averag") == 1) ? __builtin_strcmp (pszResampling , "averag") : (__extension__ ({ const unsigned char *__s2 = ( const unsigned char *) (const char *) ("averag"); int __result = (((const unsigned char *) (const char *) (pszResampling))[ 0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (pszResampling ))[1] - __s2[1]); if (__s1_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) (pszResampling ))[2] - __s2[2]); if (__s1_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) (pszResampling ))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ( "averag") && ((size_t)(const void *)(("averag") + 1) - (size_t)(const void *)("averag") == 1) && (__s2_len = __builtin_strlen ("averag"), __s2_len < 4) ? (__builtin_constant_p (pszResampling) && ((size_t)(const void *)((pszResampling ) + 1) - (size_t)(const void *)(pszResampling) == 1) ? __builtin_strcmp (pszResampling, "averag") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (pszResampling ); int __result = (((const unsigned char *) (const char *) ("averag" ))[0] - __s2[0]); if (__s2_len > 0 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("averag" ))[1] - __s2[1]); if (__s2_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("averag" ))[2] - __s2[2]); if (__s2_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) ("averag" ))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (pszResampling , "averag")))); }) : strncmp (pszResampling, "averag", 6))) == 0 | |||
451 | || strncmp(pszResampling,"AVERAG",6)(__extension__ (__builtin_constant_p (6) && ((__builtin_constant_p (pszResampling) && strlen (pszResampling) < ((size_t ) (6))) || (__builtin_constant_p ("AVERAG") && strlen ("AVERAG") < ((size_t) (6)))) ? __extension__ ({ size_t __s1_len , __s2_len; (__builtin_constant_p (pszResampling) && __builtin_constant_p ("AVERAG") && (__s1_len = __builtin_strlen (pszResampling ), __s2_len = __builtin_strlen ("AVERAG"), (!((size_t)(const void *)((pszResampling) + 1) - (size_t)(const void *)(pszResampling ) == 1) || __s1_len >= 4) && (!((size_t)(const void *)(("AVERAG") + 1) - (size_t)(const void *)("AVERAG") == 1) || __s2_len >= 4)) ? __builtin_strcmp (pszResampling, "AVERAG" ) : (__builtin_constant_p (pszResampling) && ((size_t )(const void *)((pszResampling) + 1) - (size_t)(const void *) (pszResampling) == 1) && (__s1_len = __builtin_strlen (pszResampling), __s1_len < 4) ? (__builtin_constant_p ("AVERAG" ) && ((size_t)(const void *)(("AVERAG") + 1) - (size_t )(const void *)("AVERAG") == 1) ? __builtin_strcmp (pszResampling , "AVERAG") : (__extension__ ({ const unsigned char *__s2 = ( const unsigned char *) (const char *) ("AVERAG"); int __result = (((const unsigned char *) (const char *) (pszResampling))[ 0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (pszResampling ))[1] - __s2[1]); if (__s1_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) (pszResampling ))[2] - __s2[2]); if (__s1_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) (pszResampling ))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ( "AVERAG") && ((size_t)(const void *)(("AVERAG") + 1) - (size_t)(const void *)("AVERAG") == 1) && (__s2_len = __builtin_strlen ("AVERAG"), __s2_len < 4) ? (__builtin_constant_p (pszResampling) && ((size_t)(const void *)((pszResampling ) + 1) - (size_t)(const void *)(pszResampling) == 1) ? __builtin_strcmp (pszResampling, "AVERAG") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (pszResampling ); int __result = (((const unsigned char *) (const char *) ("AVERAG" ))[0] - __s2[0]); if (__s2_len > 0 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("AVERAG" ))[1] - __s2[1]); if (__s2_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("AVERAG" ))[2] - __s2[2]); if (__s2_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) ("AVERAG" ))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (pszResampling , "AVERAG")))); }) : strncmp (pszResampling, "AVERAG", 6))) == 0 ) | |||
452 | { | |||
453 | if( nSample == 0 ) | |||
454 | { | |||
455 | for( nSourceY = 0, nDestY = nTYOff; nSourceY < nBlockYSize; nSourceY += nOMult, nDestY ++) | |||
456 | { | |||
457 | if( nDestY >= nOBlockYSize ) | |||
458 | break; | |||
459 | ||||
460 | for( nSourceX = 0, nDestX = nTXOff; nSourceX < nBlockXSize; nSourceX += nOMult, nDestX ++) | |||
461 | { | |||
462 | if( nDestX >= nOBlockXSize ) | |||
463 | break; | |||
464 | ||||
465 | nSourceXSecEnd = nSourceX + nOMult; | |||
466 | if( nSourceXSecEnd > nBlockXSize ) | |||
467 | nSourceXSecEnd = nBlockXSize; | |||
468 | nSourceYSecEnd = nSourceY + nOMult; | |||
469 | if( nSourceYSecEnd > nBlockYSize ) | |||
470 | nSourceYSecEnd = nBlockYSize; | |||
471 | nCummulator = 0; | |||
472 | for( nSourceYSec = nSourceY; nSourceYSec < nSourceYSecEnd; nSourceYSec ++) | |||
473 | { | |||
474 | for( nSourceXSec = nSourceX; nSourceXSec < nSourceXSecEnd; nSourceXSec ++) | |||
475 | { | |||
476 | nCummulator += * ( pabySrcTile + ( nSourceYSec / nVerSubsampling ) * nSourceSampleRowSize | |||
477 | + ( nSourceYSec % nVerSubsampling ) * nHorSubsampling | |||
478 | + ( nSourceXSec / nHorSubsampling ) * nSampleBlockSize | |||
479 | + ( nSourceXSec % nHorSubsampling ) ); | |||
480 | } | |||
481 | } | |||
482 | nCummulatorCount = ( nSourceXSecEnd - nSourceX ) * ( nSourceYSecEnd - nSourceY ); | |||
483 | * ( pabyOTile + ( nDestY / nVerSubsampling ) * nDestSampleRowSize | |||
484 | + ( nDestY % nVerSubsampling ) * nHorSubsampling | |||
485 | + ( nDestX / nHorSubsampling ) * nSampleBlockSize | |||
486 | + ( nDestX % nHorSubsampling ) ) = | |||
487 | ( ( nCummulator + ( nCummulatorCount >> 1 ) ) / nCummulatorCount ); | |||
488 | } | |||
489 | } | |||
490 | } | |||
491 | else | |||
492 | { | |||
493 | nSampleOffsetInSampleBlock = nHorSubsampling * nVerSubsampling + nSample - 1; | |||
494 | for( nSourceY = 0, nDestY = ( nTYOff / nVerSubsampling ); nSourceY < ( nBlockYSize / nVerSubsampling ); | |||
495 | nSourceY += nOMult, nDestY ++) | |||
496 | { | |||
497 | if( nDestY*nVerSubsampling >= nOBlockYSize ) | |||
498 | break; | |||
499 | ||||
500 | for( nSourceX = 0, nDestX = ( nTXOff / nHorSubsampling ); nSourceX < ( nBlockXSize / nHorSubsampling ); | |||
501 | nSourceX += nOMult, nDestX ++) | |||
502 | { | |||
503 | if( nDestX*nHorSubsampling >= nOBlockXSize ) | |||
504 | break; | |||
505 | ||||
506 | nSourceXSecEnd = nSourceX + nOMult; | |||
507 | if( nSourceXSecEnd > ( nBlockXSize / nHorSubsampling ) ) | |||
508 | nSourceXSecEnd = ( nBlockXSize / nHorSubsampling ); | |||
509 | nSourceYSecEnd = nSourceY + nOMult; | |||
510 | if( nSourceYSecEnd > ( nBlockYSize / nVerSubsampling ) ) | |||
511 | nSourceYSecEnd = ( nBlockYSize / nVerSubsampling ); | |||
512 | nCummulator = 0; | |||
513 | for( nSourceYSec = nSourceY; nSourceYSec < nSourceYSecEnd; nSourceYSec ++) | |||
514 | { | |||
515 | for( nSourceXSec = nSourceX; nSourceXSec < nSourceXSecEnd; nSourceXSec ++) | |||
516 | { | |||
517 | nCummulator += * ( pabySrcTile + nSourceYSec * nSourceSampleRowSize | |||
518 | + nSourceXSec * nSampleBlockSize | |||
519 | + nSampleOffsetInSampleBlock ); | |||
520 | } | |||
521 | } | |||
522 | nCummulatorCount = ( nSourceXSecEnd - nSourceX ) * ( nSourceYSecEnd - nSourceY ); | |||
523 | * ( pabyOTile + nDestY * nDestSampleRowSize | |||
524 | + nDestX * nSampleBlockSize | |||
525 | + nSampleOffsetInSampleBlock ) = | |||
526 | ( ( nCummulator + ( nCummulatorCount >> 1 ) ) / nCummulatorCount ); | |||
| ||||
527 | } | |||
528 | } | |||
529 | } | |||
530 | } | |||
531 | } | |||
532 | ||||
533 | /************************************************************************/ | |||
534 | /* TIFF_ProcessFullResBlock() */ | |||
535 | /* */ | |||
536 | /* Process one block of full res data, downsampling into each */ | |||
537 | /* of the overviews. */ | |||
538 | /************************************************************************/ | |||
539 | ||||
540 | void TIFF_ProcessFullResBlock( TIFF *hTIFF, int nPlanarConfig, | |||
541 | int bSubsampled, | |||
542 | int nHorSubsampling, int nVerSubsampling, | |||
543 | int nOverviews, int * panOvList, | |||
544 | int nBitsPerPixel, | |||
545 | int nSamples, TIFFOvrCache ** papoRawBIs, | |||
546 | uint32 nSXOff, uint32 nSYOff, | |||
547 | unsigned char *pabySrcTile, | |||
548 | uint32 nBlockXSize, uint32 nBlockYSize, | |||
549 | int nSampleFormat, const char * pszResampling ) | |||
550 | ||||
551 | { | |||
552 | int iOverview, iSample; | |||
553 | ||||
554 | for( iSample = 0; iSample < nSamples; iSample++ ) | |||
555 | { | |||
556 | /* | |||
557 | * We have to read a tile/strip for each sample for | |||
558 | * PLANARCONFIG_SEPARATE. Otherwise, we just read all the samples | |||
559 | * at once when handling the first sample. | |||
560 | */ | |||
561 | if( nPlanarConfig == PLANARCONFIG_SEPARATE2 || iSample == 0 ) | |||
562 | { | |||
563 | if( TIFFIsTiled(hTIFF) ) | |||
564 | { | |||
565 | TIFFReadEncodedTile( hTIFF, | |||
566 | TIFFComputeTile(hTIFF, nSXOff, nSYOff, | |||
567 | 0, (tsample_t)iSample ), | |||
568 | pabySrcTile, | |||
569 | TIFFTileSize(hTIFF)); | |||
570 | } | |||
571 | else | |||
572 | { | |||
573 | TIFFReadEncodedStrip( hTIFF, | |||
574 | TIFFComputeStrip(hTIFF, nSYOff, | |||
575 | (tsample_t) iSample), | |||
576 | pabySrcTile, | |||
577 | TIFFStripSize(hTIFF) ); | |||
578 | } | |||
579 | } | |||
580 | ||||
581 | /* | |||
582 | * Loop over destination overview layers | |||
583 | */ | |||
584 | for( iOverview = 0; iOverview < nOverviews; iOverview++ ) | |||
585 | { | |||
586 | TIFFOvrCache *poRBI = papoRawBIs[iOverview]; | |||
587 | unsigned char *pabyOTile; | |||
588 | uint32 nTXOff, nTYOff, nOXOff, nOYOff, nOMult; | |||
589 | uint32 nOBlockXSize = poRBI->nBlockXSize; | |||
590 | uint32 nOBlockYSize = poRBI->nBlockYSize; | |||
591 | int nSkewBits, nSampleByteOffset; | |||
592 | ||||
593 | /* | |||
594 | * Fetch the destination overview tile | |||
595 | */ | |||
596 | nOMult = panOvList[iOverview]; | |||
597 | nOXOff = (nSXOff/nOMult) / nOBlockXSize; | |||
598 | nOYOff = (nSYOff/nOMult) / nOBlockYSize; | |||
599 | ||||
600 | if( bSubsampled ) | |||
601 | { | |||
602 | pabyOTile = TIFFGetOvrBlock_Subsampled( poRBI, nOXOff, nOYOff ); | |||
603 | ||||
604 | /* | |||
605 | * Establish the offset into this tile at which we should | |||
606 | * start placing data. | |||
607 | */ | |||
608 | nTXOff = (nSXOff - nOXOff*nOMult*nOBlockXSize) / nOMult; | |||
609 | nTYOff = (nSYOff - nOYOff*nOMult*nOBlockYSize) / nOMult; | |||
610 | ||||
611 | ||||
612 | #ifdef DBMALLOC | |||
613 | malloc_chain_check( 1 ); | |||
614 | #endif | |||
615 | TIFF_DownSample_Subsampled( pabySrcTile, iSample, | |||
616 | nBlockXSize, nBlockYSize, | |||
617 | pabyOTile, | |||
618 | poRBI->nBlockXSize, poRBI->nBlockYSize, | |||
619 | nTXOff, nTYOff, | |||
620 | nOMult, pszResampling, | |||
621 | nHorSubsampling, nVerSubsampling ); | |||
622 | #ifdef DBMALLOC | |||
623 | malloc_chain_check( 1 ); | |||
624 | #endif | |||
625 | ||||
626 | } | |||
627 | else | |||
628 | { | |||
629 | ||||
630 | pabyOTile = TIFFGetOvrBlock( poRBI, nOXOff, nOYOff, iSample ); | |||
631 | ||||
632 | /* | |||
633 | * Establish the offset into this tile at which we should | |||
634 | * start placing data. | |||
635 | */ | |||
636 | nTXOff = (nSXOff - nOXOff*nOMult*nOBlockXSize) / nOMult; | |||
637 | nTYOff = (nSYOff - nOYOff*nOMult*nOBlockYSize) / nOMult; | |||
638 | ||||
639 | /* | |||
640 | * Figure out the skew (extra space between ``our samples'') and | |||
641 | * the byte offset to the first sample. | |||
642 | */ | |||
643 | assert( (nBitsPerPixel % 8) == 0 )(((nBitsPerPixel % 8) == 0) ? (void) (0) : __assert_fail ("(nBitsPerPixel % 8) == 0" , "tif_overview.c", 643, __PRETTY_FUNCTION__)); | |||
644 | if( nPlanarConfig == PLANARCONFIG_SEPARATE2 ) | |||
645 | { | |||
646 | nSkewBits = 0; | |||
647 | nSampleByteOffset = 0; | |||
648 | } | |||
649 | else | |||
650 | { | |||
651 | nSkewBits = nBitsPerPixel * (nSamples-1); | |||
652 | nSampleByteOffset = (nBitsPerPixel/8) * iSample; | |||
653 | } | |||
654 | ||||
655 | /* | |||
656 | * Perform the downsampling. | |||
657 | */ | |||
658 | #ifdef DBMALLOC | |||
659 | malloc_chain_check( 1 ); | |||
660 | #endif | |||
661 | TIFF_DownSample( pabySrcTile + nSampleByteOffset, | |||
662 | nBlockXSize, nBlockYSize, | |||
663 | nSkewBits, nBitsPerPixel, pabyOTile, | |||
664 | poRBI->nBlockXSize, poRBI->nBlockYSize, | |||
665 | nTXOff, nTYOff, | |||
666 | nOMult, nSampleFormat, pszResampling ); | |||
667 | #ifdef DBMALLOC | |||
668 | malloc_chain_check( 1 ); | |||
669 | #endif | |||
670 | } | |||
671 | } | |||
672 | } | |||
673 | } | |||
674 | ||||
675 | /************************************************************************/ | |||
676 | /* TIFF_BuildOverviews() */ | |||
677 | /* */ | |||
678 | /* Build the requested list of overviews. Overviews are */ | |||
679 | /* maintained in a bunch of temporary files and then these are */ | |||
680 | /* written back to the TIFF file. Only one pass through the */ | |||
681 | /* source TIFF file is made for any number of output */ | |||
682 | /* overviews. */ | |||
683 | /************************************************************************/ | |||
684 | ||||
685 | void TIFFBuildOverviews( TIFF *hTIFF, int nOverviews, int * panOvList, | |||
686 | int bUseSubIFDs, const char *pszResampleMethod, | |||
687 | int (*pfnProgress)( double, void * ), | |||
688 | void * pProgressData ) | |||
689 | ||||
690 | { | |||
691 | TIFFOvrCache **papoRawBIs; | |||
692 | uint32 nXSize, nYSize, nBlockXSize, nBlockYSize; | |||
693 | uint16 nBitsPerPixel, nPhotometric, nCompressFlag, nSamples, | |||
694 | nPlanarConfig, nSampleFormat; | |||
695 | int bSubsampled; | |||
696 | uint16 nHorSubsampling, nVerSubsampling; | |||
697 | int bTiled, nSXOff, nSYOff, i; | |||
698 | unsigned char *pabySrcTile; | |||
699 | uint16 *panRedMap, *panGreenMap, *panBlueMap; | |||
700 | TIFFErrorHandler pfnWarning; | |||
701 | ||||
702 | (void) pfnProgress; | |||
703 | (void) pProgressData; | |||
704 | ||||
705 | /* -------------------------------------------------------------------- */ | |||
706 | /* Get the base raster size. */ | |||
707 | /* -------------------------------------------------------------------- */ | |||
708 | TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH256, &nXSize ); | |||
709 | TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH257, &nYSize ); | |||
710 | ||||
711 | TIFFGetField( hTIFF, TIFFTAG_BITSPERSAMPLE258, &nBitsPerPixel ); | |||
712 | /* TODO: nBitsPerPixel seems misnomer and may need renaming to nBitsPerSample */ | |||
713 | TIFFGetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL277, &nSamples ); | |||
714 | TIFFGetFieldDefaulted( hTIFF, TIFFTAG_PLANARCONFIG284, &nPlanarConfig ); | |||
715 | ||||
716 | TIFFGetFieldDefaulted( hTIFF, TIFFTAG_PHOTOMETRIC262, &nPhotometric ); | |||
717 | TIFFGetFieldDefaulted( hTIFF, TIFFTAG_COMPRESSION259, &nCompressFlag ); | |||
718 | TIFFGetFieldDefaulted( hTIFF, TIFFTAG_SAMPLEFORMAT339, &nSampleFormat ); | |||
719 | ||||
720 | if( nPhotometric == PHOTOMETRIC_YCBCR6 || nPhotometric == PHOTOMETRIC_ITULAB10 ) | |||
721 | { | |||
722 | if( nBitsPerPixel != 8 || nSamples != 3 || nPlanarConfig != PLANARCONFIG_CONTIG1 || | |||
723 | nSampleFormat != SAMPLEFORMAT_UINT1) | |||
724 | { | |||
725 | /* TODO: use of TIFFError is inconsistent with use of fprintf in addtiffo.c, sort out */ | |||
726 | TIFFErrorExt( TIFFClientdata(hTIFF), "TIFFBuildOverviews", | |||
727 | "File `%s' has an unsupported subsampling configuration.\n", | |||
728 | TIFFFileName(hTIFF) ); | |||
729 | /* If you need support for this particular flavor, please contact either | |||
730 | * Frank Warmerdam warmerdam@pobox.com | |||
731 | * Joris Van Damme info@awaresystems.be | |||
732 | */ | |||
733 | return; | |||
734 | } | |||
735 | bSubsampled = 1; | |||
736 | TIFFGetField( hTIFF, TIFFTAG_YCBCRSUBSAMPLING530, &nHorSubsampling, &nVerSubsampling ); | |||
737 | /* TODO: find out if maybe TIFFGetFieldDefaulted is better choice for YCbCrSubsampling tag */ | |||
738 | } | |||
739 | else | |||
740 | { | |||
741 | if( nBitsPerPixel < 8 ) | |||
742 | { | |||
743 | /* TODO: use of TIFFError is inconsistent with use of fprintf in addtiffo.c, sort out */ | |||
744 | TIFFErrorExt( TIFFClientdata(hTIFF), "TIFFBuildOverviews", | |||
745 | "File `%s' has samples of %d bits per sample. Sample\n" | |||
746 | "sizes of less than 8 bits per sample are not supported.\n", | |||
747 | TIFFFileName(hTIFF), nBitsPerPixel ); | |||
748 | return; | |||
749 | } | |||
750 | bSubsampled = 0; | |||
751 | nHorSubsampling = 1; | |||
752 | nVerSubsampling = 1; | |||
753 | } | |||
754 | ||||
755 | /* -------------------------------------------------------------------- */ | |||
756 | /* Turn off warnings to avoid alot of repeated warnings while */ | |||
757 | /* rereading directories. */ | |||
758 | /* -------------------------------------------------------------------- */ | |||
759 | pfnWarning = TIFFSetWarningHandler( NULL((void*)0) ); | |||
760 | ||||
761 | /* -------------------------------------------------------------------- */ | |||
762 | /* Get the base raster block size. */ | |||
763 | /* -------------------------------------------------------------------- */ | |||
764 | if( TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP278, &(nBlockYSize) ) ) | |||
765 | { | |||
766 | nBlockXSize = nXSize; | |||
767 | bTiled = FALSE0; | |||
768 | } | |||
769 | else | |||
770 | { | |||
771 | TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH322, &nBlockXSize ); | |||
772 | TIFFGetField( hTIFF, TIFFTAG_TILELENGTH323, &nBlockYSize ); | |||
773 | bTiled = TRUE1; | |||
774 | } | |||
775 | ||||
776 | /* -------------------------------------------------------------------- */ | |||
777 | /* Capture the pallette if there is one. */ | |||
778 | /* -------------------------------------------------------------------- */ | |||
779 | if( TIFFGetField( hTIFF, TIFFTAG_COLORMAP320, | |||
780 | &panRedMap, &panGreenMap, &panBlueMap ) ) | |||
781 | { | |||
782 | uint16 *panRed2, *panGreen2, *panBlue2; | |||
783 | int nColorCount = 1 << nBitsPerPixel; | |||
784 | ||||
785 | panRed2 = (uint16 *) _TIFFmalloc(2*nColorCount); | |||
786 | panGreen2 = (uint16 *) _TIFFmalloc(2*nColorCount); | |||
787 | panBlue2 = (uint16 *) _TIFFmalloc(2*nColorCount); | |||
788 | ||||
789 | memcpy( panRed2, panRedMap, 2 * nColorCount ); | |||
790 | memcpy( panGreen2, panGreenMap, 2 * nColorCount ); | |||
791 | memcpy( panBlue2, panBlueMap, 2 * nColorCount ); | |||
792 | ||||
793 | panRedMap = panRed2; | |||
794 | panGreenMap = panGreen2; | |||
795 | panBlueMap = panBlue2; | |||
796 | } | |||
797 | else | |||
798 | { | |||
799 | panRedMap = panGreenMap = panBlueMap = NULL((void*)0); | |||
800 | } | |||
801 | ||||
802 | /* -------------------------------------------------------------------- */ | |||
803 | /* Initialize overviews. */ | |||
804 | /* -------------------------------------------------------------------- */ | |||
805 | papoRawBIs = (TIFFOvrCache **) _TIFFmalloc(nOverviews*sizeof(void*)); | |||
806 | ||||
807 | for( i = 0; i < nOverviews; i++ ) | |||
808 | { | |||
809 | uint32 nOXSize, nOYSize, nOBlockXSize, nOBlockYSize; | |||
810 | toff_t nDirOffset; | |||
811 | ||||
812 | nOXSize = (nXSize + panOvList[i] - 1) / panOvList[i]; | |||
813 | nOYSize = (nYSize + panOvList[i] - 1) / panOvList[i]; | |||
814 | ||||
815 | nOBlockXSize = MIN(nBlockXSize,nOXSize)((nBlockXSize<nOXSize) ? nBlockXSize : nOXSize); | |||
816 | nOBlockYSize = MIN(nBlockYSize,nOYSize)((nBlockYSize<nOYSize) ? nBlockYSize : nOYSize); | |||
817 | ||||
818 | if( bTiled ) | |||
819 | { | |||
820 | if( (nOBlockXSize % 16) != 0 ) | |||
821 | nOBlockXSize = nOBlockXSize + 16 - (nOBlockXSize % 16); | |||
822 | ||||
823 | if( (nOBlockYSize % 16) != 0 ) | |||
824 | nOBlockYSize = nOBlockYSize + 16 - (nOBlockYSize % 16); | |||
825 | } | |||
826 | ||||
827 | nDirOffset = TIFF_WriteOverview( hTIFF, nOXSize, nOYSize, | |||
828 | nBitsPerPixel, nPlanarConfig, | |||
829 | nSamples, nOBlockXSize, nOBlockYSize, | |||
830 | bTiled, nCompressFlag, nPhotometric, | |||
831 | nSampleFormat, | |||
832 | panRedMap, panGreenMap, panBlueMap, | |||
833 | bUseSubIFDs, | |||
834 | nHorSubsampling, nVerSubsampling ); | |||
835 | ||||
836 | papoRawBIs[i] = TIFFCreateOvrCache( hTIFF, nDirOffset ); | |||
837 | } | |||
838 | ||||
839 | if( panRedMap != NULL((void*)0) ) | |||
840 | { | |||
841 | _TIFFfree( panRedMap ); | |||
842 | _TIFFfree( panGreenMap ); | |||
843 | _TIFFfree( panBlueMap ); | |||
844 | } | |||
845 | ||||
846 | /* -------------------------------------------------------------------- */ | |||
847 | /* Allocate a buffer to hold a source block. */ | |||
848 | /* -------------------------------------------------------------------- */ | |||
849 | if( bTiled ) | |||
850 | pabySrcTile = (unsigned char *) _TIFFmalloc(TIFFTileSize(hTIFF)); | |||
851 | else | |||
852 | pabySrcTile = (unsigned char *) _TIFFmalloc(TIFFStripSize(hTIFF)); | |||
853 | ||||
854 | /* -------------------------------------------------------------------- */ | |||
855 | /* Loop over the source raster, applying data to the */ | |||
856 | /* destination raster. */ | |||
857 | /* -------------------------------------------------------------------- */ | |||
858 | for( nSYOff = 0; nSYOff < (int) nYSize; nSYOff += nBlockYSize ) | |||
859 | { | |||
860 | for( nSXOff = 0; nSXOff < (int) nXSize; nSXOff += nBlockXSize ) | |||
861 | { | |||
862 | /* | |||
863 | * Read and resample into the various overview images. | |||
864 | */ | |||
865 | ||||
866 | TIFF_ProcessFullResBlock( hTIFF, nPlanarConfig, | |||
867 | bSubsampled,nHorSubsampling,nVerSubsampling, | |||
868 | nOverviews, panOvList, | |||
869 | nBitsPerPixel, nSamples, papoRawBIs, | |||
870 | nSXOff, nSYOff, pabySrcTile, | |||
871 | nBlockXSize, nBlockYSize, | |||
872 | nSampleFormat, pszResampleMethod ); | |||
873 | } | |||
874 | } | |||
875 | ||||
876 | _TIFFfree( pabySrcTile ); | |||
877 | ||||
878 | /* -------------------------------------------------------------------- */ | |||
879 | /* Cleanup the rawblockedimage files. */ | |||
880 | /* -------------------------------------------------------------------- */ | |||
881 | for( i = 0; i < nOverviews; i++ ) | |||
882 | { | |||
883 | TIFFDestroyOvrCache( papoRawBIs[i] ); | |||
884 | } | |||
885 | ||||
886 | if( papoRawBIs != NULL((void*)0) ) | |||
887 | _TIFFfree( papoRawBIs ); | |||
888 | ||||
889 | TIFFSetWarningHandler( pfnWarning ); | |||
890 | } | |||
891 | ||||
892 | ||||
893 | /* | |||
894 | * Local Variables: | |||
895 | * mode: c | |||
896 | * c-basic-offset: 8 | |||
897 | * fill-column: 78 | |||
898 | * End: | |||
899 | */ |