Skip to content

Commit

Permalink
enforce type conversion to Array (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
johnnychen94 authored May 2, 2021
1 parent 28c6a9d commit 2817842
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 17 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Platform- and user- specific contents and configurations
.DS_Store
.vscode

# Files generated by invoking Julia with --code-coverage
*.jl.cov
Expand Down
33 changes: 26 additions & 7 deletions src/ImageIO.jl
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
module ImageIO

using UUIDs
using FileIO: File, DataFormat, Stream, stream
using FileIO: File, DataFormat, Stream, stream, Formatted

const idNetpbm = Base.PkgId(UUID("f09324ee-3d7c-5217-9330-fc30815ba969"), "Netpbm")
const idPNGFiles = Base.PkgId(UUID("f57f5aa1-a3ce-4bc8-8ab9-96f992907883"), "PNGFiles")
const idTiffImages = Base.PkgId(UUID("731e570b-9d59-4bfa-96dc-6df516fadf69"), "TiffImages")

# Enforce a type conversion to be backend independent (issue #25)
# Note: If the backend does not provide efficient `convert` implementation,
# there will be an extra memeory allocation and thus hurt the performance.
for FMT in (
:PBMBinary, :PGMBinary, :PPMBinary, :PBMText, :PGMText, :PPMText,
:TIFF,
:PNG,
)
@eval canonical_type(::DataFormat{$(Expr(:quote, FMT))}, ::AbstractArray{T, N}) where {T,N} =
Array{T,N}
end
@inline canonical_type(::Formatted{T}, data) where T = canonical_type(T(), data)

## PNGs

const load_locker = Threads.ReentrantLock()
Expand All @@ -19,10 +32,12 @@ function checked_import(pkgid)
end

function load(f::File{DataFormat{:PNG}}; kwargs...)
return Base.invokelatest(checked_import(idPNGFiles).load, f.filename, kwargs...)
data = Base.invokelatest(checked_import(idPNGFiles).load, f.filename, kwargs...)
return convert(canonical_type(f, data), data)
end
function load(s::Stream{DataFormat{:PNG}}; kwargs...)
return Base.invokelatest(checked_import(idPNGFiles).load, stream(s), kwargs...)
data = Base.invokelatest(checked_import(idPNGFiles).load, stream(s), kwargs...)
return convert(canonical_type(s, data), data)
end

function save(f::File{DataFormat{:PNG}}, image::S; kwargs...) where {T, S<:Union{AbstractMatrix, AbstractArray{T,3}}}
Expand All @@ -44,11 +59,13 @@ end
for NETPBMFORMAT in (:PBMBinary, :PGMBinary, :PPMBinary, :PBMText, :PGMText, :PPMText)
@eval begin
function load(f::File{DataFormat{$(Expr(:quote,NETPBMFORMAT))}})
return Base.invokelatest(checked_import(idNetpbm).load, f)
data = Base.invokelatest(checked_import(idNetpbm).load, f)
return convert(canonical_type(f, data), data)
end

function load(s::Stream{DataFormat{$(Expr(:quote,NETPBMFORMAT))}})
return Base.invokelatest(checked_import(idNetpbm).load, s)
data = Base.invokelatest(checked_import(idNetpbm).load, s)
return convert(canonical_type(s, data), data)
end

function save(f::File{DataFormat{$(Expr(:quote,NETPBMFORMAT))}}, image::S; kwargs...) where {S<:AbstractMatrix}
Expand All @@ -64,10 +81,12 @@ end
## TIFFs

function load(f::File{DataFormat{:TIFF}}; kwargs...)
return Base.invokelatest(checked_import(idTiffImages).load, f.filename, kwargs...)
data = Base.invokelatest(checked_import(idTiffImages).load, f.filename, kwargs...)
return convert(canonical_type(f, data), data)
end
function load(s::Stream{DataFormat{:TIFF}}; kwargs...)
return Base.invokelatest(checked_import(idTiffImages).load, stream(s), kwargs...)
data = Base.invokelatest(checked_import(idTiffImages).load, stream(s), kwargs...)
return convert(canonical_type(s, data), data)
end

function save(f::File{DataFormat{:TIFF}}, image::S) where {T, S<:Union{AbstractMatrix, AbstractArray{T,3}}}
Expand Down
30 changes: 20 additions & 10 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,16 @@ Threads.nthreads() <= 1 && @info "Threads.nthreads() = $(Threads.nthreads()), mu
else
@test img == img_saveload
end
@test typeof(img_saveload) == ImageIO.canonical_type(f, img_saveload)

open(io->ImageIO.save(Stream(format"PNG", io), img, permute_horizontal=false), joinpath(tmpdir, "test_io.png"), "w")
img_saveload = open(io->ImageIO.load(Stream(format"PNG", io)), joinpath(tmpdir, "test_io.png"))
open(io->ImageIO.save(Stream{format"PNG"}(io), img, permute_horizontal=false), joinpath(tmpdir, "test_io.png"), "w")
img_saveload = open(io->ImageIO.load(Stream{format"PNG"}(io)), joinpath(tmpdir, "test_io.png"))
if typ == UInt8
@test all(img .== reinterpret(UInt8, img_saveload))
else
@test img == img_saveload
end
@test typeof(img_saveload) == ImageIO.canonical_type(f, img_saveload)
end
end
end
Expand All @@ -49,10 +51,12 @@ Threads.nthreads() <= 1 && @info "Threads.nthreads() = $(Threads.nthreads()), mu
ImageIO.save(f, img)
img_saveload = ImageIO.load(f)
@test img == img_saveload
@test typeof(img_saveload) == ImageIO.canonical_type(f, img_saveload)

open(io->ImageIO.save(Stream(fmt, io), img), joinpath(tmpdir, "test_io.pbm"), "w")
img_saveload = open(io->ImageIO.load(Stream(fmt, io)), joinpath(tmpdir, "test_io.pbm"))
open(io->ImageIO.save(Stream{fmt}(io), img), joinpath(tmpdir, "test_io.pbm"), "w")
img_saveload = open(io->ImageIO.load(Stream{fmt}(io)), joinpath(tmpdir, "test_io.pbm"))
@test img == img_saveload
@test typeof(img_saveload) == ImageIO.canonical_type(f, img_saveload)
end
end

Expand All @@ -63,10 +67,12 @@ Threads.nthreads() <= 1 && @info "Threads.nthreads() = $(Threads.nthreads()), mu
ImageIO.save(f, img)
img_saveload = ImageIO.load(f)
@test img == img_saveload
@test typeof(img_saveload) == ImageIO.canonical_type(f, img_saveload)

open(io->ImageIO.save(Stream(fmt, io), img), joinpath(tmpdir, "test_io.pgm"), "w")
img_saveload = open(io->ImageIO.load(Stream(fmt, io)), joinpath(tmpdir, "test_io.pgm"))
open(io->ImageIO.save(Stream{fmt}(io), img), joinpath(tmpdir, "test_io.pgm"), "w")
img_saveload = open(io->ImageIO.load(Stream{fmt}(io)), joinpath(tmpdir, "test_io.pgm"))
@test img == img_saveload
@test typeof(img_saveload) == ImageIO.canonical_type(f, img_saveload)
end
end

Expand All @@ -77,10 +83,12 @@ Threads.nthreads() <= 1 && @info "Threads.nthreads() = $(Threads.nthreads()), mu
ImageIO.save(f, img)
img_saveload = ImageIO.load(f)
@test img == img_saveload
@test typeof(img_saveload) == ImageIO.canonical_type(f, img_saveload)

open(io->ImageIO.save(Stream(fmt, io), img), joinpath(tmpdir, "test_io.ppm"), "w")
img_saveload = open(io->ImageIO.load(Stream(fmt, io)), joinpath(tmpdir, "test_io.ppm"))
open(io->ImageIO.save(Stream{fmt}(io), img), joinpath(tmpdir, "test_io.ppm"), "w")
img_saveload = open(io->ImageIO.load(Stream{fmt}(io)), joinpath(tmpdir, "test_io.ppm"))
@test img == img_saveload
@test typeof(img_saveload) == ImageIO.canonical_type(f, img_saveload)
end
end
end
Expand All @@ -93,10 +101,12 @@ Threads.nthreads() <= 1 && @info "Threads.nthreads() = $(Threads.nthreads()), mu
ImageIO.save(f, img)
img_saveload = ImageIO.load(f)
@test img == img_saveload
@test typeof(img_saveload) == ImageIO.canonical_type(f, img_saveload)

open(io->ImageIO.save(Stream(format"TIFF", io), img), joinpath(tmpdir, "test_io.tiff"), "w")
img_saveload = open(io->ImageIO.load(Stream(format"TIFF", io)), joinpath(tmpdir, "test_io.tiff"))
open(io->ImageIO.save(Stream{format"TIFF"}(io), img), joinpath(tmpdir, "test_io.tiff"), "w")
img_saveload = open(io->ImageIO.load(Stream{format"TIFF"}(io)), joinpath(tmpdir, "test_io.tiff"))
@test img == img_saveload
@test typeof(img_saveload) == ImageIO.canonical_type(f, img_saveload)
end
end
end
Expand Down

0 comments on commit 2817842

Please sign in to comment.