using this code
import tkinter as tk
from tkinter import messagebox
from fpdf import FPDF

class PDFCanvas(tk.Canvas):
    def __init__(self, master=None):
        super().__init__(master, bg="white")
        self.text_data = []
        self.scale_factor = 1.0
        self.dragging = None

        self.bind("<ButtonPress-1>", self.on_click)
        self.bind("<B1-Motion>", self.on_drag)
        self.bind("<ButtonRelease-1>", self.on_release)

    def add_text(self, text):
        safe_text = text.encode('utf-8', 'ignore').decode('utf-8', 'ignore')
        if not safe_text.strip():
            messagebox.showwarning("Input Error", "Please enter some valid text.")
            return

        x, y = 50, 50 + len(self.text_data) * 20
        text_id = self.create_text(x, y, text=safe_text, fill="black", anchor="nw", tags="text")
        self.text_data.append((text_id, x, y, safe_text))

    def on_click(self, event):
        for text_id, x, y, text in self.text_data:
            bbox = self.bbox(text_id)
            if bbox[0] <= event.x <= bbox[2] and bbox[1] <= event.y <= bbox[3]:
                self.dragging = text_id
                self.start_x = event.x
                self.start_y = event.y
                break

    def on_drag(self, event):
        if self.dragging:
            dx = event.x - self.start_x
            dy = event.y - self.start_y
            text_id = self.dragging
            self.move(text_id, dx, dy)
            self.start_x = event.x
            self.start_y = event.y

    def on_release(self, event):
        if self.dragging:
            for index, (text_id, x, y, text) in enumerate(self.text_data):
                if text_id == self.dragging:
                    self.text_data[index] = (text_id, event.x, event.y, text)
                    break
            self.dragging = None

    def set_canvas_size(self, width, height):
        self.config(width=width, height=height)

    def zoom(self, scale):
        self.scale_factor *= scale
        self.delete("text")
        for text_id, x, y, text in self.text_data:
            new_x = x * self.scale_factor
            new_y = y * self.scale_factor
            self.create_text(new_x, new_y, text=text, fill="black", anchor="nw", tags="text")

    def export_to_pdf(self, filename, pdf_width, pdf_height):
        pdf = FPDF()
        pdf.add_page(format=(pdf_width, pdf_height))
        pdf.set_font("Arial", size=12)

        for text_id, x, y, text in self.text_data:
            pdf.text(x / self.scale_factor, y / self.scale_factor, text)

        pdf.output(filename)
        messagebox.showinfo("Success", f"PDF saved as {filename}")


class WYSIWYGApp:
    def __init__(self, root):
        self.root = root
        self.root.title("WYSIWYG Designer for FPDF")

        root.geometry("800x600")  # Fixed window size

        menubar = tk.Menu(root)
        root.config(menu=menubar)

        file_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="File", menu=file_menu)

        paper_sizes = {
            "A4": (210, 297),
            "A5": (148, 210),
            "Letter": (216, 279),
            "Legal": (216, 356),
        }

        paper_menu = tk.Menu(menubar, tearoff=0)
        for size_name, (width, height) in paper_sizes.items():
            paper_menu.add_command(
                label=size_name,
                command=lambda w=width, h=height: self.set_paper_size(w, h)
            )
        menubar.add_cascade(label="Paper Size", menu=paper_menu)

        self.zoom_percent = 100
        zoom_menu = tk.Menu(menubar, tearoff=0)
        zoom_menu.add_command(label="Zoom In", command=lambda: self.zoom(1.2))
        zoom_menu.add_command(label="Zoom Out", command=lambda: self.zoom(0.8))
        self.zoom_label = tk.StringVar(value=f"Zoom: {self.zoom_percent}%")
        zoom_display = tk.Label(zoom_menu, textvariable=self.zoom_label)
        zoom_display.pack()
        menubar.add_cascade(label="Zoom", menu=zoom_menu)


        self.canvas_frame = tk.Frame(root)
        self.canvas_frame.pack(pady=(10,0))

        self.canvas = PDFCanvas(master=self.canvas_frame)
        self.canvas.pack()

        self.set_paper_size(210, 297)  # Initial A4 size

        self.entry = tk.Entry(root, width=50)
        self.entry.pack()

        self.add_button = tk.Button(root, text="Add Text", command=self.add_text)
        self.add_button.pack()

        self.export_button = tk.Button(root, text="Export to PDF", command=self.export_pdf)
        self.export_button.pack()

    def set_paper_size(self, width_mm, height_mm):
        dpi = 96
        width_px = width_mm / 25.4 * dpi
        height_px = height_mm / 25.4 * dpi

        self.canvas_frame.config(width=width_px, height=height_px)
        self.canvas.set_canvas_size(width_px, height_px)
        self.pdf_width = width_mm
        self.pdf_height = height_mm

    def zoom(self, scale):
        current_width = self.canvas_frame.winfo_width()
        current_height = self.canvas_frame.winfo_height()

        new_width = int(current_width * scale)
        new_height = int(current_height * scale)

        self.canvas_frame.config(width=new_width, height=new_height)
        self.canvas.config(width=new_width, height=new_height)
        self.canvas.scale_factor *= scale

        self.canvas.delete("text")
        for text_id, x, y, text in self.canvas.text_data:
            new_x = x * self.canvas.scale_factor
            new_y = y * self.canvas.scale_factor
            self.canvas.create_text(new_x, new_y, text=text, fill="black", anchor="nw", tags="text")


        self.zoom_percent *= scale
        self.zoom_percent = round(self.zoom_percent)
        self.zoom_label.set(f"Zoom: {self.zoom_percent}%")

    def add_text(self):
        text = self.entry.get()
        if text:
            self.canvas.add_text(text)
            self.entry.delete(0, tk.END)
        else:
            messagebox.showwarning("Input Error", "Please enter some text.")

    def export_pdf(self):
        filename = "output.pdf"
        self.canvas.export_to_pdf(filename, self.pdf_width, self.pdf_height)


if __name__ == "__main__":
    root = tk.Tk()
    app = WYSIWYGApp(root)
    root.mainloop()

add on the right hand side a panel which will allow properties of any text selected that has been placed on the pdf