fortplot_pdf_text_render.f90 Source File


Source Code

module fortplot_pdf_text_render
    !! High level PDF text drawing routines

    use iso_fortran_env, only: wp => real64
    use fortplot_pdf_core, only: pdf_context_core, PDF_FONT_SIZE, &
        PDF_LABEL_SIZE, PDF_TITLE_SIZE
    use fortplot_pdf_text_escape, only: escape_pdf_string
    use fortplot_pdf_text_segments, only: process_text_segments, &
        process_rotated_text_segments, render_mixed_font_at_position
    implicit none
    private

    public :: draw_pdf_text
    public :: draw_mixed_font_text
    public :: draw_rotated_mixed_font_text
    public :: draw_pdf_text_direct
    public :: draw_pdf_text_bold

contains

    subroutine draw_pdf_text(this, x, y, text)
        class(pdf_context_core), intent(inout) :: this
        real(wp), intent(in) :: x, y
        character(len=*), intent(in) :: text
        character(len=:), allocatable :: escaped_text
        character(len=1024) :: text_cmd
        integer :: escaped_len

        allocate(character(len=len(text) * 6) :: escaped_text)
        call escape_pdf_string(text, escaped_text, escaped_len)

        this%stream_data = this%stream_data // 'BT' // new_line('a')

        write(text_cmd, '("/F", I0, 1X, F0.1, " Tf")') &
            this%fonts%get_helvetica_obj(), PDF_FONT_SIZE
        this%stream_data = this%stream_data // trim(adjustl(text_cmd)) // new_line('a')

        write(text_cmd, '("1 0 0 1 ", F0.3, 1X, F0.3, " Tm")') &
            x, y
        this%stream_data = this%stream_data // trim(adjustl(text_cmd)) // new_line('a')

        this%stream_data = this%stream_data // '(' // escaped_text(1:escaped_len) // &
            ') Tj' // new_line('a')

        this%stream_data = this%stream_data // 'ET' // new_line('a')
    end subroutine draw_pdf_text

    subroutine draw_mixed_font_text(this, x, y, text, font_size)
        class(pdf_context_core), intent(inout) :: this
        real(wp), intent(in) :: x, y
        character(len=*), intent(in) :: text
        real(wp), intent(in), optional :: font_size
        character(len=1024) :: text_cmd
        logical :: in_symbol_font
        real(wp) :: fs

        in_symbol_font = .false.
        fs = PDF_LABEL_SIZE
        if (present(font_size)) fs = font_size

        this%stream_data = this%stream_data // 'BT' // new_line('a')

        write(text_cmd, '("/F", I0, 1X, F0.1, " Tf")') &
            this%fonts%get_helvetica_obj(), fs
        this%stream_data = this%stream_data // trim(adjustl(text_cmd)) // new_line('a')

        write(text_cmd, '("1 0 0 1 ", F0.3, 1X, F0.3, " Tm")') &
            x, y
        this%stream_data = this%stream_data // trim(adjustl(text_cmd)) // new_line('a')

        call process_text_segments(this, text, in_symbol_font, fs)

        this%stream_data = this%stream_data // 'ET' // new_line('a')
    end subroutine draw_mixed_font_text

    subroutine draw_rotated_mixed_font_text(this, x, y, text, font_size)
        class(pdf_context_core), intent(inout) :: this
        real(wp), intent(in) :: x, y
        character(len=*), intent(in) :: text
        real(wp), intent(in), optional :: font_size
        character(len=1024) :: font_cmd
        real(wp) :: fs

        fs = PDF_LABEL_SIZE
        if (present(font_size)) fs = font_size

        this%stream_data = this%stream_data // 'BT' // new_line('a')

        write(font_cmd, '("/F", I0, 1X, F0.1, " Tf")') &
            this%fonts%get_helvetica_obj(), fs
        this%stream_data = this%stream_data // trim(adjustl(font_cmd)) // new_line('a')

        call setup_rotated_text_matrix(this, x, y)

        call process_rotated_text_segments(this, text, fs)

        this%stream_data = this%stream_data // 'ET' // new_line('a')
    end subroutine draw_rotated_mixed_font_text

    subroutine draw_pdf_text_direct(this, x, y, text)
        class(pdf_context_core), intent(inout) :: this
        real(wp), intent(in) :: x, y
        character(len=*), intent(in) :: text
        character(len=1024) :: text_cmd

        this%stream_data = this%stream_data // 'BT' // new_line('a')

        write(text_cmd, '("/F", I0, 1X, F0.1, " Tf")') &
            this%fonts%get_helvetica_obj(), PDF_FONT_SIZE
        this%stream_data = this%stream_data // trim(adjustl(text_cmd)) // new_line('a')

        write(text_cmd, '("1 0 0 1 ", F0.3, 1X, F0.3, " Tm")') &
            x, y
        this%stream_data = this%stream_data // trim(adjustl(text_cmd)) // new_line('a')
        this%stream_data = this%stream_data // '(' // text // ') Tj' // new_line('a')

        this%stream_data = this%stream_data // 'ET' // new_line('a')
    end subroutine draw_pdf_text_direct

    subroutine draw_pdf_text_bold(this, x, y, text)
        class(pdf_context_core), intent(inout) :: this
        real(wp), intent(in) :: x, y
        character(len=*), intent(in) :: text
        character(len=1024) :: text_cmd
        character(len=:), allocatable :: escaped_text
        integer :: escaped_len

        this%stream_data = this%stream_data // 'BT' // new_line('a')
        this%stream_data = this%stream_data // '2 Tr' // new_line('a')
        this%stream_data = this%stream_data // '0.3 w' // new_line('a')

        write(text_cmd, '("/F", I0, 1X, F0.1, " Tf")') &
            this%fonts%get_helvetica_obj(), PDF_TITLE_SIZE
        this%stream_data = this%stream_data // trim(adjustl(text_cmd)) // new_line('a')

        allocate(character(len=len(text) * 6) :: escaped_text)
        call escape_pdf_string(text, escaped_text, escaped_len)

        write(text_cmd, '("1 0 0 1 ", F0.3, 1X, F0.3, " Tm")') &
            x, y
        this%stream_data = this%stream_data // trim(adjustl(text_cmd)) // &
            new_line('a')
        this%stream_data = this%stream_data // '(' // &
            escaped_text(1:escaped_len) // ') Tj' // new_line('a')

        this%stream_data = this%stream_data // '0 Tr' // new_line('a')
        this%stream_data = this%stream_data // 'ET' // new_line('a')
    end subroutine draw_pdf_text_bold

    subroutine setup_rotated_text_matrix(this, x, y)
        class(pdf_context_core), intent(inout) :: this
        real(wp), intent(in) :: x, y
        character(len=256) :: matrix_cmd

        write(matrix_cmd, '("0 1 -1 0 ", F0.3, 1X, F0.3, " Tm")') &
            x, y
        this%stream_data = this%stream_data // trim(adjustl(matrix_cmd)) // &
            new_line('a')
    end subroutine setup_rotated_text_matrix

end module fortplot_pdf_text_render