]>
Commit | Line | Data |
---|---|---|
8414a40c VZ |
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 FALSE | |
59 | # define FALSE 0 | |
60 | # define TRUE 1 | |
61 | #endif | |
62 | ||
63 | #ifndef MAX | |
64 | # define MIN(a,b) ((a<b) ? a : b) | |
65 | # define MAX(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, int nXSize, int 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 | uint32 nBaseDirOffset; | |
93 | uint32 nOffset; | |
94 | ||
95 | nBaseDirOffset = TIFFCurrentDirOffset( hTIFF ); | |
96 | ||
97 | TIFFCreateDirectory( hTIFF ); | |
98 | ||
99 | /* -------------------------------------------------------------------- */ | |
100 | /* Setup TIFF fields. */ | |
101 | /* -------------------------------------------------------------------- */ | |
102 | TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize ); | |
103 | TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize ); | |
104 | if( nSamples == 1 ) | |
105 | TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); | |
106 | else | |
107 | TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanarConfig ); | |
108 | ||
109 | TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerPixel ); | |
110 | TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples ); | |
111 | TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompressFlag ); | |
112 | TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric ); | |
113 | TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat ); | |
114 | ||
115 | if( bTiled ) | |
116 | { | |
117 | TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize ); | |
118 | TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ); | |
119 | } | |
120 | else | |
121 | TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nBlockYSize ); | |
122 | ||
123 | TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE ); | |
124 | ||
125 | if( nPhotometric == PHOTOMETRIC_YCBCR || nPhotometric == PHOTOMETRIC_ITULAB ) | |
126 | { | |
127 | TIFFSetField( hTIFF, TIFFTAG_YCBCRSUBSAMPLING, nHorSubsampling, nVerSubsampling); | |
128 | /* TODO: also write YCbCrPositioning and YCbCrCoefficients tag identical to source IFD */ | |
129 | } | |
130 | /* TODO: add command-line parameter for selecting jpeg compression quality | |
131 | * that gets ignored when compression isn't jpeg */ | |
132 | ||
133 | /* -------------------------------------------------------------------- */ | |
134 | /* Write color table if one is present. */ | |
135 | /* -------------------------------------------------------------------- */ | |
136 | if( panRed != NULL ) | |
137 | { | |
138 | TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue ); | |
139 | } | |
140 | ||
141 | /* -------------------------------------------------------------------- */ | |
142 | /* Write directory, and return byte offset. */ | |
143 | /* -------------------------------------------------------------------- */ | |
144 | if( TIFFWriteCheck( hTIFF, bTiled, "TIFFBuildOverviews" ) == 0 ) | |
145 | return 0; | |
146 | ||
147 | TIFFWriteDirectory( hTIFF ); | |
148 | TIFFSetDirectory( hTIFF, (tdir_t) (TIFFNumberOfDirectories(hTIFF)-1) ); | |
149 | ||
150 | nOffset = TIFFCurrentDirOffset( hTIFF ); | |
151 | ||
152 | TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); | |
153 | ||
154 | return nOffset; | |
155 | } | |
156 | ||
157 | /************************************************************************/ | |
158 | /* TIFF_GetSourceSamples() */ | |
159 | /************************************************************************/ | |
160 | ||
161 | static void | |
162 | TIFF_GetSourceSamples( double * padfSamples, unsigned char *pabySrc, | |
163 | int nPixelBytes, int nSampleFormat, | |
164 | int nXSize, int nYSize, | |
165 | int nPixelOffset, int nLineOffset ) | |
166 | { | |
167 | int iXOff, iYOff, iSample; | |
168 | ||
169 | iSample = 0; | |
170 | ||
171 | for( iYOff = 0; iYOff < nYSize; iYOff++ ) | |
172 | { | |
173 | for( iXOff = 0; iXOff < nXSize; iXOff++ ) | |
174 | { | |
175 | unsigned char *pabyData; | |
176 | ||
177 | pabyData = pabySrc + iYOff * nLineOffset + iXOff * nPixelOffset; | |
178 | ||
179 | if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 1 ) | |
180 | { | |
181 | padfSamples[iSample++] = *pabyData; | |
182 | } | |
183 | else if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 2 ) | |
184 | { | |
185 | padfSamples[iSample++] = ((uint16 *) pabyData)[0]; | |
186 | } | |
187 | else if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 4 ) | |
188 | { | |
189 | padfSamples[iSample++] = ((uint32 *) pabyData)[0]; | |
190 | } | |
191 | else if( nSampleFormat == SAMPLEFORMAT_INT && nPixelBytes == 2 ) | |
192 | { | |
193 | padfSamples[iSample++] = ((int16 *) pabyData)[0]; | |
194 | } | |
195 | else if( nSampleFormat == SAMPLEFORMAT_INT && nPixelBytes == 32 ) | |
196 | { | |
197 | padfSamples[iSample++] = ((int32 *) pabyData)[0]; | |
198 | } | |
199 | else if( nSampleFormat == SAMPLEFORMAT_IEEEFP && nPixelBytes == 4 ) | |
200 | { | |
201 | padfSamples[iSample++] = ((float *) pabyData)[0]; | |
202 | } | |
203 | else if( nSampleFormat == SAMPLEFORMAT_IEEEFP && nPixelBytes == 8 ) | |
204 | { | |
205 | padfSamples[iSample++] = ((double *) pabyData)[0]; | |
206 | } | |
207 | } | |
208 | } | |
209 | } | |
210 | ||
211 | /************************************************************************/ | |
212 | /* TIFF_SetSample() */ | |
213 | /************************************************************************/ | |
214 | ||
215 | static void | |
216 | TIFF_SetSample( unsigned char * pabyData, int nPixelBytes, int nSampleFormat, | |
217 | double dfValue ) | |
218 | ||
219 | { | |
220 | if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 1 ) | |
221 | { | |
222 | *pabyData = (unsigned char) MAX(0,MIN(255,dfValue)); | |
223 | } | |
224 | else if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 2 ) | |
225 | { | |
226 | *((uint16 *)pabyData) = (uint16) MAX(0,MIN(65535,dfValue)); | |
227 | } | |
228 | else if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 4 ) | |
229 | { | |
230 | *((uint32 *)pabyData) = (uint32) dfValue; | |
231 | } | |
232 | else if( nSampleFormat == SAMPLEFORMAT_INT && nPixelBytes == 2 ) | |
233 | { | |
234 | *((int16 *)pabyData) = (int16) MAX(-32768,MIN(32767,dfValue)); | |
235 | } | |
236 | else if( nSampleFormat == SAMPLEFORMAT_INT && nPixelBytes == 32 ) | |
237 | { | |
238 | *((int32 *)pabyData) = (int32) dfValue; | |
239 | } | |
240 | else if( nSampleFormat == SAMPLEFORMAT_IEEEFP && nPixelBytes == 4 ) | |
241 | { | |
242 | *((float *)pabyData) = (float) dfValue; | |
243 | } | |
244 | else if( nSampleFormat == SAMPLEFORMAT_IEEEFP && nPixelBytes == 8 ) | |
245 | { | |
246 | *((double *)pabyData) = dfValue; | |
247 | } | |
248 | } | |
249 | ||
250 | /************************************************************************/ | |
251 | /* TIFF_DownSample() */ | |
252 | /* */ | |
253 | /* Down sample a tile of full res data into a window of a tile */ | |
254 | /* of downsampled data. */ | |
255 | /************************************************************************/ | |
256 | ||
257 | static | |
258 | void TIFF_DownSample( unsigned char *pabySrcTile, | |
259 | int nBlockXSize, int nBlockYSize, | |
260 | int nPixelSkewBits, int nBitsPerPixel, | |
261 | unsigned char * pabyOTile, | |
262 | int nOBlockXSize, int nOBlockYSize, | |
263 | int nTXOff, int nTYOff, int nOMult, | |
264 | int nSampleFormat, const char * pszResampling ) | |
265 | ||
266 | { | |
267 | int i, j, k, nPixelBytes = (nBitsPerPixel) / 8; | |
268 | int nPixelGroupBytes = (nBitsPerPixel+nPixelSkewBits)/8; | |
269 | unsigned char *pabySrc, *pabyDst; | |
270 | double *padfSamples; | |
271 | ||
272 | assert( nBitsPerPixel >= 8 ); | |
273 | ||
274 | padfSamples = (double *) malloc(sizeof(double) * nOMult * nOMult); | |
275 | ||
276 | /* ==================================================================== */ | |
277 | /* Loop over scanline chunks to process, establishing where the */ | |
278 | /* data is going. */ | |
279 | /* ==================================================================== */ | |
280 | for( j = 0; j*nOMult < nBlockYSize; j++ ) | |
281 | { | |
282 | if( j + nTYOff >= nOBlockYSize ) | |
283 | break; | |
284 | ||
285 | pabyDst = pabyOTile + ((j+nTYOff)*nOBlockXSize + nTXOff) | |
286 | * nPixelBytes * nPixelGroupBytes; | |
287 | ||
288 | /* -------------------------------------------------------------------- */ | |
289 | /* Handler nearest resampling ... we don't even care about the */ | |
290 | /* data type, we just do a bytewise copy. */ | |
291 | /* -------------------------------------------------------------------- */ | |
292 | if( strncmp(pszResampling,"nearest",4) == 0 | |
293 | || strncmp(pszResampling,"NEAR",4) == 0 ) | |
294 | { | |
295 | pabySrc = pabySrcTile + j*nOMult*nBlockXSize * nPixelGroupBytes; | |
296 | ||
297 | for( i = 0; i*nOMult < nBlockXSize; i++ ) | |
298 | { | |
299 | if( i + nTXOff >= nOBlockXSize ) | |
300 | break; | |
301 | ||
302 | /* | |
303 | * For now use simple subsampling, from the top left corner | |
304 | * of the source block of pixels. | |
305 | */ | |
306 | ||
307 | for( k = 0; k < nPixelBytes; k++ ) | |
308 | pabyDst[k] = pabySrc[k]; | |
309 | ||
310 | pabyDst += nPixelBytes * nPixelGroupBytes; | |
311 | pabySrc += nOMult * nPixelGroupBytes; | |
312 | } | |
313 | } | |
314 | ||
315 | /* -------------------------------------------------------------------- */ | |
316 | /* Handle the case of averaging. For this we also have to */ | |
317 | /* handle each sample format we are concerned with. */ | |
318 | /* -------------------------------------------------------------------- */ | |
319 | else if( strncmp(pszResampling,"averag",6) == 0 | |
320 | || strncmp(pszResampling,"AVERAG",6) == 0 ) | |
321 | { | |
322 | pabySrc = pabySrcTile + j*nOMult*nBlockXSize * nPixelGroupBytes; | |
323 | ||
324 | for( i = 0; i*nOMult < nBlockXSize; i++ ) | |
325 | { | |
326 | double dfTotal; | |
327 | int iSample; | |
328 | int nXSize, nYSize; | |
329 | ||
330 | if( i + nTXOff >= nOBlockXSize ) | |
331 | break; | |
332 | ||
333 | nXSize = MIN(nOMult,nBlockXSize-i); | |
334 | nYSize = MIN(nOMult,nBlockYSize-j); | |
335 | ||
336 | TIFF_GetSourceSamples( padfSamples, pabySrc, | |
337 | nPixelBytes, nSampleFormat, | |
338 | nXSize, nYSize, | |
339 | nPixelGroupBytes, | |
340 | nPixelGroupBytes * nBlockXSize ); | |
341 | ||
342 | dfTotal = 0; | |
343 | for( iSample = 0; iSample < nXSize*nYSize; iSample++ ) | |
344 | { | |
345 | dfTotal += padfSamples[iSample]; | |
346 | } | |
347 | ||
348 | TIFF_SetSample( pabyDst, nPixelBytes, nSampleFormat, | |
349 | dfTotal / (nXSize*nYSize) ); | |
350 | ||
351 | pabySrc += nOMult * nPixelGroupBytes; | |
352 | pabyDst += nPixelBytes; | |
353 | } | |
354 | } | |
355 | } | |
356 | ||
357 | free( padfSamples ); | |
358 | } | |
359 | ||
360 | static | |
361 | void TIFF_DownSample_Subsampled( unsigned char *pabySrcTile, int nSample, | |
362 | int nBlockXSize, int nBlockYSize, | |
363 | unsigned char * pabyOTile, | |
364 | int nOBlockXSize, int nOBlockYSize, | |
365 | int nTXOff, int nTYOff, int nOMult, | |
366 | const char * pszResampling, | |
367 | int nHorSubsampling, int nVerSubsampling ) | |
368 | { | |
369 | /* TODO: test with variety of subsampling values, and incovinient tile/strip sizes */ | |
370 | int nSampleBlockSize; | |
371 | int nSourceSampleRowSize; | |
372 | int nDestSampleRowSize; | |
373 | int nSourceX, nSourceY; | |
374 | int nSourceXSec, nSourceYSec; | |
375 | int nSourceXSecEnd, nSourceYSecEnd; | |
376 | int nDestX, nDestY; | |
377 | int nSampleOffsetInSampleBlock; | |
378 | unsigned char * pSourceBase; | |
379 | unsigned char * pDestBase; | |
380 | int nSourceBaseInc; | |
381 | unsigned char * pSourceBaseEnd; | |
382 | unsigned int nCummulator; | |
383 | unsigned int nCummulatorCount; | |
384 | ||
385 | nSampleBlockSize = nHorSubsampling * nVerSubsampling + 2; | |
386 | nSourceSampleRowSize = ( ( nBlockXSize + nHorSubsampling - 1 ) / nHorSubsampling ) * nSampleBlockSize; | |
387 | nDestSampleRowSize = ( ( nOBlockXSize + nHorSubsampling - 1 ) / nHorSubsampling ) * nSampleBlockSize; | |
388 | ||
389 | if( strncmp(pszResampling,"nearest",4) == 0 | |
390 | || strncmp(pszResampling,"NEAR",4) == 0 ) | |
391 | { | |
392 | if( nSample == 0 ) | |
393 | { | |
394 | #ifdef NOOPTIMIZATION | |
395 | /* | |
396 | * This version is not optimized, and should not be used except as documentation and as more clear | |
397 | * starting point for bug fixes (hope not) and extension | |
398 | */ | |
399 | for( nSourceY = 0, nDestY = nTYOff; nSourceY < nBlockYSize; nSourceY += nOMult, nDestY ++) | |
400 | { | |
401 | for( nSourceX = 0, nDestX = nTXOff; nSourceX < nBlockXSize; nSourceX += nOMult, nDestX ++) | |
402 | { | |
403 | * ( pabyOTile + ( nDestY / nVerSubsampling ) * nDestSampleRowSize | |
404 | + ( nDestY % nVerSubsampling ) * nHorSubsampling | |
405 | + ( nDestX / nHorSubsampling ) * nSampleBlockSize | |
406 | + ( nDestX % nHorSubsampling ) ) = | |
407 | * ( pabySrcTile + ( nSourceY / nVerSubsampling ) * nSourceSampleRowSize | |
408 | + ( nSourceY % nVerSubsampling ) * nHorSubsampling | |
409 | + ( nSourceX / nHorSubsampling ) * nSampleBlockSize | |
410 | + ( nSourceX % nHorSubsampling ) ); | |
411 | } | |
412 | } | |
413 | #else | |
414 | for( nSourceY = 0, nDestY = nTYOff; nSourceY < nBlockYSize; nSourceY += nOMult, nDestY ++) | |
415 | { | |
416 | pSourceBase = pabySrcTile + ( nSourceY / nVerSubsampling ) * nSourceSampleRowSize | |
417 | + ( nSourceY % nVerSubsampling ) * nHorSubsampling; | |
418 | pDestBase = pabyOTile + ( nDestY / nVerSubsampling ) * nDestSampleRowSize | |
419 | + ( nDestY % nVerSubsampling ) * nHorSubsampling; | |
420 | for( nSourceX = 0, nDestX = nTXOff; nSourceX < nBlockXSize; nSourceX += nOMult, nDestX ++) | |
421 | { | |
422 | * ( pDestBase + ( nDestX / nHorSubsampling ) * nSampleBlockSize | |
423 | + ( nDestX % nHorSubsampling ) ) = | |
424 | * ( pSourceBase + ( nSourceX / nHorSubsampling ) * nSampleBlockSize | |
425 | + ( nSourceX % nHorSubsampling ) ); | |
426 | } | |
427 | } | |
428 | #endif | |
429 | } | |
430 | else | |
431 | { | |
432 | #ifdef NOOPTIMIZATION | |
433 | /* | |
434 | * This version is not optimized, and should not be used except as documentation and as more clear | |
435 | * starting point for bug fixes (hope not) and extension | |
436 | */ | |
437 | nSampleOffsetInSampleBlock = nHorSubsampling * nVerSubsampling + nSample - 1; | |
438 | for( nSourceY = 0, nDestY = ( nTYOff / nVerSubsampling ); nSourceY < ( nBlockYSize / nVerSubsampling ); | |
439 | nSourceY += nOMult, nDestY ++) | |
440 | { | |
441 | for( nSourceX = 0, nDestX = ( nTXOff / nHorSubsampling ); nSourceX < ( nBlockXSize / nHorSubsampling ); | |
442 | nSourceX += nOMult, nDestX ++) | |
443 | { | |
444 | * ( pabyOTile + nDestY * nDestSampleRowSize | |
445 | + nDestX * nSampleBlockSize | |
446 | + nSampleOffsetInSampleBlock ) = | |
447 | * ( pabySrcTile + nSourceY * nSourceSampleRowSize | |
448 | + nSourceX * nSampleBlockSize | |
449 | + nSampleOffsetInSampleBlock ); | |
450 | } | |
451 | } | |
452 | #else | |
453 | nSampleOffsetInSampleBlock = nHorSubsampling * nVerSubsampling + nSample - 1; | |
454 | nSourceBaseInc = nOMult * nSampleBlockSize; | |
455 | for( nSourceY = 0, nDestY = ( nTYOff / nVerSubsampling ); nSourceY < ( nBlockYSize / nVerSubsampling); | |
456 | nSourceY += nOMult, nDestY ++) | |
457 | { | |
458 | pSourceBase = pabySrcTile + nSourceY * nSourceSampleRowSize | |
459 | + nSampleOffsetInSampleBlock; | |
460 | pSourceBaseEnd = pSourceBase + ( ( ( nBlockXSize / nHorSubsampling ) + nOMult - 1 ) / nOMult ) * nSourceBaseInc; | |
461 | pDestBase = pabyOTile + nDestY * nDestSampleRowSize | |
462 | + ( nTXOff / nHorSubsampling ) * nSampleBlockSize | |
463 | + nSampleOffsetInSampleBlock; | |
464 | for( ; pSourceBase < pSourceBaseEnd; pSourceBase += nSourceBaseInc, pDestBase += nSampleBlockSize) | |
465 | * pDestBase = * pSourceBase; | |
466 | } | |
467 | #endif | |
468 | } | |
469 | } | |
470 | else if( strncmp(pszResampling,"averag",6) == 0 | |
471 | || strncmp(pszResampling,"AVERAG",6) == 0 ) | |
472 | { | |
473 | if( nSample == 0 ) | |
474 | { | |
475 | for( nSourceY = 0, nDestY = nTYOff; nSourceY < nBlockYSize; nSourceY += nOMult, nDestY ++) | |
476 | { | |
477 | for( nSourceX = 0, nDestX = nTXOff; nSourceX < nBlockXSize; nSourceX += nOMult, nDestX ++) | |
478 | { | |
479 | nSourceXSecEnd = nSourceX + nOMult; | |
480 | if( nSourceXSecEnd > nBlockXSize ) | |
481 | nSourceXSecEnd = nBlockXSize; | |
482 | nSourceYSecEnd = nSourceY + nOMult; | |
483 | if( nSourceYSecEnd > nBlockYSize ) | |
484 | nSourceYSecEnd = nBlockYSize; | |
485 | nCummulator = 0; | |
486 | for( nSourceYSec = nSourceY; nSourceYSec < nSourceYSecEnd; nSourceYSec ++) | |
487 | { | |
488 | for( nSourceXSec = nSourceX; nSourceXSec < nSourceXSecEnd; nSourceXSec ++) | |
489 | { | |
490 | nCummulator += * ( pabySrcTile + ( nSourceYSec / nVerSubsampling ) * nSourceSampleRowSize | |
491 | + ( nSourceYSec % nVerSubsampling ) * nHorSubsampling | |
492 | + ( nSourceXSec / nHorSubsampling ) * nSampleBlockSize | |
493 | + ( nSourceXSec % nHorSubsampling ) ); | |
494 | } | |
495 | } | |
496 | nCummulatorCount = ( nSourceXSecEnd - nSourceX ) * ( nSourceYSecEnd - nSourceY ); | |
497 | * ( pabyOTile + ( nDestY / nVerSubsampling ) * nDestSampleRowSize | |
498 | + ( nDestY % nVerSubsampling ) * nHorSubsampling | |
499 | + ( nDestX / nHorSubsampling ) * nSampleBlockSize | |
500 | + ( nDestX % nHorSubsampling ) ) = | |
501 | ( ( nCummulator + ( nCummulatorCount >> 1 ) ) / nCummulatorCount ); | |
502 | } | |
503 | } | |
504 | } | |
505 | else | |
506 | { | |
507 | nSampleOffsetInSampleBlock = nHorSubsampling * nVerSubsampling + nSample - 1; | |
508 | for( nSourceY = 0, nDestY = ( nTYOff / nVerSubsampling ); nSourceY < ( nBlockYSize / nVerSubsampling ); | |
509 | nSourceY += nOMult, nDestY ++) | |
510 | { | |
511 | for( nSourceX = 0, nDestX = ( nTXOff / nHorSubsampling ); nSourceX < ( nBlockXSize / nHorSubsampling ); | |
512 | nSourceX += nOMult, nDestX ++) | |
513 | { | |
514 | nSourceXSecEnd = nSourceX + nOMult; | |
515 | if( nSourceXSecEnd > ( nBlockXSize / nHorSubsampling ) ) | |
516 | nSourceXSecEnd = ( nBlockXSize / nHorSubsampling ); | |
517 | nSourceYSecEnd = nSourceY + nOMult; | |
518 | if( nSourceYSecEnd > ( nBlockYSize / nVerSubsampling ) ) | |
519 | nSourceYSecEnd = ( nBlockYSize / nVerSubsampling ); | |
520 | nCummulator = 0; | |
521 | for( nSourceYSec = nSourceY; nSourceYSec < nSourceYSecEnd; nSourceYSec ++) | |
522 | { | |
523 | for( nSourceXSec = nSourceX; nSourceXSec < nSourceXSecEnd; nSourceXSec ++) | |
524 | { | |
525 | nCummulator += * ( pabySrcTile + nSourceYSec * nSourceSampleRowSize | |
526 | + nSourceXSec * nSampleBlockSize | |
527 | + nSampleOffsetInSampleBlock ); | |
528 | } | |
529 | } | |
530 | nCummulatorCount = ( nSourceXSecEnd - nSourceX ) * ( nSourceYSecEnd - nSourceY ); | |
531 | * ( pabyOTile + nDestY * nDestSampleRowSize | |
532 | + nDestX * nSampleBlockSize | |
533 | + nSampleOffsetInSampleBlock ) = | |
534 | ( ( nCummulator + ( nCummulatorCount >> 1 ) ) / nCummulatorCount ); | |
535 | } | |
536 | } | |
537 | } | |
538 | } | |
539 | } | |
540 | ||
541 | /************************************************************************/ | |
542 | /* TIFF_ProcessFullResBlock() */ | |
543 | /* */ | |
544 | /* Process one block of full res data, downsampling into each */ | |
545 | /* of the overviews. */ | |
546 | /************************************************************************/ | |
547 | ||
548 | void TIFF_ProcessFullResBlock( TIFF *hTIFF, int nPlanarConfig, | |
549 | int bSubsampled, int nHorSubsampling, int nVerSubsampling, | |
550 | int nOverviews, int * panOvList, | |
551 | int nBitsPerPixel, | |
552 | int nSamples, TIFFOvrCache ** papoRawBIs, | |
553 | int nSXOff, int nSYOff, | |
554 | unsigned char *pabySrcTile, | |
555 | int nBlockXSize, int nBlockYSize, | |
556 | int nSampleFormat, const char * pszResampling ) | |
557 | ||
558 | { | |
559 | int iOverview, iSample; | |
560 | ||
561 | for( iSample = 0; iSample < nSamples; iSample++ ) | |
562 | { | |
563 | /* | |
564 | * We have to read a tile/strip for each sample for | |
565 | * PLANARCONFIG_SEPARATE. Otherwise, we just read all the samples | |
566 | * at once when handling the first sample. | |
567 | */ | |
568 | if( nPlanarConfig == PLANARCONFIG_SEPARATE || iSample == 0 ) | |
569 | { | |
570 | if( TIFFIsTiled(hTIFF) ) | |
571 | { | |
572 | TIFFReadEncodedTile( hTIFF, | |
573 | TIFFComputeTile(hTIFF, nSXOff, nSYOff, | |
574 | 0, (tsample_t)iSample ), | |
575 | pabySrcTile, | |
576 | TIFFTileSize(hTIFF)); | |
577 | } | |
578 | else | |
579 | { | |
580 | TIFFReadEncodedStrip( hTIFF, | |
581 | TIFFComputeStrip(hTIFF, nSYOff, | |
582 | (tsample_t) iSample), | |
583 | pabySrcTile, | |
584 | TIFFStripSize(hTIFF) ); | |
585 | } | |
586 | } | |
587 | ||
588 | /* | |
589 | * Loop over destination overview layers | |
590 | */ | |
591 | for( iOverview = 0; iOverview < nOverviews; iOverview++ ) | |
592 | { | |
593 | TIFFOvrCache *poRBI = papoRawBIs[iOverview]; | |
594 | unsigned char *pabyOTile; | |
595 | int nTXOff, nTYOff, nOXOff, nOYOff, nOMult; | |
596 | int nOBlockXSize = poRBI->nBlockXSize; | |
597 | int nOBlockYSize = poRBI->nBlockYSize; | |
598 | int nSkewBits, nSampleByteOffset; | |
599 | ||
600 | /* | |
601 | * Fetch the destination overview tile | |
602 | */ | |
603 | nOMult = panOvList[iOverview]; | |
604 | nOXOff = (nSXOff/nOMult) / nOBlockXSize; | |
605 | nOYOff = (nSYOff/nOMult) / nOBlockYSize; | |
606 | ||
607 | if( bSubsampled ) | |
608 | { | |
609 | pabyOTile = TIFFGetOvrBlock_Subsampled( poRBI, nOXOff, nOYOff ); | |
610 | ||
611 | /* | |
612 | * Establish the offset into this tile at which we should | |
613 | * start placing data. | |
614 | */ | |
615 | nTXOff = (nSXOff - nOXOff*nOMult*nOBlockXSize) / nOMult; | |
616 | nTYOff = (nSYOff - nOYOff*nOMult*nOBlockYSize) / nOMult; | |
617 | ||
618 | ||
619 | #ifdef DBMALLOC | |
620 | malloc_chain_check( 1 ); | |
621 | #endif | |
622 | TIFF_DownSample_Subsampled( pabySrcTile, iSample, | |
623 | nBlockXSize, nBlockYSize, | |
624 | pabyOTile, | |
625 | poRBI->nBlockXSize, poRBI->nBlockYSize, | |
626 | nTXOff, nTYOff, | |
627 | nOMult, pszResampling, | |
628 | nHorSubsampling, nVerSubsampling ); | |
629 | #ifdef DBMALLOC | |
630 | malloc_chain_check( 1 ); | |
631 | #endif | |
632 | ||
633 | } | |
634 | else | |
635 | { | |
636 | ||
637 | pabyOTile = TIFFGetOvrBlock( poRBI, nOXOff, nOYOff, iSample ); | |
638 | ||
639 | /* | |
640 | * Establish the offset into this tile at which we should | |
641 | * start placing data. | |
642 | */ | |
643 | nTXOff = (nSXOff - nOXOff*nOMult*nOBlockXSize) / nOMult; | |
644 | nTYOff = (nSYOff - nOYOff*nOMult*nOBlockYSize) / nOMult; | |
645 | ||
646 | /* | |
647 | * Figure out the skew (extra space between ``our samples'') and | |
648 | * the byte offset to the first sample. | |
649 | */ | |
650 | assert( (nBitsPerPixel % 8) == 0 ); | |
651 | if( nPlanarConfig == PLANARCONFIG_SEPARATE ) | |
652 | { | |
653 | nSkewBits = 0; | |
654 | nSampleByteOffset = 0; | |
655 | } | |
656 | else | |
657 | { | |
658 | nSkewBits = nBitsPerPixel * (nSamples-1); | |
659 | nSampleByteOffset = (nBitsPerPixel/8) * iSample; | |
660 | } | |
661 | ||
662 | /* | |
663 | * Perform the downsampling. | |
664 | */ | |
665 | #ifdef DBMALLOC | |
666 | malloc_chain_check( 1 ); | |
667 | #endif | |
668 | TIFF_DownSample( pabySrcTile + nSampleByteOffset, | |
669 | nBlockXSize, nBlockYSize, | |
670 | nSkewBits, nBitsPerPixel, pabyOTile, | |
671 | poRBI->nBlockXSize, poRBI->nBlockYSize, | |
672 | nTXOff, nTYOff, | |
673 | nOMult, nSampleFormat, pszResampling ); | |
674 | #ifdef DBMALLOC | |
675 | malloc_chain_check( 1 ); | |
676 | #endif | |
677 | } | |
678 | } | |
679 | } | |
680 | } | |
681 | ||
682 | /************************************************************************/ | |
683 | /* TIFF_BuildOverviews() */ | |
684 | /* */ | |
685 | /* Build the requested list of overviews. Overviews are */ | |
686 | /* maintained in a bunch of temporary files and then these are */ | |
687 | /* written back to the TIFF file. Only one pass through the */ | |
688 | /* source TIFF file is made for any number of output */ | |
689 | /* overviews. */ | |
690 | /************************************************************************/ | |
691 | ||
692 | void TIFFBuildOverviews( TIFF *hTIFF, int nOverviews, int * panOvList, | |
693 | int bUseSubIFDs, const char *pszResampleMethod, | |
694 | int (*pfnProgress)( double, void * ), | |
695 | void * pProgressData ) | |
696 | ||
697 | { | |
698 | TIFFOvrCache **papoRawBIs; | |
699 | uint32 nXSize, nYSize, nBlockXSize, nBlockYSize; | |
700 | uint16 nBitsPerPixel, nPhotometric, nCompressFlag, nSamples, | |
701 | nPlanarConfig, nSampleFormat; | |
702 | int bSubsampled; | |
703 | uint16 nHorSubsampling, nVerSubsampling; | |
704 | int bTiled, nSXOff, nSYOff, i; | |
705 | unsigned char *pabySrcTile; | |
706 | uint16 *panRedMap, *panGreenMap, *panBlueMap; | |
707 | TIFFErrorHandler pfnWarning; | |
708 | ||
709 | /* -------------------------------------------------------------------- */ | |
710 | /* Get the base raster size. */ | |
711 | /* -------------------------------------------------------------------- */ | |
712 | TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize ); | |
713 | TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &nYSize ); | |
714 | ||
715 | TIFFGetField( hTIFF, TIFFTAG_BITSPERSAMPLE, &nBitsPerPixel ); | |
716 | /* TODO: nBitsPerPixel seems misnomer and may need renaming to nBitsPerSample */ | |
717 | TIFFGetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, &nSamples ); | |
718 | TIFFGetFieldDefaulted( hTIFF, TIFFTAG_PLANARCONFIG, &nPlanarConfig ); | |
719 | ||
720 | TIFFGetFieldDefaulted( hTIFF, TIFFTAG_PHOTOMETRIC, &nPhotometric ); | |
721 | TIFFGetFieldDefaulted( hTIFF, TIFFTAG_COMPRESSION, &nCompressFlag ); | |
722 | TIFFGetFieldDefaulted( hTIFF, TIFFTAG_SAMPLEFORMAT, &nSampleFormat ); | |
723 | ||
724 | if( nPhotometric == PHOTOMETRIC_YCBCR || nPhotometric == PHOTOMETRIC_ITULAB ) | |
725 | { | |
726 | if( nBitsPerPixel != 8 || nSamples != 3 || nPlanarConfig != PLANARCONFIG_CONTIG || | |
727 | nSampleFormat != SAMPLEFORMAT_UINT) | |
728 | { | |
729 | /* TODO: use of TIFFError is inconsistent with use of fprintf in addtiffo.c, sort out */ | |
730 | TIFFErrorExt( TIFFClientdata(hTIFF), "TIFFBuildOverviews", | |
731 | "File `%s' has an unsupported subsampling configuration.\n", | |
732 | TIFFFileName(hTIFF) ); | |
733 | /* If you need support for this particular flavor, please contact either | |
734 | * Frank Warmerdam warmerdam@pobox.com | |
735 | * Joris Van Damme info@awaresystems.be | |
736 | */ | |
737 | return; | |
738 | } | |
739 | bSubsampled = 1; | |
740 | TIFFGetField( hTIFF, TIFFTAG_YCBCRSUBSAMPLING, &nHorSubsampling, &nVerSubsampling ); | |
741 | /* TODO: find out if maybe TIFFGetFieldDefaulted is better choice for YCbCrSubsampling tag */ | |
742 | } | |
743 | else | |
744 | { | |
745 | if( nBitsPerPixel < 8 ) | |
746 | { | |
747 | /* TODO: use of TIFFError is inconsistent with use of fprintf in addtiffo.c, sort out */ | |
748 | TIFFErrorExt( TIFFClientdata(hTIFF), "TIFFBuildOverviews", | |
749 | "File `%s' has samples of %d bits per sample. Sample\n" | |
750 | "sizes of less than 8 bits per sample are not supported.\n", | |
751 | TIFFFileName(hTIFF), nBitsPerPixel ); | |
752 | return; | |
753 | } | |
754 | bSubsampled = 0; | |
755 | nHorSubsampling = 1; | |
756 | nVerSubsampling = 1; | |
757 | } | |
758 | ||
759 | /* -------------------------------------------------------------------- */ | |
760 | /* Turn off warnings to avoid alot of repeated warnings while */ | |
761 | /* rereading directories. */ | |
762 | /* -------------------------------------------------------------------- */ | |
763 | pfnWarning = TIFFSetWarningHandler( NULL ); | |
764 | ||
765 | /* -------------------------------------------------------------------- */ | |
766 | /* Get the base raster block size. */ | |
767 | /* -------------------------------------------------------------------- */ | |
768 | if( TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP, &(nBlockYSize) ) ) | |
769 | { | |
770 | nBlockXSize = nXSize; | |
771 | bTiled = FALSE; | |
772 | } | |
773 | else | |
774 | { | |
775 | TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &nBlockXSize ); | |
776 | TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &nBlockYSize ); | |
777 | bTiled = TRUE; | |
778 | } | |
779 | ||
780 | /* -------------------------------------------------------------------- */ | |
781 | /* Capture the pallette if there is one. */ | |
782 | /* -------------------------------------------------------------------- */ | |
783 | if( TIFFGetField( hTIFF, TIFFTAG_COLORMAP, | |
784 | &panRedMap, &panGreenMap, &panBlueMap ) ) | |
785 | { | |
786 | uint16 *panRed2, *panGreen2, *panBlue2; | |
787 | int nColorCount = 1 << nBitsPerPixel; | |
788 | ||
789 | panRed2 = (uint16 *) _TIFFmalloc(2*nColorCount); | |
790 | panGreen2 = (uint16 *) _TIFFmalloc(2*nColorCount); | |
791 | panBlue2 = (uint16 *) _TIFFmalloc(2*nColorCount); | |
792 | ||
793 | memcpy( panRed2, panRedMap, 2 * nColorCount ); | |
794 | memcpy( panGreen2, panGreenMap, 2 * nColorCount ); | |
795 | memcpy( panBlue2, panBlueMap, 2 * nColorCount ); | |
796 | ||
797 | panRedMap = panRed2; | |
798 | panGreenMap = panGreen2; | |
799 | panBlueMap = panBlue2; | |
800 | } | |
801 | else | |
802 | { | |
803 | panRedMap = panGreenMap = panBlueMap = NULL; | |
804 | } | |
805 | ||
806 | /* -------------------------------------------------------------------- */ | |
807 | /* Initialize overviews. */ | |
808 | /* -------------------------------------------------------------------- */ | |
809 | papoRawBIs = (TIFFOvrCache **) _TIFFmalloc(nOverviews*sizeof(void*)); | |
810 | ||
811 | for( i = 0; i < nOverviews; i++ ) | |
812 | { | |
813 | int nOXSize, nOYSize, nOBlockXSize, nOBlockYSize; | |
814 | uint32 nDirOffset; | |
815 | ||
816 | nOXSize = (nXSize + panOvList[i] - 1) / panOvList[i]; | |
817 | nOYSize = (nYSize + panOvList[i] - 1) / panOvList[i]; | |
818 | ||
819 | nOBlockXSize = MIN((int)nBlockXSize,nOXSize); | |
820 | nOBlockYSize = MIN((int)nBlockYSize,nOYSize); | |
821 | ||
822 | if( bTiled ) | |
823 | { | |
824 | if( (nOBlockXSize % 16) != 0 ) | |
825 | nOBlockXSize = nOBlockXSize + 16 - (nOBlockXSize % 16); | |
826 | ||
827 | if( (nOBlockYSize % 16) != 0 ) | |
828 | nOBlockYSize = nOBlockYSize + 16 - (nOBlockYSize % 16); | |
829 | } | |
830 | ||
831 | nDirOffset = TIFF_WriteOverview( hTIFF, nOXSize, nOYSize, | |
832 | nBitsPerPixel, nPlanarConfig, | |
833 | nSamples, nOBlockXSize, nOBlockYSize, | |
834 | bTiled, nCompressFlag, nPhotometric, | |
835 | nSampleFormat, | |
836 | panRedMap, panGreenMap, panBlueMap, | |
837 | bUseSubIFDs, | |
838 | nHorSubsampling, nVerSubsampling ); | |
839 | ||
840 | papoRawBIs[i] = TIFFCreateOvrCache( hTIFF, nDirOffset ); | |
841 | } | |
842 | ||
843 | if( panRedMap != NULL ) | |
844 | { | |
845 | _TIFFfree( panRedMap ); | |
846 | _TIFFfree( panGreenMap ); | |
847 | _TIFFfree( panBlueMap ); | |
848 | } | |
849 | ||
850 | /* -------------------------------------------------------------------- */ | |
851 | /* Allocate a buffer to hold a source block. */ | |
852 | /* -------------------------------------------------------------------- */ | |
853 | if( bTiled ) | |
854 | pabySrcTile = (unsigned char *) _TIFFmalloc(TIFFTileSize(hTIFF)); | |
855 | else | |
856 | pabySrcTile = (unsigned char *) _TIFFmalloc(TIFFStripSize(hTIFF)); | |
857 | ||
858 | /* -------------------------------------------------------------------- */ | |
859 | /* Loop over the source raster, applying data to the */ | |
860 | /* destination raster. */ | |
861 | /* -------------------------------------------------------------------- */ | |
862 | for( nSYOff = 0; nSYOff < (int) nYSize; nSYOff += nBlockYSize ) | |
863 | { | |
864 | for( nSXOff = 0; nSXOff < (int) nXSize; nSXOff += nBlockXSize ) | |
865 | { | |
866 | /* | |
867 | * Read and resample into the various overview images. | |
868 | */ | |
869 | ||
870 | TIFF_ProcessFullResBlock( hTIFF, nPlanarConfig, | |
871 | bSubsampled,nHorSubsampling,nVerSubsampling, | |
872 | nOverviews, panOvList, | |
873 | nBitsPerPixel, nSamples, papoRawBIs, | |
874 | nSXOff, nSYOff, pabySrcTile, | |
875 | nBlockXSize, nBlockYSize, | |
876 | nSampleFormat, pszResampleMethod ); | |
877 | } | |
878 | } | |
879 | ||
880 | _TIFFfree( pabySrcTile ); | |
881 | ||
882 | /* -------------------------------------------------------------------- */ | |
883 | /* Cleanup the rawblockedimage files. */ | |
884 | /* -------------------------------------------------------------------- */ | |
885 | for( i = 0; i < nOverviews; i++ ) | |
886 | { | |
887 | TIFFDestroyOvrCache( papoRawBIs[i] ); | |
888 | } | |
889 | ||
890 | if( papoRawBIs != NULL ) | |
891 | _TIFFfree( papoRawBIs ); | |
892 | ||
893 | TIFFSetWarningHandler( pfnWarning ); | |
894 | } | |
895 | ||
896 |