function metadata = impicinfo(filename)
% adapted from:
% http://www.bu.edu/cism/cismdx/ref/dx.Samples/util/biorad-pic/PIC2dx.c
% http://rsb.info.nih.gov/ij/plugins/download/Biorad_Reader.java
% constants
HEADER_LEN = 76;
NOTE_LEN = 96;
NOTE_TYPE_LIVE = 1; % Information about live collection
NOTE_TYPE_FILE1 = 2; % Note from image #1
NOTE_TYPE_NUMBER = 3; % Number in multiple image file
NOTE_TYPE_USER = 4; % User notes generated notes
NOTE_TYPE_LINE = 5; % Line mode info
NOTE_TYPE_COLLECT = 6; % Collect mode info
NOTE_TYPE_FILE2 = 7; % Note from image #2
NOTE_TYPE_SCALEBAR = 8; % Scale bar info
NOTE_TYPE_MERGE = 9; % Merge Info
NOTE_TYPE_THRUVIEW = 10; % Thruview Info
NOTE_TYPE_ARROW = 11; % Arrow info
NOTE_TYPE_VARIABLE = 20; % Again internal variable ,except held as
NOTE_TYPE_STRUCTURE = 21; % a structure.
AXT_D = 1; % distance in microns
AXT_T = 2; % time in sec
AXT_A = 3; % angle in degrees
AXT_I = 4; % intensity in grey levels
AXT_M4 = 5; % 4-bit merged image
AXT_R = 6; % Ratio
AXT_LR = 7; % Log Ratio
AXT_P = 8; % Product
AXT_C = 9; % Calibrated
AXT_PHOTON = 10; % intensity in photons/sec
AXT_RGB = 11; % RGB type
AXT_SEQ = 12; % SEQ type (eg 'experiments')
AXT_6D = 13; % 6th level of axis
AXT_TC = 14; % Time Course axis
AXT_S = 15; % Intensity signoid cal
AXT_LS = 16; % Intensity log signoid cal
AXT_BASE = base2dec('FF', 16); % mask for axis TYPE
AXT_XY = base2dec('100', 16); % axis is XY, needs updating by LENS
AXT_WORD = base2dec('200', 16); % axis is word. only corresponds to axis[0]
% read header
fid = fopen(filename, 'r');
if fid ~= -1
% Initialize universal structure fields to fix the order
metadata.Filename = '';
metadata.FileModDate = [];
metadata.FileSize = [];
metadata.Format = 'pic';
metadata.FormatVersion = [];
metadata.Width = [];
metadata.Height = [];
metadata.BitDepth = [];
metadata.ColorType = 'grayscale';
filename = fopen(fid); % Get the full path name if not in pwd
d = dir(filename); % Read directory information
metadata.Filename = filename;
metadata.FileModDate = d.date;
metadata.FileSize = d.bytes;
% check to make sure that the file isn't zero length
fseek(fid, 0, 'eof');
endOfFile = ftell(fid);
if endOfFile > HEADER_LEN
% read header
fseek(fid, 0, 'bof');
metadata.Width = fread(fid, 1, 'int16');
metadata.Height = fread(fid, 1, 'int16');
metadata.NumImages = fread(fid, 1, 'int16');
metadata.Ramp1 = fread(fid, 2, 'int16');
metadata.Notes = fread(fid, 1, 'int32');
byteFormat = fread(fid, 1, 'int16');
metadata.ImageNumber = fread(fid, 1, 'int16');
fread(fid, 32, 'char');
if fread(fid, 1, 'int16')
% merged format is not currently supported
metadata = [];
return
end
metadata.ColorStatus1 = fread(fid, 1, 'int16');
if fread(fid, 1, 'int16') ~= 12345
metadata = [];
return
end
metadata.Ramp2 = fread(fid, 2, 'int16');
metadata.ColorStatus2 = fread(fid, 1, 'int16');
metadata.IsEdited = fread(fid, 1, 'int16');
metadata.LensMagnification = fread(fid, 1, 'int16');
metadata.LensFactor = fread(fid, 1, 'float32');
fread(fid, 3, 'int16');
if byteFormat == 1
metadata.BitDepth = 8;
else
metadata.BitDepth = 16;
end
% read notes
fseek(fid, metadata.Width * metadata.Height * metadata.NumImages * metadata.BitDepth / 8, 'cof');
notesOffset = ftell(fid);
getAxisInfo;
fclose(fid);
else
metadata = []; %tell calling subroutine that the file was zero length
end
else
metadata = []; %tell calling subroutine that no file was found
end
function getAxisInfo
% read all of the notes
fseek(fid, notesOffset, 'bof');
noteIndex = 1;
while notesOffset + NOTE_LEN * (noteIndex - 1) <= endOfFile
metadata.Note{noteIndex} = readNote(noteIndex);
if metadata.Note{noteIndex}.type == NOTE_TYPE_VARIABLE
if strfind(metadata.Note{noteIndex}.text, 'AXIS_2') == 1
% horizontal axis
tempData = sscanf(metadata.Note{noteIndex}.text(7:end), ' %d %g %g %s');
axisType = tempData(1);
if axisType == AXT_D
metadata.Origin(1) = tempData(2);
metadata.Delta(1) = tempData(3);
end
metadata.Units{1} = char(tempData(4:end)');
elseif strfind(metadata.Note{noteIndex}.text, 'AXIS_3') == 1
% vertical axis
tempData = sscanf(metadata.Note{noteIndex}.text(7:end), ' %d %g %g %s');
axisType = tempData(1);
if axisType == AXT_D
metadata.Origin(2) = tempData(2);
metadata.Delta(2) = tempData(3);
end
metadata.Units{2} = char(tempData(4:end)');
elseif strfind(metadata.Note{noteIndex}.text, 'AXIS_4') == 1
% z axis
axisType = sscanf(metadata.Note{noteIndex}.text(7:end), ' %d');
if axisType == AXT_D
tempData = sscanf(metadata.Note{noteIndex}.text(7:end), ' %d %g %g %s');
metadata.Origin(3) = tempData(2);
metadata.Delta(3) = tempData(3);
end
metadata.Units{3} = char(tempData(4:end)');
elseif strfind(metadata.Note{noteIndex}.text, 'AXIS_9') == 1
tempData = sscanf(metadata.Note{noteIndex}.text(7:end), ' %d %g %g %s');
axisType = tempData(1);
if axisType == AXT_RGB
metadata.Origin(4) = tempData(2);
metadata.Delta(4) = tempData(3);
metadata.Units{4} = char(tempData(4:end)');
end
elseif strfind(metadata.Note{noteIndex}.text, 'INFO_FRAME_RATE') == 1
metadata.FramesPerSecond = sscanf(metadata.Note{noteIndex}.text(14:end), ' %d');
elseif strfind(metadata.Note{noteIndex}.text, 'INFO_OBJECTIVE_NAME = ') == 1
metadata.Objective = metadata.Note{noteIndex}.text(23:end);
metadata.Objective = metadata.Objective(metadata.Objective ~= char(0));
elseif strfind(metadata.Note{noteIndex}.text, 'PIC_FF_VERSION = ') == 1
metadata.FormatVersion = str2double(metadata.Note{noteIndex}.text(18:end));
else
% add any note you care about here
end
else
% add info about other note types here
end
noteIndex = noteIndex + 1;
end
end
function note = readNote(index)
fseek(fid, notesOffset + (index - 1) * NOTE_LEN, 'bof');
note.level = fread(fid, 1, 'int16');
note.next = fread(fid, 1, 'int32');
note.num = fread(fid, 1, 'int16');
note.status = fread(fid, 1, 'int16');
note.type = fread(fid, 1, 'int16');
note.x = fread(fid, 1, 'int16');
note.y = fread(fid, 1, 'int16');
note.text = char(fread(fid, 80, 'char')');
end
end