Import Cbf Byte_offset compressed images

This function imports Cbf file with byte_offset compression
see: http://www.bernstein-plus-sons.com/software/CBF/doc/CBFlib.html#3.3.3
for compression description and lots of other information. This compression is easy enough that it can be done in Igor Pro directly. Load time on 2M image on high level Macbook Pro (2013) is about 0.6 seconds. Tested on Pilatus 2M images (from PSI).


//*************************************************************************************************
//	This function imports Cbf file with byte_offset compression
// see: http://www.bernstein-plus-sons.com/software/CBF/doc/CBFlib.html#3.3.3
// for compression description and lots of other information. 
// tested on Pilatus 2M images (from PSI)
//*************************************************************************************************
Function LoadCbfCompresedImage(PathName,FileNameToLoad, WaveNameToCreate)
	string PathName,  FileNameToLoad, WaveNameToCreate
	//this function loads and uncompresses the Cbf byte_offset compressed file format with:
	// conversions="x-CBF_BYTE_OFFSET";Content-Transfer-Encoding=BINARY;
        //X-Binary-Element-Type="signed 32-bit integer";X-Binary-Element-Byte-Order=LITTLE_ENDIAN;
	//Searches for start of binary data, checks how much data there should be and creates 1D wave output wave (stream) 
        //     with uncompressed data in the current data folder. 
	variable SkipBytes
	variable filevar
	variable bufSize 
	variable sizeToExpect
	string testLine
	//locate start of the binary data
	open /R/P=$(PathName) filevar as FileNameToLoad
	testLine=""
	testLine=PadString (testLine, 16800, 0x20)
	FBinRead filevar, testLine
	close filevar
	SkipBytes=strsearch(testLine, "\014\032\004\325" , 0)+4		//this is string I found in test images
	if(SkipBytes<5)										//string not found...
		SkipBytes=strsearch(testLine, "\012\026\004\213" , 0)+4	//this is per http://www.bernstein-plus-sons.com/software/CBF/doc/CBFlib.html#3.2.2 what should be there. Go figure... 
	endif
	if(SkipBytes<5)
		Abort "Failed to find start of binary section in the Cbf file"	//string still not found. This is problem. 
	endif
	//Figure out now how much data are we expecting
	//    this header is quite messy, let's clean ti up a bit
	testLine=ReplaceString("\r\n\r\n", testLine, ";")
	testLine=ReplaceString("\r\n", testLine, ";")
	testLine=ReplaceString("#", testLine, "")
	testLine=ReplaceString(";;;;", testLine, ";")
	testLine=ReplaceString(";;;", testLine, ";")
	testLine=ReplaceString(";;", testLine, ";")
	testLine = ReplaceString(":", testLine, "=")
	sizeToExpect = NumberByKey("X-Binary-Number-of-Elements", testLine, "=", ";")
	//read the data in binary free wave so we can use them here
	Open /Z/R/P=$(PathName)/T="????" filevar as FileNameToLoad
	if (V_flag)
		close filevar
		Abort "Cannot open file, something is wrong here"		// could not open file
	endif
	FSetPos fileVar, SkipBytes								//start of the image
	FStatus fileVar
	bufSize = V_logEOF-V_filePos							//this is how mcuh data we have in the image starting at the binary data start
	make/B/O/N=(bufSize)/Free BufWv						//signed 1 byte wave for the data
	make/O/N=(sizeToExpect)/Free ResultImage				//here go teh converted singed integers. Note, they can be 8, 16, or 32 bits. 64bits not supported here. 
	FBinRead/B=1/F=1 fileVar, BufWv						//read 1 Byte each into singed integers wave
	close filevar
	//and not decompress the data here 	
	variable i, j, PixelValue, ReadValue
	j=0												// j is index of the signed 1 byte wave (stream of data in) 
	PixelValue = 0										//value in current pixel in image. 
	For(i=0;i<(sizeToExpect);i+=1)							//i is index for output wave
		if(j>bufSize-1)
			break									//just in case, we run our of j. Should never happen
		endif
		ReadValue = BufWv[j]							//read 1 Byte integer
		if(ReadValue>-128)								//this is useable value if +/- 127
			PixelValue += ReadValue						//add to prior pixel value
			ResultImage[i] = PixelValue					//store in output stream
			j+=1										// move to another j point 
		elseif(ReadValue==-128)							// This is indicator that the difference did not fit in 1Byte, read 2 bytes and use those.
			j+=1										// move to another point to start reading the 2 bytes
			ReadValue = Conv2Bytes(BufWv[j],BufWv[j+1])	        //read and convert 2 Bytes in integer
			if(ReadValue>-32768)						// This is useable value, use these two bytes
				PixelValue += ReadValue					//add to prior pixel value
				ResultImage[i] = PixelValue				//store in output stream
				j+=2									//move to another j point  
			elseif(ReadValue==-32768)					// This is indicator that the difference did not fit in 2Bytes, read 4 bytes and use those.
				j+=2									//move to another point to start reading the 4 bytes 
				ReadValue = Conv4Bytes(BufWv[j],BufWv[j+1], BufWv[j+2], BufWv[j+3])		//read and convert next 4 Bytes in integer
				if(abs(ReadValue)<2147483648)				//this is correct value for 32 bits
					PixelValue += ReadValue				//add to prior pixel value
					ResultImage[i] = PixelValue			//store in output stream
					j+=4								//move to another j point 
				else									//abort, do not support 64 byte integers (no such detector exists... 
					abort "64 bits data are not supported"
				endif
			else
				print "error"
			endif
		else
			print "error"
		endif
	endfor
	Duplicate/O ResultImage, $(WaveNameToCreate)			
	//create wave user requested. Note, this is 1D wave and needs to be redimensioned to 2D wave (image). Could be done here... 
end
//*************************************************************************************************
//*************************************************************************************************
//*************************************************************************************************
static Function Conv2Bytes(B1,B2)		
	variable B1, B2
	//takes two signed integer bytes, and converts them to 16 bit signed integer, little-endian, two's complement signed interpretation
	//assume B1 is first byte for little-endian should be unsigned integer as it is the smaller part of the data
	//assume B2 contains the larger values and sign
	variable unsB1=(B1>=0) ? B1 : (256 + B1)	//this should convert two's complement signed interpretation to Usigned interpretation
	return unsB1 + 256*B2
end
//*************************************************************************************************
//*************************************************************************************************
static Function Conv4Bytes(B1,B2, B3, B4)		
	variable B1, B2, B3, B4
	//takes four signed integer bytes, and converts them to 32 bit signed integer, little-endian, two's complement signed interpretation
	//assume B1, B2, B3 are first bytes for little-endian should be unsigned integer as it is the smaller part of the data
	//assume B4 contains the larger values and sign
	variable unsB1=(B1>=0) ? B1 : (256 + B1)	//this should convert two's complement signed interpretation to Usigned interpretation
	variable unsB2=(B2>=0) ? B2 : (256 + B2)	//this should convert two's complement signed interpretation to Usigned interpretation
	variable unsB3=(B3>=0) ? B3 : (256 + B3)	//this should convert two's complement signed interpretation to Usigned interpretation
	return unsB1 + 256*unsB2 + 256*256*unsB3 + 256*256*256*B4
end
//*************************************************************************************************
//*************************************************************************************************

Forum

Support

Gallery

Igor Pro 10

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More