-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathReadDM3.m
More file actions
364 lines (328 loc) · 10.5 KB
/
ReadDM3.m
File metadata and controls
364 lines (328 loc) · 10.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
function [m sx sy]=ReadDM3(filename,logfile)
% function [m sx sy]=ReadDM3(filename,logfile)
% Read a Digital Micrograph file and return the first image in its native
% data format (e.g. int16), along with its pixel scale information
% (typically in nm). If a logfile name is specified, a description of the
% entire tree will be written to the console and also to the file.
% F. Sigworth, July 2009
% Code was based on the description by Greg Jefferis at
% http://rsb.info.nih.gov/ij/plugins/DM3Format.gj.html
%
% This function has been written assuming that it will run on a
% little-endian (e.g. Intel) machine, reading a file written by a
% little-endan machine. Otherwise the use of the swapbytes function will
% have to be made conditional on the local machine type and the byteorder
% variable. Also, swapbytes may have to be added to the GetData function.
%
% Note that the code here allows any
% fields from the tree to be extracted. Here is where we define the fields
% that we will extract. We grab the data value at the first match of each
% of these tags. Here numerals represent unnamed fields. To see what all
% the tags are, specify a logfile to receive the hundreds of lines of
% information!
celltags={'ImageList 2 ImageData Calibrations Dimension 1 Scale'
'ImageList 2 ImageData Calibrations Dimension 2 Scale'
'ImageList 2 ImageData Dimensions 1'
'ImageList 2 ImageData Dimensions 2'
'ImageList 2 ImageData Data'};
found=zeros(size(celltags));
output=cell(size(celltags));
% Set up the log file. We use my mprintf function to allow printing to the
% console as well, and suppressing printing when the handle is zero.
if nargin>1
flog=fopen(logfile,'w');
hs=[1 flog]; % log file handles
else
flog=0;
hs=[0];
end;
tabstring='| ';
level=0;
maxprint=4;
OutputOn=1;
% Read the whole file into memory as a byte array.
fb=fopen(filename,'r');
d=fread(fb,inf,'*uint8'); % read the whole file as bytes
fclose(fb);
p=int32(1); % byte pointer--also a global variable
Tags=cell(1,10); % Keeps track of the sequence of tags, for matching with the tag strings.
% Pick up the header
version=GetLong;
if version ~=3
error(['ReadDM3: Wrong file type. Version = ' num2str(version)]);
end;
nbytes=GetLong;
% Handle little- and big-endian files and machines
dle=GetLong; % boolean to tell whether data is little endian
[str,maxsize,endian] = computer;
mle= (endian=='L'); % machine is little endian: we'll have to swap bytes in reading the tree.
dswap=(dle~=mle); % swap byte-order when reading data
% Traverse the tree
GetTagGroup;
% Close the logfile
if flog>0
fclose(flog);
end;
% Extract the output parameters
sx=output{1};
sy=output{2};
xdim=output{3};
ydim=output{4};
m=reshape(output{5},xdim,ydim);
% end of main function
% ---- here are all the local functions, called recursively ----
function GetTagGroup
sorted=GetByte;
open=GetByte;
NumTags=GetLong;
for i=1:NumTags
GetTagEntry(i);
end;
end
function GetTagEntry(MemberIndex)
level=level+1;
PutNew;
PutTabs;
isdata=GetByte;
labelsize=GetInt;
labelstring=GetString(labelsize);
PutStr('-');
PutStr([labelstring ':']);
if numel(labelstring)<1
labelstring=num2str(MemberIndex);
end;
Tags{level}=labelstring;
if isdata==21
GetTagType
elseif isdata==20
GetTagGroup
else
error(['Unknown TagEntry type ' num2str(isdata)]);
end;
Tags{level}=[];
level=level-1;
end
function GetTagType
dum=GetLong;
if dum ~= 623191333
disp(['Illegal TagType value ' num2str(dum)]);
end
deflen=GetLong;
EncType=GetLong;
x=GetData(EncType);
index=CheckTags;
if index>0
output{index}=x;
end;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This is the function that slows everything down, which checks the
% entire tag list for each tagged type. It is inefficient, but simple.
function r=CheckTags
for i=1:numel(celltags)
ok=~found(i);
c=celltags{i};
j=1;
while ok && (numel(c)>0)
[s c]=strtok(c);
ok=strcmp(s,'*')||strcmp(s,Tags{j});
j=j+1;
end;
if ok
r=i;
return
end;
end;
r=0;
end
function x=GetData(ftype,num)
if nargin<2
num=1;
end;
x=[];
% disp(['GetData ' num2str(ftype)]);
switch ftype
case 2 % short
x=typecast(d(p:p+num*2-1),'int16');
p=p+2*num;
case 3 % long
x=typecast(d(p:p+num*4-1),'int32');
p=p+4*num;
case 4 % ushort
x=typecast(d(p:p+num*2-1),'uint16');
p=p+2*num;
case 5 % ulong
x=typecast(d(p:p+num*4-1),'uint32');
p=p+4*num;
case 6 % float
x=typecast(d(p:p+num*4-1),'single');
p=p+4*num;
case 7 % double
x=typecast(d(p:p+num*8-1),'double');
p=p+8*num;
case 8 % boolean
x=d(p:p+num-1);
p=p+num;
case 9 % char
x=char(d(p:p+num-1));
p=p+num;
case 10 % octet
x=(d(p:p+num-1));
p=p+num;
case 15 % Struct
PutStr('struct');
StructNameLength=GetLong;
NumFields=GetLong;
x=[];
for i=1:NumFields
FieldNameLength(i)=GetLong;
FieldType(i)=GetLong;
end;
StructName=GetString(StructNameLength);
PutStr(StructName);
PutNew; PutTabs;
for i=1:NumFields
% FieldNameLen=FieldNameLength(i);
FieldName=GetString(FieldNameLength(i));
FieldTy=FieldType(i);
PutStr(FieldName);
x(i)=GetData(FieldType(i));
PutNew; PutTabs;
end;
case 18 % string
length=GetLong;
x=char(d(p:p+length-1)');
PutVal(x); PutNew;
p=p+length;
case 20 % Array
ArrayType=GetLong;
if ArrayType==15 % Struct is special case
StructNameLength=GetLong;
NumFields=GetLong;
x=[];
for i=1:NumFields
FieldNameLength(i)=GetLong;
FieldType(i)=GetLong;
end;
end;
ArrayLength=GetLong;
if ArrayType ~=4
PutStr('array of');
PutVal(ArrayLength);
PutStr(' --type'); PutVal(ArrayType);
end;
if ArrayType==15
PutStr('structs');
PutNew;
for j=1:ArrayLength
OutputOn=j<=maxprint;
for i=1:NumFields
FieldNameLen=FieldNameLength(i);
FieldName=GetString(FieldNameLength(i));
FieldTy=FieldType(i);
PutTabs;
PutStr(FieldName);
x(i)=GetData(FieldType(i));
PutNew;
end;
OutputOn=1;
end;
elseif ArrayType==4
OutputOn=0;
for j=1:ArrayLength
x(j)=GetData(ArrayType);
end;
OutputOn=1;
PutVal(char(x'));
else
% Might be long data
if (ArrayLength > 1000) % try to handle a long array
OutputOn=0;
x=GetData(ArrayType,ArrayLength);
OutputOn=1;
else
PutNew;
for j=1:ArrayLength
OutputOn=j<=maxprint;
PutTabs;
x(j)=GetData(ArrayType);
PutNew;
end;
OutputOn=1;
end; % long data
end;
otherwise
x=0;
disp(['Unrecognized data type ' num2str(ftype)]);
end; % switch
if (ftype < 15) && OutputOn
PutVal(x);
end;
end % GetData
function PutStr(s)
if OutputOn
mprintf(hs,'%s ',s);
end;
end
function PutTabs
if OutputOn
for i=1:level-1
mprintf(hs,'%s',tabstring);
end;
end;
end
function PutVal(x)
if OutputOn
if isa(x,'char')
mprintf(hs,'%s ',x);
else
mprintf(hs,'%d ',x);
end;
end;
end
function PutNew
if OutputOn
mprintf(hs,'\n');
end;
end
function s=GetString(len)
len=int32(len);
if len<1
s=[];
else
s=char(d(p:p+len-1)');
p=p+len;
end;
end
function x=GetLong
x=typecast(d(p:p+3),'int32');
x=swapbytes(x);
p=p+4;
end
function x=GetWord
x=typecast(d(p:p+1),'int16');
x=swapbytes(x);
p=p+2;
end
function x=GetInt
x=typecast(d(p:p+1),'int16');
x=swapbytes(x);
p=p+2;
end
function x=GetByte
x=d(p);
p=p+1;
end
function mprintf(handles,varargin)
% function mprintf(handles,varargin) % copy of my utility function to
% make ReadDM3 self-contained.
% Write the same formatted text to multiple files. handles is an array of
% file handles. The function fprintf is called multiple times, once for
% each handle number. Handles of 0 are ignored.
for i=1:numel(handles)
if handles(i)>0
fprintf(handles(i),varargin{:});
end;
end
end % mprintf
end