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
28 changes: 19 additions & 9 deletions packages/pdfx/android/src/main/kotlin/io/scer/pdfx/Messages.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.Matrix
import android.graphics.Rect
import android.graphics.pdf.LoadParams
import android.graphics.pdf.PdfRenderer
import android.os.Build
import android.os.ParcelFileDescriptor
import android.os.ext.SdkExtensions
import android.util.Log
import android.util.SparseArray
import android.view.Surface
Expand Down Expand Up @@ -45,7 +47,7 @@ class Messages(private val binding : FlutterPlugin.FlutterPluginBinding,
) {
val resultResponse = Pigeon.OpenReply()
try {
val documentRenderer = openDataDocument(message.data!!)
val documentRenderer = openDataDocument(message.data!!, message.password)
val document = documents.register(documentRenderer)
resultResponse.id = document.id
resultResponse.pagesCount = document.pagesCount.toLong()
Expand All @@ -66,7 +68,7 @@ class Messages(private val binding : FlutterPlugin.FlutterPluginBinding,
val resultResponse = Pigeon.OpenReply()
try {
val path = message.path
val documentRenderer = openFileDocument(File(path!!))
val documentRenderer = openFileDocument(File(path!!), message.password)
val document = documents.register(documentRenderer)
resultResponse.id = document.id
resultResponse.pagesCount = document.pagesCount.toLong()
Expand All @@ -91,7 +93,7 @@ class Messages(private val binding : FlutterPlugin.FlutterPluginBinding,
val resultResponse = Pigeon.OpenReply()
try {
val path = message.path
val documentRenderer = openAssetDocument(path!!)
val documentRenderer = openAssetDocument(path!!, message.password)
val document = documents.register(documentRenderer)
resultResponse.id = document.id
resultResponse.pagesCount = document.pagesCount.toLong()
Expand Down Expand Up @@ -356,16 +358,16 @@ class Messages(private val binding : FlutterPlugin.FlutterPluginBinding,
surfaceProducers.remove(id)
}

private fun openDataDocument(data: ByteArray): Pair<ParcelFileDescriptor, PdfRenderer> {
private fun openDataDocument(data: ByteArray, password: String?): Pair<ParcelFileDescriptor, PdfRenderer> {
val tempDataFile = File(binding.applicationContext.cacheDir, "$randomFilename.pdf")
if (!tempDataFile.exists()) {
tempDataFile.writeBytes(data)
}
Log.d("pdf_renderer", "OpenDataDocument. Created file: " + tempDataFile.path)
return openFileDocument(tempDataFile)
return openFileDocument(tempDataFile, password)
}

private fun openAssetDocument(assetPath: String): Pair<ParcelFileDescriptor, PdfRenderer> {
private fun openAssetDocument(assetPath: String, password: String?): Pair<ParcelFileDescriptor, PdfRenderer> {
val fullAssetPath = binding.flutterAssets.getAssetFilePathByName(assetPath)
val tempAssetFile = File(binding.applicationContext.cacheDir, "$randomFilename.pdf")
if (!tempAssetFile.exists()) {
Expand All @@ -374,14 +376,22 @@ class Messages(private val binding : FlutterPlugin.FlutterPluginBinding,
inputStream.close()
}
Log.d("pdf_renderer", "OpenAssetDocument. Created file: " + tempAssetFile.path)
return openFileDocument(tempAssetFile)
return openFileDocument(tempAssetFile, password)
}

private fun openFileDocument(file: File): Pair<ParcelFileDescriptor, PdfRenderer> {
private fun openFileDocument(file: File, password: String?): Pair<ParcelFileDescriptor, PdfRenderer> {
Log.d("pdf_renderer", "OpenFileDocument. File: " + file.path)
val fileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY)
return if (fileDescriptor != null) {
val pdfRenderer = PdfRenderer(fileDescriptor)
val pdfRenderer = if (password != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && SdkExtensions.getExtensionVersion(Build.VERSION_CODES.S) >= 13) {
PdfRenderer(fileDescriptor, LoadParams.Builder().setPassword(password).build())
} else {
throw CreateRendererException()
}
} else {
PdfRenderer(fileDescriptor)
}
Pair(fileDescriptor, pdfRenderer)
} else throw CreateRendererException()
}
Expand Down
8 changes: 7 additions & 1 deletion packages/pdfx/example/ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
PODS:
- Flutter (1.0.0)
- integration_test (0.0.1):
- Flutter
- pdfx (1.0.0):
- Flutter

DEPENDENCIES:
- Flutter (from `Flutter`)
- integration_test (from `.symlinks/plugins/integration_test/ios`)
- pdfx (from `.symlinks/plugins/pdfx/ios`)

EXTERNAL SOURCES:
Flutter:
:path: Flutter
integration_test:
:path: ".symlinks/plugins/integration_test/ios"
pdfx:
:path: ".symlinks/plugins/pdfx/ios"

SPEC CHECKSUMS:
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
pdfx: 77f4dddc48361fbb01486fa2bdee4532cbb97ef3

PODFILE CHECKSUM: 4305caec6b40dde0ae97be1573c53de1882a07e5

COCOAPODS: 1.16.2
COCOAPODS: 1.14.2
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
Expand Down Expand Up @@ -72,6 +73,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
Expand Down
68 changes: 40 additions & 28 deletions packages/pdfx/example/lib/pinch.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:flutter/material.dart';
import 'package:internet_file/internet_file.dart';
import 'package:pdfx/pdfx.dart';
import 'package:universal_platform/universal_platform.dart';

class PinchPage extends StatefulWidget {
const PinchPage({Key? key}) : super(key: key);
Expand All @@ -10,11 +9,9 @@ class PinchPage extends StatefulWidget {
State<PinchPage> createState() => _PinchPageState();
}

enum DocShown { sample, tutorial, hello, password }

class _PinchPageState extends State<PinchPage> {
static const int _initialPage = 1;
DocShown _showing = DocShown.sample;
String _title = 'Sample PDF';
late PdfControllerPinch _pdfControllerPinch;

@override
Expand Down Expand Up @@ -42,7 +39,7 @@ class _PinchPageState extends State<PinchPage> {
return Scaffold(
backgroundColor: Colors.grey,
appBar: AppBar(
title: const Text('Pdfx example'),
title: Text(_title),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.navigate_before),
Expand Down Expand Up @@ -72,34 +69,49 @@ class _PinchPageState extends State<PinchPage> {
);
},
),
IconButton(
icon: const Icon(Icons.refresh),
onPressed: () {
switch (_showing) {
case DocShown.sample:
case DocShown.tutorial:
_pdfControllerPinch.loadDocument(
PdfDocument.openAsset('assets/flutter_tutorial.pdf'));
_showing = DocShown.hello;
PopupMenuButton<String>(
icon: const Icon(Icons.file_open),
onSelected: (String asset) {
String title;
switch (asset) {
case 'assets/hello.pdf':
title = 'Hello PDF';
break;
case DocShown.hello:
_pdfControllerPinch
.loadDocument(PdfDocument.openAsset('assets/hello.pdf'));
_showing = UniversalPlatform.isWeb
? DocShown.password
: DocShown.tutorial;
case 'assets/flutter_tutorial.pdf':
title = 'Flutter Tutorial';
break;

case DocShown.password:
_pdfControllerPinch.loadDocument(PdfDocument.openAsset(
'assets/password.pdf',
password: 'MyPassword',
));
_showing = DocShown.tutorial;
case 'assets/password.pdf':
title = 'Password Protected PDF';
break;
default:
title = 'Pdfx example';
}
setState(() {
_title = title;
});
String? password;
if (asset == 'assets/password.pdf') {
password = 'MyPassword';
}
_pdfControllerPinch.loadDocument(
PdfDocument.openAsset(asset, password: password),
);
},
)
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
const PopupMenuItem<String>(
value: 'assets/hello.pdf',
child: Text('Hello PDF'),
),
const PopupMenuItem<String>(
value: 'assets/flutter_tutorial.pdf',
child: Text('Flutter Tutorial'),
),
const PopupMenuItem<String>(
value: 'assets/password.pdf',
child: Text('Password Protected'),
),
],
),
],
),
body: PdfViewPinch(
Expand Down
44 changes: 29 additions & 15 deletions packages/pdfx/ios/Classes/SwiftPdfxPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class SwiftPdfxPlugin: NSObject, FlutterPlugin, PdfxApi {
message: "Arguments not sended",
details: nil))
}
guard let renderer = openDataDocument(data: data.data) else {
guard let renderer = openDataDocument(data: data.data, password: message.password) else {
return completion(nil, FlutterError(code: "RENDER_ERROR",
message: "Invalid PDF format",
details: nil))
Expand All @@ -56,7 +56,7 @@ public class SwiftPdfxPlugin: NSObject, FlutterPlugin, PdfxApi {
message: "Arguments not sended",
details: nil))
}
guard let renderer = openFileDocument(pdfFilePath: pdfFilePath) else {
guard let renderer = openFileDocument(pdfFilePath: pdfFilePath, password: message.password) else {
return completion(nil, FlutterError(code: "RENDER_ERROR",
message: "Invalid PDF format",
details: nil))
Expand All @@ -76,7 +76,7 @@ public class SwiftPdfxPlugin: NSObject, FlutterPlugin, PdfxApi {
message: "Arguments not sended",
details: nil))
}
guard let renderer = openAssetDocument(name: name) else {
guard let renderer = openAssetDocument(name: name, password: message.password) else {
return completion(nil, FlutterError(code: "RENDER_ERROR",
message: "Invalid PDF format",
details: nil))
Expand Down Expand Up @@ -259,24 +259,38 @@ public class SwiftPdfxPlugin: NSObject, FlutterPlugin, PdfxApi {

}

func openDataDocument(data: Data) -> CGPDFDocument? {
func openDataDocument(data: Data, password: String?) -> CGPDFDocument? {
guard let datProv = CGDataProvider(data: data as CFData) else { return nil }
let docment = CGPDFDocument(datProv)
if docment?.isUnlocked == false {
return nil
guard let document = CGPDFDocument(datProv) else { return nil }

if document.isEncrypted {
if let password = password {
document.unlockWithPassword(password)
}
if !document.isUnlocked {
return nil
}
}
return docment

return document
}

func openFileDocument(pdfFilePath: String) -> CGPDFDocument? {
let docment = CGPDFDocument(URL(fileURLWithPath: pdfFilePath) as CFURL)
if docment?.isEncrypted == true {
return nil
func openFileDocument(pdfFilePath: String, password: String?) -> CGPDFDocument? {
guard let document = CGPDFDocument(URL(fileURLWithPath: pdfFilePath) as CFURL) else { return nil }

if document.isEncrypted {
if let password = password {
document.unlockWithPassword(password)
}
if !document.isUnlocked {
return nil
}
}
return docment

return document
}

func openAssetDocument(name: String) -> CGPDFDocument? {
func openAssetDocument(name: String, password: String?) -> CGPDFDocument? {
#if os(iOS)
guard let path = Bundle.main.path(forResource: "Frameworks/App.framework/flutter_assets/" + name, ofType: "") else {
return nil
Expand All @@ -285,7 +299,7 @@ public class SwiftPdfxPlugin: NSObject, FlutterPlugin, PdfxApi {
let path = Bundle.main.bundlePath + "/Contents/Frameworks/App.framework/Resources/flutter_assets/" + name;
#endif

return openFileDocument(pdfFilePath: path)
return openFileDocument(pdfFilePath: path, password: password)
}
}

Expand Down
3 changes: 0 additions & 3 deletions packages/pdfx/lib/src/renderer/interfaces/document.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,18 @@ abstract class PdfDocument {
/// Opening the specified file.
/// For Web, [filePath] can be relative path from `index.html` or any
/// arbitrary URL but it may be restricted by CORS.
/// `password supported only for web!`
static Future<PdfDocument> openFile(String filePath, {String? password}) {
assertHasPdfSupport();
return PdfxPlatform.instance.openFile(filePath, password: password);
}

/// Opening the specified asset.
/// `password supported only for web!`
static Future<PdfDocument> openAsset(String name, {String? password}) {
assertHasPdfSupport();
return PdfxPlatform.instance.openAsset(name, password: password);
}

/// Opening the PDF on memory.
/// `password supported only for web!`
static Future<PdfDocument> openData(FutureOr<Uint8List> data,
{String? password}) {
assertHasPdfSupport();
Expand Down
15 changes: 12 additions & 3 deletions packages/pdfx/lib/src/renderer/io/platform_method_channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ class PdfxPlatformMethodChannel extends PdfxPlatform {
return _open(
(await _channel.invokeMethod<Map<dynamic, dynamic>>(
'open.document.file',
filePath,
{
'path': filePath,
'password': password,
},
))!,
'file:$filePath',
);
Expand All @@ -45,7 +48,10 @@ class PdfxPlatformMethodChannel extends PdfxPlatform {
Future<PdfDocument> openAsset(String name, {String? password}) async => _open(
(await _channel.invokeMethod<Map<dynamic, dynamic>>(
'open.document.asset',
name,
{
'name': name,
'password': password,
},
))!,
'asset:$name',
);
Expand All @@ -57,7 +63,10 @@ class PdfxPlatformMethodChannel extends PdfxPlatform {
_open(
(await _channel.invokeMethod<Map<dynamic, dynamic>>(
'open.document.data',
await data,
{
'data': await data,
'password': password,
},
))!,
'memory:binary',
);
Expand Down
Loading