www.pudn.com > viewImage.rar > TifIFD.cpp


// TifIFD.cpp: implementation of the CTifIFD class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "Huffman.h" 
#include "TifIFD.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
#define DECODE_BUF_EXTEND_LEN		90000	// Old value is 6000 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CTifIFD::CTifIFD() 
{ 
	//Initial class members 
	m_pEntry = NULL; 
	m_image.lpImage = NULL; 
 
	m_outImage.lpImage = NULL; 
	m_outImage.lnCount = 0;	 
 
	m_lOldVRes = 0; 
	m_lOldHRes = 0; 
 
	m_lnRow = 0; 
} 
 
CTifIFD::~CTifIFD() 
{ 
	FreeMem(); 
} 
 
//	--------------------------------------------------------------------------- 
//	Load one tiff page from file 
// 
BOOL CTifIFD::LoadIFD(HANDLE hFile, WORD wByteOrderFlag) 
{ 
	register WORD i; 
	WORD wEntryCount; 
	DWORD dwNumOfByteRead; 
	WORD wLastTag; 
 
	//Initial values 
	WORD wIfdError=0; 
 
	short nCompression=1; 
	long int lnPhotometricInterpretation=-1; 
	long int lnHres=0; 
	long int lnVres=0; 
	long int lnRes[2]; 
	short int nOures=1; 
 
	//free memory first. 
	FreeMem(); 
 
	//Get EntryCount form file; 
	if(ReadFile(hFile,&wEntryCount,sizeof(WORD), 
		&dwNumOfByteRead,NULL)==0) 
		return FALSE; 
 
	//alloc memory for entry 
	m_pEntry = new TIFFMARK[wEntryCount]; 
	if(m_pEntry == 0) 
		return FALSE; 
	 
	wLastTag=0;	// init last tag 
 
	//Initialize some value , add by zsxl 
	m_image.wBitOrder = 1; 
	m_image.wOptions = 4;	// what's the meaing of 4 
 
	//end initialize 
	//Read and process entries. 
	for(i=0;i>=24 ; 
				else if (m_pEntry[i].wType==IFD_SHORT)  
					m_pEntry[i].dwValue>>=16 ; 
			} 
		} 
 
		switch (m_pEntry[i].wTag) 
		{ 
		case ImageWidth_tag:	// ImageWidth must be 864, there is no default 
            m_image.wWidth=(unsigned short int)m_pEntry[i].dwValue; 
			break; 
 
		case ImageLength_tag:	// ImageLength must be strip size, there is no default 
			m_image.wLength=(unsigned short int)m_pEntry[i].dwValue; 
			break; 
 
		case BitsPerSample_tag:	//  BitsPerSample must be 1, default is ok 
			if ((unsigned short int)m_pEntry[i].dwValue!=1)  
				wIfdError=1 ; 
			break; 
		case Compression_tag:	// Compression must be 3 or 4 ,the default is no good  
			nCompression = (short int)m_pEntry[i].dwValue; 
			break; 
		case PhotometricInterpretation_tag:  /* PhotometricInterpretation must be 0 */ 
											/* there is no default */ 
			lnPhotometricInterpretation=(unsigned short int)m_pEntry[i].dwValue; 
			break; 
 
		case FillOrder_tag:		// FillOrder can be 1 or 2 , take what comes 
			m_image.wBitOrder=(unsigned short)m_pEntry[i].dwValue; 
			break; 
 
		case StripOffsets_tag:		/* StripOffsets we need to know */ 
									/* there is no default */ 
			m_image.dwOffset=m_pEntry[i].dwValue; 
			break; 
 
		case SamplesPerPixel_tag:	/* SamplesPerPixel must be 1 */ 
                                       /* default is ok */ 
			if((unsigned short int)m_pEntry[i].dwValue!=1)  
				wIfdError=1 ; 
			break ; 
 
		case RowsPerStrip_tag:		/* RowsPerStrip must be single strip */ 
                                       /* default is ok */ 
			if (m_image.wLength>7) ; 
 
	device.source_width = m_lImgWidth;	// fax width & length 
	device.source_height = m_lImgHeight; 
	device.total_lines = 1; 
	device.dest_width = m_lImgWidth;	//	fax width 
	device.dest_height = m_lImgHeight;	//	fax length 
 
	if (! ProcessLine(&device,INIT))  
		return NULL; 
	 
	// init decoding first 
	if(! InitDecoding()) 
		return NULL; 
 
	/* Preliminaries for each image in the file - fseek to the start of 
	the image.  (If we can't we give it a zero length and ignore). If a 
	2-D or a T.6 image, set up pointers to the reference line and the 
	current line.  If a T.6 image (which has no initial EOL) set up our 
	key variables to the right initial state.  If a T.4 image just set 
	our resync flag, which forces us to ignore everything until the next 
	EOL code */ 
 
	cpTwolines = new char[((m_lImgWidth+7)/8)*2];	// used for some condition 
 
	if(m_image.wOptions&3) 
	{ 
		memset (cpTwolines,0x00,((m_lImgWidth+7)/8)*2); 
		cpRef_line= &cpTwolines[0] ; 
		device.cur_line= &cpTwolines[(m_lImgWidth+7)/8] ; 
	} 
	else  
	{ 
		device.cur_line= NULL ; 
	} 
 
	// will not be used again 
	delete cpTwolines; 
 
	if(m_image.wOptions&2) 
	{ 
		bCoding_scheme= 2 ; 
		lnResync= 0 ; 
		device.color= WHITE ; 
		lnDots_left= m_lImgWidth;/*FAXWIDTH*/ ; 
		tree= (NODE *)&gTwoTree ; 
		lnHorz_runs= lnCode= 0 ; 
		lnA0= (-1) ; 
	} 
	else  
	{ 
		lnResync= 1 ; 
	} 
 
	/* This is the main loop for processing an image - we have a double 
	loop, with the outer executing for each byte (octet) in the image, 
	and the inner executing 8 times for each octet and processing each 
	bit in turn.  The only exits before a completed image are on 
	physical end of file, on error if writing Output file, or on EOFB 
	in a T.6 file. */ 
 
	lpSrcBuf=m_image.lpImage; 
	dwByteCount=m_image.dwByteCount; 
 
	for (;dwByteCount;dwByteCount--) 
	{ 
		if ((device.id== U_TIFF)&&(device.hFile== NULL))  
			break; 
 
		bOctet=*lpSrcBuf++;	// get the source data 
		if (m_image.wBitOrder==2)  
			bOctet=gBackward[bOctet]; 
 
		for(i=0; i<8;i++,bOctet<<= 1) // decode each bit 
		{ 
			/* We have three checks for every bit in the file.  First we 
            check for EOL in T.6 mode - there is no EOL marker, but we 
            should have exactly the right number of dots decoded. 
            There should be none left in the line.  If we pass the 
            test we Output the line and reset our key variables */ 
 
			if((m_image.wOptions&2)&&(lnHorz_runs==0)&&(lnDots_left==0)) 
            { 
				if(! ProcessLine(&device, OUREOL)) 
					return NULL; 
 
				bCoding_scheme= 2 ; 
				lnResync= 0 ; 
				device.color= WHITE ; 
	            lnDots_left= m_lImgWidth;//FAXWIDTH ; 
		        tree= (NODE *)&gTwoTree ; 
			    cpTmp_line= cpRef_line ; 
				cpRef_line= device.cur_line ; 
				device.cur_line= cpTmp_line ; 
				memset (device.cur_line,0x00,(m_lImgWidth+7)/*FAXWIDTH*//8) ; 
				lnHorz_runs= lnCode= 0 ; 
				lnA0= (-1) ; 
            } 
 
			/* Next check is for an EOL code.  If we have one in T.6 it 
            marks the end of the image (EOFB).  Otherwise, we ignore 
            any 0 fill bits in the EOL code and carry on till the 1 
            which marks its end. We then reset our resync flag (set at 
            the start and on a decoding error and reset our key 
            variables to the start of the line. If we are 2-D coding, we 
            set a dummy OUREOL2 code to force reading of the next tag 
            bit. If we are 1-D coding we start the next line pointing at 
            the root of the white run decoding tree */ 
 
			if (lnCode== OUREOL) 
            { 
				if (m_image.wOptions&2)  
					break; 
				if ((bOctet&0x80)== 0)  
					continue; 
 
				lnResync= 0 ; 
				device.color= WHITE ; 
				lnDots_left= m_lImgWidth;//FAXWIDTH ; 
				if (m_image.wOptions&1)  
					lnCode= OUREOL2 ; 
				else 
				{ 
					tree= (NODE *)&gWTree ; 
					lnCode= 0 ; 
				} 
				continue; 
            } 
 
			/* Next check is for the tag bit when 2-D coding.  We set our 
            bCoding_scheme flag appropriately and then start the next line 
            pointing either to the root of the white decoding tree, or else 
            to the two-dimensional code word coding tree, as 
            appropriate */ 
 
			if (lnCode== OUREOL2) 
            { 
				bCoding_scheme= ((bOctet&0x80) >> 7); 
				 
				if (bCoding_scheme== 1) 
				{ 
					tree= (NODE *)&gWTree; 
				} 
				else 
				{ 
					tree= (NODE *)&gTwoTree ; 
					lnHorz_runs= 0 ; 
					lnA0= (-1) ; 
				} 
				cpTmp_line= cpRef_line ; 
				cpRef_line= device.cur_line ; 
				device.cur_line= cpTmp_line ; 
				memset (device.cur_line,0x00,(m_lImgWidth+7)/*FAXWIDTH*//8) ; 
				lnCode= 0 ; 
				continue ; 
            } 
 
         /* Now for the main decoding algorithm.  The codes are 
            arranged as a binary tree.  We take the left fork for 
            a 0 bit and the right fork for a one bit, and make that 
            our new code word.  If the code word is either zero or a 
            minus number we have a run length, but all positive code 
            words represent pointers to the next branch in the tree. 
            There are two types of run lengths - those below 64 are 
            terminating codes, which mean we flip the colour and start 
            the next code with the root of the other decoding tree.  For 
            make-up codes of 64 and above we start the next code with 
            the root of the same tree.  If we happened to be doing 
            1-D coding because we were in a 2-D horizontal run 
            (horz-run is decremented to zero) we point the next code at 
            the two-dimensional tree */ 
 
			if(lnCode > 91) 
				lnCode = 0; 
			else 
				lnCode= (*tree)[lnCode][(bOctet&0x80)>>7]  ; 
 
			if (lnCode<1) 
            { 
				lnCode= (-lnCode) ; 
				if (!lnResync)  
				{ 
					if ((lnDots_left-= lnCode)<0)  
						lnResync= 1 ; 
				} 
 
				if ((!lnResync)&&(lnCode!= 0))  
					if(! ProcessLine(&device, lnCode)) 
						return NULL; 
 
				if (lnCode < 64) 
				{ 
					device.color= (~device.color) ; 
					tree= device.color ? (NODE *)&gBTree : (NODE *)&gWTree; 
					if (m_image.wOptions&3) 
					{ 
						if ((bCoding_scheme!= 1)&&(--lnHorz_runs== 0)) 
						{ 
							lnA0= 0 ; 
							tree= (NODE *)&gTwoTree ; 
						} 
					} 
				} 
				lnCode= 0 ; 
				continue ; 
			} 
			if (lnCode>(lnA0%8)) ; 
				if (cpRef_line[j]&bThis_bit)  
					bRef_color= BLACK ;  
				else  
					bRef_color= WHITE ; 
            } 
 
			for (lnB1= lnA0+1;lnB1>(lnB1%8)) ; 
				if ((cpRef_line[j]&bThis_bit)!= (bRef_color&bThis_bit))  
					break ; 
            } 
			if (bRef_color!= device.color) 
            { 
				for (lnB1++;lnB1>(lnB1%8)) ; 
					if ((cpRef_line[j]&bThis_bit)==(bRef_color&bThis_bit))  
						break ; 
				} 
            } 
			if (lnB1>m_lImgWidth)//FAXWIDTH)  
				lnB1= m_lImgWidth;//FAXWIDTH ; 
			lnA0= (m_lImgWidth/*FAXWIDTH*/-lnDots_left) ; 
 
			/* If the code is below PASSMODE then it is one of the	 
            vertical code words, which are pretty easy to decipher as 
            we have all the data. Vertical mode flips the colour and 
            then continues. */ 
 
			if (lnCode>(lnB2%8)) ; 
				if ((cpRef_line[j]&bThis_bit)== (device.color&bThis_bit))  
					break ; 
            } 
			if (lnB2>m_lImgWidth/*FAXWIDTH*/) lnB2= m_lImgWidth;//FAXWIDTH ; 
 
			if (lnCode== PASSMODE) 
            { 
				lnCode= (lnB2-lnA0) ; 
				if (!lnResync)  
				{ 
					if ((lnDots_left-= lnCode)<0)  
						lnResync= 1 ; 
				} 
				 
				if ((!lnResync)&&(lnCode!= 0))  
					if(! ProcessLine(&device, lnCode) ) 
						return NULL; 
 
				lnCode= 0 ; 
				continue ; 
            } 
 
			/* Finally, if we weren't pass mode, we lnResync if T4, else 
            abandon if T6 */ 
 
			if (m_image.wOptions&2)  
				return NULL; 
 
			lnResync= 1 ; 
			continue ; 
		} 
	} 
	 
	if(! ProcessLine(&device, DEINIT) ) 
		return NULL;  
 
	// no image ????????, should never be true!! 
	if(m_outImage.lpImage == NULL) 
		return NULL; 
 
	// --- make dib image  
	BITMAPINFOHEADER bih; 
	RGBQUAD rgb[2]; 
 
	bih.biSize = sizeof(BITMAPINFOHEADER); 
	bih.biWidth = m_outImage.wWidth; 
	bih.biHeight = m_outImage.wLength; 
	bih.biPlanes = 1; 
	bih.biBitCount = 1; 
	bih.biCompression = BI_RGB;  // uncompressed format 
	WORD wWidthBytes = WIDTHBYTES(bih.biWidth*bih.biBitCount); 
	bih.biSizeImage = wWidthBytes*bih.biHeight; 
	bih.biXPelsPerMeter = 0; 
	bih.biYPelsPerMeter = 0; 
	bih.biClrUsed = 0; 
	bih.biClrImportant = 0; 
 
	rgb[0].rgbBlue=0x00; 
	rgb[0].rgbGreen=0x00; 
	rgb[0].rgbRed=0x00; 
	rgb[0].rgbReserved=0; 
 
	rgb[1].rgbBlue=0xff; 
	rgb[1].rgbGreen=0xff; 
	rgb[1].rgbRed=0xff; 
	rgb[1].rgbReserved=0;	 
 
	// flip 0, 1 in image bits 
	DWORD dwPos = 0; 
	BYTE  byDelta, byPixel = 0; 
	for (int row=0; row>= byDelta; 
		byPixel <<= byDelta; 
		*(m_outImage.lpImage+dwPos) = byPixel; 
	} 
 
	// vertically flip image buffer 
	if (! VertFlipBuf(m_outImage.lpImage, wWidthBytes, bih.biHeight)) 
		return FALSE; 
 
    // Allocate enough memory for the new CF_DIB, and copy bits  
	DWORD dwBitsSize = bih.biSizeImage; 
	DWORD dwColorTableSize = (1<dest_width/8)*device->total_lines; 
		m_lpFaxline = new BYTE[m_lnFaxBytes]; 
		if (m_lpFaxline==NULL)  
			return 0; 
 
		m_lnSliceBytes = device->total_lines/8; 
 
		memset(m_lpFaxline,0x00,m_lnFaxBytes) ; 
		m_lnIndex=0 ; 
		m_lnThisbit=8 ; 
		m_ln2DIndex=0 ; 
		m_ln2DBit=8 ; 
		m_lnLastSaveByte=0 ; 
		m_lnRow = 0; 
		HorizScale(device,(long int)m_lnIndex) ; 
		VerticalScale(device,(long int)-1) ; 
		device->color=WHITE ; 
		device->this_line=device->total_lines ; 
		return (1) ; 
	}	 
 
	/************************************************************************** 
 
	We deinitialize here - we just free memory and get out 
 
	**************************************************************************/ 
 
	if (iRunlength==DEINIT) 
	{ 
		delete m_lpFaxline; 
		m_lpFaxline=NULL; 
		return (1) ; 
	} 
 
	/************************************************************************** 
 
	At the end of each page we make sure any partial lines get printed 
	(by calling Output).  We reset our m_lnLastSaveByte marker, set our Output buffer 
	to white space and reset vertical scaling.  We do the relevant 
	newpage function for our device and get out. 
 
	**************************************************************************/ 
 
	if (iRunlength==OUREOP) 
	{ 
		if (device->total_lines>1) 
		{ 
			//  while (device->this_line!=device->total_lines) 
			//   Output(device,m_lpFaxline,m_lnRow,m_lnLastSaveByte) ; 
		} 
		//else if (m_lnLastSaveByte!=0)  
		//	   Output(device,m_lpFaxline,m_lnRow,m_lnLastSaveByte) ; 
		m_lnLastSaveByte=0 ; 
		memset(m_lpFaxline,0x00,m_lnFaxBytes) ; 
		m_lnRow = 0 ; 
		//VerticalScale(device,(long int)-1) ; 
		//newpage(device) ; 
		return 1; 
	} 
 
	/************************************************************************** 
 
	At the end of each scan line things start to get complicated. 
 
	We always call vscale and see how many lines we have to Output. 
 
	1) If we have no lines to Output we reset our indices (leaving our 
	data intact for ORIng in with later lines) and return with indices, 
	color and horizontal scaling reset. 
 
	2) If we have multiple lines to Output, we start a loop for each 
	Output line. The number of lines we Output at a time (as set in the 
	DEVPARMS member total_lines) could be 1 (for raster devices such as 
	screen and HP type lasers) or a multiple of 8 (for 24-pin dot-matrix 
	and bubblejet printers that go in slices - note that as 9-pin dot 
	matrix printer have a lower resolution than a fax they never have 
	more than one line to Output and therefore don't get handled just 
	yet). We have to handle these cases in different ways. 
 
	i) For multislice printers which Output multiple lines in different 
		bit positions we need to cater for two further cases. 
 
		One is where we really do Output, which is only if we reach the 
		last line of the slice (when DEVPARMS this_line decrements to 1) ; 
		In this case, we call the Output function and then set the Output 
		buffer to white space before looping. 
 
		The other multislice case is where the slice isn't complete so we 
		cannot call Output just yet.  What we do is to duplicate the bit 
		of the slice we have reached into the next bit. This involves 
		first finding out the bit we have reached from m_lnSliceBytes and 
		this_line (which is stored in the m_lnLastSaveByte of bBit) and then ORing 
		that back in at the next bit position (which might be in the 
		following byte). 
 
		For all multislice cases we then go on to the next m_lnRow and the 
		next bit in the slice (increment m_lnRow and decrement DEVPARMS 
		this_line) before carrying on with the loop. 
 
	ii) For single-slice printers or screens we simply Output, increment 
		m_lnRow, and loop again.  9-pin dot matric printers also come to here. 
 
		We then have a special check to see if we really printed on a 8-slice 
		printer (9-pin dot matrix) and if we did, we reset m_lnLastSaveByte to 0 and reset 
		the Output buffer to white space. 
 
	Finally, we reset indices to zero, reset bits unused to 8, 
	reinitialize hor scaling, reinitialize colour to white, and go back. 
 
	**************************************************************************/ 
 
	if (iRunlength==OUREOL) 
	{ 
		m_ln2DIndex=0 ; 
		m_ln2DBit=8 ; 
		lnTemp = 1;//VerticalScale(device,(long int)m_lnRow) ; 
		if (lnTemp==0) 
		{ 
			m_lnIndex=0 ; 
			m_lnThisbit=8 ; 
			HorizScale(device,(long int)m_lnIndex) ; 
			device->color=WHITE ; 
			return 1; 
		} 
		for (; lnTemp>0 ; lnTemp--) 
		{ 
			if (device->total_lines>8) 
			{ 
				if (device->this_line==1) 
				{ 
					if(!Output(device,m_lpFaxline,m_lnRow,m_lnLastSaveByte)) 
						return 0; 
					m_lnRow++ ; 
					for (m_lnIndex=0 ; m_lnIndexthis_line/8) ; 
							bBit=m_lpFaxline[m_lnIndex+m_lnThisbit] ; 
							m_lnThisbit=device->this_line%8 ; 
							if (m_lnThisbit==0)  
								m_lnThisbit=8 ; 
							m_lnThisbit = 1 << (m_lnThisbit-1) ; 
							bBit=(bBit&m_lnThisbit) ; 
							if (bBit!=0)  
								bBit=1 ; 
							m_lnThisbit=(device->this_line-1)%8 ; 
							if (m_lnThisbit==0)  
								m_lnThisbit=8 ; 
							if (m_lnThisbit>1)  
								bBit <<= (m_lnThisbit-1) ; 
							m_lnThisbit=m_lnSliceBytes- 
								((device->this_line-1)/8) ; 
							m_lpFaxline[m_lnIndex+m_lnThisbit]= 
								m_lpFaxline[m_lnIndex+m_lnThisbit]|bBit ; 
						} 
					} 
					m_lnRow++ ; 
					--device->this_line ; 
				} 
			} 
			else 
			{ 
				if(!Output(device,m_lpFaxline,m_lnRow,m_lnLastSaveByte)) 
					return 0; 
				m_lnRow++ ; 
			} 
		} 
		if ((device->this_line==device->total_lines) 
			&&(device->total_lines<=8)) 
		{ 
			m_lnLastSaveByte=0 ; 
			for (m_lnIndex=0;m_lnIndexcolor=WHITE ; 
		return 1; 
	} 
 
	/************************************************************************** 
 
	Our final case is going to be normal run length.  We understabably 
	ignore a run length of 0 (though it's a valid terminating run 
	length). 
 
	If we are decoding a 2-D file (we see that the cur_line current line 
	buffer is in use) we must preserve a copy of the current scan line 
	being decoded for use as the reference line when decoding the next 
	scan line.  We keep this copy in the buffer pointed at by cur_line. 
	We take a copy of the run length as it gets destroyed.  Then for 
	white runs, we just skip the correct number of bits as cur_line 
	buffer is always initialized to white space.  For black runs, we OR a 
	series of 1s into the cur_line buffer until the run is exhausted - 
	where we can we do this in octets, but where we cannot we OR single 
	bits.  Then we carry on as normal with the original run-length. 
 
	The run length is scaled horizontally - we ignore cases where it is 
	scaled down to zero. 
 
	We treat multislice printers (which Output more than one scan line at 
	a time with different line occupying different bit positions) 
	differently to raster devices like screens and lasers. 
 
	Raster devices simply require setting the same number of consecutive 
	bits as the run length in the Output buffer.  If the run is white, 
	presetting the buffer to white space enables us to simply skip. If 
	the run is black, we OR bit in till the run is used up. We also set 
	the m_lnLastSaveByte marker to the final black position if it is greater than the 
	last m_lnLastSaveByte value. 
 
	Multislice printer require setting the identical bit in the same 
	number of consecutive slices as the run length in the Output buffer. 
	Again, if the run is white, presetting the buffer to white space 
	enables us to skip, but we skip slices rather than bits.  If the run 
	is black, we first set m_lnLastSaveByte and then OR a bit in the right position 
	(we calculate the relative bit and slice position from this_line 
	knowing that we have 8 lines to a byte) till the run is used up. 
 
 
	**************************************************************************/ 
 
	if (!iRunlength)  
		return 1; 
 
	if (device->cur_line!=NULL) 
	{	 
		lnCopyRun=iRunlength ; 
		if (device->color==WHITE) 
		{ 
			m_ln2DBit-=(lnCopyRun%8) ; 
			m_ln2DIndex+=(lnCopyRun/8) ; 
			if (m_ln2DBit<0) 
			{ 
				m_ln2DBit+=8 ; 
				m_ln2DIndex++ ; 
			} 
		} 
		else for (;;) 
		{ 
			while (m_ln2DBit>0) 
			{ 
				device->cur_line[m_ln2DIndex]|=(1<<(m_ln2DBit-1)) ; 
				m_ln2DBit-- ; 
				if (!(--lnCopyRun))  
					break; 
			} 
			if(lnCopyRun==0)  
				break ; 
			m_ln2DIndex++; 
			for (; lnCopyRun>8 ; lnCopyRun-=8)  
				device->cur_line[m_ln2DIndex++]=(char)0xff ; 
			if (lnCopyRun==0)  
				break; 
			m_ln2DBit=8; 
		} 
	} 
 
	iRunlength=HorizScale(device,(long int)iRunlength) ; 
	if (!iRunlength)  
		return 1; 
 
	if (device->total_lines>1) 
	{ 
		if (device->color==WHITE) 
		{ 
			m_lnIndex+=(m_lnSliceBytes*iRunlength) ; 
			if (m_lnIndex>m_lnFaxBytes)  
				m_lnIndex=m_lnFaxBytes ; 
			return 1; 
		} 
		bBit = 1 ; 
		m_lnThisbit=device->this_line%8 ; 
		if (m_lnThisbit==0)  
			m_lnThisbit=8 ; 
		if (m_lnThisbit>1)  
			bBit <<= (m_lnThisbit-1) ; 
		m_lnThisbit=m_lnSliceBytes-(device->this_line/8) ; 
		for (;;) 
		{	 
			if (m_lnLastSaveByte<=m_lnIndex)  
				m_lnLastSaveByte=(m_lnIndex+1) ; 
			m_lpFaxline[m_lnIndex+m_lnThisbit]|=bBit ; 
			if (m_lnIndexcolor==WHITE) 
	{ 
		m_lnThisbit-=(iRunlength%8) ; 
		m_lnIndex+=(iRunlength/8) ; 
		if (m_lnThisbit<0) 
		{ 
			m_lnThisbit+=8 ; 
			m_lnIndex++ ; 
		} 
		return 1; 
	} 
	for (;;) 
	{ 
		if (m_lnLastSaveByte<=m_lnIndex)  
			m_lnLastSaveByte=(m_lnIndex+1) ; 
		while (m_lnThisbit>0) 
		{ 
			m_lpFaxline[m_lnIndex]|=(1<<(m_lnThisbit-1)) ; 
			m_lnThisbit-- ; 
			if (!(--iRunlength))  
				return 1; 
		} 
		if (iRunlength==0)  
			return 1; 
		m_lnIndex++ ; 
		for (; iRunlength>8 ; iRunlength-=8)  
			m_lpFaxline[m_lnIndex++]=0xff ; 
		if (iRunlength==0)  
			return 1; 
		m_lnThisbit=8 ; 
	} 
} 
 
/**************************************************************************/ 
// ---------------------------------------------------------------------------- 
// init the decoding buffer 
// 
BOOL CTifIFD::InitDecoding() 
{ 
	// ALLOCATE OUTPUT MEMORY 
	FreeOutImageMem(); 
	m_outImage.wWidth = (WORD)m_lImgWidth;  
	m_outImage.wLength = (WORD)m_lImgHeight;  
 
	long lnBufLen = ((m_outImage.wWidth+31)/32*32)/8* 
		((long)(m_outImage.wLength+400))+ DECODE_BUF_EXTEND_LEN; 
	 
	m_outImage.lnBufLen = lnBufLen*4; 
	m_outImage.lpImage = (LPBYTE) new BYTE[m_outImage.lnBufLen]; 	// why add 6000??? 
 
	if(m_outImage.lpImage == 0) 
		return FALSE; 
 
	memset(m_outImage.lpImage,0,m_outImage.lnBufLen); 
 
	return TRUE; 
} 
 
int CTifIFD::HorizScale(DEVPARMS * device, long int run) 
{ 
	static long int remainder ; 
	static char borrow ; 
 
	if (!run) 
	{ 
		remainder=0 ; 
		borrow=0 ; 
		return(0) ; 
	} 
 
	run=(run*(long int)device->dest_width); 
	run=run+remainder ; 
	remainder=run%device->source_width ; 
	run=run/device->source_width ; 
 
	if ((!run)&&(!borrow)) 
	{ 
		run++ ; 
		borrow++ ; 
	} 
 
	if ((run>1)&&(borrow!=0)) 
	{ 
		run-- ; 
		borrow-- ; 
	} 
 
	return (int)(run) ; 
} 
 
int CTifIFD::VerticalScale(DEVPARMS * device, long int count) 
{ 
	static long int remainder ; 
 
	if (count<0) 
	{ 
		remainder=0 ; 
		return(0) ; 
	} 
 
	count=remainder+device->dest_height ; 
	remainder=count%(device->source_height*device->res) ; 
	count=count/(device->source_height*device->res) ; 
	return (int)(count) ; 
} 
 
BOOL CTifIFD::Output(DEVPARMS * device, unsigned char * our_line, int our_row, int lsb) 
{ 
	DWORD newWidth = (m_lImgWidth+31)/32*32/8; 
	switch (device->id) 
	{ 
	case DEVICE_MEMORY: 
		{ 
			int nLen = ((m_outImage.wWidth+31)/32*32)/8*((long)(m_outImage.wLength+400))  
				+ 4000 -m_lImgWidth/8;	// why add 4000 
			 
			if(m_outImage.lnCount >= m_outImage.lnBufLen) 
			{ 
#if 0 
				return FALSE; 
#endif 
			}			 
			if(our_line == NULL) 
			{ 
				return FALSE; 
			} 
			ASSERT((WORD)(m_outImage.lnCount + newWidth) < m_outImage.lnBufLen); 
 
			memcpy(m_outImage.lpImage+m_outImage.lnCount, 
				our_line,newWidth); 
 
			m_outImage.lnCount += newWidth; 
			break; 
		} 
   /* for uncompressed TIFF files, we simply fwrite the exact number 
      of bytes to the output file and increment the count of lines in 
      the image */ 
#if 0 
   case U_TIFF : 
		if ((fwrite (our_line,1,((m_lImgWidth+7)/*FAXWIDTH*//8),device->tiffile))==0) 
		{ 
			fclose (device->tiffile); 
			device->tiffile=NULL;  
		} 
		device->ifd->ImageLength.value++; 
		break; 
#endif 
	default: 
	   break; 
	} 
	return TRUE; 
} 
 
BOOL CTifIFD::VertFlipBuf(BYTE* inbuf, UINT widthBytes, UINT height) 
{    
	BYTE  *tb1; 
	BYTE  *tb2; 
 
	if (inbuf==NULL) 
		return FALSE; 
 
	UINT bufsize; 
 
	bufsize=widthBytes; 
 
	tb1= (BYTE *)new BYTE[bufsize]; 
	if (tb1==NULL) { 
		return FALSE; 
	} 
 
	tb2= (BYTE *)new BYTE [bufsize]; 
	if (tb1==NULL) { 
		return FALSE; 
	} 
	 
	UINT row_cnt;      
	ULONG off1=0; 
	ULONG off2=0; 
 
	for (row_cnt=0;row_cnt<(height+1)/2;row_cnt++) { 
		off1=row_cnt*bufsize; 
		off2=((height-1)-row_cnt)*bufsize;    
		 
		memcpy(tb1,inbuf+off1,bufsize); 
		memcpy(tb2,inbuf+off2,bufsize);	 
		memcpy(inbuf+off1,tb2,bufsize); 
		memcpy(inbuf+off2,tb1,bufsize); 
	}	 
 
	delete [] tb1; 
	delete [] tb2; 
 
	return TRUE; 
}         
 
void reverse (void *pointer,int lnCountdown) 
{ 
	int lnCountup=0 ; 
	BYTE bStore; 
	LPBYTE lpAddress = (LPBYTE)pointer ; 
 
	if (pointer==NULL) return; 
	if (lnCountdown%2) return; 
 
	while (lnCountup