Skip to content

Commit 8823e13

Browse files
authored
fix: center PNG title over plot area (fixes #999)
- CI: All checks green post-rebase (Linux tests, coverage, Windows)\n- Local: make test-ci and make test passed\n- Review: small, focused change; adds compute_title_position and a raster title centering test; no backward-incompatible changes
2 parents fc70135 + 2b1ce82 commit 8823e13

File tree

2 files changed

+67
-12
lines changed

2 files changed

+67
-12
lines changed

src/backends/raster/fortplot_raster_axes.f90

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ module fortplot_raster_axes
1414

1515
private
1616
public :: raster_draw_axes_and_labels, raster_render_ylabel
17+
public :: compute_title_position
1718

1819
contains
1920

@@ -277,22 +278,33 @@ subroutine render_title_centered(raster, width, height, plot_area, title_text)
277278
character(len=500) :: processed_text, escaped_text
278279
integer :: processed_len
279280

280-
! Process LaTeX commands and Unicode
281-
call process_latex_in_text(title_text, processed_text, processed_len)
282-
call escape_unicode_for_raster(processed_text(1:processed_len), escaped_text)
283-
284-
! Calculate title position centered over plot area
285-
! X position: center of plot area horizontally
286-
title_px = real(plot_area%left + plot_area%width / 2, wp)
287-
288-
! Y position: above plot area (like matplotlib)
289-
! Place title approximately 30 pixels above the plot area
290-
title_py = real(plot_area%bottom - TITLE_VERTICAL_OFFSET, wp)
281+
! Compute title position (centered like matplotlib)
282+
call compute_title_position(plot_area, title_text, processed_text, processed_len, escaped_text, title_px, title_py)
291283

292284
! Get current color and render title directly in pixel coordinates
293285
call raster%get_color_bytes(r, g, b)
294286
call render_text_to_image(raster%image_data, width, height, &
295287
int(title_px), int(title_py), trim(escaped_text), r, g, b)
296288
end subroutine render_title_centered
297289

298-
end module fortplot_raster_axes
290+
subroutine compute_title_position(plot_area, title_text, processed_text, processed_len, escaped_text, title_px, title_py)
291+
!! Compute centered title position and return processed/escaped text
292+
!! Exposed for reuse and testing; keeps render routine small and focused
293+
type(plot_area_t), intent(in) :: plot_area
294+
character(len=*), intent(in) :: title_text
295+
character(len=*), intent(out) :: processed_text
296+
integer, intent(out) :: processed_len
297+
character(len=*), intent(out) :: escaped_text
298+
real(wp), intent(out) :: title_px, title_py
299+
300+
integer :: text_width
301+
302+
call process_latex_in_text(title_text, processed_text, processed_len)
303+
call escape_unicode_for_raster(processed_text(1:processed_len), escaped_text)
304+
305+
text_width = calculate_text_width(trim(escaped_text))
306+
title_px = real(plot_area%left + plot_area%width / 2 - text_width / 2, wp)
307+
title_py = real(plot_area%bottom - TITLE_VERTICAL_OFFSET, wp)
308+
end subroutine compute_title_position
309+
310+
end module fortplot_raster_axes
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
program test_title_centering_raster
2+
!! Verifies raster title centering over plot area
3+
use fortplot_layout, only: plot_margins_t, plot_area_t, calculate_plot_area
4+
use fortplot_constants, only: TITLE_VERTICAL_OFFSET
5+
use fortplot_text, only: calculate_text_width
6+
use fortplot_raster_axes, only: compute_title_position
7+
use, intrinsic :: iso_fortran_env, only: wp => real64
8+
implicit none
9+
10+
type(plot_margins_t) :: margins
11+
type(plot_area_t) :: plot_area
12+
integer, parameter :: CANVAS_WIDTH = 640
13+
integer, parameter :: CANVAS_HEIGHT = 480
14+
15+
character(len=*), parameter :: title_text = 'Simple Sine Wave'
16+
character(len=500) :: processed_text, escaped_text
17+
integer :: processed_len
18+
real(wp) :: title_px_r, title_py_r
19+
integer :: expected_px, expected_py, measured_width
20+
21+
margins = plot_margins_t()
22+
call calculate_plot_area(CANVAS_WIDTH, CANVAS_HEIGHT, margins, plot_area)
23+
24+
call compute_title_position(plot_area, title_text, processed_text, processed_len, &
25+
escaped_text, title_px_r, title_py_r)
26+
27+
measured_width = calculate_text_width(trim(escaped_text))
28+
expected_px = plot_area%left + plot_area%width/2 - measured_width/2
29+
expected_py = plot_area%bottom - TITLE_VERTICAL_OFFSET
30+
31+
if (int(title_px_r) /= expected_px) then
32+
print *, 'FAIL: Title X not centered; got ', int(title_px_r), ' expected ', expected_px
33+
stop 1
34+
end if
35+
36+
if (int(title_py_r) /= expected_py) then
37+
print *, 'FAIL: Title Y offset incorrect; got ', int(title_py_r), ' expected ', expected_py
38+
stop 1
39+
end if
40+
41+
print *, 'PASS: Title centering matches expected pixel position'
42+
end program test_title_centering_raster
43+

0 commit comments

Comments
 (0)