Skip to content

Commit 5349e2a

Browse files
committed
Add support for writemime
1 parent c3ff161 commit 5349e2a

File tree

3 files changed

+64
-6
lines changed

3 files changed

+64
-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, [:nothing])
810
function $fchk(pkg::Symbol)
@@ -17,5 +19,20 @@ for (appl,fchk,fadd,dct) in ((:applicable_loaders, :check_loader, :add_loader, :
1719
end
1820
end
1921

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

0 commit comments

Comments
 (0)