diff --git a/backend/app/__init__.py b/backend/app/__init__.py
index 2325631..d3a95ae 100644
--- a/backend/app/__init__.py
+++ b/backend/app/__init__.py
@@ -65,6 +65,7 @@ def _health():
from blueprints.compress_pdf import compress_pdf_bp
from blueprints.protect_pdf import protect_pdf_bp
from blueprints.unlock_pdf import unlock_pdf_bp
+ from blueprints.pdf_to_pptx import pdf_pptx_bp
app.register_blueprint(pdf_bp)
app.register_blueprint(pdf_docx_bp)
@@ -82,5 +83,6 @@ def _health():
app.register_blueprint(compress_pdf_bp)
app.register_blueprint(protect_pdf_bp)
app.register_blueprint(unlock_pdf_bp)
+ app.register_blueprint(pdf_pptx_bp)
return app
diff --git a/backend/blueprints/pdf_to_pptx.py b/backend/blueprints/pdf_to_pptx.py
new file mode 100644
index 0000000..b5be183
--- /dev/null
+++ b/backend/blueprints/pdf_to_pptx.py
@@ -0,0 +1,82 @@
+import traceback
+from io import BytesIO
+
+import fitz
+from pptx import Presentation
+from pptx.util import Emu
+
+from flask import Blueprint, request, send_file
+
+from utils.helpers import error, safe_gc_collect
+from utils.validators import validate_uploaded_file, validate_pdf_file
+
+pdf_pptx_bp = Blueprint("pdf_pptx", __name__)
+
+
+@pdf_pptx_bp.route("/convertPptx", methods=["POST"])
+def convert_pdf_to_pptx():
+ doc = None
+ output = None
+ try:
+ pdf_file, filename, upload_error = validate_uploaded_file(request, "file")
+ if upload_error:
+ return upload_error
+
+ pdf_error = validate_pdf_file(pdf_file, filename)
+ if pdf_error:
+ return pdf_error
+
+ pdf_bytes = pdf_file.read()
+ doc = fitz.open(stream=pdf_bytes, filetype="pdf")
+
+ if len(doc) == 0:
+ return error("PDF file has no pages", 400)
+
+ prs = Presentation()
+ prs.slide_width = Emu(int(doc[0].rect.width * 12700))
+ prs.slide_height = Emu(int(doc[0].rect.height * 12700))
+
+ layout_index = min(6, len(prs.slide_layouts) - 1)
+ blank_layout = prs.slide_layouts[layout_index]
+
+ for page_num in range(len(doc)):
+ page = doc.load_page(page_num)
+ mat = fitz.Matrix(200 / 72, 200 / 72)
+ pix = page.get_pixmap(matrix=mat, alpha=False)
+
+ img_bytes = BytesIO(pix.tobytes(output="png"))
+ slide = prs.slides.add_slide(blank_layout)
+ slide.shapes.add_picture(
+ img_bytes,
+ 0, 0,
+ prs.slide_width,
+ prs.slide_height,
+ )
+ img_bytes.close()
+ pix = None
+
+ output = BytesIO()
+ prs.save(output)
+ output.seek(0)
+
+ base = filename.rsplit(".", 1)[0]
+ download_name = f"{base}.pptx"
+
+ return send_file(
+ output,
+ mimetype="application/vnd.openxmlformats-officedocument.presentationml.presentation",
+ as_attachment=True,
+ download_name=download_name,
+ )
+
+ except Exception as e:
+ traceback.print_exc()
+ return error(str(e), 500)
+
+ finally:
+ if doc:
+ try:
+ doc.close()
+ except Exception:
+ pass
+ safe_gc_collect()
diff --git a/backend/requirements.txt b/backend/requirements.txt
index 2a3546e..1562743 100644
--- a/backend/requirements.txt
+++ b/backend/requirements.txt
@@ -67,3 +67,5 @@ tzdata==2025.2
urllib3==2.5.0
Werkzeug==3.1.3
markdown2>=1.0.0
+pdf2docx>=0.5.8
+python-pptx>=1.0.2
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index aa3c3ab..94d527d 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -41,6 +41,7 @@ const PdfCompress = lazy(() => import("./pages/PdfCompress"));
const PdfUnlock = lazy(() => import("./pages/PdfUnlock"));
const PdfMetadata = lazy(() => import("./pages/PdfMetadata"));
const PdfToText = lazy(() => import("./pages/PdfToText"));
+const PdfPptx = lazy(() => import("./pages/PdfPptx"));
const PdfInfo = lazy(() => import("./pages/PdfInfo"));
const PdfPageNumber = lazy(() => import("./pages/PdfPageNumber"));
const CsvToJson = lazy(() => import("./pages/CsvtoJson"));
@@ -87,6 +88,7 @@ function App() {
} />
} />
} />
+ } />
} />
} />
diff --git a/frontend/src/data/toolsData.jsx b/frontend/src/data/toolsData.jsx
index d3e8166..6aead9a 100644
--- a/frontend/src/data/toolsData.jsx
+++ b/frontend/src/data/toolsData.jsx
@@ -23,6 +23,7 @@ import {
Type,
BookOpen,
Hash,
+ Presentation,
} from "lucide-react";
const tools = [
@@ -381,7 +382,18 @@ const tools = [
path: "/csv-to-json",
gradient: "from-emerald-500/10 to-blue-500/10",
iconGradient: "from-emerald-500 to-blue-500",
- }
+ },
+ {
+ id: "pdf-to-powerpoint",
+ name: "PDF to PowerPoint",
+ category: "Conversion Tools",
+ icon: ,
+ description:
+ "Convert PDF documents into editable PowerPoint (.pptx) presentations.",
+ path: "/pdf-to-powerpoint",
+ gradient: "from-red-500/10 to-orange-500/10",
+ iconGradient: "from-red-500 to-orange-500",
+ },
];
diff --git a/frontend/src/pages/PdfPptx.jsx b/frontend/src/pages/PdfPptx.jsx
new file mode 100644
index 0000000..4ce1fba
--- /dev/null
+++ b/frontend/src/pages/PdfPptx.jsx
@@ -0,0 +1,44 @@
+import { useCallback } from "react";
+import ToolPageTemplate from "../components/ToolPageTemplate";
+import { FileText } from "lucide-react";
+
+function PdfPptx() {
+ const validateFile = useCallback((selectedFile) => {
+ if (selectedFile && selectedFile.type === "application/pdf") {
+ return {
+ isValid: true,
+ message: `File "${selectedFile.name}" selected (${(
+ selectedFile.size / 1024
+ ).toFixed(1)} KB)`,
+ };
+ }
+ return {
+ isValid: false,
+ message: "Please select a valid PDF file.",
+ };
+ }, []);
+
+ const getDownloadFilename = (fileName) =>
+ fileName.replace(/\.pdf$/i, ".pptx");
+
+ return (
+ }
+ defaultText="Choose PDF file or drag & drop here"
+ supportText="Each PDF page becomes a separate slide."
+ />
+ );
+}
+
+export default PdfPptx;