Коммит fb981781 создал по автору Красавин Никита Сергеевич's avatar Красавин Никита Сергеевич
Просмотр файлов

Merge branch 'move-to-flutter-3.24' into 'master'

[feature] Move to flutter 3.24.0

See merge request oss/flutter/flutter-community-plugins/pdfrx!2
владельцы e87898c2 3f78d8b7
# pdfrx
[Pdfrx](https://pub.dartlang.org/packages/pdfrx) plugin with Aurora support.
The plugin supports Aurora, Android, iOS, Windows, macOS, Linux.
Web support will be added after the release of flutter-aurora 3.24.
The plugin supports Aurora, Android, iOS, Windows, macOS, Linux, Web.
## Interactive Demo
......@@ -82,9 +81,8 @@ It supports all the features of `pdfrx-1.0.82` and includes support for Aurora p
dependencies:
pdfrx:
git:
url: https://gitlab.com/omprussia/flutter/flutter-plugins.git
ref: pdfrx-1.0.82
path: packages/pdfrx_aurora
url: https://os-git.omprussia.ru/oss/flutter/flutter-community-plugins/pdfrx.git
ref: pdfrx-1.0.82-aurora
```
***.spec**
......
// ignore_for_file: avoid_web_libraries_in_flutter
@JS()
library pdf.js;
import 'dart:js_interop';
import 'dart:js_interop_unsafe';
import 'dart:typed_data';
import 'package:synchronized/extension.dart';
import 'package:web/web.dart' as web;
import '../../pdfrx.dart';
/// Default pdf.js version
const _pdfjsVersion = '4.4.168';
/// Default pdf.js URL
const _pdfjsUrl = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/$_pdfjsVersion/pdf.min.mjs';
/// Default pdf.worker.js URL
const _pdfjsWorkerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/$_pdfjsVersion/pdf.worker.min.mjs';
/// Default CMap URL
const _pdfjsCMapUrl = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/$_pdfjsVersion/cmaps/';
bool get _isPdfjsLoaded => globalContext['pdfjsLib'] != null;
@JS('pdfjsLib.getDocument')
external _PDFDocumentLoadingTask _pdfjsGetDocument(_PdfjsDocumentInitParameters data);
extension type _PdfjsDocumentInitParameters._(JSObject _) implements JSObject {
external _PdfjsDocumentInitParameters({
String? url,
JSArrayBuffer? data,
JSAny? httpHeaders,
bool? withCredentials,
String? password,
String? cMapUrl,
bool? cMapPacked,
bool? useSystemFonts,
String? standardFontDataUrl,
});
external String? get url;
external JSArrayBuffer? get data;
external JSAny? get httpHeaders;
external bool? get withCredentials;
external String? get password;
external String? get cMapUrl;
external bool? get cMapPacked;
external bool? get useSystemFonts;
external String? get standardFontDataUrl;
}
@JS('pdfjsLib.GlobalWorkerOptions.workerSrc')
external set _pdfjsWorkerSrc(String src);
extension type _PDFDocumentLoadingTask(JSObject _) implements JSObject {
external JSPromise<PdfjsDocument> get promise;
}
Future<PdfjsDocument> pdfjsGetDocument(
String url, {
String? password,
Map<String, String>? headers,
bool withCredentials = false,
}) =>
_pdfjsGetDocument(
_PdfjsDocumentInitParameters(
url: url,
password: password,
httpHeaders: headers?.jsify(),
withCredentials: withCredentials,
cMapUrl: PdfJsConfiguration.configuration?.cMapUrl ?? _pdfjsCMapUrl,
cMapPacked: PdfJsConfiguration.configuration?.cMapPacked ?? true,
useSystemFonts: PdfJsConfiguration.configuration?.useSystemFonts,
standardFontDataUrl: PdfJsConfiguration.configuration?.standardFontDataUrl,
),
).promise.toDart;
Future<PdfjsDocument> pdfjsGetDocumentFromData(ByteBuffer data, {String? password}) => _pdfjsGetDocument(
_PdfjsDocumentInitParameters(
data: data.toJS,
password: password,
cMapUrl: PdfJsConfiguration.configuration?.cMapUrl,
cMapPacked: PdfJsConfiguration.configuration?.cMapPacked,
useSystemFonts: PdfJsConfiguration.configuration?.useSystemFonts,
standardFontDataUrl: PdfJsConfiguration.configuration?.standardFontDataUrl,
),
).promise.toDart;
extension type PdfjsDocument._(JSObject _) implements JSObject {
external JSPromise<PdfjsPage> getPage(int pageNumber);
external JSPromise<JSArray<JSNumber>?> getPermissions();
external int get numPages;
external void destroy();
external JSPromise<JSNumber> getPageIndex(PdfjsRef ref);
external JSPromise<JSObject> getDestination(String id);
external JSPromise<JSArray<PdfjsOutlineNode>?> getOutline();
}
extension type PdfjsPage._(JSObject _) implements JSObject {
external PdfjsViewport getViewport(PdfjsViewportParams params);
external PdfjsRender render(PdfjsRenderContext params);
external int get pageNumber;
external int get rotate;
external JSNumber get userUnit;
external JSArray<JSNumber> get view;
external JSPromise<PdfjsTextContent> getTextContent(PdfjsGetTextContentParameters params);
external ReadableStream streamTextContent(PdfjsGetTextContentParameters params);
external JSPromise<JSArray<PdfjsAnnotation>> getAnnotations(PdfjsGetAnnotationsParameters params);
}
extension type PdfjsAnnotation._(JSObject _) implements JSObject {
external String get subtype;
external int get annotationType;
external JSArray<JSNumber> get rect;
external String? get url;
external String? get unsafeUrl;
external int get annotationFlags;
external JSAny? get dest;
}
extension type PdfjsViewportParams._(JSObject _) implements JSObject {
external PdfjsViewportParams({
double scale,
int rotation, // 0, 90, 180, 270
double offsetX,
double offsetY,
bool dontFlip,
});
external double get scale;
external set scale(double scale);
external int get rotation;
external set rotation(int rotation);
external double get offsetX;
external set offsetX(double offsetX);
external double get offsetY;
external set offsetY(double offsetY);
external bool get dontFlip;
external set dontFlip(bool dontFlip);
}
extension type PdfjsViewport(JSObject _) implements JSObject {
external JSArray<JSNumber> get viewBox;
external set viewBox(JSArray<JSNumber> viewBox);
external double get scale;
external set scale(double scale);
/// 0, 90, 180, 270
external int get rotation;
external set rotation(int rotation);
external double get offsetX;
external set offsetX(double offsetX);
external double get offsetY;
external set offsetY(double offsetY);
external bool get dontFlip;
external set dontFlip(bool dontFlip);
external double get width;
external set width(double w);
external double get height;
external set height(double h);
external JSArray<JSNumber>? get transform;
external set transform(JSArray<JSNumber>? m);
}
extension type PdfjsRenderContext._(JSObject _) implements JSObject {
external PdfjsRenderContext({
required web.CanvasRenderingContext2D canvasContext,
required PdfjsViewport viewport,
String intent,
int annotationMode,
bool renderInteractiveForms,
JSArray<JSNumber>? transform,
JSObject imageLayer,
JSObject canvasFactory,
JSObject background,
});
external web.CanvasRenderingContext2D get canvasContext;
external set canvasContext(web.CanvasRenderingContext2D ctx);
external PdfjsViewport get viewport;
external set viewport(PdfjsViewport viewport);
/// `display` or `print`
external String get intent;
external set intent(String intent);
/// DISABLE=0, ENABLE=1, ENABLE_FORMS=2, ENABLE_STORAGE=3
external int get annotationMode;
external set annotationMode(int annotationMode);
external bool get renderInteractiveForms;
external set renderInteractiveForms(bool renderInteractiveForms);
external JSArray<JSNumber>? get transform;
external set transform(JSArray<JSNumber>? transform);
external JSObject get imageLayer;
external set imageLayer(JSObject imageLayer);
external JSObject get canvasFactory;
external set canvasFactory(JSObject canvasFactory);
external JSObject get background;
external set background(JSObject background);
}
extension type PdfjsRender._(JSObject _) implements JSObject {
external JSPromise get promise;
}
extension type PdfjsGetTextContentParameters._(JSObject _) implements JSObject {
external PdfjsGetTextContentParameters({
bool includeMarkedContent,
bool disableNormalization,
});
external bool includeMarkedContent;
external bool disableNormalization;
}
extension type PdfjsTextContent._(JSObject _) implements JSObject {
/// Either [PdfjsTextItem] or [PdfjsTextMarkedContent]
external JSArray<PdfjsTextItem> get items;
external JSObject get styles;
}
extension type PdfjsTextItem._(JSObject _) implements JSObject {
external String get str;
/// Text direction: `ttb`, `ltr` or `rtl`.
external String get dir;
/// Matrix for transformation, in the form [a b c d e f], equivalent to:
/// ```
/// | a b 0 |
/// | c d 0 |
/// | e f 1 |
/// ```
///
/// Translation is performed with `[1 0 0 1 tx ty]`.
/// Scaling is performed with `[sx 0 0 sy 0 0]`.
/// See PDF Reference 1.7, 4.2.2 Common Transformations for more.
external JSArray<JSNumber> get transform;
external num get width;
external num get height;
external String get fontName;
external bool get hasEOL;
}
extension type PdfjsTextMarkedContent._(JSObject _) implements JSObject {
external String get type;
external String get id;
}
extension type PdfjsTextStyle._(JSObject _) implements JSObject {
external num get ascent;
external num get descent;
external bool get vertical;
external String get fontFamily;
}
extension type PdfjsBaseException._(JSObject _) implements JSObject {
external String get message;
external String get name;
}
extension type PdfjsPasswordException._(JSObject _) implements JSObject {
external String get message;
external String get name;
external String get code;
}
extension type PdfjsGetAnnotationsParameters._(JSObject _) implements JSObject {
external PdfjsGetAnnotationsParameters({String intent});
/// `display` or `print` or, `any`
external String get intent;
}
extension type PdfjsRef._(JSObject _) implements JSObject {
external int get num;
external int get gen;
}
extension type PdfjsAnnotationData._(JSObject _) implements JSObject {
external String get subtype;
external int get annotationType;
external JSArray<JSNumber> get rect;
external String? get url;
external String? get unsafeUrl;
external int get annotationFlags;
external JSObject? get dest;
}
extension type PdfjsOutlineNode._(JSObject _) implements JSObject {
external String get title;
external JSAny? get dest;
external JSArray<PdfjsOutlineNode> get items;
}
Object _dummyJsSyncContext = {};
bool _pdfjsInitialized = false;
Future<void> ensurePdfjsInitialized() async {
if (_pdfjsInitialized) return;
await _dummyJsSyncContext.synchronized(() async {
await _pdfjsInitialize();
});
}
Future<void> _pdfjsInitialize() async {
if (_pdfjsInitialized) return;
if (_isPdfjsLoaded) {
_pdfjsInitialized = true;
return;
}
final pdfJsSrc = PdfJsConfiguration.configuration?.pdfJsSrc ?? _pdfjsUrl;
try {
final script = web.document.createElement('script') as web.HTMLScriptElement
..type = 'text/javascript'
..charset = 'utf-8'
..async = true
..type = 'module'
..src = pdfJsSrc;
web.document.querySelector('head')!.appendChild(script);
await script.onLoad.first
.timeout(PdfJsConfiguration.configuration?.pdfJsDownloadTimeout ?? const Duration(seconds: 10));
} catch (e) {
throw StateError('Failed to load pdf.js from $pdfJsSrc: $e');
}
if (!_isPdfjsLoaded) {
throw StateError('Failed to load pdfjs');
}
_pdfjsWorkerSrc = PdfJsConfiguration.configuration?.workerSrc ?? _pdfjsWorkerSrc;
_pdfjsInitialized = true;
}
extension type ReadableStream._(JSObject _) implements JSObject {
external JSPromise cancel();
external ReadableStreamDefaultReader getReader(JSObject options);
}
extension type ReadableStreamDefaultReader._(JSObject _) implements JSObject {
external JSPromise<JSObject> cancel(JSObject reason);
external JSPromise<ReadableStreamChunk> read();
external void releaseLock();
}
extension type ReadableStreamChunk._(JSObject _) implements JSObject {
external JSObject get value;
external bool get done;
}
//FIXME: uncomment web on flutter 3.24
/// Configuration for the PDF.js library.
///
/// Set [PdfJsConfiguration.configuration] before using any APIs. It can be typically set in the main function.
......
// ignore_for_file: public_member_api_docs, sort_constructors_first
// ignore_for_file: avoid_web_libraries_in_flutter
import 'dart:async';
import 'dart:js_interop';
import 'dart:ui';
import 'package:flutter/services.dart';
import 'package:synchronized/extension.dart';
import 'package:web/web.dart' as web;
import '../../pdfrx.dart';
import 'pdf.js.dart';
class PdfDocumentFactoryImpl extends PdfDocumentFactory {
@override
Future<PdfDocument> openAsset(
String name, {
PdfPasswordProvider? passwordProvider,
bool firstAttemptByEmptyPassword = true,
}) =>
_openByFunc(
(password) async {
// NOTE: Moving the asset load outside the loop may cause:
// Uncaught TypeError: Cannot perform Construct on a detached ArrayBuffer
final bytes = await rootBundle.load(name);
return await pdfjsGetDocumentFromData(bytes.buffer, password: password);
},
sourceName: 'asset:$name',
passwordProvider: passwordProvider,
firstAttemptByEmptyPassword: firstAttemptByEmptyPassword,
);
@override
Future<PdfDocument> openCustom({
required FutureOr<int> Function(Uint8List buffer, int position, int size) read,
required int fileSize,
required String sourceName,
PdfPasswordProvider? passwordProvider,
bool firstAttemptByEmptyPassword = true,
int? maxSizeToCacheOnMemory,
void Function()? onDispose,
}) async {
final buffer = Uint8List(fileSize);
await read(buffer, 0, fileSize);
return _openByFunc(
(password) => pdfjsGetDocumentFromData(
buffer.buffer,
password: password,
),
sourceName: sourceName,
passwordProvider: passwordProvider,
firstAttemptByEmptyPassword: firstAttemptByEmptyPassword,
onDispose: onDispose,
);
}
@override
Future<PdfDocument> openData(
Uint8List data, {
PdfPasswordProvider? passwordProvider,
bool firstAttemptByEmptyPassword = true,
String? sourceName,
void Function()? onDispose,
}) async {
return _openByFunc(
(password) => pdfjsGetDocumentFromData(
data.buffer,
password: password,
),
sourceName: sourceName ?? 'memory-${data.hashCode}',
passwordProvider: passwordProvider,
firstAttemptByEmptyPassword: firstAttemptByEmptyPassword,
onDispose: onDispose,
);
}
@override
Future<PdfDocument> openFile(
String filePath, {
PdfPasswordProvider? passwordProvider,
bool firstAttemptByEmptyPassword = true,
}) =>
_openByFunc(
(password) => pdfjsGetDocument(
filePath,
password: password,
),
sourceName: filePath,
passwordProvider: passwordProvider,
firstAttemptByEmptyPassword: firstAttemptByEmptyPassword,
);
@override
Future<PdfDocument> openUri(
Uri uri, {
PdfPasswordProvider? passwordProvider,
bool firstAttemptByEmptyPassword = true,
PdfDownloadProgressCallback? progressCallback,
PdfDownloadReportCallback? reportCallback,
bool preferRangeAccess = false,
Map<String, String>? headers,
bool withCredentials = false,
}) =>
_openByFunc(
(password) => pdfjsGetDocument(
uri.toString(),
password: password,
headers: headers,
withCredentials: withCredentials,
),
sourceName: uri.toString(),
passwordProvider: passwordProvider,
firstAttemptByEmptyPassword: firstAttemptByEmptyPassword,
);
Future<PdfDocument> _openByFunc(
Future<PdfjsDocument> Function(String? password) openDocument, {
required String sourceName,
PdfPasswordProvider? passwordProvider,
bool firstAttemptByEmptyPassword = true,
void Function()? onDispose,
}) async {
for (int i = 0;; i++) {
final String? password;
if (firstAttemptByEmptyPassword && i == 0) {
password = null;
} else {
password = await passwordProvider?.call();
if (password == null) {
throw const PdfPasswordException('No password supplied by PasswordProvider.');
}
}
try {
await ensurePdfjsInitialized();
return PdfDocumentWeb.fromDocument(
await openDocument(password),
sourceName: sourceName,
onDispose: onDispose,
);
} catch (e) {
if (!_isPasswordError(e)) {
rethrow;
}
}
}
}
static bool _isPasswordError(dynamic e) => e.toString().startsWith('PasswordException:');
}
class PdfDocumentWeb extends PdfDocument {
PdfDocumentWeb._(
this._document, {
required super.sourceName,
required this.isEncrypted,
required this.permissions,
this.onDispose,
});
@override
final bool isEncrypted;
@override
final PdfPermissions? permissions;
final PdfjsDocument _document;
final void Function()? onDispose;
static Future<PdfDocumentWeb> fromDocument(
PdfjsDocument document, {
required String sourceName,
void Function()? onDispose,
}) async {
final perms = (await document.getPermissions().toDart)?.toDart.cast<int>();
final doc = PdfDocumentWeb._(
document,
sourceName: sourceName,
isEncrypted: perms != null,
permissions: perms != null ? PdfPermissions(perms.fold<int>(0, (p, e) => p | e), 2) : null,
onDispose: onDispose,
);
final pageCount = document.numPages;
final pages = <PdfPage>[];
for (int i = 0; i < pageCount; i++) {
pages.add(await doc._getPage(document, i + 1));
}
doc.pages = List.unmodifiable(pages);
return doc;
}
@override
Future<void> dispose() async {
_document.destroy();
onDispose?.call();
}
Future<PdfPage> _getPage(PdfjsDocument document, int pageNumber) async {
final page = await _document.getPage(pageNumber).toDart;
final vp1 = page.getViewport(PdfjsViewportParams(scale: 1));
return PdfPageWeb._(
document: this,
pageNumber: pageNumber,
page: page,
width: vp1.width,
height: vp1.height,
rotation: PdfPageRotation.values[page.rotate ~/ 90]);
}
@override
late final List<PdfPage> pages;
@override
bool isIdenticalDocumentHandle(Object? other) => other is PdfDocumentWeb && _document == other._document;
Future<JSObject?> _getDestObject(JSAny? dest) async {
if (dest == null) return null;
if (dest is String) {
final destObj = await _document.getDestination(dest as String).toDart;
return destObj;
} else {
return dest as JSObject;
}
}
@override
Future<List<PdfOutlineNode>> loadOutline() async {
final outline = await _document.getOutline().toDart;
if (outline == null) return [];
final nodes = <PdfOutlineNode>[];
for (final node in outline.toDart) {
nodes.add(await _pdfOutlineNodeFromOutline(node));
}
return nodes;
}
Future<PdfOutlineNode> _pdfOutlineNodeFromOutline(PdfjsOutlineNode outline) async {
final children = <PdfOutlineNode>[];
for (final item in outline.items.toDart) {
children.add(await _pdfOutlineNodeFromOutline(item));
}
return PdfOutlineNode(
title: outline.title,
dest: await _getDestination(outline.dest),
children: children,
);
}
/// NOTE: The returned [PdfDest] is always compacted.
Future<PdfDest?> _getDestination(JSAny? dest) async {
final destObj = await _getDestObject(dest);
if (destObj is! JSArray) return null;
final arr = destObj.toDart;
final ref = arr[0] as PdfjsRef;
final cmdStr = _getName(arr[1]);
final params = arr.length < 3 ? null : List<double?>.unmodifiable(arr.sublist(2).cast<double?>());
return PdfDest(
(await _document.getPageIndex(ref).toDart).toDartInt + 1,
_parseCmdStr(cmdStr),
params,
);
}
static PdfDestCommand _parseCmdStr(String cmdStr) {
switch (cmdStr) {
case 'XYZ':
return PdfDestCommand.xyz;
case 'Fit':
return PdfDestCommand.fit;
case 'FitB':
return PdfDestCommand.fitB;
case 'FitH':
return PdfDestCommand.fitH;
case 'FitBH':
return PdfDestCommand.fitBH;
case 'FitV':
return PdfDestCommand.fitV;
case 'FitBV':
return PdfDestCommand.fitBV;
case 'FitR':
return PdfDestCommand.fitR;
default:
return PdfDestCommand.unknown;
}
}
static String _getName(JSAny? name) {
final obj = name.dartify();
if (obj is Map) {
return obj['name'].toString();
} else {
return obj.toString();
}
}
}
class PdfPageWeb extends PdfPage {
PdfPageWeb._({
required this.document,
required this.pageNumber,
required this.page,
required this.width,
required this.height,
required this.rotation,
});
@override
final PdfDocumentWeb document;
@override
final int pageNumber;
final PdfjsPage page;
@override
final double width;
@override
final double height;
@override
final PdfPageRotation rotation;
@override
Future<PdfImage?> render({
int x = 0,
int y = 0,
int? width,
int? height,
double? fullWidth,
double? fullHeight,
Color? backgroundColor,
PdfAnnotationRenderingMode annotationRenderingMode = PdfAnnotationRenderingMode.annotationAndForms,
PdfPageRenderCancellationToken? cancellationToken,
}) async {
if (cancellationToken != null && cancellationToken is! PdfPageRenderCancellationTokenWeb) {
throw ArgumentError(
'cancellationToken must be created by PdfPage.createCancellationToken().',
'cancellationToken',
);
}
fullWidth ??= this.width;
fullHeight ??= this.height;
width ??= fullWidth.toInt();
height ??= fullHeight.toInt();
return await synchronized(() async {
if (cancellationToken is PdfPageRenderCancellationTokenWeb && cancellationToken.isCanceled == true) {
return null;
}
final data = await _renderRaw(
x,
y,
width!,
height!,
fullWidth!,
fullHeight!,
backgroundColor,
false,
annotationRenderingMode,
);
return PdfImageWeb(
width: width,
height: height,
pixels: data,
);
});
}
@override
PdfPageRenderCancellationTokenWeb createCancellationToken() => PdfPageRenderCancellationTokenWeb();
Future<Uint8List> _renderRaw(
int x,
int y,
int width,
int height,
double fullWidth,
double fullHeight,
Color? backgroundColor,
bool dontFlip,
PdfAnnotationRenderingMode annotationRenderingMode,
) async {
final vp1 = page.getViewport(PdfjsViewportParams(scale: 1));
final pageWidth = vp1.width;
if (width <= 0 || height <= 0) {
throw PdfException('Invalid PDF page rendering rectangle ($width x $height)');
}
final vp = page.getViewport(PdfjsViewportParams(
scale: fullWidth / pageWidth, offsetX: -x.toDouble(), offsetY: -y.toDouble(), dontFlip: dontFlip));
final canvas = web.document.createElement('canvas') as web.HTMLCanvasElement;
canvas.width = width;
canvas.height = height;
if (backgroundColor != null) {
canvas.context2D.fillStyle = '#${backgroundColor.value.toRadixString(16).padLeft(8, '0')}'.toJS;
canvas.context2D.fillRect(0, 0, width, height);
}
await page
.render(
PdfjsRenderContext(
canvasContext: canvas.context2D,
viewport: vp,
annotationMode: annotationRenderingMode.index,
),
)
.promise
.toDart;
final src = canvas.context2D.getImageData(0, 0, width, height).data.toDart.buffer.asUint8List();
return src;
}
@override
Future<PdfPageText> loadText() => PdfPageTextWeb._loadText(this);
@override
Future<List<PdfLink>> loadLinks({bool compact = false}) async {
final annots = (await page.getAnnotations(PdfjsGetAnnotationsParameters()).toDart).toDart;
final links = <PdfLink>[];
for (final annot in annots) {
if (annot.subtype != 'Link') {
continue;
}
final rect = annot.rect.toDart.cast<double>();
final rects = List<PdfRect>.unmodifiable([PdfRect(rect[0], rect[3], rect[2], rect[1])]);
if (annot.url != null) {
links.add(
PdfLink(rects, url: Uri.parse(annot.url!)),
);
continue;
}
final dest = await document._getDestination(annot.dest);
if (dest != null) {
links.add(
PdfLink(rects, dest: dest),
);
continue;
}
}
return compact ? List.unmodifiable(links) : links;
}
}
class PdfPageRenderCancellationTokenWeb extends PdfPageRenderCancellationToken {
bool _canceled = false;
@override
void cancel() => _canceled = true;
@override
bool get isCanceled => _canceled;
}
class PdfImageWeb extends PdfImage {
PdfImageWeb({required this.width, required this.height, required this.pixels});
@override
final int width;
@override
final int height;
@override
final Uint8List pixels;
@override
PixelFormat get format => PixelFormat.rgba8888;
@override
void dispose() {}
}
class PdfPageTextFragmentWeb implements PdfPageTextFragment {
PdfPageTextFragmentWeb(this.index, this.bounds, this.text);
@override
final int index;
@override
int get length => text.length;
@override
int get end => index + length;
@override
final PdfRect bounds;
@override
List<PdfRect>? get charRects => null;
@override
final String text;
}
class PdfPageTextWeb extends PdfPageText {
PdfPageTextWeb({
required this.pageNumber,
required this.fullText,
required this.fragments,
});
@override
final int pageNumber;
@override
final String fullText;
@override
final List<PdfPageTextFragment> fragments;
static Future<PdfPageTextWeb> _loadText(PdfPageWeb page) async {
final content = await page.page
.getTextContent(
PdfjsGetTextContentParameters(
includeMarkedContent: false,
disableNormalization: false,
),
)
.toDart;
final sb = StringBuffer();
final fragments = <PdfPageTextFragmentWeb>[];
for (final item in content.items.toDart) {
final t = item.transform.toDart.cast<double>();
final x = t[4];
final y = t[5];
final str = item.hasEOL ? '${item.str}\n' : item.str;
if (str == '\n' && fragments.isNotEmpty) {
final prev = fragments.last;
fragments.add(
PdfPageTextFragmentWeb(
sb.length,
PdfRect(
prev.bounds.right,
prev.bounds.top,
prev.bounds.right + item.width.toDouble(),
prev.bounds.bottom,
),
str,
),
);
} else {
fragments.add(
PdfPageTextFragmentWeb(
sb.length,
PdfRect(
x,
y + item.height.toDouble(),
x + item.width.toDouble(),
y,
),
str,
),
);
}
sb.write(str);
}
return PdfPageTextWeb(pageNumber: page.pageNumber, fullText: sb.toString(), fragments: fragments);
}
}
......@@ -189,6 +189,7 @@ class _PdfTextRenderBox extends RenderBox with Selectable, SelectionRegistrant {
PdfPage get _page => _textWidget._state.widget.page;
List<PdfPageTextFragment> get _fragments => _textWidget._state.fragments!;
@override
List<Rect> get boundingBoxes => <Rect>[paintBounds];
@override
......
......@@ -244,7 +244,7 @@ class PdfTextSearcher extends Listenable {
/// Paint callback to highlight the matches.
///
/// Use this with PdfViewerParams.pagePaintCallback to highlight the matches.
/// Use this with [PdfViewerParams.pagePaintCallback] to highlight the matches.
void pageTextMatchPaintCallback(ui.Canvas canvas, Rect pageRect, PdfPage page) {
final range = getMatchesRangeForPage(page.pageNumber);
if (range == null) return;
......
// SPDX-FileCopyrightText: Copyright 2018 @espresso3389 (Takashi Kawasaki)
// SPDX-FileCopyrightText: Copyright 2024 Noname_1111788
// SPDX-FileCopyrightText: Copyright 2024 Open Mobile Platform LLC <community@omp.ru>
// SPDX-License-Identifier: BSD-3-Clause
// ignore_for_file: public_member_api_docs
import 'dart:async';
import 'dart:io';
......@@ -455,9 +450,8 @@ class _PdfViewerState extends State<PdfViewer> with SingleTickerProviderStateMix
/// Key pressing state of ⌘ or Control depending on the platform.
static bool get _isCommandKeyPressed => Platform.isMacOS || Platform.isIOS
? RawKeyboard.instance.keysPressed.contains(LogicalKeyboardKey.meta) //HardwareKeyboard.instance.isMetaPressed
: RawKeyboard.instance.keysPressed
.contains(LogicalKeyboardKey.control); //HardwareKeyboard.instance.isControlPressed;
? HardwareKeyboard.instance.isMetaPressed
: HardwareKeyboard.instance.isControlPressed;
KeyEventResult _onKeyEvent(FocusNode node, KeyEvent event) {
final isDown = event is KeyDownEvent;
......
......@@ -9,7 +9,7 @@ version: 1.0.82
publish_to: "none"
environment:
sdk: ">=3.2.2 <4.0.0"
sdk: ">=3.3.0 <4.0.0"
flutter: ">=3.16.0"
dependencies:
......@@ -33,7 +33,7 @@ dependencies:
url: https://gitlab.com/omprussia/flutter/packages.git
path: packages/url_launcher_aurora
vector_math: ^2.1.4
web: ^0.3.0
web: ^0.5.1
package_info_plus: ^4.1.0
package_info_plus_aurora:
git:
......
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать