Skip to content

elsadeny/spdfcore

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

spdfcore

A cross-platform PDF processing library built in Rust with FFI bindings for mobile and desktop applications.

πŸš€ Features

  • PDF Information: Get page count, file size, and validation
  • PDF Merging: Combine multiple PDF files using advanced lopdf techniques
  • Cross-Platform: Works on macOS, iOS, Android, and Linux
  • Mobile-Optimized: Pure Rust implementation for mobile platforms
  • FFI Interface: C-compatible API for integration with mobile apps
  • Command Line Tool: Standalone binary for desktop usage

πŸ“± Platform Support

Platform Status Implementation
macOS βœ… qpdf + lopdf
iOS βœ… Pure lopdf
Android βœ… Pure lopdf
Linux βœ… qpdf + lopdf
Windows 🟑 Not tested

πŸ› οΈ Installation

Prerequisites

  • Rust (latest stable)
  • qpdf (for desktop platforms)
  • Android NDK (for Android builds)
  • Xcode (for iOS builds)

Desktop Installation

# Clone the repository
git clone <repository-url>
cd spdfcore

# Build the library
cargo build --release

# Build for specific platforms
make mac      # macOS build
make android  # Android build (all architectures)
make ios      # iOS build

πŸ“– Usage

Command Line Interface

# Get PDF information
./target/release/spdfcore info document.pdf

# Merge PDF files
./target/release/spdfcore merge file1.pdf file2.pdf file3.pdf output.pdf

# Split PDF at specific page
./target/release/spdfcore split document.pdf 5 output_prefix

FFI Integration (C/Mobile)

#include "spdfcore.h"

// Initialize the library
spdfcore_init();

// Get page count
int page_count;
PdfErrorCode error_code;
char* error_message;

bool success = pdf_get_page_count(
    "document.pdf",
    &page_count,
    &error_code,
    &error_message
);

if (success) {
    printf("PDF has %d pages\n", page_count);
}

// Merge PDFs
const char* input_files[] = {"file1.pdf", "file2.pdf", NULL};
success = pdf_merge_files(
    input_files,
    "merged.pdf",
    &error_code,
    &error_message
);

// Cleanup
spdfcore_cleanup();

Rust Integration

use spdfcore::merge_real::merge_pdfs;

// Merge PDF files
let files = vec![
    "file1.pdf".to_string(),
    "file2.pdf".to_string(),
    "file3.pdf".to_string(),
];

match merge_pdfs(&files, "output.pdf") {
    Ok(()) => println!("βœ… Merge successful!"),
    Err(e) => eprintln!("❌ Error: {}", e),
}

πŸ—οΈ Architecture

Core Components

  • src/core.rs - Essential PDF operations (page count, validation, file size)
  • src/merge_real.rs - PDF merging implementation using lopdf
  • src/ffi.rs - FFI interface for mobile/C integration
  • src/main.rs - Command line interface
  • src/error.rs - Error handling and types
  • src/types.rs - Data structures and type definitions

Mobile Implementation

On Android and iOS, spdfcore uses a pure Rust implementation with the lopdf library to ensure compatibility with mobile app sandboxes and App Store requirements.

On Desktop platforms, spdfcore can leverage external tools like qpdf for enhanced functionality while falling back to pure Rust when needed.

πŸ”§ Building

Android Build

# Install Android targets
rustup target add aarch64-linux-android
rustup target add armv7-linux-androideabi
rustup target add i686-linux-android
rustup target add x86_64-linux-android

# Build for Android
make android

Output: target/android/ with libraries for all architectures

iOS Build

# Install iOS targets
rustup target add aarch64-apple-ios
rustup target add x86_64-apple-ios

# Build for iOS
make ios

macOS Build

make mac

πŸ“š API Reference

FFI Functions

Function Description
spdfcore_init() Initialize the library
spdfcore_cleanup() Clean up resources
pdf_get_page_count() Get number of pages in PDF
pdf_get_file_size() Get PDF file size in bytes
pdf_validate() Validate PDF file
pdf_merge_files() Merge multiple PDF files
pdf_split_at_page() Split PDF at specific page

Error Codes

Code Description
Success Operation completed successfully
FileNotFound PDF file not found
InvalidPdf Invalid or corrupted PDF
InvalidParameter Invalid function parameter
IoError File I/O error
UnsupportedFeature Feature not implemented

πŸ§ͺ Testing

# Run tests
cargo test

# Build and test Android
make android

# Test CLI
./target/release/spdfcore info test.pdf

πŸ“„ Examples

Android Integration

  1. Copy target/android/ folder to your Android project
  2. Add to build.gradle:
    android {
      sourceSets {
        main {
          jniLibs.srcDirs = ['src/main/jniLibs']
        }
      }
    }
  3. Use SpdfCore.java for JNI interface

iOS Integration

  1. Add the compiled library to your Xcode project
  2. Include spdfcore.h header
  3. Call FFI functions from Objective-C/Swift

Flutter Integration

import 'dart:ffi';
import 'package:ffi/ffi.dart';

// Load the library
final DynamicLibrary spdfcore = DynamicLibrary.open('libspdfcore_ffi.so');

// Define function signatures
typedef GetPageCountC = Bool Function(Pointer<Utf8>, Pointer<Int32>, Pointer<Int32>, Pointer<Pointer<Utf8>>);
typedef GetPageCountDart = bool Function(Pointer<Utf8>, Pointer<Int32>, Pointer<Int32>, Pointer<Pointer<Utf8>>);

// Get function
final getPageCount = spdfcore.lookupFunction<GetPageCountC, GetPageCountDart>('pdf_get_page_count');

// Use the function
final path = 'document.pdf'.toNativeUtf8();
final pageCount = calloc<Int32>();
final errorCode = calloc<Int32>();
final errorMessage = calloc<Pointer<Utf8>>();

final success = getPageCount(path, pageCount, errorCode, errorMessage);

πŸ“ Project Structure

spdfcore/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ main.rs           # CLI application
β”‚   β”œβ”€β”€ lib.rs            # Library entry point
β”‚   β”œβ”€β”€ core.rs           # Core PDF operations (25 lines)
β”‚   β”œβ”€β”€ merge_real.rs     # PDF merging (120 lines)
β”‚   β”œβ”€β”€ ffi.rs            # FFI interface
β”‚   β”œβ”€β”€ error.rs          # Error handling
β”‚   └── types.rs          # Type definitions (47 lines)
β”œβ”€β”€ scripts/
β”‚   β”œβ”€β”€ build-android.sh  # Android build script
β”‚   β”œβ”€β”€ build-ios.sh      # iOS build script
β”‚   β”œβ”€β”€ build-mac.sh      # macOS build script
β”‚   └── README.md         # Scripts documentation
β”œβ”€β”€ target/               # Build outputs (gitignored)
β”œβ”€β”€ Cargo.toml           # Rust project configuration
β”œβ”€β”€ Makefile             # Build system (20+ targets)
β”œβ”€β”€ cbindgen.toml        # C header generation
└── README.md            # This file

🀝 Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

πŸ“ License

This project is licensed under the MIT License - see the LICENSE file for details.

🚨 Troubleshooting

Common Issues

Android Build Fails:

  • Ensure Android NDK is installed and ANDROID_NDK_HOME is set
  • Install required Rust targets: rustup target add aarch64-linux-android

PDF Merge Fails:

  • Verify input PDF files are valid and readable
  • Check file permissions
  • Ensure sufficient disk space for output

qpdf Not Found:

  • Install qpdf: brew install qpdf (macOS) or apt install qpdf (Linux)
  • spdfcore will fall back to pure Rust implementation

πŸ”— Dependencies

  • lopdf - Pure Rust PDF library for mobile compatibility
  • qpdf - External tool for advanced PDF operations (desktop only)
  • cbindgen - C header generation
  • Standard Rust libraries for cross-platform support

πŸ“ˆ Performance

  • Memory Efficient: Streaming PDF processing where possible
  • Mobile Optimized: Minimal dependencies for mobile platforms
  • Fast Merging: Advanced object ID mapping for efficient PDF combination
  • Small Binary Size: Optimized for mobile deployment

Made with ❀️ in Rust | Cross-platform PDF processing for everyone

About

pdf processing library

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published