### Run pdfcombine Example Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx_engine/example/README.md Demonstrates how to run the pdfcombine example from the repository root. This example combines multiple PDF files into a single PDF. ```bash dart run packages/pdfrx_engine/example/pdfcombine.dart ``` -------------------------------- ### Installation Bundle Setup Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/pdf_combine/linux/CMakeLists.txt Configures the installation prefix to create a relocatable bundle and ensures the build bundle directory is clean before installation. This prepares the environment for installing the application bundle. ```cmake # === Installation === # By default, "installing" just makes a relocatable bundle in the build # directory. set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) endif() # Start with a clean build bundle directory every time. install(CODE " file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") " COMPONENT Runtime) set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") ``` -------------------------------- ### Run pdfcombine Example from packages/pdfrx_engine Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx_engine/example/README.md Demonstrates how to run the pdfcombine example from the packages/pdfrx_engine directory. This example combines multiple PDF files into a single PDF. ```bash dart run example/pdfcombine.dart ``` -------------------------------- ### Run pdf2image Example Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx_engine/example/README.md Demonstrates how to run the pdf2image example from the repository root. This example converts PDF pages to PNG images and extracts text. ```bash dart run packages/pdfrx_engine/example/main.dart [output_dir] ``` -------------------------------- ### Run pdf2image Example from packages/pdfrx_engine Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx_engine/example/README.md Demonstrates how to run the pdf2image example from the packages/pdfrx_engine directory. This example converts PDF pages to PNG images and extracts text. ```bash dart run example/main.dart [output_dir] ``` -------------------------------- ### Installation Paths Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/viewer/linux/CMakeLists.txt Defines the destination directories for data and libraries within the installation bundle. ```cmake set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") ``` -------------------------------- ### Install Executable Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/viewer/linux/CMakeLists.txt Installs the application executable to the root of the installation bundle. ```cmake install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT Runtime) ``` -------------------------------- ### Run PDF Viewer Example Source: https://github.com/espresso3389/pdfrx/blob/master/README.md Navigate to the viewer example directory and run the Flutter application to see the full capabilities of the pdfrx plugin. ```bash cd packages/pdfrx/example/viewer flutter run ``` -------------------------------- ### Installation Bundle Directory Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/viewer/linux/CMakeLists.txt Sets the default installation prefix to a bundle directory within the build directory. ```cmake # === Installation === # By default, "installing" just makes a relocatable bundle in the build # directory. set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) endif() ``` -------------------------------- ### Install Bundled Libraries and Native Assets Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/pdf_combine/linux/CMakeLists.txt Installs bundled libraries provided by plugins and any native assets. This step ensures that all required dynamic libraries and assets are correctly placed within the installation bundle. ```cmake foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) install(FILES "${bundled_library}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endforeach(bundled_library) # Copy the native assets provided by the build.dart from all packages. set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") if(EXISTS "${NATIVE_ASSETS_DIR}") install(DIRECTORY "${NATIVE_ASSETS_DIR}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endif() ``` -------------------------------- ### Install LLVM on Linux Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfium_dart/README.md Instructions for installing the libclang-dev package on Ubuntu/Debian or clang-devel on Fedora, which is required for PDFium FFI binding generation. ```bash # Ubuntu/Debian sudo apt-get install libclang-dev # Fedora sudo dnf install clang-devel ``` -------------------------------- ### Run PDF Combine Example Source: https://github.com/espresso3389/pdfrx/blob/master/README.md Navigate to the PDF combine example directory and run the Flutter application to demonstrate PDF page manipulation and combining features. ```bash cd packages/pdfrx/example/pdf_combine flutter run ``` -------------------------------- ### Install Application Executable and Data Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/pdf_combine/linux/CMakeLists.txt Installs the main executable, ICU data file, and Flutter library to their respective destinations within the application bundle. This ensures all necessary components are included in the final installation. ```cmake install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT Runtime) install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) ``` -------------------------------- ### Installation Rules for Runtime Files Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/pdf_combine/windows/CMakeLists.txt Configures installation paths and components for the application executable, ICU data, Flutter library, bundled plugin libraries, and native assets. ```cmake # === Installation === # Support files are copied into place next to the executable, so that it can # run in place. This is done instead of making a separate bundle (as on Linux) # so that building and running from within Visual Studio will work. set(BUILD_BUNDLE_DIR "$") # Make the "install" step default, as it's required to run. set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) endif() set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT Runtime) install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) if(PLUGIN_BUNDLED_LIBRARIES) install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endif() # Copy the native assets provided by the build.dart from all packages. set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") install(DIRECTORY "${NATIVE_ASSETS_DIR}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) ``` -------------------------------- ### Install LLVM on macOS Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfium_dart/README.md Instructions for installing LLVM on macOS using Homebrew, a prerequisite for regenerating PDFium FFI bindings. ```bash brew install llvm ``` -------------------------------- ### Install Flutter Library Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/viewer/linux/CMakeLists.txt Installs the main Flutter library file to the lib directory within the bundle. ```cmake install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) ``` -------------------------------- ### Install Bundled Plugin Libraries Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/viewer/linux/CMakeLists.txt Installs any bundled libraries from plugins to the lib directory within the bundle. ```cmake foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) install(FILES "${bundled_library}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endforeach(bundled_library) ``` -------------------------------- ### AOT Library Installation Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/pdf_combine/windows/CMakeLists.txt Installs the Ahead-Of-Time (AOT) compiled library, but only for 'Profile' and 'Release' build configurations. ```cmake # Install the AOT library on non-Debug builds only. install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" CONFIGURATIONS Profile;Release COMPONENT Runtime) ``` -------------------------------- ### GitHub CLI Command Example Source: https://github.com/espresso3389/pdfrx/blob/master/doc/agents/COMMANDS.md Demonstrates how to use the GitHub CLI (`gh`) for commenting on issues, ensuring proper quoting for arguments. ```bash # gh commands work directly but use proper quoting gh issue comment 123 --repo espresso3389/pdfrx --body "Comment text here" ``` -------------------------------- ### Publishing Packages on Windows Source: https://github.com/espresso3389/pdfrx/blob/master/doc/agents/COMMANDS.md Examples of publishing packages on Windows using PowerShell to correctly handle directory changes before executing the publish command. ```bash # Use PowerShell for pub publish pwsh.exe -Command "cd 'd:\pdfrx\packages\pdfrx'; flutter pub publish --force" ``` ```bash pwsh.exe -Command "cd 'd:\pdfrx\packages\pdfrx_engine'; dart pub publish --force" ``` -------------------------------- ### Library Installation Path Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/viewer/linux/CMakeLists.txt Sets the runtime path for bundled libraries to be relative to the binary. ```cmake set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") ``` -------------------------------- ### Windows Path Handling Example Source: https://github.com/espresso3389/pdfrx/blob/master/doc/agents/COMMANDS.md Demonstrates correct and incorrect ways to handle Windows paths when running commands in a POSIX-like shell. Use PowerShell wrappers for commands involving path manipulation or directory changes. ```bash # WRONG - may fail with path issues cd d:\pdfrx\packages\pdfrx && flutter pub get ``` ```bash # CORRECT - use PowerShell wrapper pwsh.exe -Command "cd 'd:\pdfrx\packages\pdfrx'; flutter pub get" ``` -------------------------------- ### Install Native Assets Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/viewer/linux/CMakeLists.txt Installs native assets provided by packages to the lib directory within the bundle, if they exist. ```cmake # Copy the native assets provided by the build.dart from all packages. set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") if(EXISTS "${NATIVE_ASSETS_DIR}") install(DIRECTORY "${NATIVE_ASSETS_DIR}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endif() ``` -------------------------------- ### Install ICU Data Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/viewer/linux/CMakeLists.txt Installs the ICU data file to the data directory within the bundle. ```cmake install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) ``` -------------------------------- ### Basic CMake Setup and Variables Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/pdf_combine/windows/flutter/CMakeLists.txt Sets the minimum CMake version and defines source directories for ephemeral build artifacts and C++ client wrappers. Includes generated configuration from the Flutter tool. ```cmake cmake_minimum_required(VERSION 3.14) set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") # Configuration provided via flutter tool. include(${EPHEMERAL_DIR}/generated_config.cmake) # TODO: Move the rest of this into files in ephemeral. See # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") # Set fallback configurations for older versions of the flutter tool. if (NOT DEFINED FLUTTER_TARGET_PLATFORM) set(FLUTTER_TARGET_PLATFORM "windows-x64") endif() ``` -------------------------------- ### Install Flutter Assets Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/pdf_combine/linux/CMakeLists.txt Removes any existing Flutter assets and then installs the current set of assets into the application bundle. This ensures that the application has the latest assets available. ```cmake # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") install(CODE " file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") " COMPONENT Runtime) install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) ``` -------------------------------- ### PdfViewer Progressive Loading Examples Source: https://github.com/espresso3389/pdfrx/blob/master/doc/Progressive-Loading.md Demonstrates how to use the `useProgressiveLoading` parameter with different PdfViewer constructors. PdfViewer enables progressive loading by default. ```dart PdfViewer.file('path/to/document.pdf') ``` ```dart PdfViewer.asset( 'assets/large-document.pdf', useProgressiveLoading: true, ) ``` ```dart PdfViewer.uri( Uri.parse('https://example.com/document.pdf'), useProgressiveLoading: false, ) ``` -------------------------------- ### Install AOT Library Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/pdf_combine/linux/CMakeLists.txt Installs the Ahead-Of-Time (AOT) compiled library to the bundle, but only for non-Debug build types. This optimizes performance for release builds. ```cmake # Install the AOT library on non-Debug builds only. if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endif() ``` -------------------------------- ### Flutter Library Setup Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/viewer/windows/flutter/CMakeLists.txt Defines the Flutter library path and associated header files. It also sets up interface libraries and include directories for the Flutter engine. ```cmake # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") # Published to parent scope for install step. set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) list(APPEND FLUTTER_LIBRARY_HEADERS "flutter_export.h" "flutter_windows.h" "flutter_messenger.h" "flutter_plugin_registrar.h" "flutter_texture_registrar.h" ) list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") add_library(flutter INTERFACE) target_include_directories(flutter INTERFACE "${EPHEMERAL_DIR}" ) target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") add_dependencies(flutter flutter_assemble) ``` -------------------------------- ### Running the PDF Combine App Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/pdf_combine/README.md Commands to run the PDF combine example application on different platforms. Use '-d linux', '-d macos', or '-d windows' for desktop builds, and '-d chrome' for web builds. ```bash cd packages/pdfrx/example/pdf_combine flutter run -d linux # or macos, windows flutter run -d chrome # for Web ``` -------------------------------- ### Install Flutter Assets Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/viewer/linux/CMakeLists.txt Installs the Flutter assets directory to the application's data directory. This ensures that all necessary assets for the Flutter application are available at runtime. ```cmake set(FLUTTER_ASSET_DIR_NAME "flutter_assets") install( CODE " file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") " COMPONENT Runtime) install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) ``` -------------------------------- ### Command-Line PDF Combiner Examples Source: https://github.com/espresso3389/pdfrx/blob/master/doc/PDF-Page-Manipulation.md Demonstrates various ways to combine PDF documents using the command-line tool. Supports combining entire documents, specific page ranges, and interleaving pages from multiple sources. ```bash # Combine entire documents dart run pdfrx_engine:pdfcombine -o output.pdf doc1.pdf doc2.pdf doc3.pdf -- a b c ``` ```bash # Combine specific page ranges dart run pdfrx_engine:pdfcombine -o output.pdf doc1.pdf doc2.pdf -- a[1-10] b[5-15] ``` ```bash # Mix pages from multiple documents dart run pdfrx_engine:pdfcombine -o output.pdf doc1.pdf doc2.pdf -- a[1-3] b a[4-6] b[1-2] ``` -------------------------------- ### Minimum Font Manager Setup for PdfViewer Source: https://github.com/espresso3389/pdfrx/blob/master/doc/Loading-Fonts-Dynamically.md Use this minimal setup for applications using PdfViewer to leverage platform-specific font directories. This is the basic approach before adding custom resolvers. ```dart final fontManager = PdfFontManager.platform(); PdfViewer.file( path, fontManager: fontManager, ); ``` -------------------------------- ### Process All Pages with Progress Indicator Source: https://github.com/espresso3389/pdfrx/blob/master/doc/Progressive-Loading.md This example demonstrates opening a PDF with progressive loading enabled, processing pages with a progress indicator, and extracting text and links. ```dart import 'package:pdfrx_engine/pdfrx_engine.dart'; Future processPdfPages(String filePath) async { // Open document with progressive loading final document = await PdfDocument.openFile( filePath, useProgressiveLoading: true, ); try { // Load pages progressively with progress reporting await document.loadPagesProgressively( onPageLoadProgress: (_, loadedCount, totalCount) { final progress = (loadedCount / totalCount * 100).toStringAsFixed(1); print('Loading pages: $progress% ($loadedCount/$totalCount)'); return true; // Continue loading }, ); // Now all pages are loaded, safe to process for (int i = 0; i < document.pages.length; i++) { final page = document.pages[i]; // Extract text from page final text = await page.loadText(); print('Page ${i + 1}: ${text?.text.substring(0, 100)}...'); // Extract links final links = await page.loadLinks(); print('Page ${i + 1} has ${links.length} links'); } } finally { await document.dispose(); } } ``` -------------------------------- ### Import and Get PDFium Bindings Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfium_flutter/README.md Import the package and obtain the PDFium bindings. Alternatively, load PDFium from a custom module path. ```dart import 'package:pdfium_flutter/pdfium_flutter.dart'; // Get PDFium bindings final pdfium = pdfiumBindings; // Or load with custom path final customPdfium = getPdfium(modulePath: '/custom/path/to/pdfium.so'); ``` -------------------------------- ### Clean Build Bundle Directory Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/viewer/linux/CMakeLists.txt Installs a command to remove the build bundle directory before installation, ensuring a clean state. ```cmake # Start with a clean build bundle directory every time. install(CODE " file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") " COMPONENT Runtime) ``` -------------------------------- ### Basic CMake Configuration Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/viewer/windows/flutter/CMakeLists.txt Sets the minimum CMake version required and defines an ephemeral directory for generated files. This is a foundational setup for the Flutter build process. ```cmake cmake_minimum_required(VERSION 3.14) set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") # Configuration provided via flutter tool. include(${EPHEMERAL_DIR}/generated_config.cmake) ``` -------------------------------- ### Split and reorder pages from a single file Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx_engine/example/README.md Splits and reorders pages from a single input PDF file. This example shows how to select specific page ranges and individual pages from one document. ```bash dart run example/pdfcombine.dart -o output.pdf input.pdf -- a[1-10] a[20-30] a[11-19] ``` -------------------------------- ### Get Current Text Selection Range Source: https://github.com/espresso3389/pdfrx/blob/master/doc/Text-Selection.md Retrieve the current text selection range using the textSelectionPointRange property of the PdfViewerController. This allows access to the start and end points of the selection. ```dart final controller = PdfViewerController(); // Get the current text selection point range final PdfTextSelectionRange? range = controller.textSelection.textSelectionPointRange; if (range != null) { // Access start and end points final PdfTextSelectionPoint start = range.start; final PdfTextSelectionPoint end = range.end; // Each point contains: // - text: The PdfPageText object for the page // - index: The character index within that page's text print('Selection from page ${start.text.pageNumber}, char ${start.index} ' 'to page ${end.text.pageNumber}, char ${end.index}'); } ``` -------------------------------- ### Basic PDFium Initialization Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfium_dart/README.md Demonstrates how to initialize the PDFium FFI bindings if you already have the shared library loaded. This is useful for direct low-level access. ```dart import 'package:pdfium_dart/pdfium_dart.dart'; import 'dart:ffi'; // If you already have PDFium loaded final pdfium = PDFium(DynamicLibrary.open('/path/to/libpdfium.so')); ``` -------------------------------- ### Run PDFium FFI Binding Generation Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfium_dart/README.md Command to execute the ffigen helper script, which downloads PDFium headers and generates the FFI bindings. Use `--force` to refresh headers or `--download-only` to prepare headers separately. ```bash dart tool/ffigen.dart ``` -------------------------------- ### Windows Git Command Handling Source: https://github.com/espresso3389/pdfrx/blob/master/doc/agents/COMMANDS.md Shows how to execute Git commands on Windows, either by using the `-C` flag with Git or by wrapping the command in a PowerShell execution. ```bash # WRONG - cd may not work as expected cd d:\pdfrx && git status ``` ```bash # CORRECT - use -C flag for git git -C "d:\pdfrx" status git -C "d:\pdfrx" log --oneline -10 ``` ```bash # Or use PowerShell pwsh.exe -Command "cd 'd:\pdfrx'; git status" ``` -------------------------------- ### Manual Memory Management (Not Recommended) Source: https://github.com/espresso3389/pdfrx/blob/master/doc/Low-Level-PDFium-Bindings-Access.md Illustrates manual memory management for FFI allocations using calloc.free. This approach is error-prone and not recommended over Arena. ```dart import 'package:pdfium_dart/pdfium_dart.dart'; import 'dart:ffi'; import 'package:ffi/ffi.dart'; void manualMemoryExample() { final pdfium = getPdfium(); final pathPtr = 'path/to/file.pdf'.toNativeUtf8(); try { final doc = pdfium.FPDF_LoadDocument( pathPtr.cast(), nullptr, ); if (doc != nullptr) { // Use document... pdfium.FPDF_CloseDocument(doc); } } finally { // Must manually free allocated memory calloc.free(pathPtr); } } ``` -------------------------------- ### Enable Text Selection Source: https://github.com/espresso3389/pdfrx/wiki/Text-Selection Use PdfViewerParams.enableTextSelection to enable the text selection feature in PdfViewer. This is a basic setup for text selection. ```dart PdfViewer.asset( 'assets/test.pdf', params: PdfViewerParams( enableTextSelection: true, ... ), ... ), ``` -------------------------------- ### Find System Dependencies with PkgConfig Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/pdf_combine/linux/flutter/CMakeLists.txt Uses PkgConfig to find and check for required system libraries (GTK, GLIB, GIO) and their imported targets for linking. ```cmake find_package(PkgConfig REQUIRED) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) ``` -------------------------------- ### Facing Pages Layout Source: https://github.com/espresso3389/pdfrx/wiki/Page-Layout-Customization Implement a facing-page layout, commonly used in PDF viewers. This example handles reading order and cover pages. ```dart /// Page reading order; true to L-to-R that is commonly used by books like manga or such var isRightToLeftReadingOrder = false; /// Use the first page as cover page var needCoverPage = true; ... layoutPages: (pages, params) { final width = pages.fold( 0.0, (prev, page) => max(prev, page.width)); final pageLayouts = []; final offset = needCoverPage ? 1 : 0; double y = params.margin; for (int i = 0; i < pages.length; i++) { final page = pages[i]; final pos = i + offset; final isLeft = isRightToLeftReadingOrder ? (pos & 1) == 1 : (pos & 1) == 0; final otherSide = (pos ^ 1) - offset; final h = 0 <= otherSide && otherSide < pages.length ? max(page.height, pages[otherSide].height) : page.height; pageLayouts.add( Rect.fromLTWH( isLeft ? width + params.margin - page.width : params.margin * 2 + width, y + (h - page.height) / 2, page.width, page.height, ), ); if (pos & 1 == 1 || i + 1 == pages.length) { y += h + params.margin; } } return PdfPageLayout( pageLayouts: pageLayouts, documentSize: Size( (params.margin + width) * 2 + params.margin, y, ), ); }, ``` -------------------------------- ### Start Text Search Source: https://github.com/espresso3389/pdfrx/wiki/Text-Search Initiates a text search operation in the PDF document. The search runs in the background and progress is notified via the attached listener. ```dart textSearcher.startTextSearch('hello', caseInsensitive: true); ``` -------------------------------- ### Initialize and Use PdfTextSearcher Source: https://github.com/espresso3389/pdfrx/wiki/Text-Search Illustrates the overall usage of PdfTextSearcher, including its creation, listener attachment for UI updates, and disposal. It also shows how to integrate the search highlight callback into PdfViewerParams. ```dart class _MainPageState extends State { final controller = PdfViewerController(); // create a PdfTextSearcher and add a listener to update the GUI on search result changes late final textSearcher = PdfTextSearcher(controller)..addListener(_update); void _update() { if (mounted) { setState(() {}); } } @override void dispose() { // dispose the PdfTextSearcher textSearcher.removeListener(_update); textSearcher.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Pdfrx example'), ), body: PdfViewer.asset( 'assets/hello.pdf', controller: controller, params: PdfViewerParams( // add pageTextMatchPaintCallback that paints search hit highlights pagePaintCallbacks: [ textSearcher.pageTextMatchPaintCallback ], ), ) ); } ... ``` -------------------------------- ### Platform Build Commands Source: https://github.com/espresso3389/pdfrx/blob/master/doc/agents/COMMANDS.md Commands to build the `pdfrx` viewer application for various platforms including Android, iOS, Web, Linux, Windows, and macOS. ```bash cd packages/pdfrx/example/viewer flutter run flutter build appbundle # Android flutter build ios # iOS flutter build web --wasm # Web flutter build linux # Linux flutter build windows # Windows flutter build macos # macOS ``` -------------------------------- ### Initialize pdfrx and Use Another PDF Library Source: https://github.com/espresso3389/pdfrx/blob/master/doc/Interoperability-with-other-PDFium-Libraries.md Demonstrates initializing both pdfrx and another PDFium-based library, then using `suspendPdfiumWorkerDuringAction` to safely extract text with the other library before resuming normal pdfrx operations. ```dart import 'package:pdfrx/pdfrx.dart'; import 'package:another_pdf_lib/another_pdf_lib.dart' as other; class PdfProcessor { // Initialize both libraries static Future initialize() async { // Initialize pdfrx (which calls FPDF_InitLibraryWithConfig internally) await pdfrxFlutterInitialize(); } // Process PDF with the other library Future extractTextWithOtherLibrary(String path) async { // Suspend pdfrx operations during the other library's work return await PdfrxEntryFunctions.instance.suspendPdfiumWorkerDuringAction(() async { final doc = await other.PdfDocument.open(path); final text = await doc.extractText(); await doc.close(); return text; }); } // Continue using pdfrx normally Future renderWithPdfrx(String path) async { final doc = await PdfDocument.openFile(path); // ... render pages ... await doc.dispose(); } } ``` -------------------------------- ### Use hybrid page specifications Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx_engine/example/README.md Uses hybrid page specifications to extract pages from a single PDF. This example combines page ranges and individual page selections. ```bash dart run example/pdfcombine.dart -o output.pdf doc.pdf -- a[1-3,5,6,7,10] ``` -------------------------------- ### System Dependencies Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/viewer/linux/CMakeLists.txt Finds and checks for GTK 3.0 using PkgConfig. ```cmake find_package(PkgConfig REQUIRED) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) ``` -------------------------------- ### Merge two PDFs with custom ordering Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx_engine/example/README.md Merges two PDF files with a custom page ordering. This example demonstrates interleaving pages from different input files. ```bash dart run example/pdfcombine.dart -o merged.pdf input1.pdf input2.pdf -- a[1-10] b a[11-20] ``` -------------------------------- ### Add Page Number Overlay Source: https://github.com/espresso3389/pdfrx/wiki/Adding-Page-Number-on-Page-Bottom Use `pageOverlaysBuilder` to create custom overlays for each page. This example adds a red page number at the bottom center of every page. ```dart pageOverlaysBuilder: (context, pageRect, page) { return [ Align( alignment: Alignment.bottomCenter, child: Text( page.pageNumber.toString(), style: const TextStyle(color: Colors.red), ), ), ]; }, ``` -------------------------------- ### Get Latest Page Instance via Stream Source: https://github.com/espresso3389/pdfrx/blob/master/doc/Progressive-Loading.md Use `latestPageStream` to continuously receive the most recent page instance whenever its status changes. This is useful for reacting to updates. ```dart final page = document.pages[10]; page.latestPageStream.listen((latestPage) { print('Page updated, isLoaded: ${latestPage.isLoaded}'); if (latestPage.isLoaded) { // Use the latest loaded instance } }); ``` -------------------------------- ### Facing Pages Layout Source: https://github.com/espresso3389/pdfrx/blob/master/doc/Page-Layout-Customization.md Implement a facing pages layout, common in PDF viewers, by overriding PdfViewerParams.layoutPages. This example handles right-to-left reading order and optional cover pages. ```dart /// Page reading order; true to L-to-R that is commonly used by books like manga or such var isRightToLeftReadingOrder = false; /// Use the first page as cover page var needCoverPage = true; ... layoutPages: (pages, params) { final width = pages.fold( 0.0, (prev, page) => max(prev, page.width)); final pageLayouts = []; final offset = needCoverPage ? 1 : 0; double y = params.margin; for (int i = 0; i < pages.length; i++) { final page = pages[i]; final pos = i + offset; final isLeft = isRightToLeftReadingOrder ? (pos & 1) == 1 : (pos & 1) == 0; final otherSide = (pos ^ 1) - offset; final h = 0 <= otherSide && otherSide < pages.length ? max(page.height, pages[otherSide].height) : page.height; pageLayouts.add( Rect.fromLTWH( isLeft ? width + params.margin - page.width : params.margin * 2 + width, y + (h - page.height) / 2, page.width, page.height, ), ); if (pos & 1 == 1 || i + 1 == pages.length) { y += h + params.margin; } } return PdfPageLayout( pageLayouts: pageLayouts, documentSize: Size( (params.margin + width) * 2 + params.margin, y, ), ); }, ``` -------------------------------- ### Initialize PDFium Library Once Source: https://github.com/espresso3389/pdfrx/blob/master/doc/Interoperability-with-other-PDFium-Libraries.md Ensures PDFium is initialized only once at application startup using `pdfrxFlutterInitialize()`. This is crucial for all PDFium-based libraries to function correctly. ```dart void main() async { WidgetsFlutterBinding.ensureInitialized(); // Initialize PDFium for all libraries (calls FPDF_InitLibraryWithConfig) await pdfrxFlutterInitialize(); runApp(MyApp()); } ``` -------------------------------- ### Get Visible Document Area and Scroll Source: https://github.com/espresso3389/pdfrx/blob/master/doc/Coordinate-Conversion.md Retrieves the currently visible rectangular area of the document in document coordinates and provides functionality to check if a position is visible or to scroll to a target position. ```dart // Get the currently visible area in document coordinates final visibleRect = controller.visibleRect; // Check if a specific position is visible final docPos = Offset(100, 200); final isVisible = visibleRect.contains(docPos); // Scroll to make a position visible final targetPos = Offset(500, 1000); if (!visibleRect.contains(targetPos)) { controller.goToPosition(targetPos); } ``` -------------------------------- ### Set Programmatic Text Selection Source: https://github.com/espresso3389/pdfrx/blob/master/doc/Text-Selection.md Programmatically set text selection by providing a PdfTextSelectionRange. This requires loading the page text and creating PdfTextSelectionPoint objects for the start and end of the desired selection. ```dart // The code below assumes that the controller is associated to a PdfViewer final controller = PdfViewerController(); ... // First, load the page text for the target page final page = controller.document.pages[pageNumber - 1]; final pageText = await page.loadStructuredText(); // Create selection points with page text and character indices final startPoint = PdfTextSelectionPoint(pageText, startCharIndex); final endPoint = PdfTextSelectionPoint(pageText, endCharIndex); // Create range and set the selection final range = PdfTextSelectionRange.fromPoints(startPoint, endPoint); await controller.textSelection.setTextSelectionPointRange(range); ``` -------------------------------- ### Initialize PDFium Library Directly Source: https://github.com/espresso3389/pdfrx/blob/master/doc/Low-Level-PDFium-Bindings-Access.md Own the PDFium lifecycle directly if your program only uses pdfium_dart. Ensure to call FPDF_InitLibrary and FPDF_DestroyLibrary. ```dart import 'package:pdfium_dart/pdfium_dart.dart'; final pdfium = getPdfium(); pdfium.FPDF_InitLibrary(); try { // Call PDFium APIs here. } finally { pdfium.FPDF_DestroyLibrary(); } ``` -------------------------------- ### Flutter Library Configuration Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/pdf_combine/windows/flutter/CMakeLists.txt Defines the Flutter library path, ICU data file, project build directory, and AOT library path. These are published to the parent scope for use in the install step. ```cmake # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") # Published to parent scope for install step. set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) ``` -------------------------------- ### Format Dart and Flutter Packages Source: https://github.com/espresso3389/pdfrx/blob/master/doc/agents/CODE-STYLE.md Run this command to format both Dart and Flutter packages according to project standards. ```bash dart format . ``` -------------------------------- ### Handle PDFium Function Errors Source: https://github.com/espresso3389/pdfrx/blob/master/doc/Low-Level-PDFium-Bindings-Access.md Always check the return values of PDFium functions and use `FPDF_GetLastError()` to retrieve error codes when operations fail. This example demonstrates checking the result of `FPDF_LoadDocument`. ```dart final pdfium = getPdfium(); using((arena) { final pathPtr = 'path/to/file.pdf'.toNativeUtf8(allocator: arena); final doc = pdfium.FPDF_LoadDocument(pathPtr.cast(), nullptr); if (doc == nullptr) { final error = pdfium.FPDF_GetLastError(); print('Failed to load document. Error code: $error'); // Handle error... } else { // Use document... pdfium.FPDF_CloseDocument(doc); } }); ``` -------------------------------- ### Add Dependency Libraries and Include Directories Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/pdf_combine/windows/runner/CMakeLists.txt Links necessary libraries (flutter, flutter_wrapper_app, dwmapi.lib) and adds include directories for the application target. Custom application-specific dependencies should be added here. ```cmake target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") ``` -------------------------------- ### Add Dependency Libraries and Include Directories Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/viewer/windows/runner/CMakeLists.txt Specifies the libraries and include directories required for the application's build. Application-specific dependencies should be added here. ```cmake # Add dependency libraries and include directories. Add any application-specific # dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") ``` -------------------------------- ### Apply Standard Build Settings Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/pdf_combine/windows/runner/CMakeLists.txt Applies a standard set of build configurations to the specified target. This can be customized for applications requiring different build settings. ```cmake apply_standard_settings(${BINARY_NAME}) ``` -------------------------------- ### Provide Password Interactively for PDF Viewer Source: https://github.com/espresso3389/pdfrx/wiki/Deal-with-Password-Protected-PDF-Files-using-PasswordProvider Use PdfPasswordProvider with a dialog to get the password from the user. The dialog is shown when the PDF is password-protected and the provider is called repeatedly until the document opens or null is returned. ```dart PdfViewer.asset( 'assets/test.pdf', // Most easiest way to return some password passwordProvider: _showPasswordDialog, ... ), ... Future _showPasswordDialog() async { final textController = TextEditingController(); return await showDialog( context: context, barrierDismissible: false, builder: (context) { return AlertDialog( title: const Text('Enter password'), content: TextField( controller: textController, autofocus: true, keyboardType: TextInputType.visiblePassword, obscureText: true, onSubmitted: (value) => Navigator.of(context).pop(value), ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(null), child: const Text('Cancel'), ), TextButton( onPressed: () => Navigator.of(context).pop(textController.text), child: const Text('OK'), ), ], ); }, ); } ``` -------------------------------- ### Project and Build Configuration Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/pdf_combine/windows/CMakeLists.txt Sets the minimum CMake version, project name, executable name, and configures build types for multi-config generators and single-config builds. ```cmake cmake_minimum_required(VERSION 3.14) project(pdfcombine LANGUAGES CXX) # The name of the executable created for the application. Change this to change # the on-disk name of your application. set(BINARY_NAME "pdfcombine") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. cmake_policy(VERSION 3.14...3.25) # Define build configuration option. get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(IS_MULTICONFIG) set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" CACHE STRING "" FORCE) else() if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Flutter build mode" FORCE) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Profile" "Release") endif() endif() ``` -------------------------------- ### Render PDF Page to Image Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx_engine/README.md Loads a PDF file, renders the first page to an image, and saves it as a PNG file. Ensure pdfrxInitialize() is called before use. ```dart import 'dart:io'; import 'package:image/image.dart' as img; import 'package:pdfrx_engine/pdfrx_engine.dart'; void main() async { await pdfrxInitialize(); final document = await PdfDocument.openFile('test.pdf'); final page = document.pages[0]; // first page final pageImage = await page.render( width: page.width * 200 / 72, height: page.height * 200 / 72, ); final image = pageImage!.createImageNF(); await File('output.png').writeAsBytes(img.encodePng(image)); pageImage.dispose(); document.close(); } ``` -------------------------------- ### Flutter and System Dependencies Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/pdf_combine/linux/CMakeLists.txt Includes the Flutter managed directory and finds necessary system libraries using PkgConfig, specifically GTK+. This step is crucial for integrating Flutter components and external libraries. ```cmake # Flutter library and tool build rules. set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") add_subdirectory(${FLUTTER_MANAGED_DIR}) # System-level dependencies. find_package(PkgConfig REQUIRED) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) ``` -------------------------------- ### Import Raw FFI Bindings Source: https://github.com/espresso3389/pdfrx/blob/master/doc/Low-Level-PDFium-Bindings-Access.md Import the raw FFI bindings generated from PDFium headers. This provides access to all PDFium functions with their original C API names. ```dart import 'package:pdfium_dart/pdfium_dart.dart'; ``` -------------------------------- ### Set Text Selection Across Multiple Pages Source: https://github.com/espresso3389/pdfrx/blob/master/doc/Text-Selection.md Demonstrates setting a text selection that spans across different pages. Ensure the page text is loaded for both the start and end pages, and calculate the correct character indices. ```dart // Example: Select from the beginning of page 1 to the end of page 3 final startPage = controller.document.pages[0]; final startPageText = await startPage.loadStructuredText(); final endPage = controller.document.pages[2]; final endPageText = await endPage.loadStructuredText(); if (endPageText.fullText.isNotEmpty) { final startPoint = PdfTextSelectionPoint(startPageText, 0); // NOTE: The index is inclusive - it points to the last selected character. // To select to the end of page, use (fullText.length - 1). // This assumes the page has text (fullText.length > 0). final endPoint = PdfTextSelectionPoint(endPageText, endPageText.fullText.length - 1); final range = PdfTextSelectionRange.fromPoints(startPoint, endPoint); await controller.textSelection.setTextSelectionPointRange(range); } ``` -------------------------------- ### Memory Management with Arena Source: https://github.com/espresso3389/pdfrx/blob/master/doc/Low-Level-PDFium-Bindings-Access.md Demonstrates using Dart's ffi 'using' block with Arena for automatic memory management when loading a PDF document. ```dart import 'package:pdfium_dart/pdfium_dart.dart'; import 'dart:ffi'; import 'package:ffi/ffi.dart'; void memoryExample() { final pdfium = getPdfium(); // Use arena for automatic memory management using((arena) { final pathPtr = 'path/to/file.pdf'.toNativeUtf8(allocator: arena); final doc = pdfium.FPDF_LoadDocument( pathPtr.cast(), nullptr, ); if (doc != nullptr) { // Use document... pdfium.FPDF_CloseDocument(doc); } // Memory allocated by arena is automatically freed when the using block ends }); } ``` -------------------------------- ### Control PDF File Size: Page Dimensions vs. Image Resolution Source: https://github.com/espresso3389/pdfrx/blob/master/doc/Importing-Images-to-PDF.md This example demonstrates that `width` and `height` in `createFromJpegData` only set page dimensions, not image resolution. The embedded JPEG data retains its original size, potentially leading to large files. ```dart import 'package:image/image.dart' as img; // This creates a small page, but the PDF file will still contain // the full 4000x3000 pixel JPEG data final largeImage = img.decodeImage(bytes); // 4000x3000 pixels final jpegData = Uint8List.fromList(img.encodeJpg(largeImage!, quality: 90)); final doc = await PdfDocument.createFromJpegData( jpegData, width: 200, // Small page width height: 150, // Small page height sourceName: 'small-page-large-file.pdf', ); // Result: Small visible page, but LARGE file size! ``` -------------------------------- ### Flutter Tool Backend Command Source: https://github.com/espresso3389/pdfrx/blob/master/packages/pdfrx/example/viewer/windows/flutter/CMakeLists.txt Sets up a custom command to execute the Flutter tool backend script. This command generates necessary output files like the Flutter library and headers, ensuring the build is up-to-date. ```cmake # === Flutter tool backend === # _phony_ is a non-existent file to force this command to run every time, # since currently there's no way to get a full input/output list from the # flutter tool. set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) add_custom_command( OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ${CPP_WRAPPER_SOURCES_APP} ${PHONY_OUTPUT} COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS "${FLUTTER_LIBRARY}" ${FLUTTER_LIBRARY_HEADERS} ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ${CPP_WRAPPER_SOURCES_APP} ) ``` -------------------------------- ### Publish Flutter Packages on Windows Source: https://github.com/espresso3389/pdfrx/blob/master/doc/agents/RELEASING.md Use PowerShell to publish Flutter packages from Windows, ensuring correct path handling. ```powershell pwsh.exe -Command "cd 'd:\pdfrx\packages\'; flutter pub publish --force" ```