Flutter PDF渲染插件pdfium_bindings的使用
Flutter PDF渲染插件pdfium_bindings的使用
pdfium_bindings
本项目旨在通过FFI(Foreign Function Interface)在dart中完全封装Pdfium API。
低级示例
import 'dart:ffi';
import 'dart:io';
import 'package:ffi/ffi.dart';
import 'package:image/image.dart';
import 'package:path/path.dart' as path;
import 'package:pdfium_bindings/pdfium_bindings.dart';
void main() {
final stopwatch = Stopwatch()..start();
final libraryPath = path.join(Directory.current.path, 'pdfium.dll');
final dylib = DynamicLibrary.open(libraryPath);
final pdfium = PDFiumBindings(dylib);
const allocate = calloc;
final config = allocate<FPDF_LIBRARY_CONFIG>();
config.ref.version = 2;
config.ref.m_pUserFontPaths = nullptr;
config.ref.m_pIsolate = nullptr;
config.ref.m_v8EmbedderSlot = 0;
pdfium.FPDF_InitLibraryWithConfig(config);
final filePathP = stringToNativeInt8('1417.pdf');
final doc = pdfium.FPDF_LoadDocument(filePathP, nullptr);
if (doc == nullptr) {
final err = pdfium.FPDF_GetLastError();
throw PdfiumException.fromErrorCode(err);
}
final pageCount = pdfium.FPDF_GetPageCount(doc);
print('pageCount: $pageCount');
final page = pdfium.FPDF_LoadPage(doc, 0);
if (page == nullptr) {
final err = pdfium.getLastErrorMessage();
pdfium.FPDF_CloseDocument(doc);
throw PageException(message: err);
}
const scale = 1;
final width = (pdfium.FPDF_GetPageWidth(page) * scale).round();
final height = (pdfium.FPDF_GetPageHeight(page) * scale).round();
print('page Width: $width');
print('page Height: $height');
// var backgroundStr = "FFFFFFFF"; // as int 268435455
const background = 268435455;
const startX = 0;
final sizeX = width;
const startY = 0;
final sizeY = height;
const rotate = 0;
// 创建一个空位图并将页面渲染到该位图上
// 位图始终使用每像素4字节。第一个字节总是双字对齐。
// 字节顺序为BGRx(如果无alpha通道,则最后一个字节未使用)或BGRA。
// 标志:FPDF_ANNOT | FPDF_LCD_TEXT
final bitmap = pdfium.FPDFBitmap_Create(width, height, 0);
pdfium.FPDFBitmap_FillRect(bitmap, 0, 0, width, height, background);
pdfium.FPDF_RenderPageBitmap(
bitmap, page, startX, startY, sizeX, sizeY, rotate, 0,);
// 位图缓冲区的第一个字节指针,数据以BGRA格式存储
final pointer = pdfium.FPDFBitmap_GetBuffer(bitmap);
// stride = 宽度 * 每像素4字节 BGRA
// var stride = pdfium.FPDFBitmap_GetStride(bitmap);
// print('stride $stride');
final Image image = Image.fromBytes(
width: width,
height: height,
bytes: pointer.asTypedList(width * height * 4).buffer,
order: ChannelOrder.bgra,
numChannels: 4,
);
// 将位图保存为PNG文件
File('out.png').writeAsBytesSync(encodePng(image));
// 清理
pdfium.FPDFBitmap_Destroy(bitmap);
pdfium.FPDF_ClosePage(page);
allocate.free(filePathP);
pdfium.FPDF_DestroyLibrary();
allocate.free(config);
print('end: ${stopwatch.elapsed}');
}
高级示例
示例 1
import 'package:pdfium_bindings/pdfium_bindings.dart';
void main() {
PdfiumWrap()
.loadDocumentFromPath('1417.pdf')
.loadPage(0)
.savePageAsPng('out.png')
.closePage()
.closeDocument()
.dispose();
}
示例 2
import 'package:http/http.dart' as http;
import 'package:pdfium_bindings/pdfium_bindings.dart';
void main() async {
final pdfium = PdfiumWrap();
final resp = await http.get(
Uri.parse(
'https://www.riodasostras.rj.gov.br/wp-content/uploads/2022/03/1426.pdf',
),
);
final bytes = resp.bodyBytes;
pdfium
.loadDocumentFromBytes(bytes)
.loadPage(0)
.savePageAsJpg('out.jpg', qualityJpg: 80)
.closePage()
.closeDocument()
.dispose();
}
更多关于Flutter PDF渲染插件pdfium_bindings的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter PDF渲染插件pdfium_bindings的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter中使用pdfium_bindings
插件来渲染PDF文件的示例代码。pdfium_bindings
是一个较底层的PDF渲染库,它允许你在Flutter应用中直接操作PDF文档。请注意,pdfium_bindings
需要一些原生代码的集成,因此在使用之前,请确保你已经熟悉如何在Flutter项目中添加和配置原生依赖。
首先,你需要在pubspec.yaml
文件中添加pdfium_bindings
依赖:
dependencies:
flutter:
sdk: flutter
pdfium_bindings: ^x.y.z # 请替换为最新版本号
然后,执行flutter pub get
来获取依赖。
接下来,你需要在iOS和Android平台上进行一些配置。
iOS配置
- 打开
ios/Runner/Info.plist
,并添加以下权限请求(如果需要从文件系统中加载PDF):
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>UIFileSharingEnabled</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
- 确保在
ios/Podfile
中启用了Swift支持(如果尚未启用):
platform :ios, '10.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try running flutter pub get in your flutter project."
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings['SWIFT_VERSION'] = '5.0' # 或者更高版本
end
end
end
Android配置
通常,pdfium_bindings
在Android上的配置较为简单,因为它主要依赖于CMake或ndk-build来构建原生库。你可能需要在android/app/build.gradle
中确保NDK支持已启用:
android {
...
defaultConfig {
...
externalNativeBuild {
cmake {
cppFlags "-std=c++17"
}
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
...
}
并创建一个简单的CMakeLists.txt
文件(如果尚未存在):
cmake_minimum_required(VERSION 3.4.1)
add_library(pdfium SHARED IMPORTED)
set_target_properties(pdfium PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/path/to/libpdfium.so)
find_library(log-lib log)
target_link_libraries(your_target_name pdfium ${log-lib})
请注意,这里的path/to/libpdfium.so
需要替换为实际的PDFium库路径。
Flutter代码示例
下面是一个简单的Flutter代码示例,展示如何使用pdfium_bindings
来渲染PDF页面:
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:pdfium_bindings/pdfium_bindings.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
PdfiumController? _pdfiumController;
Uint8List? _pdfData;
@override
void initState() {
super.initState();
// 这里加载你的PDF文件数据,例如从资产文件或网络加载
_loadPdf();
}
Future<void> _loadPdf() async {
// 示例:从资产文件加载PDF数据
ByteData data = await rootBundle.load('assets/sample.pdf');
_pdfData = data.buffer.asUint8List();
// 初始化PdfiumController
_pdfiumController = PdfiumController(
document: PdfiumDocument.fromData(_pdfData!),
password: '', // 如果PDF有密码,则在这里提供
);
// 渲染第一页
_pdfiumController!.jumpToPage(1);
// 设置页面大小(可选)
_pdfiumController!.setPageSize(Size(double.infinity, double.infinity));
// 监听页面渲染完成事件
_pdfiumController!.pageFinished.listen((pageIndex) {
print('Page $pageIndex finished rendering.');
});
setState(() {});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('PDFium Demo'),
),
body: _pdfiumController != null
? PdfiumView(
controller: _pdfiumController!,
)
: Center(
child: CircularProgressIndicator(),
),
),
);
}
@override
void dispose() {
_pdfiumController?.dispose();
super.dispose();
}
}
请注意,上述代码是一个简化的示例,实际应用中你可能需要处理更多的错误情况,并根据需要调整页面渲染和交互逻辑。此外,pdfium_bindings
库的API可能会随着版本更新而发生变化,因此请参考最新的官方文档和示例代码。