⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tif_jpeg.c

📁 开源组态软件
💻 C
📖 第 1 页 / 共 4 页
字号:
			    /* fast path for at least Cb and Cr */
			    for (nclump = clumps_per_line; nclump-- > 0; ) {
				*outptr++ = inptr[0];
				inptr += samples_per_clump;
			    }
			} else {
			    /* general case */
			    for (nclump = clumps_per_line; nclump-- > 0; ) {
				for (xpos = 0; xpos < hsamp; xpos++)
				    *outptr++ = inptr[xpos];
				inptr += samples_per_clump;
			    }
			}
			/* pad each scanline as needed */
			for (xpos = 0; xpos < padding; xpos++) {
			    *outptr = outptr[-1];
			    outptr++;
			}
			clumpoffset += hsamp;
		    }
		}
		sp->scancount++;
		if (sp->scancount >= DCTSIZE) {
			int n = sp->cinfo.c.max_v_samp_factor * DCTSIZE;
			if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n)
				return (0);
			sp->scancount = 0;
		}
		if (nrows > 0)
			tif->tif_row++;
		buf += sp->bytesperline;
	}
	return (1);
}

/*
 * Finish up at the end of a strip or tile.
 */
static int
JPEGPostEncode(TIFF* tif)
{
	JPEGState *sp = JState(tif);

	if (sp->scancount > 0) {
		/*
		 * Need to emit a partial bufferload of downsampled data.
		 * Pad the data vertically.
		 */
		int ci, ypos, n;
		jpeg_component_info* compptr;

		for (ci = 0, compptr = sp->cinfo.c.comp_info;
		     ci < sp->cinfo.c.num_components;
		     ci++, compptr++) {
			int vsamp = compptr->v_samp_factor;
			tsize_t row_width = compptr->width_in_blocks * DCTSIZE
				* sizeof(JSAMPLE);
			for (ypos = sp->scancount * vsamp;
			     ypos < DCTSIZE * vsamp; ypos++) {
				_TIFFmemcpy((tdata_t)sp->ds_buffer[ci][ypos],
					    (tdata_t)sp->ds_buffer[ci][ypos-1],
					    row_width);

			}
		}
		n = sp->cinfo.c.max_v_samp_factor * DCTSIZE;
		if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n)
			return (0);
	}

	return (TIFFjpeg_finish_compress(JState(tif)));
}

static void
JPEGCleanup(TIFF* tif)
{
	if (tif->tif_data) {
		JPEGState *sp = JState(tif);
                if( sp->cinfo_initialized )
                    TIFFjpeg_destroy(sp);	/* release libjpeg resources */
		if (sp->jpegtables)		/* tag value */
			_TIFFfree(sp->jpegtables);
		_TIFFfree(tif->tif_data);	/* release local state */
		tif->tif_data = NULL;
	}
}

static int
JPEGVSetField(TIFF* tif, ttag_t tag, va_list ap)
{
	JPEGState* sp = JState(tif);
	TIFFDirectory* td = &tif->tif_dir;
	uint32 v32;

	switch (tag) {
	case TIFFTAG_JPEGTABLES:
		v32 = va_arg(ap, uint32);
		if (v32 == 0) {
			/* XXX */
			return (0);
		}
		_TIFFsetByteArray(&sp->jpegtables, va_arg(ap, void*),
		    (long) v32);
		sp->jpegtables_length = v32;
		TIFFSetFieldBit(tif, FIELD_JPEGTABLES);
		break;
	case TIFFTAG_JPEGQUALITY:
		sp->jpegquality = va_arg(ap, int);
		return (1);			/* pseudo tag */
	case TIFFTAG_JPEGCOLORMODE:
		sp->jpegcolormode = va_arg(ap, int);
		/*
		 * Mark whether returned data is up-sampled or not
		 * so TIFFStripSize and TIFFTileSize return values
		 * that reflect the true amount of data.
		 */
		tif->tif_flags &= ~TIFF_UPSAMPLED;
		if (td->td_planarconfig == PLANARCONFIG_CONTIG) {
		    if (td->td_photometric == PHOTOMETRIC_YCBCR &&
		      sp->jpegcolormode == JPEGCOLORMODE_RGB) {
			tif->tif_flags |= TIFF_UPSAMPLED;
		    } else {
			if (td->td_ycbcrsubsampling[0] != 1 ||
			    td->td_ycbcrsubsampling[1] != 1)
			    ; /* XXX what about up-sampling? */
		    }
		}
		/*
		 * Must recalculate cached tile size
		 * in case sampling state changed.
		 */
		tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tsize_t) -1;
		return (1);			/* pseudo tag */
	case TIFFTAG_JPEGTABLESMODE:
		sp->jpegtablesmode = va_arg(ap, int);
		return (1);			/* pseudo tag */
	case TIFFTAG_YCBCRSUBSAMPLING:
                /* mark the fact that we have a real ycbcrsubsampling! */
		sp->ycbcrsampling_fetched = 1;
		return (*sp->vsetparent)(tif, tag, ap);
	default:
		return (*sp->vsetparent)(tif, tag, ap);
	}
	tif->tif_flags |= TIFF_DIRTYDIRECT;
	return (1);
}

/*
 * Some JPEG-in-TIFF produces do not emit the YCBCRSUBSAMPLING values in
 * the TIFF tags, but still use non-default (2,2) values within the jpeg
 * data stream itself.  In order for TIFF applications to work properly
 * - for instance to get the strip buffer size right - it is imperative
 * that the subsampling be available before we start reading the image
 * data normally.  This function will attempt to load the first strip in
 * order to get the sampling values from the jpeg data stream.  Various
 * hacks are various places are done to ensure this function gets called
 * before the td_ycbcrsubsampling values are used from the directory structure,
 * including calling TIFFGetField() for the YCBCRSUBSAMPLING field from 
 * TIFFStripSize(), and the printing code in tif_print.c. 
 *
 * Note that JPEGPreDeocode() will produce a fairly loud warning when the
 * discovered sampling does not match the default sampling (2,2) or whatever
 * was actually in the tiff tags. 
 *
 * Problems:
 *  o This code will cause one whole strip/tile of compressed data to be
 *    loaded just to get the tags right, even if the imagery is never read.
 *    It would be more efficient to just load a bit of the header, and
 *    initialize things from that. 
 *
 * See the bug in bugzilla for details:
 *
 * http://bugzilla.remotesensing.org/show_bug.cgi?id=168
 *
 * Frank Warmerdam, July 2002
 */

static void 
JPEGFixupTestSubsampling( TIFF * tif )
{
#ifdef CHECK_JPEG_YCBCR_SUBSAMPLING
    JPEGState *sp = JState(tif);
    TIFFDirectory *td = &tif->tif_dir;

    JPEGInitializeLibJPEG( tif );

    /*
     * Some JPEG-in-TIFF files don't provide the ycbcrsampling tags, 
     * and use a sampling schema other than the default 2,2.  To handle
     * this we actually have to scan the header of a strip or tile of
     * jpeg data to get the sampling.  
     */
    if( !sp->cinfo.comm.is_decompressor 
        || sp->ycbcrsampling_fetched  
        || td->td_photometric != PHOTOMETRIC_YCBCR )
        return;

    sp->ycbcrsampling_fetched = 1;
    if( TIFFIsTiled( tif ) )
    {
        if( !TIFFFillTile( tif, 0 ) )
            return;
    }
    else
    {
        if( !TIFFFillStrip( tif, 0 ) )
            return;
    }

    TIFFSetField( tif, TIFFTAG_YCBCRSUBSAMPLING, 
                  (uint16) sp->h_sampling, (uint16) sp->v_sampling );
#endif /* CHECK_JPEG_YCBCR_SUBSAMPLING */
}

static int
JPEGVGetField(TIFF* tif, ttag_t tag, va_list ap)
{
	JPEGState* sp = JState(tif);

	switch (tag) {
	case TIFFTAG_JPEGTABLES:
		/* unsigned short is bogus --- should be uint32 ??? */
		/* TIFFWriteNormalTag needs fixed  XXX */
		*va_arg(ap, unsigned short*) =
                        (unsigned short) sp->jpegtables_length;
		*va_arg(ap, void**) = sp->jpegtables;
		break;
	case TIFFTAG_JPEGQUALITY:
		*va_arg(ap, int*) = sp->jpegquality;
		break;
	case TIFFTAG_JPEGCOLORMODE:
		*va_arg(ap, int*) = sp->jpegcolormode;
		break;
	case TIFFTAG_JPEGTABLESMODE:
		*va_arg(ap, int*) = sp->jpegtablesmode;
		break;
	case TIFFTAG_YCBCRSUBSAMPLING:
                JPEGFixupTestSubsampling( tif );
		return (*sp->vgetparent)(tif, tag, ap);
		break;
	default:
		return (*sp->vgetparent)(tif, tag, ap);
	}
	return (1);
}

static void
JPEGPrintDir(TIFF* tif, FILE* fd, long flags)
{
	JPEGState* sp = JState(tif);

	(void) flags;
	if (TIFFFieldSet(tif,FIELD_JPEGTABLES))
		fprintf(fd, "  JPEG Tables: (%lu bytes)\n",
			(unsigned long) sp->jpegtables_length);
}

static uint32
JPEGDefaultStripSize(TIFF* tif, uint32 s)
{
	JPEGState* sp = JState(tif);
	TIFFDirectory *td = &tif->tif_dir;

	s = (*sp->defsparent)(tif, s);
	if (s < td->td_imagelength)
		s = TIFFroundup(s, td->td_ycbcrsubsampling[1] * DCTSIZE);
	return (s);
}

static void
JPEGDefaultTileSize(TIFF* tif, uint32* tw, uint32* th)
{
	JPEGState* sp = JState(tif);
	TIFFDirectory *td = &tif->tif_dir;

	(*sp->deftparent)(tif, tw, th);
	*tw = TIFFroundup(*tw, td->td_ycbcrsubsampling[0] * DCTSIZE);
	*th = TIFFroundup(*th, td->td_ycbcrsubsampling[1] * DCTSIZE);
}

/*
 * The JPEG library initialized used to be done in TIFFInitJPEG(), but
 * now that we allow a TIFF file to be opened in update mode it is necessary
 * to have some way of deciding whether compression or decompression is
 * desired other than looking at tif->tif_mode.  We accomplish this by 
 * examining {TILE/STRIP}BYTECOUNTS to see if there is a non-zero entry.
 * If so, we assume decompression is desired. 
 *
 * This is tricky, because TIFFInitJPEG() is called while the directory is
 * being read, and generally speaking the BYTECOUNTS tag won't have been read
 * at that point.  So we try to defer jpeg library initialization till we
 * do have that tag ... basically any access that might require the compressor
 * or decompressor that occurs after the reading of the directory. 
 *
 * In an ideal world compressors or decompressors would be setup
 * at the point where a single tile or strip was accessed (for read or write)
 * so that stuff like update of missing tiles, or replacement of tiles could
 * be done. However, we aren't trying to crack that nut just yet ...
 *
 * NFW, Feb 3rd, 2003.
 */

static int JPEGInitializeLibJPEG( TIFF * tif )
{
    JPEGState* sp = JState(tif);
    uint32 *byte_counts = NULL;
    int     data_is_empty = TRUE;

    if( sp->cinfo_initialized )
        return 1;

    /*
     * Do we have tile data already?  Make sure we initialize the
     * the state in decompressor mode if we have tile data, even if we
     * are not in read-only file access mode. 
     */
    if( TIFFIsTiled( tif ) 
        && TIFFGetField( tif, TIFFTAG_TILEBYTECOUNTS, &byte_counts ) 
        && byte_counts != NULL )
    {
        data_is_empty = byte_counts[0] == 0;
    }
    if( !TIFFIsTiled( tif ) 
        && TIFFGetField( tif, TIFFTAG_STRIPBYTECOUNTS, &byte_counts) 
        && byte_counts != NULL )
    {
        data_is_empty = byte_counts[0] == 0;
    }

    /*
     * Initialize libjpeg.
     */
    if (tif->tif_mode == O_RDONLY || !data_is_empty ) {
        if (!TIFFjpeg_create_decompress(sp))
            return (0);

    } else {
        if (!TIFFjpeg_create_compress(sp))
            return (0);
    }

    sp->cinfo_initialized = TRUE;

    return 1;
}

int
TIFFInitJPEG(TIFF* tif, int scheme)
{
	JPEGState* sp;

	assert(scheme == COMPRESSION_JPEG);

	/*
	 * Allocate state block so tag methods have storage to record values.
	 */
	tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (JPEGState));

	if (tif->tif_data == NULL) {
		TIFFError("TIFFInitJPEG", "No space for JPEG state block");
		return (0);
	}
        _TIFFmemset( tif->tif_data, 0, sizeof(JPEGState));

	sp = JState(tif);
	sp->tif = tif;				/* back link */

	/*
	 * Merge codec-specific tag information and
	 * override parent get/set field methods.
	 */
	_TIFFMergeFieldInfo(tif, jpegFieldInfo, N(jpegFieldInfo));
	sp->vgetparent = tif->tif_tagmethods.vgetfield;
	tif->tif_tagmethods.vgetfield = JPEGVGetField;	/* hook for codec tags */
	sp->vsetparent = tif->tif_tagmethods.vsetfield;
	tif->tif_tagmethods.vsetfield = JPEGVSetField;	/* hook for codec tags */
	tif->tif_tagmethods.printdir = JPEGPrintDir;	/* hook for codec tags */

	/* Default values for codec-specific fields */
	sp->jpegtables = NULL;
	sp->jpegtables_length = 0;
	sp->jpegquality = 75;			/* Default IJG quality */
	sp->jpegcolormode = JPEGCOLORMODE_RAW;
	sp->jpegtablesmode = JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF;

        sp->ycbcrsampling_fetched = 0;

	/*
	 * Install codec methods.
	 */
	tif->tif_setupdecode = JPEGSetupDecode;
	tif->tif_predecode = JPEGPreDecode;
	tif->tif_decoderow = JPEGDecode;
	tif->tif_decodestrip = JPEGDecode;
	tif->tif_decodetile = JPEGDecode;
	tif->tif_setupencode = JPEGSetupEncode;
	tif->tif_preencode = JPEGPreEncode;
	tif->tif_postencode = JPEGPostEncode;
	tif->tif_encoderow = JPEGEncode;
	tif->tif_encodestrip = JPEGEncode;
	tif->tif_encodetile = JPEGEncode;
	tif->tif_cleanup = JPEGCleanup;
	sp->defsparent = tif->tif_defstripsize;
	tif->tif_defstripsize = JPEGDefaultStripSize;
	sp->deftparent = tif->tif_deftilesize;
	tif->tif_deftilesize = JPEGDefaultTileSize;
	tif->tif_flags |= TIFF_NOBITREV;	/* no bit reversal, please */

        sp->cinfo_initialized = FALSE;

        /*
         * Mark the TIFFTAG_YCBCRSAMPLES as present even if it is not
         * see: JPEGFixupTestSubsampling().
         */
        TIFFSetFieldBit( tif, FIELD_YCBCRSUBSAMPLING );

	return (1);
}
#endif /* JPEG_SUPPORT */

/* vim: set ts=8 sts=8 sw=8 noet: */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -