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
39 changes: 39 additions & 0 deletions Core/Core/Common/Extensions/PDFKit/PDFDocumentExtensions.swift
Original file line number Diff line number Diff line change
@@ -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 <https://www.gnu.org/licenses/>.
//

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
}
}
3 changes: 3 additions & 0 deletions Core/Core/Features/Files/Model/Entities/UTI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import Combine
import UIKit
import MobileCoreServices
import VisionKit
import PDFKit
import UniformTypeIdentifiers

public enum FilePickerSource: Int, CaseIterable {
Expand Down Expand Up @@ -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..<scan.pageCount {

let usePdf = utis.contains(where: { $0.isPdf }) && !utis.contains(where: { $0.isImage })

if usePdf {
let pdfDocument = PDFDocument()

let pages = (0 ..< scan.pageCount).compactMap { PDFPage(image: scan.imageOfPage(at: $0)) }
pages.forEach { pdfDocument.insert($0, at: pdfDocument.pageCount) }

do {
let image = scan.imageOfPage(at: i)
add(try image.write())
add(try pdfDocument.write())
} catch {
showError(error)
}
} else {
for i in 0..<scan.pageCount {
do {
let image = scan.imageOfPage(at: i)
add(try image.write())
} catch {
showError(error)
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ extension SubmissionButtonPresenter: FilePickerControllerDelegate {
if assignment.allowedExtensions.isEmpty == true || allowedUTIs.contains(where: { $0.isImage || $0.isVideo }) {
filePicker.sources.append(contentsOf: [.library, .camera])
if !isMediaRecording { filePicker.sources.append(.documentScan) }
} else if allowedUTIs.contains(where: { $0.isPdf }) {
filePicker.sources.append(.documentScan)
}
if isMediaRecording { filePicker.sources.append(.audio) }
filePicker.utis = allowedUTIs
Expand Down