Skip to content

Commit 77fac44

Browse files
committed
Working DCIMG reader for a single 2D image
1 parent 862723a commit 77fac44

File tree

3 files changed

+163
-0
lines changed

3 files changed

+163
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ tools/*.jar
2020
*.iml
2121
.*.swp
2222
*.clean
23+
.vscode

components/formats-api/src/loci/formats/readers.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ loci.formats.in.MicroCTReader # vff
107107
loci.formats.in.LOFReader # lof
108108
loci.formats.in.XLEFReader # xlef
109109
loci.formats.in.OlympusTileReader # omp2info
110+
loci.formats.in.DCIMGReader # dcimg
110111

111112
# multi-extension messes
112113
loci.formats.in.JEOLReader # dat, img, par
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
package loci.formats.in;
2+
3+
import java.io.IOException;
4+
5+
import loci.common.RandomAccessInputStream;
6+
import loci.formats.CoreMetadata;
7+
import loci.formats.FormatException;
8+
import loci.formats.FormatReader;
9+
import loci.formats.FormatTools;
10+
import loci.formats.MetadataTools;
11+
import loci.formats.meta.MetadataStore;
12+
13+
/**
14+
* DCIMGReader reads Hamamatsu DCIMG files.
15+
*
16+
* Follows spec in https://github.com/python-microscopy/python-microscopy/blob/master/PYME/IO/dcimg.py.
17+
*/
18+
public class DCIMGReader extends FormatReader {
19+
20+
// -- Constants --
21+
22+
private static final boolean IS_LITTLE = true;
23+
24+
private static final long DCAM_VERSION_0 = 0x7;
25+
private static final long DCAM_VERSION_1 = 0x1000000;
26+
27+
private static final long DCIMG_PIXELTYPE_NONE = 0x00000000; // defined, but I don't know what to do with this
28+
private static final long DCIMG_PIXELTYPE_MONO8 = 0x00000001;
29+
private static final long DCIMG_PIXELTYPE_MONO16 = 0x00000002;
30+
31+
// -- Fields --
32+
33+
private long sessionOffset;
34+
private long dataOffset;
35+
private long pixelType;
36+
private int byteFactor;
37+
38+
public DCIMGReader() {
39+
super("Hamamatsu DCIMG", "dcimg");
40+
suffixSufficient = false;
41+
domains = new String[] {FormatTools.UNKNOWN_DOMAIN};
42+
}
43+
44+
@Override
45+
public boolean isThisType(RandomAccessInputStream stream) throws IOException {
46+
String desc = stream.readString(5);
47+
if (!desc.equals("DCIMG")) return false;
48+
return true;
49+
}
50+
51+
@Override
52+
public byte[] openBytes(int no, byte[] buf, int x, int y, int w, int h)
53+
throws FormatException, IOException
54+
{
55+
FormatTools.checkPlaneParameters(this, no, buf.length, x, y, w, h);
56+
57+
// DCIMG is stored column major
58+
in.seek(sessionOffset + dataOffset + byteFactor*y*getSizeX());
59+
for (int row=h-1; row>=0; row--) {
60+
in.skipBytes(byteFactor*x);
61+
in.read(buf, byteFactor*row*w, byteFactor*w);
62+
in.skipBytes(byteFactor*(getSizeX() - w - x));
63+
}
64+
65+
return buf;
66+
}
67+
68+
@Override
69+
protected void initFile(String id) throws FormatException, IOException {
70+
super.initFile(id);
71+
in = new RandomAccessInputStream(id);
72+
73+
in.order(IS_LITTLE); // big endian
74+
75+
// confirm this is DCIMG
76+
String desc = in.readString(5);
77+
if (!desc.equals("DCIMG")) throw new FormatException("Not a valid DCIMG file.");
78+
79+
in.skipBytes(3);
80+
81+
long version = in.readUnsignedInt(); // DCIMG version number
82+
if ((!(version == DCAM_VERSION_0)) && (!(version == DCAM_VERSION_1))) {
83+
throw new FormatException(String.format("Unknown DCIMG version number %d.", version));
84+
}
85+
86+
in.skipBytes(20);
87+
88+
long numSessions = in.readUnsignedInt();
89+
long numFrames = in.readUnsignedInt();
90+
sessionOffset = in.readUnsignedInt();
91+
in.skipBytes(4);
92+
long fileSize = in.readUnsignedInt();
93+
in.skipBytes(12);
94+
long fileSize2 = in.readUnsignedInt();
95+
if (fileSize != fileSize2) throw new FormatException("Improper header. File sizes do not match.");
96+
in.skipBytes(16);
97+
long mystery1 = in.readUnsignedInt(); // 1024 in all examples
98+
99+
CoreMetadata m = core.get(0);
100+
101+
m.dimensionOrder = "XYZCT";
102+
m.rgb = false;
103+
m.interleaved = false;
104+
m.littleEndian = IS_LITTLE;
105+
m.indexed = false;
106+
m.falseColor = false;
107+
m.metadataComplete = true;
108+
m.thumbnail = false;
109+
m.sizeC = 1;
110+
m.sizeZ = 1;
111+
m.imageCount = getSizeZ() * getSizeC();
112+
113+
if (version == DCAM_VERSION_0) {
114+
parseDCAMVersion0Header();
115+
} else if (version == DCAM_VERSION_1) {
116+
parseDCAMVersion1Header();
117+
}
118+
119+
if (pixelType == DCIMG_PIXELTYPE_MONO8) {
120+
m.pixelType = FormatTools.UINT8;
121+
byteFactor = 1;
122+
} else if (pixelType == DCIMG_PIXELTYPE_MONO16) {
123+
m.pixelType = FormatTools.UINT16;
124+
byteFactor = 2;
125+
}
126+
127+
addGlobalMeta("Version", version);
128+
129+
// The metadata store we're working with.
130+
MetadataStore store = makeFilterMetadata();
131+
MetadataTools.populatePixels(store, this);
132+
133+
}
134+
135+
private void parseDCAMVersion0Header() throws IOException {
136+
137+
}
138+
139+
private void parseDCAMVersion1Header() throws IOException {
140+
CoreMetadata m = core.get(0);
141+
142+
in.seek(sessionOffset);
143+
long sessionLength = in.readUnsignedInt();
144+
in.skipBytes(20);
145+
long pseudoOffset = in.readUnsignedInt();
146+
in.skipBytes(32); // unknown numbers 1, 144, 65537
147+
m.sizeT = (int) in.readUnsignedInt();
148+
pixelType = in.readUnsignedInt();
149+
long mystery1 = in.readUnsignedInt();
150+
// TODO: Is this casting always legal? I think not...
151+
m.sizeX = (int) in.readUnsignedInt(); // num columns (this is a column-major format)
152+
m.sizeY = (int) in.readUnsignedInt(); // num rows
153+
long bytesPerRow = in.readUnsignedInt();
154+
long bytesPerImage = in.readUnsignedInt();
155+
in.skipBytes(8);
156+
dataOffset = in.readUnsignedInt();
157+
in.skipBytes(16);
158+
long bytesPerFrame = in.readUnsignedInt();
159+
160+
}
161+
}

0 commit comments

Comments
 (0)