Example #1
0
void CqMixedImageBuffer::compositeOver(const CqMixedImageBuffer& source,
		const TqChannelNameMap& nameMap, TqInt topLeftX, TqInt topLeftY,
		const std::string alphaName)
{
	if(!source.channelList().hasChannel(alphaName))
	{
		copyFrom(source, nameMap, topLeftX, topLeftY);
	}
	else
	{
		// compute size and top left coords of region to copy.
		TqInt copyWidth = 0;
		TqInt destTopLeftX = 0;
		TqInt srcTopLeftX = 0;
		getCopyRegionSize(topLeftX, source.m_width, m_width,
				srcTopLeftX, destTopLeftX, copyWidth);
		TqInt copyHeight = 0;
		TqInt destTopLeftY = 0;
		TqInt srcTopLeftY = 0;
		getCopyRegionSize(topLeftY, source.m_height, m_height,
				srcTopLeftY, destTopLeftY, copyHeight);
		// return if no overlap
		if(copyWidth <= 0 || copyHeight <= 0)
			return;

		for(TqChannelNameMap::const_iterator i = nameMap.begin(), e = nameMap.end();
				i != e; ++i)
		{
			channel(i->first, destTopLeftX, destTopLeftY, copyWidth, copyHeight)
				->compositeOver(*source.channel(i->second, srcTopLeftX, srcTopLeftY, copyWidth, copyHeight),
						*source.channel(alphaName, srcTopLeftX, srcTopLeftY, copyWidth, copyHeight));
		}
	}
}
Example #2
0
void CqMixedImageBuffer::copyFrom(const CqMixedImageBuffer& source,
		TqInt topLeftX, TqInt topLeftY)
{
	if(source.m_channelList.numChannels() != m_channelList.numChannels())
		AQSIS_THROW_XQERROR(XqInternal, EqE_Limit,
			"Number of source and destination channels do not match");

	// compute size and top left coords of region to copy.
	TqInt copyWidth = 0;
	TqInt destTopLeftX = 0;
	TqInt srcTopLeftX = 0;
	getCopyRegionSize(topLeftX, source.m_width, m_width,
			srcTopLeftX, destTopLeftX, copyWidth);
	TqInt copyHeight = 0;
	TqInt destTopLeftY = 0;
	TqInt srcTopLeftY = 0;
	getCopyRegionSize(topLeftY, source.m_height, m_height,
			srcTopLeftY, destTopLeftY, copyHeight);
	// return if no overlap
	if(copyWidth <= 0 || copyHeight <= 0)
		return;

	for(TqInt i = 0; i < m_channelList.numChannels(); ++i)
	{
		channel(i, destTopLeftX, destTopLeftY, copyWidth, copyHeight)
			->copyFrom(*source.channel(i, srcTopLeftX, srcTopLeftY,
						copyWidth, copyHeight));
	}
}
void CqTiffOutputFile::writePixelsImpl(const CqMixedImageBuffer& buffer)
{
	if(!buffer.channelList().channelTypesMatch(m_header.channelList()))
	{
		AQSIS_THROW_XQERROR(XqInternal, EqE_Bug,
				"Buffer and file channels don't match");
	}
	if(m_header.findPtr<Attr::TileInfo>())
		writeTiledPixels(buffer);
	else
		writeScanlinePixels(buffer);
}
void CqTiffOutputFile::writeTiledPixels(const CqMixedImageBuffer& buffer)
{
	SqTileInfo tileInfo = m_header.find<Attr::TileInfo>();
	// Check that the buffer has a height that is a multiple of the tile height.
	if( buffer.height() % tileInfo.height != 0
		&& m_currentLine + buffer.height() != m_header.height() )
	{
		AQSIS_THROW_XQERROR(XqInternal, EqE_Bug,
				"pixel buffer with height = " << buffer.height() << " must be a multiple "
				"of requested tile height (= " << tileInfo.height << ") or run exactly to "
				"the full image height (= " << m_header.height() << ").");
	}

	CqTiffDirHandle dirHandle(m_fileHandle);
	const TqUint8* rawBuf = buffer.rawData();
	const TqInt bytesPerPixel = buffer.channelList().bytesPerPixel();
	boost::scoped_array<TqUint8> tileBuf(
			new TqUint8[bytesPerPixel*tileInfo.width*tileInfo.height]);
	const TqInt rowStride = bytesPerPixel*buffer.width();
	const TqInt tileRowStride = bytesPerPixel*tileInfo.width;
	const TqInt endLine = m_currentLine + buffer.height();
	const TqInt numTileCols = (buffer.width()-1)/tileInfo.width + 1;
	for(TqInt line = m_currentLine; line < endLine; line += tileInfo.height)
	{
		// srcBuf will point to the beginning of the memory region which will
		// become the tile.
		const TqUint8* srcBuf = rawBuf;
		for(TqInt tileCol = 0; tileCol < numTileCols; ++tileCol)
		{
			const TqInt tileDataLen = min(tileRowStride,
					rowStride - tileCol*tileRowStride);
			const TqInt tileDataHeight = min(tileInfo.height, buffer.height() - line);
			// Copy parts of the scanlines into the tile buffer.
			stridedCopy(tileBuf.get(), tileRowStride, srcBuf, rowStride,
					tileDataHeight, tileDataLen);

			TIFFWriteTile(dirHandle.tiffPtr(),
					reinterpret_cast<tdata_t>(const_cast<TqUint8*>(tileBuf.get())),
					tileCol*tileInfo.width, line, 0, 0);
			srcBuf += tileRowStride;
		}
		rawBuf += rowStride*tileInfo.height;
	}
	m_currentLine = endLine;
}
void CqTiffOutputFile::writeScanlinePixels(const CqMixedImageBuffer& buffer)
{
	CqTiffDirHandle dirHandle(m_fileHandle);
	// Simplest possible implementation using scanline TIFF I/O.  Could use
	// Strip-based IO if performance is ever a problem here.
	const TqUint8* rawBuf = buffer.rawData();
	const TqInt rowStride = buffer.channelList().bytesPerPixel()*buffer.width();
	const TqInt endLine = m_currentLine + buffer.height();
	// Temporary buffer for scanlines.  We need to copy the data into here
	// since libtiff trashes the buffer when encoding is turned on.  (The TIFF
	// docs don't seem to mention this though, ugh.)
	boost::scoped_array<TqUint8> lineBuf(new TqUint8[rowStride]);
	for(TqInt line = m_currentLine; line < endLine; ++line)
	{
		// copy the data into temp buffer.
		std::memcpy(lineBuf.get(), rawBuf, rowStride);
		// write data
		TIFFWriteScanline( dirHandle.tiffPtr(), reinterpret_cast<tdata_t>(lineBuf.get()),
				static_cast<uint32>(line) );
		rawBuf += rowStride;
	}
	m_currentLine = endLine;
}