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
68void 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
80uint32 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
161static void
162TIFF_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
215static void
216TIFF_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
257static
258void 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/************************************************************************/
361/*                     TIFF_DownSample_Subsampled()                     */
362/************************************************************************/
363static
364void TIFF_DownSample_Subsampled( unsigned char *pabySrcTile, int nSample,
365                                 int nBlockXSize, int nBlockYSize,
366                                 unsigned char * pabyOTile,
367                                 int nOBlockXSize, int nOBlockYSize,
368                                 int nTXOff, int nTYOff, int nOMult,
369                                 const char * pszResampling,
370                                 int nHorSubsampling, int nVerSubsampling )
371{
372    /* TODO: test with variety of subsampling values, and incovinient tile/strip sizes */
373    int nSampleBlockSize;
374    int nSourceSampleRowSize;
375    int nDestSampleRowSize;
376    int nSourceX, nSourceY;
377    int nSourceXSec, nSourceYSec;
378    int nSourceXSecEnd, nSourceYSecEnd;
379    int nDestX, nDestY;
380    int nSampleOffsetInSampleBlock;
381    unsigned char * pSourceBase;
382    unsigned char * pDestBase;
383    int nSourceBaseInc;
384    unsigned char * pSourceBaseEnd;
385    unsigned int nCummulator;
386    unsigned int nCummulatorCount;
387
388    nSampleBlockSize = nHorSubsampling * nVerSubsampling + 2;
389    nSourceSampleRowSize =
390        ( ( nBlockXSize + nHorSubsampling - 1 ) / nHorSubsampling ) * nSampleBlockSize;
391    nDestSampleRowSize =
392        ( ( nOBlockXSize + nHorSubsampling - 1 ) / nHorSubsampling ) * nSampleBlockSize;
393
394    if( strncmp(pszResampling,"nearest",4) == 0
395        || strncmp(pszResampling,"NEAR",4) == 0 )
396    {
397    	if( nSample == 0 )
398        {
399            for( nSourceY = 0, nDestY = nTYOff;
400                 nSourceY < nBlockYSize;
401                 nSourceY += nOMult, nDestY ++)
402            {
403                if( nDestY >= nOBlockYSize )
404                    break;
405
406                for( nSourceX = 0, nDestX = nTXOff;
407                     nSourceX < nBlockXSize;
408                     nSourceX += nOMult, nDestX ++)
409                {
410                    if( nDestX >= nOBlockXSize )
411                        break;
412
413                    * ( pabyOTile + ( nDestY / nVerSubsampling ) * nDestSampleRowSize
414                        + ( nDestY % nVerSubsampling ) * nHorSubsampling
415                        + ( nDestX / nHorSubsampling ) * nSampleBlockSize
416                        + ( nDestX % nHorSubsampling ) ) =
417                        * ( pabySrcTile + ( nSourceY / nVerSubsampling ) * nSourceSampleRowSize
418                            + ( nSourceY % nVerSubsampling ) * nHorSubsampling
419                            + ( nSourceX / nHorSubsampling ) * nSampleBlockSize
420                            + ( nSourceX % nHorSubsampling ) );
421                }
422            }
423        }
424        else
425        {
426            nSampleOffsetInSampleBlock = nHorSubsampling * nVerSubsampling + nSample - 1;
427            for( nSourceY = 0, nDestY = ( nTYOff / nVerSubsampling );
428                 nSourceY < ( nBlockYSize / nVerSubsampling );
429                 nSourceY += nOMult, nDestY ++)
430            {
431                if( nDestY*nVerSubsampling >= nOBlockYSize )
432                    break;
433
434            	for( nSourceX = 0, nDestX = ( nTXOff / nHorSubsampling );
435                     nSourceX < ( nBlockXSize / nHorSubsampling );
436                     nSourceX += nOMult, nDestX ++)
437                {
438                    if( nDestX*nHorSubsampling >= nOBlockXSize )
439                        break;
440
441                    * ( pabyOTile + nDestY * nDestSampleRowSize
442                        + nDestX * nSampleBlockSize
443                        + nSampleOffsetInSampleBlock ) =
444                    	* ( pabySrcTile + nSourceY * nSourceSampleRowSize
445                            + nSourceX * nSampleBlockSize
446                            + nSampleOffsetInSampleBlock );
447                }
448            }
449        }
450    }
451    else if( strncmp(pszResampling,"averag",6) == 0
452             || strncmp(pszResampling,"AVERAG",6) == 0 )
453    {
454    	if( nSample == 0 )
455        {
456            for( nSourceY = 0, nDestY = nTYOff; nSourceY < nBlockYSize; nSourceY += nOMult, nDestY ++)
457            {
458                if( nDestY >= nOBlockYSize )
459                    break;
460
461                for( nSourceX = 0, nDestX = nTXOff; nSourceX < nBlockXSize; nSourceX += nOMult, nDestX ++)
462                {
463                    if( nDestX >= nOBlockXSize )
464                        break;
465
466                    nSourceXSecEnd = nSourceX + nOMult;
467                    if( nSourceXSecEnd > nBlockXSize )
468                        nSourceXSecEnd = nBlockXSize;
469                    nSourceYSecEnd = nSourceY + nOMult;
470                    if( nSourceYSecEnd > nBlockYSize )
471                        nSourceYSecEnd = nBlockYSize;
472                    nCummulator = 0;
473                    for( nSourceYSec = nSourceY; nSourceYSec < nSourceYSecEnd; nSourceYSec ++)
474                    {
475                        for( nSourceXSec = nSourceX; nSourceXSec < nSourceXSecEnd; nSourceXSec ++)
476                        {
477                            nCummulator += * ( pabySrcTile + ( nSourceYSec / nVerSubsampling ) * nSourceSampleRowSize
478                                               + ( nSourceYSec % nVerSubsampling ) * nHorSubsampling
479                                               + ( nSourceXSec / nHorSubsampling ) * nSampleBlockSize
480                                               + ( nSourceXSec % nHorSubsampling ) );
481                        }
482                    }
483                    nCummulatorCount = ( nSourceXSecEnd - nSourceX ) * ( nSourceYSecEnd - nSourceY );
484                    * ( pabyOTile + ( nDestY / nVerSubsampling ) * nDestSampleRowSize
485                        + ( nDestY % nVerSubsampling ) * nHorSubsampling
486                        + ( nDestX / nHorSubsampling ) * nSampleBlockSize
487                        + ( nDestX % nHorSubsampling ) ) =
488                        ( ( nCummulator + ( nCummulatorCount >> 1 ) ) / nCummulatorCount );
489                }
490            }
491        }
492        else
493        {
494            nSampleOffsetInSampleBlock = nHorSubsampling * nVerSubsampling + nSample - 1;
495            for( nSourceY = 0, nDestY = ( nTYOff / nVerSubsampling ); nSourceY < ( nBlockYSize / nVerSubsampling );
496                 nSourceY += nOMult, nDestY ++)
497            {
498                if( nDestY*nVerSubsampling >= nOBlockYSize )
499                    break;
500
501                for( nSourceX = 0, nDestX = ( nTXOff / nHorSubsampling ); nSourceX < ( nBlockXSize / nHorSubsampling );
502                     nSourceX += nOMult, nDestX ++)
503                {
504                    if( nDestX*nHorSubsampling >= nOBlockXSize )
505                        break;
506
507                    nSourceXSecEnd = nSourceX + nOMult;
508                    if( nSourceXSecEnd > ( nBlockXSize / nHorSubsampling ) )
509                        nSourceXSecEnd = ( nBlockXSize / nHorSubsampling );
510                    nSourceYSecEnd = nSourceY + nOMult;
511                    if( nSourceYSecEnd > ( nBlockYSize / nVerSubsampling ) )
512                        nSourceYSecEnd = ( nBlockYSize / nVerSubsampling );
513                    nCummulator = 0;
514                    for( nSourceYSec = nSourceY; nSourceYSec < nSourceYSecEnd; nSourceYSec ++)
515                    {
516                        for( nSourceXSec = nSourceX; nSourceXSec < nSourceXSecEnd; nSourceXSec ++)
517                        {
518                            nCummulator += * ( pabySrcTile + nSourceYSec * nSourceSampleRowSize
519                                               + nSourceXSec * nSampleBlockSize
520                                               + nSampleOffsetInSampleBlock );
521                        }
522                    }
523                    nCummulatorCount = ( nSourceXSecEnd - nSourceX ) * ( nSourceYSecEnd - nSourceY );
524                    * ( pabyOTile + nDestY * nDestSampleRowSize
525                        + nDestX * nSampleBlockSize
526                        + nSampleOffsetInSampleBlock ) =
527                        ( ( nCummulator + ( nCummulatorCount >> 1 ) ) / nCummulatorCount );
528                }
529            }
530        }
531    }
532}
533
534/************************************************************************/
535/*                      TIFF_ProcessFullResBlock()                      */
536/*                                                                      */
537/*      Process one block of full res data, downsampling into each      */
538/*      of the overviews.                                               */
539/************************************************************************/
540
541void TIFF_ProcessFullResBlock( TIFF *hTIFF, int nPlanarConfig,
542                               int bSubsampled, int nHorSubsampling, int nVerSubsampling,
543                               int nOverviews, int * panOvList,
544                               int nBitsPerPixel,
545                               int nSamples, TIFFOvrCache ** papoRawBIs,
546                               int nSXOff, int nSYOff,
547                               unsigned char *pabySrcTile,
548                               int nBlockXSize, int nBlockYSize,
549                               int nSampleFormat, const char * pszResampling )
550
551{
552    int		iOverview, iSample;
553
554    for( iSample = 0; iSample < nSamples; iSample++ )
555    {
556        /*
557         * We have to read a tile/strip for each sample for
558         * PLANARCONFIG_SEPARATE.  Otherwise, we just read all the samples
559         * at once when handling the first sample.
560         */
561        if( nPlanarConfig == PLANARCONFIG_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;
588            int	nTXOff, nTYOff, nOXOff, nOYOff, nOMult;
589            int	nOBlockXSize = poRBI->nBlockXSize;
590            int	nOBlockYSize = poRBI->nBlockYSize;
591            int	nSkewBits, nSampleByteOffset;
592
593            /*
594             * Fetch the destination overview tile
595             */
596            nOMult = panOvList[iOverview];
597            nOXOff = (nSXOff/nOMult) / nOBlockXSize;
598            nOYOff = (nSYOff/nOMult) / nOBlockYSize;
599
600            if( bSubsampled )
601            {
602                pabyOTile = TIFFGetOvrBlock_Subsampled( poRBI, nOXOff, nOYOff );
603
604                /*
605                 * Establish the offset into this tile at which we should
606                 * start placing data.
607                 */
608                nTXOff = (nSXOff - nOXOff*nOMult*nOBlockXSize) / nOMult;
609                nTYOff = (nSYOff - nOYOff*nOMult*nOBlockYSize) / nOMult;
610
611
612#ifdef DBMALLOC
613                malloc_chain_check( 1 );
614#endif
615                TIFF_DownSample_Subsampled( pabySrcTile, iSample,
616                                            nBlockXSize, nBlockYSize,
617                                            pabyOTile,
618                                            poRBI->nBlockXSize, poRBI->nBlockYSize,
619                                            nTXOff, nTYOff,
620                                            nOMult, pszResampling,
621                                            nHorSubsampling, nVerSubsampling );
622#ifdef DBMALLOC
623                malloc_chain_check( 1 );
624#endif
625
626            }
627            else
628            {
629
630                pabyOTile = TIFFGetOvrBlock( poRBI, nOXOff, nOYOff, iSample );
631
632                /*
633                 * Establish the offset into this tile at which we should
634                 * start placing data.
635                 */
636                nTXOff = (nSXOff - nOXOff*nOMult*nOBlockXSize) / nOMult;
637                nTYOff = (nSYOff - nOYOff*nOMult*nOBlockYSize) / nOMult;
638
639                /*
640                 * Figure out the skew (extra space between ``our samples'') and
641                 * the byte offset to the first sample.
642                 */
643                assert( (nBitsPerPixel % 8) == 0 );
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
685void TIFFBuildOverviews( TIFF *hTIFF, int nOverviews, int * panOvList,
686                         int bUseSubIFDs, const char *pszResampleMethod,
687                         int (*pfnProgress)( double, void * ),
688                         void * pProgressData )
689
690{
691    TIFFOvrCache	**papoRawBIs;
692    uint32		nXSize, nYSize, nBlockXSize, nBlockYSize;
693    uint16		nBitsPerPixel, nPhotometric, nCompressFlag, nSamples,
694        nPlanarConfig, nSampleFormat;
695    int         bSubsampled;
696    uint16      nHorSubsampling, nVerSubsampling;
697    int			bTiled, nSXOff, nSYOff, i;
698    unsigned char	*pabySrcTile;
699    uint16		*panRedMap, *panGreenMap, *panBlueMap;
700    TIFFErrorHandler    pfnWarning;
701
702/* -------------------------------------------------------------------- */
703/*      Get the base raster size.                                       */
704/* -------------------------------------------------------------------- */
705    TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize );
706    TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &nYSize );
707
708    TIFFGetField( hTIFF, TIFFTAG_BITSPERSAMPLE, &nBitsPerPixel );
709    /* TODO: nBitsPerPixel seems misnomer and may need renaming to nBitsPerSample */
710    TIFFGetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, &nSamples );
711    TIFFGetFieldDefaulted( hTIFF, TIFFTAG_PLANARCONFIG, &nPlanarConfig );
712
713    TIFFGetFieldDefaulted( hTIFF, TIFFTAG_PHOTOMETRIC, &nPhotometric );
714    TIFFGetFieldDefaulted( hTIFF, TIFFTAG_COMPRESSION, &nCompressFlag );
715    TIFFGetFieldDefaulted( hTIFF, TIFFTAG_SAMPLEFORMAT, &nSampleFormat );
716
717    if( nPhotometric == PHOTOMETRIC_YCBCR || nPhotometric == PHOTOMETRIC_ITULAB )
718    {
719        if( nBitsPerPixel != 8 || nSamples != 3 || nPlanarConfig != PLANARCONFIG_CONTIG ||
720            nSampleFormat != SAMPLEFORMAT_UINT)
721        {
722            /* TODO: use of TIFFError is inconsistent with use of fprintf in addtiffo.c, sort out */
723            TIFFErrorExt( TIFFClientdata(hTIFF), "TIFFBuildOverviews",
724                          "File `%s' has an unsupported subsampling configuration.\n",
725                          TIFFFileName(hTIFF) );
726            /* If you need support for this particular flavor, please contact either
727             * Frank Warmerdam warmerdam@pobox.com
728             * Joris Van Damme info@awaresystems.be
729             */
730            return;
731        }
732        bSubsampled = 1;
733        TIFFGetField( hTIFF, TIFFTAG_YCBCRSUBSAMPLING, &nHorSubsampling, &nVerSubsampling );
734        /* TODO: find out if maybe TIFFGetFieldDefaulted is better choice for YCbCrSubsampling tag */
735    }
736    else
737    {
738        if( nBitsPerPixel < 8 )
739        {
740            /* TODO: use of TIFFError is inconsistent with use of fprintf in addtiffo.c, sort out */
741            TIFFErrorExt( TIFFClientdata(hTIFF), "TIFFBuildOverviews",
742                          "File `%s' has samples of %d bits per sample.  Sample\n"
743                          "sizes of less than 8 bits per sample are not supported.\n",
744                          TIFFFileName(hTIFF), nBitsPerPixel );
745            return;
746        }
747        bSubsampled = 0;
748        nHorSubsampling = 1;
749        nVerSubsampling = 1;
750    }
751
752/* -------------------------------------------------------------------- */
753/*      Turn off warnings to avoid alot of repeated warnings while      */
754/*      rereading directories.                                          */
755/* -------------------------------------------------------------------- */
756    pfnWarning = TIFFSetWarningHandler( NULL );
757
758/* -------------------------------------------------------------------- */
759/*      Get the base raster block size.                                 */
760/* -------------------------------------------------------------------- */
761    if( TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP, &(nBlockYSize) ) )
762    {
763        nBlockXSize = nXSize;
764        bTiled = FALSE;
765    }
766    else
767    {
768        TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &nBlockXSize );
769        TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &nBlockYSize );
770        bTiled = TRUE;
771    }
772
773/* -------------------------------------------------------------------- */
774/*	Capture the pallette if there is one.				*/
775/* -------------------------------------------------------------------- */
776    if( TIFFGetField( hTIFF, TIFFTAG_COLORMAP,
777                      &panRedMap, &panGreenMap, &panBlueMap ) )
778    {
779        uint16		*panRed2, *panGreen2, *panBlue2;
780        int             nColorCount = 1 << nBitsPerPixel;
781
782        panRed2 = (uint16 *) _TIFFmalloc(2*nColorCount);
783        panGreen2 = (uint16 *) _TIFFmalloc(2*nColorCount);
784        panBlue2 = (uint16 *) _TIFFmalloc(2*nColorCount);
785
786        memcpy( panRed2, panRedMap, 2 * nColorCount );
787        memcpy( panGreen2, panGreenMap, 2 * nColorCount );
788        memcpy( panBlue2, panBlueMap, 2 * nColorCount );
789
790        panRedMap = panRed2;
791        panGreenMap = panGreen2;
792        panBlueMap = panBlue2;
793    }
794    else
795    {
796        panRedMap = panGreenMap = panBlueMap = NULL;
797    }
798
799/* -------------------------------------------------------------------- */
800/*      Initialize overviews.                                           */
801/* -------------------------------------------------------------------- */
802    papoRawBIs = (TIFFOvrCache **) _TIFFmalloc(nOverviews*sizeof(void*));
803
804    for( i = 0; i < nOverviews; i++ )
805    {
806        int	nOXSize, nOYSize, nOBlockXSize, nOBlockYSize;
807        uint32  nDirOffset;
808
809        nOXSize = (nXSize + panOvList[i] - 1) / panOvList[i];
810        nOYSize = (nYSize + panOvList[i] - 1) / panOvList[i];
811
812        nOBlockXSize = MIN((int)nBlockXSize,nOXSize);
813        nOBlockYSize = MIN((int)nBlockYSize,nOYSize);
814
815        if( bTiled )
816        {
817            if( (nOBlockXSize % 16) != 0 )
818                nOBlockXSize = nOBlockXSize + 16 - (nOBlockXSize % 16);
819
820            if( (nOBlockYSize % 16) != 0 )
821                nOBlockYSize = nOBlockYSize + 16 - (nOBlockYSize % 16);
822        }
823
824        nDirOffset = TIFF_WriteOverview( hTIFF, nOXSize, nOYSize,
825                                         nBitsPerPixel, nPlanarConfig,
826                                         nSamples, nOBlockXSize, nOBlockYSize,
827                                         bTiled, nCompressFlag, nPhotometric,
828                                         nSampleFormat,
829                                         panRedMap, panGreenMap, panBlueMap,
830                                         bUseSubIFDs,
831                                         nHorSubsampling, nVerSubsampling );
832
833        papoRawBIs[i] = TIFFCreateOvrCache( hTIFF, nDirOffset );
834    }
835
836    if( panRedMap != NULL )
837    {
838        _TIFFfree( panRedMap );
839        _TIFFfree( panGreenMap );
840        _TIFFfree( panBlueMap );
841    }
842
843/* -------------------------------------------------------------------- */
844/*      Allocate a buffer to hold a source block.                       */
845/* -------------------------------------------------------------------- */
846    if( bTiled )
847        pabySrcTile = (unsigned char *) _TIFFmalloc(TIFFTileSize(hTIFF));
848    else
849        pabySrcTile = (unsigned char *) _TIFFmalloc(TIFFStripSize(hTIFF));
850
851/* -------------------------------------------------------------------- */
852/*      Loop over the source raster, applying data to the               */
853/*      destination raster.                                             */
854/* -------------------------------------------------------------------- */
855    for( nSYOff = 0; nSYOff < (int) nYSize; nSYOff += nBlockYSize )
856    {
857        for( nSXOff = 0; nSXOff < (int) nXSize; nSXOff += nBlockXSize )
858        {
859            /*
860             * Read and resample into the various overview images.
861             */
862
863            TIFF_ProcessFullResBlock( hTIFF, nPlanarConfig,
864                                      bSubsampled,nHorSubsampling,nVerSubsampling,
865                                      nOverviews, panOvList,
866                                      nBitsPerPixel, nSamples, papoRawBIs,
867                                      nSXOff, nSYOff, pabySrcTile,
868                                      nBlockXSize, nBlockYSize,
869                                      nSampleFormat, pszResampleMethod );
870        }
871    }
872
873    _TIFFfree( pabySrcTile );
874
875/* -------------------------------------------------------------------- */
876/*      Cleanup the rawblockedimage files.                              */
877/* -------------------------------------------------------------------- */
878    for( i = 0; i < nOverviews; i++ )
879    {
880        TIFFDestroyOvrCache( papoRawBIs[i] );
881    }
882
883    if( papoRawBIs != NULL )
884        _TIFFfree( papoRawBIs );
885
886    TIFFSetWarningHandler( pfnWarning );
887}
888
889
890/*
891 * Local Variables:
892 * mode: c
893 * c-basic-offset: 8
894 * fill-column: 78
895 * End:
896 */
897