]>
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 | ||
80ed523f | 80 | uint32 TIFF_WriteOverview( TIFF *hTIFF, uint32 nXSize, uint32 nYSize, |
8414a40c VZ |
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 | { | |
80ed523f VZ |
92 | toff_t nBaseDirOffset; |
93 | toff_t nOffset; | |
94 | ||
95 | (void) bUseSubIFDs; | |
8414a40c VZ |
96 | |
97 | nBaseDirOffset = TIFFCurrentDirOffset( hTIFF ); | |
98 | ||
99 | TIFFCreateDirectory( hTIFF ); | |
100 | ||
101 | /* -------------------------------------------------------------------- */ | |
102 | /* Setup TIFF fields. */ | |
103 | /* -------------------------------------------------------------------- */ | |
104 | TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize ); | |
105 | TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize ); | |
106 | if( nSamples == 1 ) | |
107 | TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); | |
108 | else | |
109 | TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanarConfig ); | |
110 | ||
111 | TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerPixel ); | |
112 | TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples ); | |
113 | TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompressFlag ); | |
114 | TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric ); | |
115 | TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat ); | |
116 | ||
117 | if( bTiled ) | |
118 | { | |
119 | TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize ); | |
120 | TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ); | |
121 | } | |
122 | else | |
123 | TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nBlockYSize ); | |
124 | ||
125 | TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE ); | |
126 | ||
127 | if( nPhotometric == PHOTOMETRIC_YCBCR || nPhotometric == PHOTOMETRIC_ITULAB ) | |
128 | { | |
129 | TIFFSetField( hTIFF, TIFFTAG_YCBCRSUBSAMPLING, 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 ) | |
139 | { | |
140 | TIFFSetField( hTIFF, TIFFTAG_COLORMAP, 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, | |
80ed523f | 166 | uint32 nXSize, uint32 nYSize, |
8414a40c VZ |
167 | int nPixelOffset, int nLineOffset ) |
168 | { | |
80ed523f VZ |
169 | uint32 iXOff, iYOff; |
170 | int iSample; | |
8414a40c VZ |
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_UINT && nPixelBytes == 1 ) | |
183 | { | |
184 | padfSamples[iSample++] = *pabyData; | |
185 | } | |
186 | else if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 2 ) | |
187 | { | |
188 | padfSamples[iSample++] = ((uint16 *) pabyData)[0]; | |
189 | } | |
190 | else if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 4 ) | |
191 | { | |
192 | padfSamples[iSample++] = ((uint32 *) pabyData)[0]; | |
193 | } | |
194 | else if( nSampleFormat == SAMPLEFORMAT_INT && nPixelBytes == 2 ) | |
195 | { | |
196 | padfSamples[iSample++] = ((int16 *) pabyData)[0]; | |
197 | } | |
198 | else if( nSampleFormat == SAMPLEFORMAT_INT && nPixelBytes == 32 ) | |
199 | { | |
200 | padfSamples[iSample++] = ((int32 *) pabyData)[0]; | |
201 | } | |
202 | else if( nSampleFormat == SAMPLEFORMAT_IEEEFP && nPixelBytes == 4 ) | |
203 | { | |
204 | padfSamples[iSample++] = ((float *) pabyData)[0]; | |
205 | } | |
206 | else if( nSampleFormat == SAMPLEFORMAT_IEEEFP && 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_UINT && nPixelBytes == 1 ) | |
224 | { | |
225 | *pabyData = (unsigned char) MAX(0,MIN(255,dfValue)); | |
226 | } | |
227 | else if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 2 ) | |
228 | { | |
229 | *((uint16 *)pabyData) = (uint16) MAX(0,MIN(65535,dfValue)); | |
230 | } | |
231 | else if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 4 ) | |
232 | { | |
233 | *((uint32 *)pabyData) = (uint32) dfValue; | |
234 | } | |
235 | else if( nSampleFormat == SAMPLEFORMAT_INT && nPixelBytes == 2 ) | |
236 | { | |
237 | *((int16 *)pabyData) = (int16) MAX(-32768,MIN(32767,dfValue)); | |
238 | } | |
239 | else if( nSampleFormat == SAMPLEFORMAT_INT && nPixelBytes == 32 ) | |
240 | { | |
241 | *((int32 *)pabyData) = (int32) dfValue; | |
242 | } | |
243 | else if( nSampleFormat == SAMPLEFORMAT_IEEEFP && nPixelBytes == 4 ) | |
244 | { | |
245 | *((float *)pabyData) = (float) dfValue; | |
246 | } | |
247 | else if( nSampleFormat == SAMPLEFORMAT_IEEEFP && 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, | |
80ed523f | 262 | uint32 nBlockXSize, uint32 nBlockYSize, |
8414a40c VZ |
263 | int nPixelSkewBits, int nBitsPerPixel, |
264 | unsigned char * pabyOTile, | |
80ed523f VZ |
265 | uint32 nOBlockXSize, uint32 nOBlockYSize, |
266 | uint32 nTXOff, uint32 nTYOff, int nOMult, | |
8414a40c VZ |
267 | int nSampleFormat, const char * pszResampling ) |
268 | ||
269 | { | |
80ed523f VZ |
270 | uint32 i, j; |
271 | int k, nPixelBytes = (nBitsPerPixel) / 8; | |
8414a40c VZ |
272 | int nPixelGroupBytes = (nBitsPerPixel+nPixelSkewBits)/8; |
273 | unsigned char *pabySrc, *pabyDst; | |
274 | double *padfSamples; | |
275 | ||
276 | assert( nBitsPerPixel >= 8 ); | |
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) == 0 | |
297 | || 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) == 0 | |
324 | || 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; | |
80ed523f | 331 | uint32 nXSize, nYSize, iSample; |
8414a40c VZ |
332 | |
333 | if( i + nTXOff >= nOBlockXSize ) | |
334 | break; | |
335 | ||
80ed523f VZ |
336 | nXSize = MIN((uint32)nOMult,nBlockXSize-i); |
337 | nYSize = MIN((uint32)nOMult,nBlockYSize-j); | |
8414a40c VZ |
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 | ||
80ed523f VZ |
363 | /************************************************************************/ |
364 | /* TIFF_DownSample_Subsampled() */ | |
365 | /************************************************************************/ | |
8414a40c VZ |
366 | static |
367 | void TIFF_DownSample_Subsampled( unsigned char *pabySrcTile, int nSample, | |
80ed523f | 368 | uint32 nBlockXSize, uint32 nBlockYSize, |
8414a40c | 369 | unsigned char * pabyOTile, |
80ed523f VZ |
370 | uint32 nOBlockXSize, uint32 nOBlockYSize, |
371 | uint32 nTXOff, uint32 nTYOff, int nOMult, | |
372 | const char *pszResampling, | |
8414a40c VZ |
373 | int nHorSubsampling, int nVerSubsampling ) |
374 | { | |
375 | /* TODO: test with variety of subsampling values, and incovinient tile/strip sizes */ | |
80ed523f | 376 | int nSampleBlockSize; |
8414a40c VZ |
377 | int nSourceSampleRowSize; |
378 | int nDestSampleRowSize; | |
80ed523f VZ |
379 | uint32 nSourceX, nSourceY; |
380 | uint32 nSourceXSec, nSourceYSec; | |
381 | uint32 nSourceXSecEnd, nSourceYSecEnd; | |
382 | uint32 nDestX, nDestY; | |
8414a40c | 383 | int nSampleOffsetInSampleBlock; |
8414a40c VZ |
384 | unsigned int nCummulator; |
385 | unsigned int nCummulatorCount; | |
386 | ||
387 | nSampleBlockSize = nHorSubsampling * nVerSubsampling + 2; | |
80ed523f VZ |
388 | nSourceSampleRowSize = |
389 | ( ( nBlockXSize + nHorSubsampling - 1 ) / nHorSubsampling ) * nSampleBlockSize; | |
390 | nDestSampleRowSize = | |
391 | ( ( nOBlockXSize + nHorSubsampling - 1 ) / nHorSubsampling ) * nSampleBlockSize; | |
8414a40c VZ |
392 | |
393 | if( strncmp(pszResampling,"nearest",4) == 0 | |
80ed523f VZ |
394 | || strncmp(pszResampling,"NEAR",4) == 0 ) |
395 | { | |
8414a40c VZ |
396 | if( nSample == 0 ) |
397 | { | |
80ed523f VZ |
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 ++) | |
8414a40c | 408 | { |
80ed523f VZ |
409 | if( nDestX >= nOBlockXSize ) |
410 | break; | |
411 | ||
8414a40c | 412 | * ( pabyOTile + ( nDestY / nVerSubsampling ) * nDestSampleRowSize |
80ed523f VZ |
413 | + ( nDestY % nVerSubsampling ) * nHorSubsampling |
414 | + ( nDestX / nHorSubsampling ) * nSampleBlockSize | |
415 | + ( nDestX % nHorSubsampling ) ) = | |
8414a40c | 416 | * ( pabySrcTile + ( nSourceY / nVerSubsampling ) * nSourceSampleRowSize |
80ed523f VZ |
417 | + ( nSourceY % nVerSubsampling ) * nHorSubsampling |
418 | + ( nSourceX / nHorSubsampling ) * nSampleBlockSize | |
419 | + ( nSourceX % nHorSubsampling ) ); | |
8414a40c VZ |
420 | } |
421 | } | |
8414a40c VZ |
422 | } |
423 | else | |
424 | { | |
8414a40c | 425 | nSampleOffsetInSampleBlock = nHorSubsampling * nVerSubsampling + nSample - 1; |
80ed523f VZ |
426 | for( nSourceY = 0, nDestY = ( nTYOff / nVerSubsampling ); |
427 | nSourceY < ( nBlockYSize / nVerSubsampling ); | |
428 | nSourceY += nOMult, nDestY ++) | |
8414a40c | 429 | { |
80ed523f VZ |
430 | if( nDestY*nVerSubsampling >= nOBlockYSize ) |
431 | break; | |
432 | ||
433 | for( nSourceX = 0, nDestX = ( nTXOff / nHorSubsampling ); | |
434 | nSourceX < ( nBlockXSize / nHorSubsampling ); | |
435 | nSourceX += nOMult, nDestX ++) | |
8414a40c | 436 | { |
80ed523f VZ |
437 | if( nDestX*nHorSubsampling >= nOBlockXSize ) |
438 | break; | |
439 | ||
8414a40c | 440 | * ( pabyOTile + nDestY * nDestSampleRowSize |
80ed523f VZ |
441 | + nDestX * nSampleBlockSize |
442 | + nSampleOffsetInSampleBlock ) = | |
8414a40c | 443 | * ( pabySrcTile + nSourceY * nSourceSampleRowSize |
80ed523f VZ |
444 | + nSourceX * nSampleBlockSize |
445 | + nSampleOffsetInSampleBlock ); | |
8414a40c VZ |
446 | } |
447 | } | |
8414a40c VZ |
448 | } |
449 | } | |
450 | else if( strncmp(pszResampling,"averag",6) == 0 | |
80ed523f | 451 | || strncmp(pszResampling,"AVERAG",6) == 0 ) |
8414a40c VZ |
452 | { |
453 | if( nSample == 0 ) | |
454 | { | |
455 | for( nSourceY = 0, nDestY = nTYOff; nSourceY < nBlockYSize; nSourceY += nOMult, nDestY ++) | |
456 | { | |
80ed523f VZ |
457 | if( nDestY >= nOBlockYSize ) |
458 | break; | |
459 | ||
8414a40c VZ |
460 | for( nSourceX = 0, nDestX = nTXOff; nSourceX < nBlockXSize; nSourceX += nOMult, nDestX ++) |
461 | { | |
80ed523f VZ |
462 | if( nDestX >= nOBlockXSize ) |
463 | break; | |
464 | ||
8414a40c VZ |
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 | |
80ed523f VZ |
477 | + ( nSourceYSec % nVerSubsampling ) * nHorSubsampling |
478 | + ( nSourceXSec / nHorSubsampling ) * nSampleBlockSize | |
479 | + ( nSourceXSec % nHorSubsampling ) ); | |
8414a40c VZ |
480 | } |
481 | } | |
482 | nCummulatorCount = ( nSourceXSecEnd - nSourceX ) * ( nSourceYSecEnd - nSourceY ); | |
483 | * ( pabyOTile + ( nDestY / nVerSubsampling ) * nDestSampleRowSize | |
80ed523f VZ |
484 | + ( nDestY % nVerSubsampling ) * nHorSubsampling |
485 | + ( nDestX / nHorSubsampling ) * nSampleBlockSize | |
486 | + ( nDestX % nHorSubsampling ) ) = | |
8414a40c VZ |
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 ); | |
80ed523f | 495 | nSourceY += nOMult, nDestY ++) |
8414a40c | 496 | { |
80ed523f VZ |
497 | if( nDestY*nVerSubsampling >= nOBlockYSize ) |
498 | break; | |
499 | ||
8414a40c | 500 | for( nSourceX = 0, nDestX = ( nTXOff / nHorSubsampling ); nSourceX < ( nBlockXSize / nHorSubsampling ); |
80ed523f | 501 | nSourceX += nOMult, nDestX ++) |
8414a40c | 502 | { |
80ed523f VZ |
503 | if( nDestX*nHorSubsampling >= nOBlockXSize ) |
504 | break; | |
505 | ||
8414a40c VZ |
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 | |
80ed523f VZ |
518 | + nSourceXSec * nSampleBlockSize |
519 | + nSampleOffsetInSampleBlock ); | |
8414a40c VZ |
520 | } |
521 | } | |
522 | nCummulatorCount = ( nSourceXSecEnd - nSourceX ) * ( nSourceYSecEnd - nSourceY ); | |
523 | * ( pabyOTile + nDestY * nDestSampleRowSize | |
80ed523f VZ |
524 | + nDestX * nSampleBlockSize |
525 | + nSampleOffsetInSampleBlock ) = | |
8414a40c VZ |
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, | |
80ed523f VZ |
541 | int bSubsampled, |
542 | int nHorSubsampling, int nVerSubsampling, | |
8414a40c VZ |
543 | int nOverviews, int * panOvList, |
544 | int nBitsPerPixel, | |
545 | int nSamples, TIFFOvrCache ** papoRawBIs, | |
80ed523f | 546 | uint32 nSXOff, uint32 nSYOff, |
8414a40c | 547 | unsigned char *pabySrcTile, |
80ed523f | 548 | uint32 nBlockXSize, uint32 nBlockYSize, |
8414a40c VZ |
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_SEPARATE || 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; | |
80ed523f VZ |
588 | uint32 nTXOff, nTYOff, nOXOff, nOYOff, nOMult; |
589 | uint32 nOBlockXSize = poRBI->nBlockXSize; | |
590 | uint32 nOBlockYSize = poRBI->nBlockYSize; | |
591 | int nSkewBits, nSampleByteOffset; | |
8414a40c VZ |
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 ); | |
644 | if( nPlanarConfig == PLANARCONFIG_SEPARATE ) | |
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 | ||
80ed523f VZ |
702 | (void) pfnProgress; |
703 | (void) pProgressData; | |
704 | ||
8414a40c VZ |
705 | /* -------------------------------------------------------------------- */ |
706 | /* Get the base raster size. */ | |
707 | /* -------------------------------------------------------------------- */ | |
708 | TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize ); | |
709 | TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &nYSize ); | |
710 | ||
711 | TIFFGetField( hTIFF, TIFFTAG_BITSPERSAMPLE, &nBitsPerPixel ); | |
712 | /* TODO: nBitsPerPixel seems misnomer and may need renaming to nBitsPerSample */ | |
713 | TIFFGetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, &nSamples ); | |
714 | TIFFGetFieldDefaulted( hTIFF, TIFFTAG_PLANARCONFIG, &nPlanarConfig ); | |
715 | ||
716 | TIFFGetFieldDefaulted( hTIFF, TIFFTAG_PHOTOMETRIC, &nPhotometric ); | |
717 | TIFFGetFieldDefaulted( hTIFF, TIFFTAG_COMPRESSION, &nCompressFlag ); | |
718 | TIFFGetFieldDefaulted( hTIFF, TIFFTAG_SAMPLEFORMAT, &nSampleFormat ); | |
719 | ||
720 | if( nPhotometric == PHOTOMETRIC_YCBCR || nPhotometric == PHOTOMETRIC_ITULAB ) | |
721 | { | |
722 | if( nBitsPerPixel != 8 || nSamples != 3 || nPlanarConfig != PLANARCONFIG_CONTIG || | |
723 | nSampleFormat != SAMPLEFORMAT_UINT) | |
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_YCBCRSUBSAMPLING, &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 ); | |
760 | ||
761 | /* -------------------------------------------------------------------- */ | |
762 | /* Get the base raster block size. */ | |
763 | /* -------------------------------------------------------------------- */ | |
764 | if( TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP, &(nBlockYSize) ) ) | |
765 | { | |
766 | nBlockXSize = nXSize; | |
767 | bTiled = FALSE; | |
768 | } | |
769 | else | |
770 | { | |
771 | TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &nBlockXSize ); | |
772 | TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &nBlockYSize ); | |
773 | bTiled = TRUE; | |
774 | } | |
775 | ||
776 | /* -------------------------------------------------------------------- */ | |
777 | /* Capture the pallette if there is one. */ | |
778 | /* -------------------------------------------------------------------- */ | |
779 | if( TIFFGetField( hTIFF, TIFFTAG_COLORMAP, | |
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; | |
800 | } | |
801 | ||
802 | /* -------------------------------------------------------------------- */ | |
803 | /* Initialize overviews. */ | |
804 | /* -------------------------------------------------------------------- */ | |
805 | papoRawBIs = (TIFFOvrCache **) _TIFFmalloc(nOverviews*sizeof(void*)); | |
806 | ||
807 | for( i = 0; i < nOverviews; i++ ) | |
808 | { | |
80ed523f VZ |
809 | uint32 nOXSize, nOYSize, nOBlockXSize, nOBlockYSize; |
810 | toff_t nDirOffset; | |
8414a40c VZ |
811 | |
812 | nOXSize = (nXSize + panOvList[i] - 1) / panOvList[i]; | |
813 | nOYSize = (nYSize + panOvList[i] - 1) / panOvList[i]; | |
814 | ||
80ed523f VZ |
815 | nOBlockXSize = MIN(nBlockXSize,nOXSize); |
816 | nOBlockYSize = MIN(nBlockYSize,nOYSize); | |
8414a40c VZ |
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 ) | |
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 ) | |
887 | _TIFFfree( papoRawBIs ); | |
888 | ||
889 | TIFFSetWarningHandler( pfnWarning ); | |
890 | } | |
891 | ||
892 | ||
80ed523f VZ |
893 | /* |
894 | * Local Variables: | |
895 | * mode: c | |
896 | * c-basic-offset: 8 | |
897 | * fill-column: 78 | |
898 | * End: | |
899 | */ |