Skip to content

Commit fd6e1e8

Browse files
committed
Merge pull request #37 from JuliaIO/teh/writemime
Add support for writemime
2 parents 7256f85 + 1fa4f7f commit fd6e1e8

File tree

5 files changed

+74
-6
lines changed

5 files changed

+74
-6
lines changed

README.md

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,10 @@ This means MeshIO supports loading and saving of the `off` format.
7676
You can add multiple loaders and specifiers like this:
7777
```jl
7878
add_format(
79-
format"BMP",
79+
format"BMP",
8080
UInt8[0x42,0x4d],
8181
".bmp",
82-
[:OSXNativeIO, LOAD, OSX],
82+
[:OSXNativeIO, LOAD, OSX],
8383
[:ImageMagick]
8484
)
8585
```
@@ -91,6 +91,18 @@ Users are encouraged to contribute these definitions to the
9191
`registry.jl` file of this package, so that information about file
9292
formats exists in a centralized location.
9393

94+
Handling MIME outputs is similar, except that one also provides the
95+
type of the object to be written:
96+
```jl
97+
mimewritable(::MIME"image/png", img::AbstractArray) = ndims(img) == 2
98+
add_mime(MIME("image/png"), AbstractArray, :ImageMagick)
99+
```
100+
101+
In cases where the type is defined in Base julia, such declarations
102+
can by included in FileIO's `registry` file. In contrast, when the
103+
type is defined in a package, that package should call them. Note that
104+
`add_mime` should be called from the package's `__init__` function.
105+
94106
## Implementing loaders/savers
95107

96108
In your package, write code like the following:
@@ -130,6 +142,19 @@ automatically even if the code inside the `do` scope throws an error.)
130142
Conversely, `load(::Stream)` and `save(::Stream)` should not close the
131143
input stream.
132144

145+
For MIME output, you would implement a method like this:
146+
```jl
147+
function Base.writemime(s::Stream{format"ImageMagick"}, ::MIME"image/png", x)
148+
io = stream(s)
149+
# Do the stuff needed to create the output
150+
end
151+
```
152+
153+
It's perfectly acceptable to also create a `Base.writemime(s::IO,
154+
::MIME"image/png", x)` method. Such methods will generally take
155+
precedence over FileIO's generic fallback `writemime` function, and
156+
therefore in some cases might improve performance.
157+
133158
## Help
134159

135160
You can get an API overview by typing `?FileIO` at the REPL prompt.

src/FileIO.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export DataFormat,
2323
add_format,
2424
del_format,
2525
add_loader,
26+
add_mime,
2627
add_saver,
2728
filename,
2829
file_extension,
@@ -85,6 +86,21 @@ function save(s::@compat(Union{AbstractString,IO}), data...; options...)
8586
rethrow(last_exception)
8687
end
8788

89+
function Base.writemime(io::IO, mime::MIME, x)
90+
handlers = applicable_mime(mime)
91+
last_exception = ErrorException("No package available to writemime $mime")
92+
for (T,pkg) in handlers
93+
isa(x, T) || continue
94+
try
95+
check_mime(pkg)
96+
return writemime(Stream(DataFormat{pkg}, io), mime, x)
97+
catch e
98+
last_exception = e
99+
end
100+
end
101+
rethrow(last_exception)
102+
end
103+
88104
# Fallbacks
89105
load{F}(f::Formatted{F}; options...) = error("No load function defined for format ", F, " with filename ", filename(f))
90106
save{F}(f::Formatted{F}, data...; options...) = error("No save function defined for format ", F, " with filename ", filename(f))

src/loadsave.jl

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
const sym2loader = Dict{Symbol,Vector{Symbol}}()
22
const sym2saver = Dict{Symbol,Vector{Symbol}}()
3+
const mimedict = Dict{Symbol,Vector{Any}}()
34

4-
for (appl,fchk,fadd,dct) in ((:applicable_loaders, :check_loader, :add_loader, :sym2loader),
5-
(:applicable_savers, :check_saver, :add_saver, :sym2saver))
5+
for (appl,fchk,fadd,dct) in (
6+
(:applicable_loaders, :check_loader, :add_loader, :sym2loader),
7+
(:applicable_savers, :check_saver, :add_saver, :sym2saver))
68
@eval begin
79
$appl{sym}(::Formatted{DataFormat{sym}}) = get($dct, sym, [:FileIO]) # if no loader is declared, fallback to FileIO
810
function $fchk(pkg::Symbol)
@@ -16,5 +18,20 @@ for (appl,fchk,fadd,dct) in ((:applicable_loaders, :check_loader, :add_loader, :
1618
end
1719
end
1820

19-
@doc "`add_loader(fmt, :Package)` forces `using Package` before loading format `fmt`" -> add_loader
20-
@doc "`add_saver(fmt, :Package)` forces `using Package` before saving format `fmt`" -> add_saver
21+
applicable_mime{sym}(::MIME{sym}) = get(mimedict, sym, [:nothing])
22+
function check_mime(pkg::Symbol)
23+
pkg == :nothing && error("No MIME package available")
24+
!isdefined(Main, pkg) && eval(Main, Expr(:import, pkg))
25+
return pkg
26+
end
27+
28+
@doc """
29+
`add_mime(mime, T, :Package)` triggers `using Package` before attempting to write object of type `T` in format `mime`.
30+
""" ->
31+
function add_mime{sym,T}(::MIME{sym}, ::Type{T}, pkg::Symbol)
32+
list = get(mimedict, sym, Any[])
33+
mimedict[sym] = push!(list, (T,pkg))
34+
end
35+
36+
@doc "`add_loader(fmt, :Package)` triggers `using Package` before loading format `fmt`" -> add_loader
37+
@doc "`add_saver(fmt, :Package)` triggers `using Package` before saving format `fmt`" -> add_saver

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ using FactCheck
44
facts("FileIO") do
55
include("query.jl")
66
include("loadsave.jl")
7+
include("writemime.jl")
78
end
89
# make Travis fail when tests fail:
910
FactCheck.exitstatus()

test/writemime.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Base.writemime(s::Stream{format"FileIO"}, ::MIME"test/floatvector", v::Vector{Float32}) = print(stream(s), v)
2+
context("writemime") do
3+
add_mime(MIME("test/floatvector"), Vector{Float32}, :FileIO)
4+
io = IOBuffer()
5+
t = rand(Float32, 88)
6+
writemime(io, MIME("test/floatvector"), t)
7+
@fact takebuf_string(io) --> string(t)
8+
close(io)
9+
end

0 commit comments

Comments
 (0)