CFEL - ASG Software Suite  2.5.0
CASS
cbf_handle.hpp
Go to the documentation of this file.
1 //Copyright (C) 2012 Lutz Foucar
2 
3 /**
4  * @file cbf_handle.hpp handle cbf files
5  *
6  * @author Lutz Foucar
7  */
8 
9 #ifndef _CBFHANDLE_
10 #define _CBFHANDLE_
11 
12 #include <QtCore/QString>
13 #include <QtCore/QFileInfo>
14 
15 #include <vector>
16 #include <string>
17 #include <fstream>
18 #include <sstream>
19 
20 #include "cass_version.h"
21 
22 namespace cass
23 {
24 namespace CBF
25 {
26 /** write cbf file
27  *
28  * @param filename the filename to write the cbf to
29  * @param data iterator to the data that should be written
30  * @param shape the shape of the image
31  *
32  * @author Stephan Kassemeyer
33  */
34 inline
35 void write(const std::string &filename, std::vector<float>::const_iterator data,
36  const std::pair<int,int>& shape)
37 {
38  const int nx = shape.first;
39  const int ny = shape.second;
40 
41  /** cbf parameters: */
42  int IOBUFSIZ = 4096;
43  char MARKBYTE[4] = {static_cast<char>(0x0C),
44  static_cast<char>(0x1A),
45  static_cast<char>(0x04),
46  static_cast<char>(0xD5)};
47 
48  /** create the cbf file */
49  std::ofstream cbf_file;
50  cbf_file.open(filename.c_str(), std::ios::out|std::ios::binary);
51 
52  /** find out length of the compressed array: */
53  int nbytes = 0;
54  int pixvalue = 0;
55  int diff;
56  int absdiff;
57  for (int iadr=0; iadr<nx*ny; ++iadr)
58  {
59  diff = ((int) data[iadr]) - pixvalue;
60  pixvalue = (int) data[iadr];
61  absdiff = abs(diff);
62  ++nbytes;
63  if (absdiff < 128)
64  continue;
65  nbytes += 2;
66  if (absdiff < 32768)
67  continue;
68  nbytes += 4;
69  }
70 
71  QString fn(QString::fromStdString(filename));
72  QString bn(QFileInfo(fn).fileName());
73  std::string fbn(bn.toStdString());
74 
75  /** write image header */
76  cbf_file << "###CBF: Generated by CASS " << VERSION << "\r\n";
77  cbf_file << "" << "\r\n";
78  cbf_file << fbn << "\r\n";
79  cbf_file << "" << "\r\n";
80  cbf_file << "_array_data.header_convention \"XDS special\"" << "\r\n";
81  cbf_file << "_array_data.header_contents" << "\r\n";
82  cbf_file << ";" << "\r\n";
83  cbf_file << ";" << "\r\n";
84  cbf_file << "" << "\r\n";
85  cbf_file << "_array_data.data" << "\r\n";
86  cbf_file << ";" << "\r\n";
87  cbf_file << "--CIF-BINARY-FORMAT-SECTION--" << "\r\n";
88  cbf_file << "Content-Type: application/octet-stream;" << "\r\n";
89  cbf_file << " conversions=\"x-CBF_BYTE_OFFSET\"" << "\r\n";
90  cbf_file << "Content-Transfer-Encoding: BINARY" << "\r\n";
91  cbf_file << "X-Binary-Size: " << nbytes << "\r\n";
92  cbf_file << "X-Binary-ID: 1" << "\r\n";
93  cbf_file << "X-Binary-Element-Type: \"signed 32-bit integer\"" << "\r\n";
94  cbf_file << "X-Binary-Element-Byte-Order: LITTLE_ENDIAN" << "\r\n";
95  cbf_file << "X-Binary-Number-of-Elements: " << nx*ny << "\r\n";
96  cbf_file << "X-Binary-Size-Fastest-Dimension: " << nx << "\r\n";
97  cbf_file << "X-Binary-Size-Second-Dimension: " << ny << "\r\n";
98  cbf_file << "X-Binary-Size-Padding: " << IOBUFSIZ-1 << "\r\n";
99  cbf_file << "" << "\r\n";
100  cbf_file << MARKBYTE[0] << MARKBYTE[1] << MARKBYTE[2] << MARKBYTE[3];
101 
102 
103  // determine endianness
104  int step, first2, last2, first4, last4;
105  union
106  {
107  uint32_t ii;
108  char cc[4];
109  }
110  bint = {0x01020304};
111  if (bint.cc[0] == 1)
112  {
113  // big endian
114  step = -1;
115  first2=1; last2=0;
116  first4=3; last4=0;
117  }
118  else
119  {
120  // little endian
121  step = 1;
122  first2=0; last2=1;
123  first4=0; last4=3;
124  }
125 
126  /** write histogram data
127  * compress image using the byte offset method and save as octet stream
128  */
129  pixvalue = 0;
130 
131  signed char onebyte[1];
132  signed char twobytes[2];
133  signed char fourbytes[4];
134  int shortint;
135 
136  for (int iadr=0; iadr<nx*ny; ++iadr)
137  {
138  diff = ((int) data[iadr]) - pixvalue;
139  absdiff = abs(diff);
140  pixvalue = (int)data[iadr];
141 
142  onebyte[0] = -128;
143  if (absdiff < 128)
144  onebyte[0] = diff;
145  cbf_file << onebyte[0];
146  if (absdiff < 128)
147  continue;
148 
149  shortint = -32768;
150  if (absdiff < 32768)
151  shortint = diff;
152  *((char*)(&twobytes)+0) = *((char*)(&shortint)+0);
153  *((char*)(&twobytes)+1) = *((char*)(&shortint)+1);
154 
155  for (int ii=first2; ii!=last2+step; ii+=step)
156  cbf_file << twobytes[ii];
157  if (absdiff < 32768)
158  continue;
159 
160  *((char*)(&fourbytes)+0) = *((char*)(&diff)+0);
161  *((char*)(&fourbytes)+1) = *((char*)(&diff)+1);
162  *((char*)(&fourbytes)+2) = *((char*)(&diff)+2);
163  *((char*)(&fourbytes)+3) = *((char*)(&diff)+3);
164 
165  for (int ii=first4; ii!=last4+step; ii+=step)
166  cbf_file << fourbytes[ii];
167  }
168 
169  /** terminate image data part with the MIME footer */
170  cbf_file << "" << "\r\n";
171  cbf_file << "--CIF-BINARY-FORMAT-SECTION----" << "\r\n";
172  cbf_file << ";" << "\r\n";
173  cbf_file << "" << "\r\n";
174 
175  /** and pad last record of file with zeros: */
176  char zerobyte;
177  zerobyte = 0;
178  for (int ii=0; ii<IOBUFSIZ; ++ii)
179  cbf_file << zerobyte;
180 
181  cbf_file.close();
182 }
183 
184 /** read the cbf data into a linearized 2d array
185  *
186  * @param[in] filename the name of the cbf file to read
187  * @param[out] headerstring the complete header of the cbf file
188  * @param[out] matrix the output matrix, will be resized to fit the data
189  * @param[out] shape the shape of the matrix
190  */
191 void read(const std::string & filename, std::string &headerstring,
192  std::vector<float>& matrix, std::pair<int,int>& shape)
193 {
194  /** open file and determine filesize */
195  std::ifstream cbf_file(filename.c_str(), std::ios::in | std::ios::binary);
196  cbf_file.seekg(0,std::ios::end);
197  std::streampos fsize(cbf_file.tellg());
198  cbf_file.seekg(0,std::ios::beg);
199 
200 
201  /** create a buffer and copy the whole header to it */
202  bool eohfound=false;
203  std::vector<char> header(fsize);
204  std::vector<uint8_t> eohMarker(4,0);
205  int hidx(0);
206  while (!cbf_file.eof())
207  {
208  cbf_file.read(reinterpret_cast<char*>(&eohMarker[0]),1);
209 
210  if (eohMarker[0] == 0x0C)
211  {
212  cbf_file.read(reinterpret_cast<char*>(&eohMarker[1]),1);
213  cbf_file.read(reinterpret_cast<char*>(&eohMarker[2]),1);
214  cbf_file.read(reinterpret_cast<char*>(&eohMarker[3]),1);
215  if (eohMarker[1] == 0x1A && eohMarker[2] == 0x04 && eohMarker[3] == 0xD5)
216  {
217  eohfound = true;
218  break;
219  }
220  }
221 
222  header[hidx++] = eohMarker[0];
223  }
224  if (!eohfound)
225  throw std::invalid_argument(filename + " is not a cbf file");
226 
227 
228  /** parse the header */
229  headerstring.assign(header.begin(),header.begin()+hidx);
230  std::istringstream headerstream(headerstring);
231  while(!headerstream.eof())
232  {
233  std::string line;
234  std::getline(headerstream,line);
235 
236  if (line.find("X-Binary-Size-Fastest-Dimension:") != std::string::npos)
237  {
238  std::istringstream iss(line);
239  std::vector<std::string> tokens;
240  std::string token;
241  while(std::getline(iss,token,' '))
242  tokens.push_back(token);
243  shape.first = atoi(tokens.back().c_str());
244  }
245 
246  if (line.find("X-Binary-Size-Second-Dimension:") != std::string::npos)
247  {
248  std::istringstream iss(line);
249  std::vector<std::string> tokens;
250  std::string token;
251  while(std::getline(iss,token,' '))
252  tokens.push_back(token);
253  shape.second = atoi(tokens.back().c_str());
254  }
255  }
256 
257  /** read the matrix data */
258  matrix.resize(shape.first*shape.second);
259  int cInd = 0;
260  int8_t onebyte = 0;
261  int16_t twobytes = 0;
262  int32_t fourbytes = 0;
263  float cVal = 0;
264  while (!cbf_file.eof() && cInd < shape.first * shape.second)
265  {
266  cbf_file.read(reinterpret_cast<char*>(&onebyte),1);
267  if (onebyte == -128)
268  {
269  cbf_file.read(reinterpret_cast<char *>(&twobytes),2);
270  if (twobytes == -32768)
271  {
272  cbf_file.read(reinterpret_cast<char *>(&fourbytes),4);
273  cVal += fourbytes;
274  }
275  else
276  cVal += twobytes;
277  }
278  else
279  cVal += onebyte;
280  matrix[cInd] = cVal;
281  ++cInd;
282  }
283 }
284 
285 }//end namespace cbf
286 }//end namespace cass
287 
288 #endif
fromStdString(const std::string &str)
void read(const std::string &filename, std::string &headerstring, std::vector< float > &matrix, std::pair< int, int > &shape)
read the cbf data into a linearized 2d array
Definition: cbf_handle.hpp:191
auxiliary data[Processor]
void write(const std::string &filename, std::vector< float >::const_iterator data, const std::pair< int, int > &shape)
write cbf file
Definition: cbf_handle.hpp:35