Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions backend/app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
82 changes: 82 additions & 0 deletions backend/blueprints/pdf_to_pptx.py
Original file line number Diff line number Diff line change
@@ -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()
2 changes: 2 additions & 0 deletions backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 2 additions & 0 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand Down Expand Up @@ -87,6 +88,7 @@ function App() {
<Route path="/pdf-to-text" element={<PdfToText />} />
<Route path="/pdf-info" element={<PdfInfo />} />
<Route path="/pdf-page-number" element={<PdfPageNumber />} />
<Route path="/pdf-to-powerpoint" element={<PdfPptx />} />

<Route path="/image-blur" element={<BlurImage />} />
<Route path="/image-to-webp" element={<ImageWbp />} />
Expand Down
14 changes: 13 additions & 1 deletion frontend/src/data/toolsData.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
Type,
BookOpen,
Hash,
Presentation,
} from "lucide-react";

const tools = [
Expand Down Expand Up @@ -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: <Presentation />,
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",
},

];

Expand Down
44 changes: 44 additions & 0 deletions frontend/src/pages/PdfPptx.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<ToolPageTemplate
title="PDF to PowerPoint"
description="Convert PDF documents into editable PowerPoint (.pptx) presentations."
accept=".pdf"
validateFile={validateFile}
apiEndpoint="/convertPptx"
fileFieldName="file"
getDownloadFilename={getDownloadFilename}
submitButtonText="Convert to PowerPoint"
loadingButtonText="Converting…"
maxWidthClass="max-w-[700px]"
inputId="pdf-pptx-input"
defaultIcon={<FileText className="w-16 h-16" />}
defaultText="Choose PDF file or drag & drop here"
supportText="Each PDF page becomes a separate slide."
/>
);
}

export default PdfPptx;
Loading