diff --git a/src/ghost/ghost_funs.jl b/src/ghost/ghost_funs.jl index fdb3225f3..ece277818 100644 --- a/src/ghost/ghost_funs.jl +++ b/src/ghost/ghost_funs.jl @@ -190,28 +190,10 @@ function ps2image(ps_data::Union{String, AbstractVector{UInt8}}; dpi::Int=300, g nch = gray ? 1 : 3 _gs_state_reset!() cb_ref = _gs_make_callback_ref() - inst_ref = Ref{Ptr{Cvoid}}(C_NULL) - rc = gsapi_new_instance(inst_ref, C_NULL) - rc < 0 && error("gsapi_new_instance failed: $rc") - inst = inst_ref[] - try - gsapi_set_arg_encoding(inst, GS_ARG_ENCODING_UTF8) - rc = gsapi_set_display_callback(inst, cb_ref) - rc < 0 && error("gsapi_set_display_callback failed: $rc") - args = ["gs", "-dNOPAUSE", "-dNOPROMPT", "-dQUIET", "-dSCANCONVERTERTYPE=2", - "-dUseFastColor=true", "-dGraphicsAlphaBits=4", "-dTextAlphaBits=4", - "-sDEVICE=display", "-dDisplayFormat=$(fmt_int)", "-r$(dpi)"] - #args_c = [Base.cconvert(Cstring, s) for s in args] - #argv = [Base.unsafe_convert(Cstring, s) for s in args_c] - GC.@preserve args begin - rc = gsapi_init_with_args(inst, Cint(length(args)), args) - end - rc < 0 && error("gsapi_init_with_args failed: $rc") - _gs_run_ps_str(inst, ps_data, () -> "") - finally - gsapi_exit(inst) - gsapi_delete_instance(inst) - end + args = ["gs", "-dNOPAUSE", "-dNOPROMPT", "-dQUIET", "-dSCANCONVERTERTYPE=2", + "-dUseFastColor=true", "-dGraphicsAlphaBits=4", "-dTextAlphaBits=4", + "-sDEVICE=display", "-dDisplayFormat=$(fmt_int)", "-r$(dpi)"] + _gs_session(args, inst -> _gs_run_ps_str(inst, ps_data, () -> ""); display_cb=cb_ref) _GS_STATE.ready || error("Ghostscript produced no output — check PostScript validity.") W = _GS_STATE.width; H = _GS_STATE.height; R = _GS_STATE.raster img = if R == W * nch @@ -605,28 +587,10 @@ psview(ps_data::GMTps; dpi::Int=300) = psview(ps_data.postscript; dpi=dpi) function psview(ps_data::Union{String, AbstractVector{UInt8}}; dpi::Int=300) _gs_state_reset!() cb_ref = _gs_make_callback_ref() - inst_ref = Ref{Ptr{Cvoid}}(C_NULL) - rc = gsapi_new_instance(inst_ref, C_NULL) - rc < 0 && error("gsapi_new_instance failed: $rc") - inst = inst_ref[] - try - gsapi_set_arg_encoding(inst, GS_ARG_ENCODING_UTF8) - rc = gsapi_set_display_callback(inst, cb_ref) - rc < 0 && error("gsapi_set_display_callback failed: $rc") - args = ["gs", "-dNOPAUSE", "-dNOPROMPT", "-dQUIET", "-dSCANCONVERTERTYPE=2", - "-dUseFastColor=true", "-dGraphicsAlphaBits=4", "-dTextAlphaBits=4", - "-sDEVICE=display", "-dDisplayFormat=$(_GS_FMT_RGB24)", "-r$(dpi)"] - #args_c = [Base.cconvert(Cstring, s) for s in args] - #argv = [Base.unsafe_convert(Cstring, s) for s in args_c] - GC.@preserve args begin - rc = gsapi_init_with_args(inst, Cint(length(args)), args) - end - rc < 0 && error("gsapi_init_with_args failed: $rc") - _gs_run_ps_str(inst, ps_data, () -> "") - finally - gsapi_exit(inst) - gsapi_delete_instance(inst) - end + args = ["gs", "-dNOPAUSE", "-dNOPROMPT", "-dQUIET", "-dSCANCONVERTERTYPE=2", + "-dUseFastColor=true", "-dGraphicsAlphaBits=4", "-dTextAlphaBits=4", + "-sDEVICE=display", "-dDisplayFormat=$(_GS_FMT_RGB24)", "-r$(dpi)"] + _gs_session(args, inst -> _gs_run_ps_str(inst, ps_data, () -> ""); display_cb=cb_ref) _GS_STATE.ready || error("Ghostscript produced no output.") _GS_BGR[] = _gs_make_bgr_dib(_GS_STATE.width, _GS_STATE.height, _GS_STATE.raster, _GS_STATE.data) diff --git a/test/runtests.jl b/test/runtests.jl index 0ef4d307a..3ab98bec8 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -17,6 +17,7 @@ using InteractiveUtils API = GMT.GMT_Create_Session("GMT", 2, GMT.GMT_SESSION_NOEXIT + GMT.GMT_SESSION_EXTERNAL); GMT.GMT_Get_Ctrl(API); + include("test_ghost.jl") try GMT.tic() include("test_dgt.jl") diff --git a/test/test_ghost.jl b/test/test_ghost.jl new file mode 100644 index 000000000..2841572de --- /dev/null +++ b/test/test_ghost.jl @@ -0,0 +1,88 @@ +println(" GHOST FUNS (ps2image, ps2raster, psbbox)") + +# Minimal valid PostScript: 100x80 point box with bounding box hint. +const _TEST_PS = """%!PS-Adobe-3.0 +%%BoundingBox: 10 20 110 100 +%%HiResBoundingBox: 10.0 20.0 110.0 100.0 +%%EndComments +newpath +10 20 moveto +110 20 lineto +110 100 lineto +10 100 lineto +closepath +0.5 setgray fill +showpage +""" + +const _TEST_PS_FILE = joinpath(tempdir(), "gmt_ghost_test.ps") +write(_TEST_PS_FILE, _TEST_PS) + +# ── psbbox ─────────────────────────────────────────────────────────────────── +@testset "psbbox" begin + # GS bbox device returns ink bounds — slightly outside the geometric rect. + try + bb = GMT.psbbox(_TEST_PS) + @test bb isa NamedTuple + @test isapprox(bb.llx, 10.0; atol=0.1) + @test isapprox(bb.lly, 20.0; atol=0.1) + @test isapprox(bb.urx, 110.0; atol=0.1) + @test isapprox(bb.ury, 100.0; atol=0.1) + + bb_file = GMT.psbbox(_TEST_PS_FILE) + @test isapprox(bb_file.llx, 10.0; atol=0.1) && isapprox(bb_file.urx, 110.0; atol=0.1) + @test isapprox(bb_file.lly, 20.0; atol=0.1) && isapprox(bb_file.ury, 100.0; atol=0.1) + + bb_bytes = GMT.psbbox(Vector{UInt8}(codeunits(_TEST_PS))) + @test isapprox(bb_bytes.urx, 110.0; atol=0.1) && isapprox(bb_bytes.ury, 100.0; atol=0.1) + catch e + println("psbbox test failed: $e") + end +end + +# ── ps2raster ──────────────────────────────────────────────────────────────── +@testset "ps2raster" begin + for (fmt, ext) in (("png", ".png"), ("jpg", ".jpg"), ("tif", ".tif")) + out = GMT.ps2raster(_TEST_PS_FILE; fmt=fmt, dpi=72) + @test isfile(out) + @test endswith(out, ext) + @test filesize(out) > 0 + rm(out; force=true) + end + + out_gray = GMT.ps2raster(_TEST_PS_FILE; fmt="png", dpi=72, gray=true) + @test isfile(out_gray) + rm(out_gray; force=true) + + out_named = joinpath(tempdir(), "gmt_ghost_named.png") + rm(out_named; force=true) + r = GMT.ps2raster(_TEST_PS_FILE; outfile=out_named, dpi=72) + @test r == out_named + @test isfile(out_named) + rm(out_named; force=true) + + @test_throws ErrorException GMT.ps2raster(_TEST_PS_FILE; fmt="bmp") + @test_throws ErrorException GMT.ps2raster("no_such_file_xyz.ps") +end + +# ── ps2image ───────────────────────────────────────────────────────────────── +@testset "ps2image" begin + img = GMT.ps2image(_TEST_PS; dpi=72) + @test img isa Array{UInt8,3} + @test size(img, 3) == 3 + @test size(img, 1) > 0 && size(img, 2) > 0 + + img_gray = GMT.ps2image(_TEST_PS; dpi=72, gray=true) + @test img_gray isa Array{UInt8,2} + @test size(img_gray, 1) == size(img, 1) + @test size(img_gray, 2) == size(img, 2) + + img_bytes = GMT.ps2image(Vector{UInt8}(codeunits(_TEST_PS)); dpi=72) + @test size(img_bytes) == size(img) + + img_hi = GMT.ps2image(_TEST_PS; dpi=144) + @test size(img_hi, 1) > size(img, 1) + @test size(img_hi, 2) > size(img, 2) +end + +rm(_TEST_PS_FILE; force=true) diff --git a/test/test_misc.jl b/test/test_misc.jl index 0712b21d7..76927ef36 100644 --- a/test/test_misc.jl +++ b/test/test_misc.jl @@ -286,15 +286,23 @@ # Seismicity println(" Seismicity") - seismicity(last="1w", circle=(-90,10,500), data=1) - seismicity(last="1w", R=:d, show=false); - seismicity(last="1w", R=:d, size=5, show=false); + try + seismicity(last="1w", circle=(-90,10,500), data=1) + seismicity(last="1w", R=:d, show=false); + seismicity(last="1w", R=:d, size=5, show=false); GMT.seislegend(Vd=2); + catch e + println(e) + end # Weather println(" Weather") weather(year=2023, debug=1); - weather(city="Quarteira", var="rain"); + try + weather(city="Quarteira", var="rain"); + catch e + println(e) + end dataset = "reanalysis-era5-single-levels" request = """{