How to add File Format to FileIO.jl and Image related formats to ImageIO.jl

Ashwani Rathee
4 min readJan 1, 2023

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_decodeand 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 using Base.require(id::PkgId), where a PkgId combines the name and UUID that you supplied via add_format
  • call JpegTurbo.load(file) where file is File.

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.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Ashwani Rathee
Ashwani Rathee

Written by Ashwani Rathee

From house of sangrinmid. I am a Julian. I like movies, music, code and everything stitch.

No responses yet

Write a response