Skip to content

Commit 84c9ead

Browse files
authored
Merge pull request #171 from JuliaIO/teh/precompile
Add some precompile statements and clean up the tests
2 parents e41a652 + 889f820 commit 84c9ead

File tree

6 files changed

+140
-95
lines changed

6 files changed

+140
-95
lines changed

src/ImageMagick.jl

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,14 @@ function _metadata(wand)
110110
sz, T, cs, channelorder
111111
end
112112

113-
load(imagefile::File{T}, args...; key_args...) where {T <: DataFormat} = load_(filename(imagefile), args...; key_args...)
114-
load(filename::AbstractString, args...; key_args...) = load_(filename, args...; key_args...)
115-
save(imagefile::File{T}, args...; key_args...) where {T <: DataFormat} = save_(filename(imagefile), args...; key_args...)
116-
save(filename::AbstractString, args...; key_args...) = save_(filename, args...; key_args...)
113+
load(@nospecialize(imagefile::File{<:DataFormat}), @nospecialize(args...); key_args...) = load_(filename(imagefile), args...; key_args...)
114+
load(filename::AbstractString, @nospecialize(args...); key_args...) = load_(filename, args...; key_args...)
115+
save(@nospecialize(imagefile::File{<:DataFormat}), @nospecialize(args...); key_args...) = save_(filename(imagefile), args...; key_args...)
116+
save(filename::AbstractString, @nospecialize(args...); key_args...) = save_(filename, args...; key_args...)
117117

118-
load(imgstream::Stream{T}, args...; key_args...) where {T <: DataFormat} = load_(stream(imgstream), args...; key_args...)
118+
load(@nospecialize(imgstream::Stream{<:DataFormat}), @nospecialize(args...); key_args...) = load_(stream(imgstream), args...; key_args...)
119119
load(imgstream::IO, args...; key_args...) = load_(imgstream, args...; key_args...)
120-
save(imgstream::Stream{T}, args...; key_args...) where {T <: DataFormat} = save_(imgstream, args...; key_args...)
120+
save(@nospecialize(imgstream::Stream{<:DataFormat}), args...; key_args...) = save_(imgstream, args...; key_args...)
121121

122122
const ufixedtype = Dict(10=>N6f10, 12=>N4f12, 14=>N2f14, 16=>N0f16)
123123

@@ -147,7 +147,7 @@ function load_(file::Union{AbstractString,IO,Vector{UInt8}}, permute_horizontal=
147147
end
148148

149149

150-
function save_(filename::AbstractString, img, permute_horizontal=true; mapi = identity, quality = nothing, kwargs...)
150+
function save_(filename::AbstractString, @nospecialize(img), permute_horizontal=true; mapi = identity, quality = nothing, kwargs...)
151151
wand = image2wand(img, mapi, quality, permute_horizontal; kwargs...)
152152
writeimage(wand, filename)
153153
end
@@ -160,7 +160,7 @@ function save_(s::Stream, img, permute_horizontal=true; mapi = clamp01nan, quali
160160
write(stream(s), blob)
161161
end
162162

163-
function image2wand(img, mapi=identity, quality=nothing, permute_horizontal=true; kwargs...)
163+
function image2wand(@nospecialize(img), mapi=identity, quality=nothing, permute_horizontal=true; kwargs...)
164164
local imgw
165165
try
166166
imgw = map(x->mapIM(mapi(x)), img)
@@ -269,4 +269,7 @@ end
269269
to_explicit(A::Array{T}) where {T<:Normed} = rawview(A)
270270
to_explicit(A::Array{T}) where {T<:AbstractFloat} = to_explicit(convert(Array{N0f8}, A))
271271

272+
include("precompile.jl")
273+
_precompile_()
274+
272275
end # module

src/libmagickwand.jl

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,16 @@ flip12(A) = view(A, reverse(axes(A,1)), reverse(axes(A,2)), ntuple(x->Colon(),nd
9292
vertical_major(img::AbstractVector) = img
9393
vertical_major(A) = PermutedDimsArray(A, [2;1;3:ndims(A)])
9494

95+
# This orientation is used so often it's worth naming it for better precompilation
96+
default_orientation(A, ph) = ph ? vertical_major(A) : A
97+
9598
const orientation_dict = Dict(
96-
nothing => (A,ph) -> ph ? vertical_major(A) : identity(A),
97-
"1" => (A,ph) -> ph ? vertical_major(A) : identity(A),
99+
nothing => default_orientation,
100+
"1" => (A,ph) -> ph ? vertical_major(A) : A,
98101
"2" => (A,ph) -> ph ? vertical_major(flip1(A)) : flip1(A),
99102
"3" => (A,ph) -> ph ? vertical_major(flip12(A)) : flip12(A),
100103
"4" => (A,ph) -> ph ? vertical_major(flip2(A)) : flip2(A),
101-
"5" => (A,ph) -> ph ? identity(A) : vertical_major(A),
104+
"5" => (A,ph) -> ph ? A : vertical_major(A),
102105
"6" => (A,ph) -> ph ? flip2(A) : vertical_major(flip2(A)),
103106
"7" => (A,ph) -> ph ? flip12(A) : vertical_major(flip12(A)),
104107
"8" => (A,ph) -> ph ? flip1(A) : vertical_major(flip1(A)))
@@ -205,7 +208,8 @@ bitdepth(buffer::AbstractArray{C}) where {C<:Colorant} = 8*sizeof(eltype(C))
205208
bitdepth(buffer::AbstractArray{T}) where {T} = 8*sizeof(T)
206209

207210
# colorspace is included for consistency with constituteimage, but it is not used
208-
function exportimagepixels!(buffer::AbstractArray{T}, wand::MagickWand, colorspace::String, channelorder::String; x = 0, y = 0) where T<:Unsigned
211+
function exportimagepixels!(@nospecialize(buffer::AbstractArray{<:Unsigned}), wand::MagickWand, colorspace::String, channelorder::String; x = 0, y = 0)
212+
T = eltype(buffer)
209213
cols, rows, nimages = getsize(buffer, channelorder)
210214
ncolors = colorsize(buffer, channelorder)
211215
if isa(buffer, Array)

src/precompile.jl

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
const __bodyfunction__ = Dict{Method,Any}()
2+
3+
# Find keyword "body functions" (the function that contains the body
4+
# as written by the developer, called after all missing keyword-arguments
5+
# have been assigned values), in a manner that doesn't depend on
6+
# gensymmed names.
7+
# `mnokw` is the method that gets called when you invoke it without
8+
# supplying any keywords.
9+
function __lookup_kwbody__(mnokw::Method)
10+
function getsym(arg)
11+
isa(arg, Symbol) && return arg
12+
@assert isa(arg, GlobalRef)
13+
return arg.name
14+
end
15+
16+
f = get(__bodyfunction__, mnokw, nothing)
17+
if f === nothing
18+
fmod = mnokw.module
19+
# The lowered code for `mnokw` should look like
20+
# %1 = mkw(kwvalues..., #self#, args...)
21+
# return %1
22+
# where `mkw` is the name of the "active" keyword body-function.
23+
ast = Base.uncompressed_ast(mnokw)
24+
if isa(ast, Core.CodeInfo) && length(ast.code) >= 2
25+
callexpr = ast.code[end-1]
26+
if isa(callexpr, Expr) && callexpr.head == :call
27+
fsym = callexpr.args[1]
28+
if isa(fsym, Symbol)
29+
f = getfield(fmod, fsym)
30+
elseif isa(fsym, GlobalRef)
31+
if fsym.mod === Core && fsym.name === :_apply
32+
f = getfield(mnokw.module, getsym(callexpr.args[2]))
33+
elseif fsym.mod === Core && fsym.name === :_apply_iterate
34+
f = getfield(mnokw.module, getsym(callexpr.args[3]))
35+
else
36+
f = getfield(fsym.mod, fsym.name)
37+
end
38+
else
39+
f = missing
40+
end
41+
else
42+
f = missing
43+
end
44+
else
45+
f = missing
46+
end
47+
__bodyfunction__[mnokw] = f
48+
end
49+
return f
50+
end
51+
52+
function _precompile_()
53+
ccall(:jl_generating_output, Cint, ()) == 1 || return nothing
54+
precompile(Tuple{typeof(load),File})
55+
precompile(Tuple{typeof(load_),String})
56+
precompile(Tuple{typeof(save_),String,AbstractArray})
57+
precompile(Tuple{typeof(exportimagepixels!),AbstractArray,MagickWand,String,String})
58+
precompile(Tuple{typeof(storagetype),Type{UInt8}})
59+
for C in (Gray{N0f8}, RGB{N0f8})
60+
precompile(Tuple{typeof(default_orientation),Matrix{C},Bool})
61+
end
62+
precompile(Tuple{typeof(__init__)})
63+
64+
let fbody = try __lookup_kwbody__(which(load_, (String,Bool,))) catch missing end
65+
if !ismissing(fbody)
66+
precompile(fbody, (Type,String,Nothing,Bool,typeof(load_),String,Bool,))
67+
end
68+
end
69+
end

test/constructed_images.jl

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ using ImageShow # for show(io, ::MIME, img) & ImageMeta
33
using Test
44
using ImageCore
55

6-
ontravis = haskey(ENV, "TRAVIS")
7-
86
mutable struct TestType end
97

108
@testset "IO" begin
@@ -18,12 +16,11 @@ mutable struct TestType end
1816

1917
a = [TestType() TestType()]
2018
fn = joinpath(workdir, "5by5.png")
21-
errfile, io = mktemp() # suppress warning message
22-
redirect_stderr(io) do
19+
io = IOBuffer()
20+
with_logger(SimpleLogger(io)) do # suppress warning
2321
@test_throws MethodError ImageMagick.save(fn, a)
2422
end
25-
close(io)
26-
rm(errfile)
23+
@test occursin("out-of-range", String(take!(io)))
2724

2825
@testset "Binary png" begin
2926
a = rand(Bool,5,5)
@@ -120,26 +117,18 @@ mutable struct TestType end
120117
@testset "Alpha" begin
121118
c = reinterpret(BGRA{N0f8}, [0xf0884422]'')
122119
fn = joinpath(workdir, "alpha.png")
123-
ImageMagick.save(fn, c)
120+
ImageMagick.save(fn, c)
124121
C = ImageMagick.load(fn)
125-
if !ontravis || !Sys.islinux()
126-
# disabled on Linux Travis because it has a weird copy of
127-
# ImageMagick for which this fails (see Images#261)
128-
@test C[1] == c[1]
129-
end
122+
@test C[1] == c[1]
130123
ImageMagick.save(fn, reinterpret(ARGB32, [0xf0884422]''))
131124
D = ImageMagick.load(fn)
132-
if !ontravis || !Sys.islinux()
133-
@test D[1] == c[1]
134-
end
125+
@test D[1] == c[1]
135126

136127
# Images#396
137128
c = colorview(RGBA, normedview(permuteddimsview(reshape(0x00:0x11:0xff, 2, 2, 4), (3,1,2))))
138129
ImageMagick.save(fn, c)
139130
D = ImageMagick.load(fn)
140-
if !ontravis || !Sys.islinux()
141-
@test D == c
142-
end
131+
@test D == c
143132
end
144133

145134
@testset "3D TIFF (issue #307)" begin
@@ -167,18 +156,16 @@ mutable struct TestType end
167156
@test A == B
168157
end
169158

170-
#= FAILS ON SCIENTIFIC LINUX 7.2 WITH IMAGEMAGICK 6.9.5, works for other combos
171-
@testset "32-bit TIFF (issue #49)" begin
172-
Ar = rand(0x00000000:0xffffffff, 2, 2, 4)
173-
Ar[1] = 0xffffffff
174-
A = map(x->Gray(reinterpret(N0f32, x)), Ar)
175-
fn = joinpath(workdir, "3d32.tif")
176-
ImageMagick.save(fn, A)
177-
B = ImageMagick.load(fn)
178-
179-
@test A == B
180-
end
181-
=#
159+
# @testset "32-bit TIFF (issue #49)" begin
160+
# Ar = rand(0x00000000:0xffffffff, 2, 2, 4)
161+
# Ar[1] = 0xffffffff
162+
# A = map(x->Gray(reinterpret(N0f32, x)), Ar)
163+
# fn = joinpath(workdir, "3d32.tif")
164+
# ImageMagick.save(fn, A)
165+
# B = ImageMagick.load(fn)
166+
#
167+
# @test A == B
168+
# end
182169

183170
@testset "Clamping (issue #256)" begin
184171
Ar = rand(2,2)
@@ -286,7 +273,7 @@ mutable struct TestType end
286273
end
287274

288275
@testset "permute_horizontal" begin
289-
Ar = [0x00 0xff; 0x00 0x00]
276+
Ar = [0x00 0xff; 0x00 0x00]
290277
A = map(x->Gray(N0f8(x,0)), Ar)
291278
fn = joinpath(workdir, "2d.tif")
292279

@@ -307,5 +294,3 @@ mutable struct TestType end
307294
@test transpose(A)==B
308295
end
309296
end
310-
311-
nothing

test/readremote.jl

Lines changed: 34 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,13 @@ end
4949
@test m[1] == reverse(size(img))
5050
@test ndims(img) == 2
5151
@test eltype(img) in (GrayA{N0f8}, RGBA{N0f8})
52-
if Sys.islinux()
53-
outname = joinpath(writedir, "wmark_image.png")
54-
ImageMagick.save(outname, img)
55-
sleep(0.2)
56-
imgc = ImageMagick.load(outname)
57-
@test img == imgc
58-
open(outname, "w") do file
59-
show(file, MIME("image/png"), img)
60-
end
52+
outname = joinpath(writedir, "wmark_image.png")
53+
ImageMagick.save(outname, img)
54+
sleep(0.2)
55+
imgc = ImageMagick.load(outname)
56+
@test img == imgc
57+
open(outname, "w") do file
58+
show(file, MIME("image/png"), img)
6159
end
6260
@test reinterpret(UInt32, map(RGB24, img)) ==
6361
map(x->x&0x00ffffff, reinterpret(UInt32, map(ARGB32, img)))
@@ -74,8 +72,7 @@ end
7472
ImageMagick.save(outname, img)
7573
imgc = ImageMagick.load(outname)
7674
T = eltype(imgc)
77-
# Why does this one fail on OSX??
78-
Sys.isapple() || @test img == imgc
75+
@test img == imgc
7976
@test reinterpret(UInt32, map(RGB24, img)) ==
8077
map(x->x&0x00ffffff, reinterpret(UInt32, map(ARGB32, img)))
8178
imgrgb8 = map(RGB{N0f8}, img)
@@ -93,14 +90,12 @@ end
9390
@test ndims(img) == 2
9491
@test eltype(img) == RGBA{N0f16}
9592
outname = joinpath(writedir, "autumn_leaves.png")
96-
Sys.isapple() || begin
97-
ImageMagick.save(outname, img)
98-
sleep(0.2)
99-
imgc = ImageMagick.load(outname)
100-
@test img == imgc
101-
@test reinterpret(UInt32, map(RGB24, img)) ==
102-
map(x->x&0x00ffffff, reinterpret(UInt32, map(ARGB32, img)))
103-
end
93+
ImageMagick.save(outname, img)
94+
sleep(0.2)
95+
imgc = ImageMagick.load(outname)
96+
@test img == imgc
97+
@test reinterpret(UInt32, map(RGB24, img)) ==
98+
map(x->x&0x00ffffff, reinterpret(UInt32, map(ARGB32, img)))
10499
open(outname, "w") do file
105100
show(file, MIME("image/png"), img)
106101
end
@@ -122,7 +117,7 @@ end
122117
@testset "Images with a temporal dimension" begin
123118
fname = "swirl_video.gif"
124119
#fname = "bunny_anim.gif" # this one has transparency but LibMagick gets confused about its size
125-
file = getfile(fname) # this also has transparency
120+
file = getfile(fname)
126121
img = ImageMagick.load(file)
127122
@test ImageMagick.metadata(file) == (size(img)[[2,1,3]], RGB{N0f8})
128123
@test size(img, 3) == 26
@@ -134,32 +129,29 @@ end
134129
end
135130

136131
@testset "Extra properties" begin
137-
Sys.isapple() || begin
138-
file = getfile("autumn_leaves.png")
139-
# List properties
140-
extraProps = magickinfo(file)
141-
@show extraProps
132+
file = getfile("autumn_leaves.png")
133+
# List properties
134+
extraProps = magickinfo(file)
142135

143-
img = ImageMagick.load(file)
144-
@test ImageMagick.metadata(file) == (reverse(size(img)), RGBA{N0f16})
145-
props = magickinfo(file, extraProps)
146-
for key in extraProps
147-
@test haskey(props, key) == true
148-
@test props[key] != nothing
149-
end
136+
img = ImageMagick.load(file)
137+
@test ImageMagick.metadata(file) == (reverse(size(img)), RGBA{N0f16})
138+
props = magickinfo(file, extraProps)
139+
for key in extraProps
140+
@test haskey(props, key) == true
141+
@test props[key] != nothing
142+
end
150143

151-
props = magickinfo(file, extraProps[1])
152-
@test haskey(props, extraProps[1]) == true
153-
@test props[extraProps[1]] != nothing
144+
props = magickinfo(file, extraProps[1])
145+
@test haskey(props, extraProps[1]) == true
146+
@test props[extraProps[1]] != nothing
154147

155-
warnfile, io = mktemp()
156-
props = redirect_stderr(io) do
157-
magickinfo(file, "Nonexistent property")
158-
end
159-
close(io)
160-
@test haskey(props, "Nonexistent property") == true
161-
@test props["Nonexistent property"] == nothing
148+
io = IOBuffer()
149+
props = with_logger(SimpleLogger(io)) do
150+
magickinfo(file, "Nonexistent property")
162151
end
152+
@test occursin("Undefined", String(take!(io)))
153+
@test haskey(props, "Nonexistent property") == true
154+
@test props["Nonexistent property"] == nothing
163155
end
164156
end
165157

@@ -182,5 +174,3 @@ end
182174
end
183175
ZipFile.close(r)
184176
end
185-
186-
nothing

test/runtests.jl

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@ using Random: bitrand
44
using Base.CoreLogging: SimpleLogger, with_logger
55
using Pkg
66

7-
function is_ci()
8-
get(ENV, "TRAVIS", "") == "true" ||
9-
get(ENV, "APPVEYOR", "") in ("true", "True") ||
10-
get(ENV, "CI", "") in ("true", "True")
11-
end
12-
137
include("constructed_images.jl")
148
include("readremote.jl")
159
include("badimages.jl")

0 commit comments

Comments
 (0)