How to add File Format to FileIO.jl and Image related formats to ImageIO.jl
In this post, I document how to add new file formats to FileIO.jl and ImageIO.jl . Let’s say you have written JpegTurbo.jl which provides load and save support for jpeg, jpg files.
JpegTurbo.jl
Support for decoding of a file/iostream and encoding of a file/iostream are located in decode.jl and encode.jl of src/ folder of the project.
using JpegTurbo
img = rand(64, 64)
# jpeg_encode provides encoding support
bytes = jpeg_encode(img) # Vector{UInt8}
# jpeg_decode provides decoding support
img_saveload = jpeg_decode(bytes) # size: 64x64
To start to work on this, we need to create fileio.jl which provides method that FileIO.jl to use jpeg_decode
and jpeg_encode
provided by JpegTurbo.jl .
We create fileio.jl and add it to JpegTurbo.jl, write the below written code which i’ll explain in a bit and write the tests. There will be slight difference depending on your specific file format. Like File{format"JPEG”}
and jpeg_decode
and jpeg_encode
will be changed mostly.
using FileIO
# These are private load, save function that will be conditionally
# called by fileio as needed
function fileio_load(f::File{format"JPEG"}; kwargs...)
open(f.filename, "r") do io
jpeg_decode(io; kwargs...)
end
end
fileio_load(io::Stream{format"JPEG"}; kwargs...) = jpeg_decode(read(io); kwargs...)
# both load and save take File and Stream object
# more info on them here:
# https://juliaio.github.io/FileIO.jl/stable/reference/#FileIO.File
function fileio_save(f::File{format"JPEG"}, img::AbstractArray; kwargs...)
open(f.filename, "w") do io
jpeg_encode(io, img; kwargs...)
end
end
function fileio_save(io::Stream{format"JPEG"}, img::AbstractArray; kwargs...)
jpeg_encode(io.io, img; kwargs...)
end
# inside these functions like fileio_load and fileio_save we have methods
# from JpegTurbo that do the heavy lifting.
More details in this PR:
FileIO support

FileIO aims to provide a common framework for detecting file formats and dispatching to appropriate readers/writers. The two core functions in this package are called load
and save
, and offer high-level support for formatted files (in contrast with julia's low-level read
and write
).
FileIO provides two method for every file format that’s registered: load
and save
, neat isn’t it~
When FileIO detects that a file or stream should be handled by a particular package, it will try to call private methods in that package for processing the request. For example, suppose you have created a package called JpegTurbo
to handle files of a particular format; then load("somefile.jpeg")
for a suitable file will cause FileIO to:
- attempt to load your package
JpegTurbo
usingBase.require(id::PkgId)
, where aPkgId
combines the name andUUID
that you supplied viaadd_format
- call
JpegTurbo.load(file)
wherefile
isFile
.
Important point is that JpegTurbo.load
does not extend FileIO.load
: it is a private function defined in module JpegTurbo
. This is important for ensuring that single formats can be supported by multiple packages by module-qualification.
More details can be found here:
So we have written fileio.jl in JpegTurbo.jl, then we write the tests like here:
We write the test set to test the functions in src/fileio.jl and include it in runtests.jl
@testset "FileIO" begin
img = testimage("cameraman")
ref = jpeg_decode(jpeg_encode(img))
tmpfile = File{format"JPEG"}(joinpath(tmpdir, "tmp.jpg"))
JpegTurbo.fileio_save(tmpfile, img)
data = JpegTurbo.fileio_load(tmpfile)
# checks if original file and file encoded by JpegTurbo are same or not.
@test data == ref
end
Support in FileIO.jl
Adding the file format in FileIO.jl is quite simple:
- We need to add details about the package in registry of FileIO.jl
To do that we add below written code to src/registry.jl in FileIO.jl repo :
const idJpegTurbo = :JpegTurbo => UUID("b835a17e-a41a-41e7-81f0-2f016b05efe0")
add_format(
format"JPEG", # DataFormat type, created as format"IDENTIFIER"
UInt8[0xff,0xd8,0xff], # Magic Bytes, Bytes that uniquely identify format
[".jpeg", ".jpg", ".JPG"], # types of file decode and encodable
[idJpegTurbo], # first choice
[idQuartzImageIO, OSX], # choice after JpegTurbo incase JpegTurbo fails in OSX
[idImageMagick] # last choice
) # 0xe1
We want to sunset ImageMagick.jl in the long run hence it being the last choice.
More details can be found here:
And for ImageIO.jl, we do something similar for which more details can be found here:
It has similar load, save functions for ImageIO and tests after that. Hope you got to know about it and learn more on the topic.