Example #1
0
void

_TIFFDefaultTileSize(TIFF* tif, uint32* tw, uint32* th)

{

    (void) tif;

    if (*(int32*) tw < 1)

        *tw = 256;

    if (*(int32*) th < 1)

        *th = 256;

    /* roundup to a multiple of 16 per the spec */

    if (*tw & 0xf)

        *tw = TIFFroundup(*tw, 16);

    if (*th & 0xf)

        *th = TIFFroundup(*th, 16);

}
Example #2
0
/*
 * Compute the # bytes in a variable height, row-aligned strip.
 */
tsize_t
TIFFVStripSize(TIFF* tif, uint32 nrows)
{
	TIFFDirectory *td = &tif->tif_dir;

	if (nrows == (uint32) -1)
		nrows = td->td_imagelength;
#ifdef YCBCR_SUPPORT
	if (td->td_planarconfig == PLANARCONFIG_CONTIG &&
	    td->td_photometric == PHOTOMETRIC_YCBCR &&
	    !isUpSampled(tif)) {
		/*
		 * Packed YCbCr data contain one Cb+Cr for every
		 * HorizontalSampling*VerticalSampling Y values.
		 * Must also roundup width and height when calculating
		 * since images that are not a multiple of the
		 * horizontal/vertical subsampling area include
		 * YCbCr data for the extended image.
		 */
		tsize_t w =
		    TIFFroundup(td->td_imagewidth, td->td_ycbcrsubsampling[0]);
		tsize_t scanline = TIFFhowmany(w*td->td_bitspersample, 8);
		tsize_t samplingarea =
		    td->td_ycbcrsubsampling[0]*td->td_ycbcrsubsampling[1];
		nrows = TIFFroundup(nrows, td->td_ycbcrsubsampling[1]);
		/* NB: don't need TIFFhowmany here 'cuz everything is rounded */
		return ((tsize_t)
		    (nrows*scanline + 2*(nrows*scanline / samplingarea)));
	} else
#endif
		return ((tsize_t)(nrows * TIFFScanlineSize(tif)));
}
Example #3
0
/*
 * Compute the # bytes in a variable height, row-aligned strip.
 */
tsize_t
TIFFVStripSize(TIFF* tif, uint32 nrows)
{
	TIFFDirectory *td = &tif->tif_dir;

	if (nrows == (uint32) -1)
		nrows = td->td_imagelength;
	if (td->td_planarconfig == PLANARCONFIG_CONTIG &&
	    td->td_photometric == PHOTOMETRIC_YCBCR &&
	    !isUpSampled(tif)) {
		/*
		 * Packed YCbCr data contain one Cb+Cr for every
		 * HorizontalSampling*VerticalSampling Y values.
		 * Must also roundup width and height when calculating
		 * since images that are not a multiple of the
		 * horizontal/vertical subsampling area include
		 * YCbCr data for the extended image.
		 */
                uint16 ycbcrsubsampling[2];
                tsize_t w, scanline, samplingarea;
		ycbcrsubsampling[0] = 0;
		ycbcrsubsampling[1] = 0;

                TIFFGetField( tif, TIFFTAG_YCBCRSUBSAMPLING, 
                              ycbcrsubsampling + 0, 
                              ycbcrsubsampling + 1 );
		/* make sure we dont get division by 0 due to bad tiffs */
		if (!ycbcrsubsampling[0]) ycbcrsubsampling[0] = 1;
		if (!ycbcrsubsampling[1]) ycbcrsubsampling[1] = 1;

		samplingarea = ycbcrsubsampling[0]*ycbcrsubsampling[1];
		if (samplingarea == 0) {
			_TIFFError(tif, tif->tif_name,
				"Invalid YCbCr subsampling");
			return 0;
		}

		w = TIFFroundup(td->td_imagewidth, ycbcrsubsampling[0]);
		scanline = TIFFhowmany8(multiply(tif, w, td->td_bitspersample,
						 "TIFFVStripSize"));
		nrows = TIFFroundup(nrows, ycbcrsubsampling[1]);
		/* NB: don't need TIFFhowmany here 'cuz everything is rounded */
		scanline = multiply(tif, nrows, scanline, "TIFFVStripSize");
		return ((tsize_t)
		    summarize(tif, scanline,
			      multiply(tif, 2, scanline / samplingarea,
				       "TIFFVStripSize"), "TIFFVStripSize"));
	} else
		return ((tsize_t) multiply(tif, nrows, TIFFScanlineSize(tif),
					   "TIFFVStripSize"));
}
Example #4
0
/*
 * Setup the raw data buffer in preparation for
 * reading a strip of raw data.  If the buffer
 * is specified as zero, then a buffer of appropriate
 * size is allocated by the library.  Otherwise,
 * the client must guarantee that the buffer is
 * large enough to hold any individual strip of
 * raw data.
 */
int
TIFFReadBufferSetup(TIFF* tif, tdata_t bp, tsize_t size)
{
	static const char module[] = "TIFFReadBufferSetup";

	if (tif->tif_rawdata) {
		if (tif->tif_flags & TIFF_MYBUFFER)
			_TIFFfree(tif->tif_rawdata);
		tif->tif_rawdata = NULL;
	}
	if (bp) {
		tif->tif_rawdatasize = size;
		tif->tif_rawdata = (tidata_t) bp;
		tif->tif_flags &= ~TIFF_MYBUFFER;
	} else {
		tif->tif_rawdatasize = TIFFroundup(size, 1024);
		tif->tif_rawdata = (tidata_t) _TIFFmalloc(tif->tif_rawdatasize);
		tif->tif_flags |= TIFF_MYBUFFER;
	}
	if (tif->tif_rawdata == NULL) {
		TIFFError(module,
		    "%s: No space for data buffer at scanline %ld",
		    tif->tif_name, (long) tif->tif_row);
		tif->tif_rawdatasize = 0;
		return (0);
	}
	return (1);
}
Example #5
0
/*
 * Compute the # bytes in a variable length, row-aligned tile.
 */
tsize_t
TIFFVTileSize(TIFF* tif, uint32 nrows)
{
	TIFFDirectory *td = &tif->tif_dir;
	tsize_t tilesize;

	if (td->td_tilelength == 0 || td->td_tilewidth == 0 ||
	    td->td_tiledepth == 0)
		return ((tsize_t) 0);
	if (td->td_planarconfig == PLANARCONFIG_CONTIG &&
	    td->td_photometric == PHOTOMETRIC_YCBCR &&
	    !isUpSampled(tif)) {
		/*
		 * Packed YCbCr data contain one Cb+Cr for every
		 * HorizontalSampling*VerticalSampling Y values.
		 * Must also roundup width and height when calculating
		 * since images that are not a multiple of the
		 * horizontal/vertical subsampling area include
		 * YCbCr data for the extended image.
		 */
		tsize_t w =
		    TIFFroundup(td->td_tilewidth, td->td_ycbcrsubsampling[0]);
		tsize_t rowsize =
		    TIFFhowmany8(multiply(tif, w, td->td_bitspersample,
					  "TIFFVTileSize"));
		tsize_t samplingarea =
		    td->td_ycbcrsubsampling[0]*td->td_ycbcrsubsampling[1];
		if (samplingarea == 0) {
			TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Invalid YCbCr subsampling");
			return 0;
		}
		nrows = TIFFroundup(nrows, td->td_ycbcrsubsampling[1]);
		/* NB: don't need TIFFhowmany here 'cuz everything is rounded */
		tilesize = multiply(tif, nrows, rowsize, "TIFFVTileSize");
		tilesize = summarize(tif, tilesize,
				     multiply(tif, 2, tilesize / samplingarea,
					      "TIFFVTileSize"),
				     "TIFFVTileSize");
	} else
		tilesize = multiply(tif, nrows, TIFFTileRowSize(tif),
				    "TIFFVTileSize");
	return ((tsize_t)
	    multiply(tif, tilesize, td->td_tiledepth, "TIFFVTileSize"));
}
Example #6
0
/*
 * Initialize the YCbCr->RGB conversion tables.  The conversion
 * is done according to the 6.0 spec:
 *
 *    R = Y + Cr*(2 - 2*LumaRed)
 *    B = Y + Cb*(2 - 2*LumaBlue)
 *    G =   Y
 *    - LumaBlue*Cb*(2-2*LumaBlue)/LumaGreen
 *    - LumaRed*Cr*(2-2*LumaRed)/LumaGreen
 *
 * To avoid floating point arithmetic the fractional constants that
 * come out of the equations are represented as fixed point values
 * in the range 0...2^16.  We also eliminate multiplications by
 * pre-calculating possible values indexed by Cb and Cr (this code
 * assumes conversion is being done for 8-bit samples).
 */
static void
TIFFYCbCrToRGBInit(TIFFYCbCrToRGB* ycbcr, TIFF* tif)
{
    TIFFRGBValue* clamptab;
    float* coeffs;
    int i;

    clamptab = (TIFFRGBValue*)(
    (tidata_t) ycbcr+TIFFroundup(sizeof (TIFFYCbCrToRGB), sizeof (long)));
    _TIFFmemset(clamptab, 0, 256);  /* v < 0 => 0 */
    ycbcr->clamptab = (clamptab += 256);
    for (i = 0; i < 256; i++)
    clamptab[i] = i;
    _TIFFmemset(clamptab+256, 255, 2*256);  /* v > 255 => 255 */
    TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRCOEFFICIENTS, &coeffs);
    _TIFFmemcpy(ycbcr->coeffs, coeffs, 3*sizeof (float));
    { float f1 = 2-2*LumaRed;       int32 D1 = FIX(f1);
      float f2 = LumaRed*f1/LumaGreen;  int32 D2 = -FIX(f2);
      float f3 = 2-2*LumaBlue;      int32 D3 = FIX(f3);
      float f4 = LumaBlue*f3/LumaGreen; int32 D4 = -FIX(f4);
      int x;

      ycbcr->Cr_r_tab = (int*) (clamptab + 3*256);
      ycbcr->Cb_b_tab = ycbcr->Cr_r_tab + 256;
      ycbcr->Cr_g_tab = (int32*) (ycbcr->Cb_b_tab + 256);
      ycbcr->Cb_g_tab = ycbcr->Cr_g_tab + 256;
      /*
       * i is the actual input pixel value in the range 0..255
       * Cb and Cr values are in the range -128..127 (actually
       * they are in a range defined by the ReferenceBlackWhite
       * tag) so there is some range shifting to do here when
       * constructing tables indexed by the raw pixel data.
       *
       * XXX handle ReferenceBlackWhite correctly to calculate
       *     Cb/Cr values to use in constructing the tables.
       */
      for (i = 0, x = -128; i < 256; i++, x++) {
      ycbcr->Cr_r_tab[i] = (int)((D1*x + ONE_HALF)>>SHIFT);
      ycbcr->Cb_b_tab[i] = (int)((D3*x + ONE_HALF)>>SHIFT);
      ycbcr->Cr_g_tab[i] = D2*x;
      ycbcr->Cb_g_tab[i] = D4*x + ONE_HALF;
      }
    }
}
Example #7
0
/*
 * Return the number of bytes to read/write in a call to
 * one of the scanline-oriented i/o routines.  Note that
 * this number may be 1/samples-per-pixel if data is
 * stored as separate planes.
 */
tsize_t
TIFFScanlineSize(TIFF* tif)
{
	TIFFDirectory *td = &tif->tif_dir;
	tsize_t scanline;

	if (td->td_planarconfig == PLANARCONFIG_CONTIG) {
		if (td->td_photometric == PHOTOMETRIC_YCBCR
		    && !isUpSampled(tif)) {
			uint16 ycbcrsubsampling[2];

			TIFFGetField(tif, TIFFTAG_YCBCRSUBSAMPLING,
				     ycbcrsubsampling + 0,
				     ycbcrsubsampling + 1);

			if (ycbcrsubsampling[0] == 0) {
				TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
					     "Invalid YCbCr subsampling");
				return 0;
			}

			scanline = TIFFroundup(td->td_imagewidth,
					       ycbcrsubsampling[0]);
			scanline = TIFFhowmany8(multiply(tif, scanline,
							 td->td_bitspersample,
							 "TIFFScanlineSize"));
			return ((tsize_t)
				summarize(tif, scanline,
					  multiply(tif, 2,
						scanline / ycbcrsubsampling[0],
						"TIFFVStripSize"),
					  "TIFFVStripSize"));
		} else {
			scanline = multiply(tif, td->td_imagewidth,
					    td->td_samplesperpixel,
					    "TIFFScanlineSize");
		}
	} else
		scanline = td->td_imagewidth;
	return ((tsize_t) TIFFhowmany8(multiply(tif, scanline,
						td->td_bitspersample,
						"TIFFScanlineSize")));
}
Example #8
0
static tileContigRoutine
initYCbCrConversion(TIFFRGBAImage* img)
{
    uint16 hs, vs;

    if (img->ycbcr == NULL) {
    img->ycbcr = (TIFFYCbCrToRGB*) _TIFFmalloc(
      TIFFroundup(sizeof (TIFFYCbCrToRGB), sizeof (long))
    + 4*256*sizeof (TIFFRGBValue)
    + 2*256*sizeof (int)
    + 2*256*sizeof (int32)
    );
    if (img->ycbcr == NULL) {
    TIFFError(TIFFFileName(img->tif),
    "No space for YCbCr->RGB conversion state");
    return (NULL);
    }
    TIFFYCbCrToRGBInit(img->ycbcr, img->tif);
    } else {
    float* coeffs;

    TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRCOEFFICIENTS, &coeffs);
    if (_TIFFmemcmp(coeffs, img->ycbcr->coeffs, 3*sizeof (float)) != 0)
    TIFFYCbCrToRGBInit(img->ycbcr, img->tif);
    }
    /*
     * The 6.0 spec says that subsampling must be
     * one of 1, 2, or 4, and that vertical subsampling
     * must always be <= horizontal subsampling; so
     * there are only a few possibilities and we just
     * enumerate the cases.
     */
    TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, &hs, &vs);
    switch ((hs<<4)|vs) {
    case 0x44: return (putcontig8bitYCbCr44tile);
    case 0x42: return (putcontig8bitYCbCr42tile);
    case 0x41: return (putcontig8bitYCbCr41tile);
    case 0x22: return (putcontig8bitYCbCr22tile);
    case 0x21: return (putcontig8bitYCbCr21tile);
    case 0x11: return (putcontig8bitYCbCr11tile);
    }
    return (NULL);
}
Example #9
0
/*
 * Read the specified tile and setup for decoding. 
 * The data buffer is expanded, as necessary, to
 * hold the tile's data.
 */
int
TIFFFillTile(TIFF* tif, ttile_t tile)
{
	static const char module[] = "TIFFFillTile";
	TIFFDirectory *td = &tif->tif_dir;
	tsize_t bytecount;

	bytecount = td->td_stripbytecount[tile];
	if (bytecount <= 0) {
		TIFFError(tif->tif_name,
		    "%lu: Invalid tile byte count, tile %lu",
		    (unsigned long) bytecount, (unsigned long) tile);
		return (0);
	}
	if (isMapped(tif) &&
	    (isFillOrder(tif, td->td_fillorder)
             || (tif->tif_flags & TIFF_NOBITREV))) {
		/*
		 * The image is mapped into memory and we either don't
		 * need to flip bits or the compression routine is going
		 * to handle this operation itself.  In this case, avoid
		 * copying the raw data and instead just reference the
		 * data from the memory mapped file image.  This assumes
		 * that the decompression routines do not modify the
		 * contents of the raw data buffer (if they try to,
		 * the application will get a fault since the file is
		 * mapped read-only).
		 */
		if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata)
			_TIFFfree(tif->tif_rawdata);
		tif->tif_flags &= ~TIFF_MYBUFFER;
		if ( td->td_stripoffset[tile] + bytecount > tif->tif_size) {
			tif->tif_curtile = NOTILE;
			return (0);
		}
		tif->tif_rawdatasize = bytecount;
		tif->tif_rawdata = tif->tif_base + td->td_stripoffset[tile];
	} else {
		/*
		 * Expand raw data buffer, if needed, to
		 * hold data tile coming from file
		 * (perhaps should set upper bound on
		 *  the size of a buffer we'll use?).
		 */
		if (bytecount > tif->tif_rawdatasize) {
			tif->tif_curtile = NOTILE;
			if ((tif->tif_flags & TIFF_MYBUFFER) == 0) {
				TIFFError(module,
				"%s: Data buffer too small to hold tile %ld",
				    tif->tif_name, (long) tile);
				return (0);
			}
			if (!TIFFReadBufferSetup(tif, 0,
			    TIFFroundup(bytecount, 1024)))
				return (0);
		}
		if (TIFFReadRawTile1(tif, tile,
                                     (unsigned char *)tif->tif_rawdata,
                                     bytecount, module) != bytecount)
			return (0);
		if (!isFillOrder(tif, td->td_fillorder) &&
		    (tif->tif_flags & TIFF_NOBITREV) == 0)
			TIFFReverseBits(tif->tif_rawdata, bytecount);
	}
	return (TIFFStartTile(tif, tile));
}
Example #10
0
/*
 * Read the specified strip and setup for decoding. 
 * The data buffer is expanded, as necessary, to
 * hold the strip's data.
 */
int
TIFFFillStrip(TIFF* tif, tstrip_t strip)
{
	static const char module[] = "TIFFFillStrip";
	TIFFDirectory *td = &tif->tif_dir;
	tsize_t bytecount;

	bytecount = td->td_stripbytecount[strip];
	if (bytecount <= 0) {
		TIFFError(tif->tif_name,
		    "%lu: Invalid strip byte count, strip %lu",
		    (u_long) bytecount, (u_long) strip);
		return (0);
	}
	if (isMapped(tif) &&
	    (isFillOrder(tif, td->td_fillorder) || (tif->tif_flags & TIFF_NOBITREV))) {
		/*
		 * The image is mapped into memory and we either don't
		 * need to flip bits or the compression routine is going
		 * to handle this operation itself.  In this case, avoid
		 * copying the raw data and instead just reference the
		 * data from the memory mapped file image.  This assumes
		 * that the decompression routines do not modify the
		 * contents of the raw data buffer (if they try to,
		 * the application will get a fault since the file is
		 * mapped read-only).
		 */
		if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata)
			_TIFFfree(tif->tif_rawdata);
		tif->tif_flags &= ~TIFF_MYBUFFER;
		if ( td->td_stripoffset[strip] + bytecount > tif->tif_size) {
			/*
			 * This error message might seem strange, but it's
			 * what would happen if a read were done instead.
			 */
			TIFFError(module,
		    "%s: Read error on strip %lu; got %lu bytes, expected %lu",
			    tif->tif_name,
			    (u_long) strip,
			    (u_long) tif->tif_size - td->td_stripoffset[strip],
			    (u_long) bytecount);
			tif->tif_curstrip = NOSTRIP;
			return (0);
		}
		tif->tif_rawdatasize = bytecount;
		tif->tif_rawdata = tif->tif_base + td->td_stripoffset[strip];
	} else {
		/*
		 * Expand raw data buffer, if needed, to
		 * hold data strip coming from file
		 * (perhaps should set upper bound on
		 *  the size of a buffer we'll use?).
		 */
		if (bytecount > tif->tif_rawdatasize) {
			tif->tif_curstrip = NOSTRIP;
			if ((tif->tif_flags & TIFF_MYBUFFER) == 0) {
				TIFFError(module,
				"%s: Data buffer too small to hold strip %lu",
				    tif->tif_name, (u_long) strip);
				return (0);
			}
			if (!TIFFReadBufferSetup(tif, 0,
			    TIFFroundup(bytecount, 1024)))
				return (0);
		}
		if (TIFFReadRawStrip1(tif, strip, (u_char *)tif->tif_rawdata,
		    bytecount, module) != bytecount)
			return (0);
		if (!isFillOrder(tif, td->td_fillorder) &&
		    (tif->tif_flags & TIFF_NOBITREV) == 0)
			TIFFReverseBits(tif->tif_rawdata, bytecount);
	}
	return (TIFFStartStrip(tif, strip));
}
Example #11
0
/*
 * Read the specified tile and setup for decoding. The data buffer is
 * expanded, as necessary, to hold the tile's data.
 */
int
TIFFFillTile(TIFF* tif, ttile_t tile)
{
	static const char module[] = "TIFFFillTile";
	TIFFDirectory *td = &tif->tif_dir;

	if ((tif->tif_flags&TIFF_NOREADRAW)==0)
	{
		/*
		 * FIXME: butecount should have tsize_t type, but for now
		 * libtiff defines tsize_t as a signed 32-bit integer and we
		 * are losing ability to read arrays larger than 2^31 bytes.
		 * So we are using uint32 instead of tsize_t here.
		 */
		uint32 bytecount = td->td_stripbytecount[tile];
		if (bytecount <= 0) {
			TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
			    "%lu: Invalid tile byte count, tile %lu",
			    (unsigned long) bytecount, (unsigned long) tile);
			return (0);
		}
		if (isMapped(tif) &&
		    (isFillOrder(tif, td->td_fillorder)
		     || (tif->tif_flags & TIFF_NOBITREV))) {
			/*
			 * The image is mapped into memory and we either don't
			 * need to flip bits or the compression routine is
			 * going to handle this operation itself.  In this
			 * case, avoid copying the raw data and instead just
			 * reference the data from the memory mapped file
			 * image.  This assumes that the decompression
			 * routines do not modify the contents of the raw data
			 * buffer (if they try to, the application will get a
			 * fault since the file is mapped read-only).
			 */
			if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata)
				_TIFFfree(tif->tif_rawdata);
			tif->tif_flags &= ~TIFF_MYBUFFER;
			/*
			 * We must check for overflow, potentially causing
			 * an OOB read. Instead of simple
			 *
			 *  td->td_stripoffset[tile]+bytecount > tif->tif_size
			 *
			 * comparison (which can overflow) we do the following
			 * two comparisons:
			 */
			if (bytecount > tif->tif_size ||
			    td->td_stripoffset[tile] > tif->tif_size - bytecount) {
				tif->tif_curtile = NOTILE;
				return (0);
			}
			tif->tif_rawdatasize = bytecount;
			tif->tif_rawdata =
				tif->tif_base + td->td_stripoffset[tile];
		} else {
			/*
			 * Expand raw data buffer, if needed, to hold data
			 * tile coming from file (perhaps should set upper
			 * bound on the size of a buffer we'll use?).
			 */
			if (bytecount > (uint32)tif->tif_rawdatasize) {
				tif->tif_curtile = NOTILE;
				if ((tif->tif_flags & TIFF_MYBUFFER) == 0) {
					TIFFErrorExt(tif->tif_clientdata,
						     module,
				"%s: Data buffer too small to hold tile %ld",
						     tif->tif_name,
						     (long) tile);
					return (0);
				}
				if (!TIFFReadBufferSetup(tif, 0,
				    TIFFroundup(bytecount, 1024)))
					return (0);
			}
			if ((uint32)TIFFReadRawTile1(tif, tile,
				(unsigned char *)tif->tif_rawdata,
				bytecount, module) != bytecount)
				return (0);
			if (!isFillOrder(tif, td->td_fillorder) &&
			    (tif->tif_flags & TIFF_NOBITREV) == 0)
				TIFFReverseBits(tif->tif_rawdata, bytecount);
		}
	}
	return (TIFFStartTile(tif, tile));
}
Example #12
0
/*
 * Compute the # bytes in a variable height, row-aligned strip.
 */
tsize_t
TIFFVStripSize(TIFF* tif, uint32 nrows)
{
	TIFFDirectory *td = &tif->tif_dir;
	uint32 stripsize;

	if (nrows == (uint32) -1)
		nrows = td->td_imagelength;
	if (td->td_planarconfig == PLANARCONFIG_CONTIG &&
	    td->td_photometric == PHOTOMETRIC_YCBCR &&
	    !isUpSampled(tif)) {
		/*
		 * Packed YCbCr data contain one Cb+Cr for every
		 * HorizontalSampling*VerticalSampling Y values.
		 * Must also roundup width and height when calculating
		 * since images that are not a multiple of the
		 * horizontal/vertical subsampling area include
		 * YCbCr data for the extended image.
		 */
		uint16 ycbcrsubsampling[2];
		uint32 w, scanline, samplingarea;

		TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING,
				      ycbcrsubsampling + 0,
				      ycbcrsubsampling + 1);

		samplingarea = ycbcrsubsampling[0]*ycbcrsubsampling[1];
		if (samplingarea == 0) {
			TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
				     "Invalid YCbCr subsampling");
			return 0;
		}

		w = TIFFroundup(td->td_imagewidth, ycbcrsubsampling[0]);
		scanline = TIFFhowmany8(multiply(tif, w, td->td_bitspersample,
						 "TIFFVStripSize"));
		nrows = TIFFroundup(nrows, ycbcrsubsampling[1]);
		/* NB: don't need TIFFhowmany here 'cuz everything is rounded */
		scanline = multiply(tif, nrows, scanline, "TIFFVStripSize");
		/* a zero anywhere in here means overflow, must return zero */
		if (scanline > 0) {
			uint32 extra =
			    multiply(tif, 2, scanline / samplingarea,
				     "TIFFVStripSize");
			if (extra > 0)
				stripsize = summarize(tif, scanline, extra,
						      "TIFFVStripSize");
			else
				stripsize = 0;
		} else
			stripsize = 0;
	} else
		stripsize = multiply(tif, nrows, TIFFScanlineSize(tif),
				     "TIFFVStripSize");
	/* Because tsize_t is signed, we might have conversion overflow */
	if (((tsize_t) stripsize) < 0) {
		TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Integer overflow in %s", "TIFFVStripSize");
		stripsize = 0;
	}
	return (tsize_t) stripsize;
}