subroutine gtl_hardcopy(line,error)
  use gildas_def
  use gtv_buffers
  use gtv_graphic
  use gtv_dependencies_interfaces
  use gtv_interfaces, except_this=>gtl_hardcopy
  use gtv_types
  use gbl_message
  !---------------------------------------------------------------------
  ! @ private
  ! Support command for command
  ! HARDCOPY [Name]
  !  1  [/PRINT Destination]
  !  2  [/DEVICE Type [Options]]
  !  3  [/OVERWRITE]
  !  4  [/DIRECTORY]
  !  5  [/GEOMETRY]
  !  6  [/EXACT]
  !  7  [/FITPAGE]
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line   ! Input command line
  logical,          intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='HARDCOPY'
  integer(kind=4) :: nc,px,py
  logical :: doprint,keep,lover,isdir,found,doexact,dofitpage
  character(len=12) :: devtyp,devopt
  character(len=64) :: queue
  character(len=gtvpath_length) :: dirname
  type(gt_display) :: output
  type(gt_directory), pointer :: workdir
  type(gt_segment), pointer :: segm
  type(x_coordinates) :: geom
  character(len=32) :: argx,argy
  integer(kind=4), parameter :: optprint=1
  !
  ! 1) /PRINT (immediate plotting)
  doprint = sic_present(optprint,0)
  queue = ' '  ! Will use the default 'GAG_PRINTER' later on
  call sic_ch (line,optprint,1,queue,nc,.false.,error)
  if (error) return
  !
  ! 0) Command argument. Output can be:
  !  - a file (no /PRINT option and .not.GTV%STDOUT)
  !  - the terminal (no file name given and GTV%STDOUT is yes)
  !  - a printer (/PRINT option)
  if (doprint) then  ! /PRINT is present
    output%tofile = .true.
    output%file = 'gregplot'
    call sic_ch(line,0,1,output%file,nc,.false.,error)
    if (error)  return
    keep = sic_present(0,1)
    !
  elseif (sic_present(0,1)) then  ! A file name is given
    output%tofile = .true.
    call sic_ch(line,0,1,output%file,nc,.true.,error)
    if (error)  return
    keep = .true.
    !
  elseif (stdout) then  ! No file name, GTV%STDOUT is .true.
    output%tofile = .false.
    output%file = ''
    keep = .false.  ! Not relevant here
    !
  else  ! No file name, GTV%STDOUT is .false.
    output%tofile = .true.
    output%file = 'gregplot'
    keep = .true.
  endif
  !
  ! 2) /DEVICE (Device and Device dependent text)
  !
  ! Read from command line, if present
  if (sic_present(2,0)) then
    call sic_ke(line,2,1,devtyp,nc,.true.,error)
    if (error) return
    devopt = ' '
  else
    ! Else, read default from 'GAG_HARDCOPY'
    call sic_getlog_hardcopy(devtyp,devopt)
  endif
  !
  if (devtyp.eq.'PS' .or. devtyp.eq.'PDF') then
    ! Defaults
    output%autorotate = .true.
    output%autoscale = .true.
    output%color = .true.
    output%ps%fast  = .false.
    output%ps%exact = .false.
    ! Parse the command line arguments to setup the PostScript attributes
    call gtl_hardcopy_ps(line,output,error)
    if (error)  return
    ! Parse the device option
    call gt_hardcopy_ps(devopt,output,error)
    if (error)  return
    !
  elseif (devtyp.eq.'EPS' .or. devtyp.eq.'EPDF') then
    ! Defaults
    output%autorotate = .false.
    output%autoscale = .false.
    output%color = .true.
    output%ps%fast  = .false.
    output%ps%exact = .false.
    ! Parse the command line arguments to setup the PostScript attributes
    call gtl_hardcopy_ps(line,output,error)
    if (error)  return
    ! Parse the device option
    call gt_hardcopy_ps(devopt,output,error)
    if (error)  return
    !
  elseif (devtyp.eq.'PNG') then
    ! Defaults
    output%autorotate = .false.
    output%autoscale = .false.
    output%color = .true.
    output%background = 1  ! White
    output%png%transparency = .false.
    output%png%cropped = .false.
    output%png%noblank = .false.
    ! Parse the command line arguments to setup the PNG attributes
    call gtl_hardcopy_png(line,output,error)
    if (error)  return
    ! Parse the device option
    call gt_hardcopy_png(devopt,output,error)
    if (error)  return
    !
  elseif (devtyp.eq.'SVG') then
    ! Defaults
    output%autorotate = .false.
    output%autoscale = .false.
    output%background = 1  ! White
    output%color = .true.
    output%svg%cropped = .false.
    ! Parse the command line arguments to setup the SVG attributes
    call gtl_hardcopy_svg(line,output,error)
    if (error)  return
    ! Parse the device option
    call gt_hardcopy_svg(devopt,output,error)
    if (error)  return
    !
  endif
  if (doprint) then
    output%autorotate = .true.  ! If available on the device
    output%autoscale = .true.   ! idem
  endif
  !
  ! 3) /OVERWRITE
  lover = nofail.or.sic_present(3,0)
  !
  ! 4) /DIRECTORY. Which directory to dump? Default is current working
  !    directory.
  if (sic_present(4,0)) then
    call sic_ch(line,4,1,dirname,nc,.true.,error)
    if (error)  return
    call sic_upper(dirname)
    !
    call decode_chemin(dirname,cw_directory,workdir,isdir,segm,found)
    if (.not.found) then
      call gtv_message(seve%e,rname,'No such directory '//dirname)
      error = .true.
      return
    endif
    if (.not.isdir) then
      call gtv_message(seve%e,rname,'Input segment is not a directory')
      error = .true.
      return
    endif
    !
  else
    workdir => cw_directory
  endif
  !
  ! 5) /GEOMETRY
  if (sic_present(5,0)) then
    if (devtyp.ne.'PNG' .and. devtyp.ne.'SVG') then
      call gtv_message(seve%e,rname,  &
        'Option /GEOMETRY is not supported for device '//devtyp)
      error = .true.
      return
    endif
    !
    call sic_ch(line,5,1,argx,nc,.true.,error)
    if (error) return
    call sic_ch(line,5,2,argy,nc,.true.,error)
    if (error) return
    call decode_coordinates(geom,argx,argy,error)
    if (error)  return
    call compute_coordinates_geometry(rname,geom,px,py,error)
    if (error)  return
    if (devtyp.eq.'PNG') then
      output%px1 = 1
      output%px2 = px
      output%py1 = 1
      output%py2 = py
    elseif (devtyp.eq.'SVG') then
      ! Size is numbered from 0 to N-1
      output%px1 = 0
      output%px2 = px-1
      output%py1 = py-1  ! Y scale increases from top to bottom in SVG
      output%py2 = 0
    endif
  else
    ! Set size to 0, will be automatic later on
    output%px1 = 0
    output%px2 = 0
    output%py1 = 0
    output%py2 = 0
  endif
  !
  ! 6) & 7) /EXACT and /FITPAGE
  doexact = sic_present(6,0)
  dofitpage = fitpage.or.sic_present(7,0)
  if (doexact .and. dofitpage) then
    call gtv_message(seve%e,rname,'Options /EXACT and /FITPAGE are exclusive')
    error = .true.
    return
  endif
  if (doexact) then
    output%ps%exact = .true.
  elseif (dofitpage) then
    output%autorotate = .true.
    output%autoscale = .true.
  endif
  !
  ! Do the job
  call gt_hardcopy(output,devtyp,workdir,keep,lover,doprint,queue,error)
  if (error)  return
  !
end subroutine gtl_hardcopy
!
subroutine sic_getlog_hardcopy(devtyp,devopt)
  use gtv_dependencies_interfaces
  use gtv_interfaces, except_this=>sic_getlog_hardcopy
  !---------------------------------------------------------------------
  ! @ private
  ! Decode the SIC logical GAG_HARDCOPY
  !---------------------------------------------------------------------
  character(len=*), intent(out) :: devtyp  !
  character(len=*), intent(out) :: devopt  !
  ! Local
  character(len=24) :: device
  integer :: iblank,ier
  !
  device = ' '
  ier = sic_getlog('GAG_HARDCOPY',device)
  call sic_upper(device)
  !
  iblank = index(device,' ')
  if (iblank.ne.0) then
    devtyp = device(1:iblank)
    devopt = device(iblank+1:)
  else
    devtyp = device
    devopt = ' '
  endif
  !
end subroutine sic_getlog_hardcopy
!
subroutine gtl_hardcopy_ps(line,output,error)
  use gtv_dependencies_interfaces
  use gtv_interfaces, except_this=>gtl_hardcopy_ps
  use gbl_message
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private
  !  Decode the options specific to the PostScript devices coming from
  ! the command line.
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line    ! Input command line
  type(gt_display), intent(inout) :: output  ! Instance to customize
  logical,          intent(inout) :: error   ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='HARDCOPY'
  integer :: iarg,nc
  character(len=12) :: arg
  !
  ! Parse option /DEVICE
  do iarg=2,sic_narg(2)
    call sic_ke(line,2,iarg,arg,nc,.true.,error)
    if (error) return
    !
    call gt_hardcopy_ps(arg,output,error)
    if (error)  return
  enddo
  !
end subroutine gtl_hardcopy_ps
!
subroutine gt_hardcopy_ps(keyw,output,error)
  use gtv_dependencies_interfaces
  use gtv_interfaces, except_this=>gt_hardcopy_ps
  use gbl_message
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private
  !  Decode the input option specific to the PostScript devices.
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: keyw    ! Keyword to decode
  type(gt_display), intent(inout) :: output  ! Instance to customize
  logical,          intent(inout) :: error   ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='HARDCOPY'
  character(len=*), parameter :: color='COLOR'
  character(len=*), parameter :: grey='GREY'
  character(len=*), parameter :: fast='FAST'
  integer :: nk
  character(len=24) :: keyword
  !
  if (keyw.eq.' ')  return
  !
  keyword = keyw
  call sic_upper(keyword)
  nk = len_trim(keyword)
  !
  if (keyword(1:nk).eq.color(1:nk)) then
    output%color = .true.
  elseif (keyword(1:nk).eq.grey(1:nk)) then
    output%color = .false.
  elseif (keyword(1:nk).eq.fast(1:nk)) then
    output%ps%fast = .true.
  else
    call gtv_message(seve%e,rname,  &
      'PS attribute '''//keyw(1:nk)//''' not recognized')
    error = .true.
    return
  endif
  !
end subroutine gt_hardcopy_ps
!
subroutine gtl_hardcopy_png(line,output,error)
  use gtv_dependencies_interfaces
  use gtv_interfaces, except_this=>gtl_hardcopy_png
  use gbl_message
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private
  !  Decode the options specific to the PNG device coming from the
  ! command line.
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line    ! Input command line
  type(gt_display), intent(inout) :: output  ! Instance to customize
  logical,          intent(inout) :: error   ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='HARDCOPY'
  integer :: iarg,nc
  character(len=12) :: arg
  !
  ! Parse option /DEVICE
  do iarg=2,sic_narg(2)
    call sic_ke(line,2,iarg,arg,nc,.true.,error)
    if (error) return
    !
    call gt_hardcopy_png(arg,output,error)
    if (error)  return
  enddo
  !
end subroutine gtl_hardcopy_png
!
subroutine gt_hardcopy_png(keyw,output,error)
  use gtv_dependencies_interfaces
  use gtv_interfaces, except_this=>gt_hardcopy_png
  use gbl_message
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private
  !  Decode the input option specific to the PNG devices.
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: keyw    ! Keyword to decode
  type(gt_display), intent(inout) :: output  ! Instance to customize
  logical,          intent(inout) :: error   ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='HARDCOPY'
  ! Declare these strings with trailing blanks so that we can use
  ! "foo(1:nk)" with nk>len_trim(foo)
  character(len=*), parameter :: black       = 'BLACK      '
  character(len=*), parameter :: white       = 'WHITE      '
  character(len=*), parameter :: color       = 'COLOR      '
  character(len=*), parameter :: grey        = 'GREY       '
  character(len=*), parameter :: transparent = 'TRANSPARENT'
  character(len=*), parameter :: cropped     = 'CROPPED    '
  character(len=*), parameter :: noblank     = 'NOBLANK    '
  integer :: nk
  character(len=24) :: keyword
  !
  if (keyw.eq.' ')  return
  !
  keyword = keyw
  call sic_upper(keyword)
  nk = len_trim(keyword)
  !
  if (keyword(1:nk).eq.white(1:nk)) then
    output%background = 1
  elseif (keyword(1:nk).eq.black(1:nk)) then
    output%background = 0
  elseif (keyword(1:nk).eq.color(1:nk)) then
    output%color = .true.
  elseif (keyword(1:nk).eq.grey(1:nk)) then
    output%color = .false.
  elseif (keyword(1:nk).eq.transparent(1:nk)) then
    output%png%transparency = .true.
  elseif (keyword(1:nk).eq.cropped(1:nk)) then
    output%png%cropped = .true.
  elseif (keyword(1:nk).eq.noblank(1:nk)) then
    output%png%noblank = .true.
  else
    call gtv_message(seve%e,rname,  &
      'PNG attribute '''//keyword(1:nk)//''' not recognized')
    error = .true.
    return
  endif
  !
end subroutine gt_hardcopy_png
!
subroutine gtl_hardcopy_svg(line,output,error)
  use gtv_dependencies_interfaces
  use gtv_interfaces, except_this=>gtl_hardcopy_svg
  use gbl_message
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private
  !  Decode the options specific to the SVG device coming from the
  ! command line.
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line    ! Input command line
  type(gt_display), intent(inout) :: output  ! Instance to customize
  logical,          intent(inout) :: error   ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='HARDCOPY'
  integer :: iarg,nc
  character(len=12) :: arg
  !
  ! Parse option /DEVICE
  do iarg=2,sic_narg(2)
    call sic_ke(line,2,iarg,arg,nc,.true.,error)
    if (error) return
    !
    call gt_hardcopy_svg(arg,output,error)
    if (error)  return
  enddo
  !
end subroutine gtl_hardcopy_svg
!
subroutine gt_hardcopy_svg(keyw,output,error)
  use gtv_dependencies_interfaces
  use gtv_interfaces, except_this=>gt_hardcopy_svg
  use gbl_message
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private
  !  Decode the input option specific to the SVG devices.
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: keyw    ! Keyword to decode
  type(gt_display), intent(inout) :: output  ! Instance to customize
  logical,          intent(inout) :: error   ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='HARDCOPY'
  character(len=*), parameter :: cropped = 'CROPPED    '
  integer :: nk
  character(len=24) :: keyword
  !
  if (keyw.eq.' ')  return
  !
  keyword = keyw
  call sic_upper(keyword)
  nk = len_trim(keyword)
  !
  if (keyword(1:nk).eq.cropped(1:nk)) then
    output%svg%cropped = .true.
  else
    call gtv_message(seve%e,rname,  &
      'SVG attribute '''//keyword(1:nk)//''' not recognized')
    error = .true.
    return
  endif
  !
end subroutine gt_hardcopy_svg
!
subroutine gt_hardcopy(output,devtyp,directory,keep,lover,doprint,  &
  queue,error)
  use gtv_dependencies_interfaces
  use gtv_interfaces, except_this=>gt_hardcopy
  use gildas_def
  use gbl_message
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private
  !   Generic interface to the internal hardcopy engine. Can be called
  ! either from command line or from menu.
  !---------------------------------------------------------------------
  type(gt_display),   intent(inout) :: output      ! gt_display instance
  character(len=*),   intent(inout) :: devtyp      ! Device type
  type(gt_directory), intent(in)    :: directory   ! Directory to dump
  logical,            intent(in)    :: keep        ! Keep the file after printing?
  logical,            intent(in)    :: lover       ! Can overwrite existing file?
  logical,            intent(in)    :: doprint     ! Send to the printer immediately?
  character(len=*),   intent(inout) :: queue       ! Which printer?
  logical,            intent(inout) :: error       ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='HARDCOPY'
  character(len=commandline_length) :: command
  integer(kind=4) :: ier
  !
  error = gterrtst()
  if (error) return
  !
  call ghopen(output,devtyp,directory,lover,error)
  error = error.or.gterrtst()
  if (error) return
  if (output%tofile)  call gtv_message(seve%i,rname,trim(output%file)//' created')
  !
  ! Send to printer if requested
  if (doprint) then
    if (queue.eq.' ') then
      ier = sic_getlog('GAG_PRINTER',queue)
      call sic_lower(queue)
    endif
    !
    if (queue.ne.' ') then
#if defined(WIN32)
      command = trim(queue)//' '//output%file
#else
      ! Generic UNIX code
      command = ''
      ier = sic_getlog('GAG_LPR',command)
      command = trim(command)//trim(queue)//' '//output%file
#endif
      call gtv_message(seve%i,rname,'Printing '//trim(output%file)//' on '//queue)
      ier = gag_system(command)
      if (ier.ne.0) then
        call gsys_message(seve%e,rname,'Error printing '//output%file)
        error = .true.
        return
      endif
      !
    else
      ! Well, we should still be able to print, but the option "-P"
      ! should be removed in the logical GAG_LPR...
      call gtv_message(seve%e,rname,'GAG_PRINTER is not defined')
      error = .true.
      ! Do not return: cleaning hereafter
    endif
    !
    if (.not.keep) then
      call gtv_message(seve%i,rname,'Removing '//output%file)
      call gag_filrm(output%file)
    endif
  endif
  !
end subroutine gt_hardcopy
!
subroutine ghopen(output,devtyp,directory,lover,error)
  use gtv_dependencies_interfaces
  use gtv_interfaces, except_this=>ghopen
  use gildas_def
  use gbl_message
  use gtv_buffers
  use gtv_types
  use gtv_graphic
  use gtv_protocol
  !---------------------------------------------------------------------
  ! @ private
  !  Opens a specific Device of given Type, eventually using Options
  ! for setting parameters. Restricted version for hardcopies...
  !
  !  TYPE  The type of Graphics device to be used
  !        PostScript
  !
  !  DEVICE  Optional argument to indicate to which device the plot
  !          must be sent.
  !
  !  OPTION  Optional string to define some modes for specific devices
  !          PostScript Grey, Fast, Color
  !---------------------------------------------------------------------
  type(gt_display),   intent(inout) :: output      ! gt_display instance
  character(len=*)                  :: devtyp      ! Type of device PostScript
  type(gt_directory), intent(in)    :: directory   ! Directory to dump
  logical,            intent(in)    :: lover       ! Allow overwriting existing file
  logical,            intent(inout) :: error       ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='HARDCOPY'
  integer(kind=4) :: ier,dot,px,py
  character(len=filename_length) :: output_file
  character(len=8) :: extension
  type(gt_device), target :: dev
  type(x_coordinates) :: geom
  character(len=32) :: argx,argy
  character(len=message_length) :: mess
  logical :: dopdf,found
  character(len=commandline_length) :: command
  !
  if (.not.awake) then
    call gtv_message(seve%f,rname,'Graphic library not initialized')
    error = .true.
    return
  endif
  if (error_condition) then
    call gtv_message(seve%e,rname,'Library is in error condition')
    error = .true.
    return
  endif
  !
  ! Get new unit
  if (output%tofile) then
    ier = sic_getlun(output%iunit)
    if (ier.ne.1) then
      error = .true.
      return
    endif
  else
    output%iunit = 6  ! STDOUT
  endif
  !
  ! Setup device characteristics
  call gtx_setup(devtyp,dev,error)
  if (error)  goto 99
  !
  if (dev%protocol.ne.p_postscript .and.  &
      dev%protocol.ne.p_svg        .and.  &
      dev%protocol.ne.p_png) then
    call gtv_message(seve%e,rname,'Unsupported hardcopy device')
    error = .true.
    goto 99
  endif
  !
  dev%hardw_cursor = .false.
  call protocol_image_inquire(dev)  ! Colormap capabilities of the device
  !
  dopdf = .false.
  if (output%tofile) then
    ! Translate Logical Name in the file name
    output_file = output%file
    ier = sic_getlog(output%file,output_file)
    extension = '.'//device_list(dev%ident)
    if (dev%protocol.eq.p_postscript) then
      select case (devtyp)
      case ('EPS')
        extension = '.eps'
        dopdf = .false.
      case ('PDF','EPDF')
        extension = '.pdf'
        dopdf = .true.
      case default
        extension = '.ps'
        dopdf = .false.
      end select
      !
    elseif (dev%protocol.eq.p_svg) then
      extension = '.svg'
      !
    elseif (dev%protocol.eq.p_png) then
      extension = '.png'
    endif
    call sic_parse_file(output_file,' ',extension,output%file)
    dot = index(output%file,'.',.true.)
    if (output%file(dot:).ne.extension) then
      mess = 'File extension '''//trim(output%file(dot:))//  &
            ''' does not match its type '//devtyp
      call gtv_message(seve%w,rname,mess)
    endif
    !
    if (gag_inquire(output%file,len_trim(output%file)).eq.0) then
      if (lover) then
        call gag_filrm(output%file)
      else
        call gtv_message(seve%e,rname,  &
          'File '//trim(output%file)//' already exists')
        error = .true.
        goto 99
      endif
    endif
  endif
  !
  ! Define the current working output
  output%dev => dev
  dev%rxy = abs(dev%rxy)
  output%gx1 = 0.
  output%gx2 = directory%phys_size(1)
  output%gy1 = 0.
  output%gy2 = directory%phys_size(2)
  !
  ! If required for this device, open a channel for QIO's output or other
  call gtz_open(output,error)
  if (error)  goto 99
  !
  ! Update the current working directory limits (is this really needed
  ! if we are consistant everywhere else?)
  call gtv_limits(directory,error)
  if (error) then
    call gtv_message(seve%e,rname,'Updating current directory limits')
    return
  endif
  !
  ! Select appropriate protocol
  select case (dev%protocol)
  case (p_postscript)
    output%ps%encapsulated = devtyp.eq.'EPS' .or. devtyp.eq.'EPDF'
    !
    ! Set a PostScript size in pixels. This is dummy, but can be used
    ! in clip_psimage (scalx,scaly) to resample correctly images.
    output%px1 = 0
    output%px2 = nint(directory%phys_size(1)/2.54d0*72.d0)
    output%py1 = nint(directory%phys_size(2)/2.54d0*72.d0)
    output%py2 = 0
    if (dopdf) then
      output_file = output%file
      call sic_parse_file('tmp','gag_scratch:','.ps',output%file)
      ! Remove the temporary file for safety, if any (it can be absent)
      call gag_delete(output%file)
    endif
    call ps_open(output,directory,error)
    if (error) then
      call gtv_message(seve%e,rname,'Postscript open error')
      error = .true.
      goto 99
    endif
    dev%linit1 = 0
    dev%linit2 = 0
    !
  case (p_svg)
    if (output%px2.le.0 .or. output%py1.le.0) then
      ! Try to use user's logical SVG_GEOMETRY
      call sic_getlog_coordinates('SVG_GEOMETRY',argx,argy,error)
      if (error)  return
      geom%x = 0.
      geom%unitx = 'p'
      geom%y = 0.
      geom%unity = 'p'
      call decode_coordinates(geom,argx,argy,error)
      if (error)  return
      call compute_coordinates_geometry(rname,geom,px,py,error)
      if (error)  return
      ! Size is numbered from 0 to N-1
      output%px1 = 0
      output%px2 = px-1
      output%py1 = py-1  ! Y scale increases from top to bottom in SVG
      output%py2 = 0
    endif
    if (output%px2.le.0 .or. output%py1.le.0) then
      ! Fall back to device defaults
      output%px1 = output%dev%px1
      output%px2 = output%dev%px2
      output%py1 = output%dev%py1
      output%py2 = output%dev%py2
    endif
    call svg_open(output,error,directory)
    if (error) then
      call gtv_message(seve%e,rname,'SVG open error')
      error = .true.
      goto 99
    endif
    dev%linit1 = 0
    dev%linit2 = 0
    !
  case (p_png)
    if (output%px2.le.0 .or. output%py2.le.0) then
      ! Try to use user's logical PNG_GEOMETRY
      call sic_getlog_coordinates('PNG_GEOMETRY',argx,argy,error)
      if (error)  return
      geom%x = 0.
      geom%unitx = 'p'
      geom%y = 0.
      geom%unity = 'p'
      call decode_coordinates(geom,argx,argy,error)
      if (error)  return
      call compute_coordinates_geometry(rname,geom,px,py,error)
      if (error)  return
      output%px1 = 1
      output%px2 = px
      output%py1 = 1
      output%py2 = py
    endif
    if (output%px2.le.0 .or. output%py2.le.0) then
      ! Fall back to device defaults
      output%px1 = output%dev%px1
      output%px2 = output%dev%px2
      output%py1 = output%dev%py1
      output%py2 = output%dev%py2
    endif
    call png_open(output,error,directory)
    if (error) then
      call gtv_message(seve%e,rname,'PNG open error')
      error = .true.
      goto 99
    endif
    dev%linit1 = 0
    dev%linit2 = 0
    !
  end select
  !
  ! Write initialisation sequence
  if (dev%linit1.gt.0) call cwrite(output,dev%init1,dev%linit1)
  !
  ! Rewind the plot from 'directory' in the output instance:
  call gtview_rewind(output,directory)
  ! And close the output device
  call ghclos(output)
  !
  if (dopdf) then
    if (devtyp.eq.'EPDF') then
      found = gag_which('epstopdf','$PATH',command)
      if (.not.found) then
        call gtv_message(seve%e,rname,'epstopdf not found in your $PATH')
        error = .true.
        return
      endif
      command = trim(command)//' '//trim(output%file)//' --outfile='//output_file
    else
      found = gag_which('ps2pdf','$PATH',command)
      if (.not.found) then
        call gtv_message(seve%e,rname,'ps2pdf not found in your $PATH')
        error = .true.
        return
      endif
      command = trim(command)//' '//trim(output%file)//' '//output_file
    endif
    ier = gag_system(command)
    if (ier.ne.0) then
      call gsys_message(seve%e,rname,'Error converting '//trim(output%file)//' to PDF')
      call gsys_message(seve%e,rname,'Command was: '//command)
      error = .true.
      return
    endif
    call gag_filrm(output%file)  ! Remove the temporary .ps file
    output%file = output_file
  endif
  !
99 continue  ! Jump here in case of error
  call gtz_close(output)
  if (output%tofile)  call sic_frelun(output%iunit)
  call gt_output_reset(output)
  !
end subroutine ghopen
!
subroutine ghclos(output)
  use gtv_dependencies_interfaces
  use gtv_interfaces, except_this=>ghclos
  use gtv_types
  use gtv_graphic
  use gtv_protocol
  !---------------------------------------------------------------------
  ! @ private
  !   Switches back to alpha mode, and empties the buffer.
  !   GHCLOS also resets flags VECFIL and LL601.
  !
  !   AWAKE flag is not reset by GTCLOS, as GTINIT is required only once
  ! even for multiple GTOPEN calls IUNIT is closed AND libered.
  !---------------------------------------------------------------------
  type(gt_display), intent(inout) :: output  ! Output instance
  !
  if (.not.awake .or. error_condition) return
  !
  select case (output%dev%protocol)
  case(p_postscript)
    call ps_close
  case(p_svg)
    call svg_close
  case(p_png)
    call png_close(output)
  case default
    if (output%dev%linit2.gt.0)  &
      call cwrite(output,output%dev%init2,output%dev%linit2)
  end select
  !
end subroutine ghclos
!
function rgb_to_grey(r,g,b)
  !---------------------------------------------------------------------
  ! @ private
  ! Convert the 3 RGB intensities into a grey luminance
  ! Method choosen in the one implemented in the GIMP:
  !  see http://gimp-savvy.com/BOOK/index.html?node54.html
  ! ---
  !   This function transforms a 24-bit, three-channel, color image to
  ! an 8-bit, single-channel greyscale image by forming a weighted sum
  ! of the red, green, and blue components. The formula used in the GIMP
  ! is Y = 0.3R + 0.59G + 0.11B; this result is known as luminance (see
  ! [4] or [5]). The weights used to compute luminance are related to
  ! the monitor's phosphors. The explanation for these weights is due to
  ! the fact that for equal amounts of color the eye is most sensitive
  ! to green, then red, and then blue. This means that for equal amounts
  ! of green and blue light the green will, nevertheless, seem much
  ! brighter. Thus, the image obtained by the normal averaging of an
  ! image's three color components produces a greyscale brightness that
  ! is not perceptually equivalent to the brightness of the original
  ! color image. The weighted sum that defines Y, however, does.
  !---------------------------------------------------------------------
  real(kind=4) :: rgb_to_grey  ! Function value on return
  real(kind=4), intent(in) :: r  ! R intensity
  real(kind=4), intent(in) :: g  ! G intensity
  real(kind=4), intent(in) :: b  ! B intensity
  !
  ! Direct
  ! rgb_to_grey = (r+g+b)/3.
  !
  ! Natural
  rgb_to_grey = 0.3*r + 0.59*g + 0.11*b
  !
  ! Desaturate
  ! rgb_to_grey = (max(r,g,b)+min(r,g,b))/2.
  !
end function rgb_to_grey
!
subroutine gt_hardcopy_crop(output,dir,error)
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private
  ! Crop the area viewed by the output instance
  !---------------------------------------------------------------------
  type(gt_display),   intent(inout) :: output  ! Output instance
  type(gt_directory), intent(in)    :: dir     ! The directory to display
  logical,            intent(inout) :: error   ! Logical error flag
  ! Local
  integer(kind=4) :: px,py
  real(kind=4) :: pngratio,phyratio
  !
  output%gx1 = dir%gen%minmax(1)
  output%gx2 = dir%gen%minmax(2)
  output%gy1 = dir%gen%minmax(3)
  output%gy2 = dir%gen%minmax(4)
  !
  ! Rescale the device size
  px = abs(output%px2-output%px1)+1
  py = abs(output%py2-output%py1)+1
  !
  pngratio = real(py)/real(px)
  phyratio = (output%gy2-output%gy1)/(output%gx2-output%gx1)
  !
  if (phyratio.gt.pngratio) then
    ! The plot is more vertically elongated than the PNG. Shrink
    ! the PNG width
    if (output%px1.lt.output%px2) then
      output%px2 = output%px1+floor(py/phyratio)
    else
      output%px1 = output%px2+floor(py/phyratio)
    endif
  else
    ! The plot is more horizontally elongated than the PNG. Shrink
    ! the PNG height
    if (output%py1.lt.output%py2) then
      output%py2 = output%py1+floor(px*phyratio)
    else
      output%py1 = output%py2+floor(px*phyratio)
    endif
  endif
  !
end subroutine gt_hardcopy_crop
