1
2
3 from __future__ import with_statement
4 __doc__ = """
5
6 Authors:
7 ........
8 * Henning O. Sorensen & Erik Knudsen:
9 Center for Fundamental Research: Metal Structures in Four Dimensions;
10 Risoe National Laboratory;
11 Frederiksborgvej 399;
12 DK-4000 Roskilde;
13 email:erik.knudsen@risoe.dk
14 * Jon Wright, Jérôme Kieffer & Gaël Goret:
15 European Synchrotron Radiation Facility;
16 Grenoble (France)
17
18
19 """
20
21 from fabioimage import fabioimage
22 import numpy, struct, time, sys
23 import logging
24 logger = logging.getLogger("mar345image")
25 from compression import compPCK, decPCK
28 _need_a_real_file = True
30 fabioimage.__init__(self, *args, **kwargs)
31 self.numhigh = None
32 self.numpixels = None
33
34 - def read(self, fname, frame=None):
35 """ Read a mar345 image"""
36 self.filename = fname
37 f = self._open(self.filename, "rb")
38 self._readheader(f)
39 if 'compressed' in self.header['Format']:
40 try:
41 self.data = decPCK(f, self.dim1, self.dim2, self.numhigh)
42 except Exception, error:
43 logger.error('%s. importing the mar345_io backend: generate an empty 1x1 picture' % error)
44 f.close()
45 self.dim1 = 1
46 self.dim2 = 1
47 self.bytecode = numpy.int
48 self.data = numpy.resize(numpy.array([0], numpy.int), [1, 1])
49 return self
50
51 else:
52 logger.error("cannot handle these formats yet " + \
53 "due to lack of documentation")
54 return None
55 self.bytecode = numpy.uint
56 f.close()
57 return self
58
60 """ Read a mar345 image header """
61
62
63
64 f = infile
65 h = {}
66
67
68 l = f.read(64)
69
70
71
72
73
74
75 if struct.unpack("<i", l[0:4])[0] == 1234:
76 fs = '<i'
77 else:
78 fs = '>i'
79
80
81 self.dim1 = self.dim2 = int(struct.unpack(fs, l[4:8])[0])
82
83 self.numhigh = struct.unpack(fs, l[2 * 4 : (2 + 1) * 4])[0]
84 h['NumHigh'] = self.numhigh
85
86 i = struct.unpack(fs, l[3 * 4 : (3 + 1) * 4])[0]
87 if i == 1:
88 h['Format'] = 'compressed'
89 elif i == 2:
90 h['Format'] = 'spiral'
91 else:
92 h['Format'] = 'compressed'
93 logger.warning("image format could not be detetermined" + \
94 "- assuming compressed mar345")
95
96 h['Mode'] = {0:'Dose', 1: 'Time'}[struct.unpack(fs, l[4 * 4:(4 + 1) * 4])[0]]
97
98 self.numpixels = struct.unpack(fs, l[5 * 4:(5 + 1) * 4])[0]
99 h['NumPixels'] = str(self.numpixels)
100
101 h['PixelLength'] = struct.unpack(fs, l[6 * 4:(6 + 1) * 4])[0] / 1000.0
102 h['PixelHeight'] = struct.unpack(fs, l[7 * 4:(7 + 1) * 4])[0] / 1000.0
103
104 h['Wavelength'] = struct.unpack(fs, l[8 * 4:(8 + 1) * 4])[0] / 1000000.0
105
106 h['Distance'] = struct.unpack(fs, l[9 * 4:(9 + 1) * 4])[0] / 1000.0
107
108 h['StartPhi'] = struct.unpack(fs, l[10 * 4:11 * 4])[0] / 1000.0
109 h['EndPhi'] = struct.unpack(fs, l[11 * 4:12 * 4])[0] / 1000.0
110
111 h['StartOmega'] = struct.unpack(fs, l[12 * 4:13 * 4])[0] / 1000.0
112 h['EndOmega'] = struct.unpack(fs, l[13 * 4:14 * 4])[0] / 1000.0
113
114 h['Chi'] = struct.unpack(fs, l[14 * 4:15 * 4])[0] / 1000.0
115 h['TwoTheta'] = struct.unpack(fs, l[15 * 4:16 * 4])[0] / 1000.0
116
117
118
119 l = f.read(128)
120 if not 'mar research' in l:
121 logger.warning("the string \"mar research\" should be in " + \
122 "bytes 65-76 of the header but was not")
123 start = 128
124 else:
125 start = l.index('mar research')
126 f.seek(64 + start)
127 l = f.read(4096 - start - 64).strip()
128 for m in l.splitlines():
129 if m == 'END OF HEADER':
130 break
131 n = m.split(' ', 1)
132 if n[0] == '':
133 continue
134 if n[0] in ('PROGRAM', 'DATE', 'SCANNER', 'HIGH', 'MULTIPLIER',
135 'GAIN', 'WAVELENGTH', 'DISTANCE', 'RESOLUTION',
136 'CHI', 'TWOTHETA', 'MODE', 'TIME', 'GENERATOR',
137 'MONOCHROMATOR', 'REMARK'):
138 logger.debug("reading: %s %s", n[0], n[1])
139 h[n[0]] = n[1].strip()
140 continue
141 if n[0] in ('FORMAT'):
142 (h['DIM'], h['FORMAT_TYPE'], h['NO_PIXELS']) = n[1].split()
143 continue
144 if n[0] in ('PIXEL', 'OFFSET', 'PHI', 'OMEGA', 'COUNTS',
145 'CENTER', 'INTENSITY', 'HISTOGRAM', 'COLLIMATOR'):
146 n = m.split()
147 h.update([(n[0] + '_' + n[j], n[j + 1]) for j in range(1, len(n), 2)])
148 continue
149 self.header = h
150 return h
151
153 """Try to write mar345 file. This is still in beta version.
154 It uses CCP4 (LGPL) PCK1 algo from JPA"""
155 headers = self._writeheader()
156 hotpixels = self._high_intensity_pixel_records()
157 compressed_stream = compPCK(self.data)
158 try:
159 outfile = self._open(fname, mode="wb")
160 outfile.write(headers)
161 outfile.write(hotpixels)
162 outfile.write(compressed_stream)
163 outfile.close()
164 except Exception, error:
165 logger.error("Error in writing file %s: %s" % (fname, error))
166
168 """
169 @param linesep: end of line separator
170 @return string/bytes containing the mar345 header
171 """
172 try:
173 version = sys.modules["fabio"].version
174 except (KeyError, AttributeError):
175 version = "0.1.1"
176 lnsep = len(linesep)
177
178 self.header["HIGH"] = str(self.nb_overflow_pixels())
179 binheader = numpy.zeros(16, "int32")
180 binheader[:4] = numpy.array([1234, self.dim1, int(self.header["HIGH"]), 1])
181 binheader[4] = (self.header.get("MODE", "TIME") == "TIME")
182 binheader[5] = self.dim1 * self.dim2
183 binheader[6] = int(self.header.get("PIXEL_LENGTH", 1))
184 binheader[7] = int(self.header.get("PIXEL_HEIGHT", 1))
185 binheader[8] = int(float(self.header.get("WAVELENGTH", 1)) * 1e6)
186 binheader[9] = int(float(self.header.get("DISTANCE", 1)) * 1e3)
187 binheader[10] = int(float(self.header.get("PHI_START", 1)) * 1e3)
188 binheader[11] = int(float(self.header.get("PHI_END", 1)) * 1e3)
189 binheader[12] = int(float(self.header.get("OMEGA_START", 1)) * 1e3)
190 binheader[13] = int(float(self.header.get("OMEGA_END", 1)) * 1e3)
191 binheader[14] = int(float(self.header.get("CHI", 1)) * 1e3)
192 binheader[15] = int(float(self.header.get("TWOTHETA", 1)) * 1e3)
193 lstout = [binheader.tostring() + 'mar research'.ljust(64 - lnsep)]
194 lstout.append("PROGRAM".ljust(15) + (str(self.header.get("PROGRAM", "FabIO Version %s" % (version))).ljust(49 - lnsep)))
195 lstout.append("DATE".ljust(15) + (str(self.header.get("DATE", time.ctime()))).ljust(49 - lnsep))
196 key = "SCANNER"
197 if key in self.header:
198 lstout.append(key.ljust(15) + str(self.header[key]).ljust(49 - lnsep))
199 key = "FORMAT_TYPE"
200 if key in self.header:
201 lstout.append("FORMAT".ljust(15) + ("%s %s %s" % (self.dim1, self.header[key], self.dim1 * self.dim2)).ljust(49 - lnsep))
202 key = "HIGH"
203 if key in self.header:
204 lstout.append(key.ljust(15) + str(self.header[key]).ljust(49 - lnsep))
205 key1 = "PIXEL_LENGTH"
206 key2 = "PIXEL_HEIGHT"
207 if (key1 in self.header) and (key2 in self.header):
208 lstout.append("PIXEL".ljust(15) + ("LENGTH %s HEIGHT %s" % (self.header[key1], self.header[key2])).ljust(49 - lnsep))
209 key1 = "OFFSET_ROFF"
210 key2 = "OFFSET_TOFF"
211 if key1 in self.header and key2 in self.header:
212 lstout.append("OFFSET".ljust(15) + ("ROFF %s TOFF %s" % (self.header[key1], self.header[key2])).ljust(49 - lnsep))
213 key = "MULTIPLIER"
214 if key in self.header:
215 lstout.append(key.ljust(15) + str(self.header[key]).ljust(49 - lnsep))
216 key = "GAIN"
217 if key in self.header:
218 lstout.append(key.ljust(15) + str(self.header[key]).ljust(49 - lnsep))
219 key = "WAVELENGTH"
220 if key in self.header:
221 lstout.append(key.ljust(15) + str(self.header[key]).ljust(49 - lnsep))
222 key = "DISTANCE"
223 if key in self.header:
224 lstout.append(key.ljust(15) + str(self.header[key]).ljust(49 - lnsep))
225 key = "RESOLUTION"
226 if key in self.header:
227 lstout.append(key.ljust(15) + str(self.header[key]).ljust(49 - lnsep))
228 key1 = "PHI_START"
229 key2 = "PHI_END"
230 key3 = "PHI_OSC"
231 if (key1 in self.header) and (key2 in self.header) and (key3 in self.header):
232 lstout.append("PHI".ljust(15) + ("START %s END %s OSC %s" % (self.header[key1], self.header[key2], self.header[key3])).ljust(49 - lnsep))
233 key1 = "OMEGA_START"
234 key2 = "OMEGA_END"
235 key3 = "OMEGA_OSC"
236 if (key1 in self.header) and (key2 in self.header) and (key3 in self.header):
237 lstout.append("OMEGA".ljust(15) + ("START %s END %s OSC %s" % (self.header[key1], self.header[key2], self.header[key3])).ljust(49 - lnsep))
238 key = "CHI"
239 if key in self.header:
240 lstout.append(key.ljust(15) + str(self.header[key]).ljust(49 - lnsep))
241 key = "TWOTHETA"
242 if key in self.header:
243 lstout.append(key.ljust(15) + str(self.header[key]).ljust(49 - lnsep))
244 key1 = "CENTER_X"
245 key2 = "CENTER_Y"
246 if (key1 in self.header) and (key2 in self.header):
247 lstout.append("CENTER".ljust(15) + ("X %s Y %s" % (self.header[key1], self.header[key2])).ljust(49 - lnsep))
248 key = "MODE"
249 if key in self.header:
250 lstout.append(key.ljust(15) + str(self.header[key]).ljust(49 - lnsep))
251 key = "TIME"
252 if key in self.header:
253 lstout.append(key.ljust(15) + str(self.header[key]).ljust(49 - lnsep))
254 key1 = "COUNTS_START"
255 key2 = "COUNTS_END"
256 key3 = "COUNTS_NMEAS"
257 if key1 in self.header and key2 in self.header and key3 in self.header:
258 lstout.append("COUNTS".ljust(15) + ("START %s END %s NMEAS %s" % (self.header[key1], self.header[key2], self.header[key3])).ljust(49 - lnsep))
259 key1 = "COUNTS_MIN"
260 key2 = "COUNTS_MAX"
261 if key1 in self.header and key2 in self.header:
262 lstout.append("COUNTS".ljust(15) + ("MIN %s MAX %s" % (self.header[key1], self.header[key2])).ljust(49 - lnsep))
263 key1 = "COUNTS_AVE"
264 key2 = "COUNTS_SIG"
265 if key1 in self.header and key2 in self.header:
266 lstout.append("COUNTS".ljust(15) + ("AVE %s SIG %s" % (self.header[key1], self.header[key2])).ljust(49 - lnsep))
267 key1 = "INTENSITY_MIN"
268 key2 = "INTENSITY_MAX"
269 key3 = "INTENSITY_AVE"
270 key4 = "INTENSITY_SIG"
271 if key1 in self.header and key2 in self.header and key3 in self.header and key4 in self.header:
272 lstout.append("INTENSITY".ljust(15) + ("MIN %s MAX %s AVE %s SIG %s" % (self.header[key1], self.header[key2], self.header[key3], self.header[key4])).ljust(49 - lnsep))
273 key1 = "HISTOGRAM_START"
274 key2 = "HISTOGRAM_END"
275 key3 = "HISTOGRAM_MAX"
276 if key1 in self.header and key2 in self.header and key3 in self.header:
277 lstout.append("HISTOGRAM".ljust(15) + ("START %s END %s MAX %s" % (self.header[key1], self.header[key2], self.header[key3])).ljust(49 - lnsep))
278 key = "GENERATOR"
279 if key in self.header:
280 lstout.append(key.ljust(15) + str(self.header[key]).ljust(49 - lnsep))
281 key = "MONOCHROMATOR"
282 if key in self.header:
283 lstout.append(key.ljust(15) + str(self.header[key]).ljust(49 - lnsep))
284 key1 = "COLLIMATOR_WIDTH"
285 key2 = "COLLIMATOR_HEIGHT"
286 if key1 in self.header and key2 in self.header:
287 lstout.append("COLLIMATOR".ljust(15) + ("WIDTH %s HEIGHT %s" % (self.header[key1], self.header[key2])).ljust(49 - lnsep))
288 key = "REMARK"
289 if key in self.header:
290 lstout.append(key.ljust(15) + str(self.header[key]).ljust(49 - lnsep))
291 else:
292 lstout.append(key.ljust(64 - lnsep))
293 key = "END OF HEADER"
294 lstout.append(key)
295 return linesep.join(lstout).ljust(size)
296
297
299 flt_data = self.data.flatten()
300 pix_location = numpy.where(flt_data > 65535)[0]
301 nb_pix = pix_location.size
302 if nb_pix % 8 == 0:
303 tmp = numpy.zeros((nb_pix, 2), dtype="int32")
304 else:
305 tmp = numpy.zeros(((nb_pix // 8 + 1) * 8, 2), dtype="int32")
306 tmp[:nb_pix, 0] = pix_location + 1
307 tmp[:nb_pix, 1] = flt_data[pix_location]
308 return tmp.tostring()
309
311 return (self.data > 65535).sum()
312
313 @staticmethod
315 if data is None:
316 return None
317 else:
318
319 shape = data.shape
320 assert len(shape) == 2, "image has 2 dimensions"
321 mshape = max(shape)
322 z = numpy.zeros((mshape, mshape), dtype=int)
323 z[:shape[0], :shape[1]] = data
324 return z
325