JuliaImages / ImageView.jl

Interactive display of images and movies
MIT License
135 stars 34 forks source link

Inexact error when repeatedly calling imshow and scrolling #297

Closed opiateblush closed 9 months ago

opiateblush commented 9 months ago

Using Gtk to repeatedly call a function that updates the image to an image with a different resolution causes an InexactError that corrupts the Gtk loop. In order for that behavior to occur one has to scroll (resize) the image in the gui continuously and fast (it takes a few seconds before it crashes). The following example can be used to demonstrate the issue:

using Gtk4, ImageView, Images

function update_image(canvas)
    # this is problematic; imshow! or imshow doesn't matter for this demonstration; max calls not necessary just to make sure
    imshow(canvas, rand(RGB, max(Int(round((1 + rand()) * 100)), 100), max(Int(round((1 + rand()) * 100)), 100)))

    # this is fine
    # imshow(canvas, rand(RGB, (100, 100)))

    Cint(1)
end

function main()
    win = GtkWindow("Awesome window", 1200, 800)
    box = GtkBox(:h)

    frame, canvas = ImageView.frame_canvas(:auto)

    push!(box, frame)
    push!(win, box)

    imshow(canvas, rand(RGB, (100, 100)))

    Gtk4.g_timeout_add(() -> update_image(canvas), 1000)
end

main()

The error:

julia> FATAL ERROR: Gtk state corrupted by error thrown in a callback:
ERROR: InexactError: trunc(Int64, NaN)
Stacktrace:
  [1] trunc
    @ ./float.jl:893 [inlined]
  [2] round
    @ ./float.jl:384 [inlined]
  [3] Type
    @ ~/.julia/packages/RoundingIntegers/n88oz/src/RoundingIntegers.jl:99 [inlined]
  [4] convert
    @ ./number.jl:7 [inlined]
  [5] checked_conversion
    @ ~/.julia/packages/IntervalSets/viB6k/src/IntervalSets.jl:75 [inlined]
  [6] Interval
    @ ~/.julia/packages/IntervalSets/viB6k/src/interval.jl:13 [inlined]
  [7] Interval
    @ ~/.julia/packages/IntervalSets/viB6k/src/interval.jl:29 [inlined]
  [8] convert
    @ ~/.julia/packages/IntervalSets/viB6k/src/interval.jl:53 [inlined]
  [9] oftype
    @ ./essentials.jl:471 [inlined]
 [10] interior(iv::IntervalSets.ClosedInterval{Float64}, limits::IntervalSets.ClosedInterval{RoundingIntegers.RInt64})
    @ GtkObservables ~/.julia/packages/GtkObservables/diarH/src/graphics_interaction.jl:472
 [11] zoom(zr::GtkObservables.ZoomRegion{RoundingIntegers.RInt64}, s::Float64, pos::GtkObservables.XY{GtkObservables.UserUnit})
    @ GtkObservables ~/.julia/packages/GtkObservables/diarH/src/graphics_interaction.jl:518
 [12] (::GtkObservables.var"#200#202"{GtkObservables.UserUnit, GtkObservables.Canvas{GtkObservables.UserUnit}, Observables.Observable{GtkObservables.ZoomRegion{RoundingIntegers.RInt64}}, GtkObservables.var"#199#201", Symbol, Float64, Bool, Observables.Observable{Bool}})(event::GtkObservables.MouseScroll{GtkObservables.UserUnit})
    @ GtkObservables ~/.julia/packages/GtkObservables/diarH/src/graphics_interaction.jl:693
 [13] #invokelatest#2
    @ ./essentials.jl:819 [inlined]
 [14] invokelatest
    @ ./essentials.jl:816 [inlined]
 [15] notify
    @ ~/.julia/packages/Observables/YdEbO/src/Observables.jl:206 [inlined]
 [16] setindex!
    @ ~/.julia/packages/Observables/YdEbO/src/Observables.jl:123 [inlined]
 [17] mousescroll_cb(ecp::Ptr{Gtk4.GLib.GObject}, dx::Float64, dy::Float64, handler::GtkObservables.MouseHandler{GtkObservables.UserUnit})
    @ GtkObservables ~/.julia/packages/GtkObservables/diarH/src/graphics_interaction.jl:285
 [18] (::Gtk4.GLib.var"#230#231")()
    @ Gtk4.GLib ~/.julia/packages/Gtk4/qY7HD/src/GLib/loop.jl:83
 [19] g_sigatom(f::Any)
    @ Gtk4.GLib ~/.julia/packages/Gtk4/qY7HD/src/GLib/signals.jl:191
 [20] glib_main()
    @ Gtk4.GLib ~/.julia/packages/Gtk4/qY7HD/src/GLib/loop.jl:80

System Info: Ubuntu 22.04 Julia 1.9.4 Gtk4 v0.5.4 GtkObservables v2.0.3 ImageView v0.12.0 Images v0.26.0 Observables v0.5.5

jwahlstrand commented 9 months ago

I can get the same InexactError: trunc(Int64, NaN) using the following:

using GtkObservables
zr=ZoomRegion((1:100,1:100))
c=XY(UserUnit(50),UserUnit(50))

and then calling the following over and over:

zr=zoom(zr,0.5,c)

which simulates zooming in. I think this could be fixed by refusing to zoom in further when you get to the point where a pixel fills the whole canvas.