/
load.jl
145 lines (118 loc) 路 4.56 KB
/
load.jl
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
import .Iterators: partition
"""
$(SIGNATURES)
Loads a TIFF image. Optional flags `verbose`, `lazyio`, and `mmap` are set to
true, false, and false by default, respectively. Setting `verbose` to false
will hide the loading bar, while setting either `lazyio` or `mmap` to true
defer loading until the data are needed (by either of two mechanisms).
Parallelism is enabled by default, but can be disabled by setting
`JULIA_IMAGES_PARALLEL`=false in your environment
See [Lazy TIFFs](@ref) for more details about memory-mapping and lazy I/O.
"""
function load(filepath::String; mode = "r", kwargs...)
_safe_open(filepath, mode) do io
load(io; kwargs...)
end
end
load(io::IOStream; kwargs...) = load(read(io, TiffFile); kwargs...)
function load(tf::TiffFile; verbose=true, mmap = false, lazyio = false)
ifds = IFD{offset(tf)}[]
nplanes = 0
for ifd in tf
load!(tf, ifd)
push!(ifds, ifd)
nplanes += 1
end
homogeneous = is_homogeneous(ifds)
ifd = first(ifds)
if mmap && iscontiguous(ifd) && getdata(CompressionType, ifd, COMPRESSION, COMPRESSION_NONE) === COMPRESSION_NONE
return MmappedTIFF(tf, ifds)
elseif lazyio || mmap
homogeneous || error("lazy IO is only supported for homogeneous files")
mmap && @warn "Compression and discontiguous planes are not supported by `mmap`, use `lazyio = true` instead"
loaded = LazyBufferedTIFF(tf, ifds)
else
if nplanes == 1
loaded = load(tf, ifds, nothing; verbose=verbose)
else
loaded = load(tf, ifds, nplanes, Val(homogeneous); verbose=verbose)
end
end
if (tf.need_bswap && !is_irregular_bps(ifd)) || predictor(ifd) == 3
@debug "bswap'ing data"
if !homogeneous
for sub in loaded
sub .= _bswap.(sub)
end
else
loaded .= _bswap.(loaded)
end
end
close(tf.io)
if nplanes > 1 && !homogeneous
# multiple images of different sizes or color types
data = fixcolors.(loaded, ifds)
return StridedTaggedImage(data, ifds)
else
data = fixcolors(loaded, first(ifds))
return DenseTaggedImage(data, ifds)
end
end
"""
fixcolors(loaded, ifd)
Wrap the raw eltype of an image with color if needed, e.g. for space efficient
on-disk representations like palette-colored images. Otherwise, just return the passed image.
"""
function fixcolors(loaded, ifd)
if eltype(loaded) <: Palette
raw = rawtype(ifd)
loadedr = reinterpret(raw, loaded)
maxdepth = 2^(Int(ifd[BITSPERSAMPLE].data))-1
colors = ifd[COLORMAP].data
color_map = vec(reinterpret(RGB{N0f16}, reshape(colors, :, 3)'))
return IndirectArray(loadedr, OffsetArray(color_map, 0:maxdepth))
else
return loaded
end
end
function load(tf::TiffFile, ifds::AbstractVector{<:IFD}, ::Nothing; verbose = true)
ifd = first(ifds)
cache = getcache(ifd)
read!(cache, tf, ifd)
Matrix(transform(cache, ifd))
end
function load(tf::TiffFile, ifds::AbstractVector{<:IFD}, N, homogeneous::Val{true}; verbose = true)
ifd = first(ifds)
cache = getcache(ifd)
data = similar(cache, nrows(ifd), ncols(ifd), N)
@showprogress desc="Loading:" enabled=verbose for (idx, ifd) in enumerate(ifds)
read!(cache, tf, ifd)
data[:, :, idx] .= transform(cache, ifd)
end
return data
end
function load(tf::TiffFile, ifds::AbstractVector{<:IFD}, N, homogeneous::Val{false}; verbose = true)
data = Vector{AbstractMatrix}()
@showprogress desc="Loading:" enabled=verbose for (idx, ifd) in enumerate(ifds)
cache = getcache(ifd)
read!(cache, tf, ifd)
push!(data, transform(cache, ifd))
end
return data
end
transform(cache, ifd) = istiled(ifd) ? tile(cache, ifd) : cache'
function tile(cache, ifd)
rows = nrows(ifd)
cols = ncols(ifd)
width = tilecols(ifd) # width of a tile
height = tilerows(ifd) # height of a tile
tileswidth = cld(cols, width) # number of tiles in a row
tilesheight = cld(rows, height) # number of tiles in a column
tilesize = width * height # number of pixels in a tile
# tiles are encoded linearly; we need to reshape each strip into a tile and ...
tiles = adjoint.(reshape.(partition(cache, tilesize), width, height))
# ... arrange the tiles to get a padded image, which needs to be ...
padded_image = vcat(map(row -> hcat(row...), partition(tiles, tileswidth))...)
# ... cropped because the encoded image is padded to tile boundaries
padded_image[1:rows, 1:cols]
end