-
Notifications
You must be signed in to change notification settings - Fork 15
/
makepyramid-ndpi
executable file
·181 lines (149 loc) · 5.32 KB
/
makepyramid-ndpi
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
#!/bin/bash
set -e
set -x
# Check if file is BigTIFF
# $1 file
bigtiff() {
if [ "0000000 4949 002b" != "$(dd if="$1" iflag=count_bytes count=4 | od -x | head -n1)" ]; then
return 1
fi
return 0
}
# Get fieldoffset for TIFF
# $1 file
fieldoffset() {
if bigtiff "$1"; then
echo 8
else
echo 2
fi
}
# Get fieldsize for TIFF
# $1 file
fieldsize() {
if bigtiff "$1"; then
echo 20
else
echo 12
fi
}
# Get IFD offsets
# $1=IFD number
# $2=file
diroffsets() {
tiffinfo "$dest" | grep "TIFF Directory at offset" | sed -e 's;.*(\(.*\))$;\1;'
}
# Get offset for IFD
# $1=IFD number
# $2=file
diroffset() {
diroffsets "$2" | head -n$(($1 + 1)) | tail -n1
}
# Get number of tags in directory
# $1=IFD offset
# $2=file
ntags() {
echo "od -j $1 -N 2 -d \"$2\"" >&2
od -j $1 -N 2 -d "$2" | head -n1 | sed -e 's;^[0-9]* *\(.*\);\1;'
}
# Offset of next pointer in IFD
# $1=IFD offset
# $2=file
nextoffset() {
echo "$(($1 + $(fieldoffset "$2") + ($(ntags $1 "$2") * $(fieldsize "$2"))))"
}
# Write uint64 little endian value to binary file
# $1=value
# $2=destination file
# $3=offset in file
update_uint64_le() {
if bigtiff "$2"; then
printf "$(printf %.16x $1 | sed -e 's;\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\(..\);\8\7\6\5\4\3\2\1;' | sed -e 's;\(..\);\\x\1;g')" | dd of="$2" conv=notrunc,nocreat oflag=seek_bytes seek=$3
else
printf "$(printf %.8x $1 | sed -e 's;\(..\)\(..\)\(..\)\(..\);\4\3\2\1;' | sed -e 's;\(..\);\\x\1;g')" | dd of="$2" conv=notrunc,nocreat oflag=seek_bytes seek=$3
fi
}
makeuuid() {
echo "urn:uuid:$(uuidgen)"
}
src="$(ls -1 orig/*.ndpi)"
mkdir -p new
for srcfile in $src; do
base="$(basename $srcfile)"
dest="new/${base%.ndpi}-subifds.tiff"
cp "$srcfile" "$dest"
nifds=$(tiffinfo "$dest" | grep "TIFF Directory at offset" | wc -l)
echo "IFD count: $nifds"
ifds=$(seq 0 $(($nifds - 1)))
mainifd=$(echo "$ifds" | head -n1)
otherifds=$(echo "$ifds" | tail -n1)
subifds=$(echo "$ifds" | head -n$((nifds-1)) | tail -n$((nifds-2)))
nsubifds=$(echo "$subifds" | wc -l)
echo "IFDs: $ifds"
echo "Main IFDs: $mainifd"
echo "Other IFDs: $otherifds"
echo "SUBIFDs: $subifds"
# Drop private tags, where present
private_tags="65420 65421 65422 65423 65424 65425 65426 65427 65428"
for ifd in $ifds; do
for tag in $private_tags; do
tiffset -d $ifd -u $tag "$dest" || true
done
done
# Main header
tiffset -d 0 -s 270 "OME Pyramid TIFF test (from $base)" "$dest"
tiffset -d 0 -s 305 "A gnarly shell script (makepyramid-ndpi)" "$dest"
tiffset -d 0 -s 315 "Roger Leigh <[email protected]>" "$dest"
# NewSubFileType
for ifd in $mainifd $otherifds; do
tiffset -d $ifd -s 254 0 "$dest"
done
for ifd in $subifds; do
tiffset -d $ifd -s 254 1 "$dest"
done
# SubIFDs
subifds_diroffs=$(echo $(tiffinfo "$dest" | grep "TIFF Directory at offset" | sed -e 's;.*(\(.*\))$;\1;' | head -n$((nifds-2)) | tail -n$((nifds-3))))
echo "SubIFDs for series 0: $subifds_diroffs"
tiffset -d 0 -s 330 $nsubifds $subifds_diroffs "$dest"
subifds_diroffs=$(echo $(tiffinfo "$dest" | grep "TIFF Directory at offset" | sed -e 's;.*(\(.*\))$;\1;' | head -n$((nifds-2)) | tail -n$((nifds-3))))
echo "Updated SubIFDs for series 0: $subifds_diroffs"
echo "New directories:"
diroffsets "$dest"
dest2="${dest%.tiff}-flat.tiff"
cp "$dest" "$dest2"
# Relink IFDs to elide SubIFDs
series0dir="$(diroffset 0 "$dest")"
echo "s0dir $series0dir"
seriesndir="$(diroffset $(echo "$otherifds" | head -n1) "$dest")"
echo "sndir $seriesndir"
noffset="$(nextoffset $series0dir "$dest")"
echo "UPDATE: $series0dir $noffset -> [$seriesndir]"
update_uint64_le $seriesndir "$dest" $noffset
for offset in $subifds_diroffs; do
c="$(ntags $offset "$dest")"
echo "NTAGS: $c"
noffset="$(nextoffset $offset "$dest")"
echo "UPDATE: $offset $noffset -> 0"
update_uint64_le 0 "$dest" $noffset
done
tiffinfo "$dest"
# Create OME-XML metadata for the files.
dest_ometiff="${dest%.tiff}.ome.tiff"
dest2_ometiff="${dest2%.tiff}.ome.tiff"
cp "$dest" "$dest_ometiff"
cp "$dest2" "$dest2_ometiff"
bfomexml="$(showinf -nopix -noflat -omexml -omexml-only "$srcfile")"
# Add TiffData elements.
uuid="$(makeuuid)"
ome_attr="Creator=\"makepyramid-ndpi\" UUID=\"${uuid}\""
tiffdata_fmt="<TiffData FirstC=\"0\" FirstT=\"0\" FirstZ=\"0\" IFD=\"%d\" PlaneCount=\"1\"><UUID FileName=\"$(basename "${dest_ometiff}")\">${uuid}</UUID></TiffData>"
tiffdata_fmt_flat="<TiffData FirstC=\"0\" FirstT=\"0\" FirstZ=\"0\" IFD=\"%d\" PlaneCount=\"1\"><UUID FileName=\"$(basename "${dest2_ometiff}")\">${uuid}</UUID></TiffData>"
omexml_fmt="$(echo "$bfomexml" | sed -e "s;\(<OME.*\)\(\">\);\1\" ${ome_attr}>;" -e "s;<MetadataOnly\/>;${tiffdata_fmt};")"
omexml_fmt_flat="$(echo "$bfomexml" | sed -e "s;\(<OME.*\)\(\">\);\1\" ${ome_attr}>;" -e "s;<MetadataOnly\/>;${tiffdata_fmt_flat};")"
ifds="0 1"
omexml="$(printf "$omexml_fmt" $ifds)"
flatifds="$(echo $mainifd $otherifds)"
omexml_flat="$(printf "$omexml_fmt" $flatifds)"
tiffset -d 0 -s 270 "$omexml" "$dest_ometiff"
tiffset -d 0 -s 270 "$omexml_flat" "$dest2_ometiff"
done