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