diff --git a/Core/Core/Common/Extensions/PDFKit/PDFDocumentExtensions.swift b/Core/Core/Common/Extensions/PDFKit/PDFDocumentExtensions.swift
new file mode 100644
index 0000000000..e436203782
--- /dev/null
+++ b/Core/Core/Common/Extensions/PDFKit/PDFDocumentExtensions.swift
@@ -0,0 +1,39 @@
+//
+// This file is part of Canvas.
+// Copyright (C) 2025-present  Instructure, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see .
+//
+
+import PDFKit
+
+extension PDFDocument {
+
+    @discardableResult
+    public func write(to url: URL? = nil, name: String? = nil) throws -> URL {
+        let directory = url ?? URL.Directories.temporary.appendingPathComponent("Documents", isDirectory: true)
+        let name = name ?? String(Clock.now.timeIntervalSince1970)
+        try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true, attributes: nil)
+        var url = directory.appendingPathComponent(name, isDirectory: false)
+        url = url.pathExtension != "pdf" ? url.appendingPathExtension("pdf") : url
+        guard let data = dataRepresentation() else {
+            throw NSError.instructureError(String(localized: "Failed to save pdf", bundle: .core))
+        }
+        if FileManager.default.fileExists(atPath: url.path) {
+            try FileManager.default.removeItem(at: url)
+        }
+        try data.write(to: url)
+        return url
+    }
+}
diff --git a/Core/Core/Features/Files/Model/Entities/UTI.swift b/Core/Core/Features/Files/Model/Entities/UTI.swift
index 9c1856441f..628700608b 100644
--- a/Core/Core/Features/Files/Model/Entities/UTI.swift
+++ b/Core/Core/Features/Files/Model/Entities/UTI.swift
@@ -131,6 +131,9 @@ public struct UTI: Equatable, Hashable {
     public var isImage: Bool {
         return uttype?.conforms(to: .image) ?? false
     }
+    public var isPdf: Bool {
+        return uttype?.conforms(to: .pdf) ?? false
+    }
 
     public var isAudio: Bool {
         return uttype?.conforms(to: .audio) ?? false
diff --git a/Core/Core/Features/Files/View/FilePicker/FilePickerViewController.swift b/Core/Core/Features/Files/View/FilePicker/FilePickerViewController.swift
index 728acd2f7a..f6ee83eafc 100644
--- a/Core/Core/Features/Files/View/FilePicker/FilePickerViewController.swift
+++ b/Core/Core/Features/Files/View/FilePicker/FilePickerViewController.swift
@@ -20,6 +20,7 @@ import Combine
 import UIKit
 import MobileCoreServices
 import VisionKit
+import PDFKit
 import UniformTypeIdentifiers
 
 public enum FilePickerSource: Int, CaseIterable {
@@ -377,13 +378,29 @@ extension FilePickerViewController: UITableViewDelegate, UITableViewDataSource {
 extension FilePickerViewController: VNDocumentCameraViewControllerDelegate {
     public func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) {
         controller.dismiss(animated: true)
-        for i in 0..