PDF Marks

A Flutter package for viewing and annotating PDF documents with drawing, notes, shapes, and highlights.

Features

🧠 Complete PDF Annotation System

  • ✏️ Freehand Drawing - Draw with customizable colors and stroke widths
  • 🗒️ Text Notes - Add sticky note-style annotations
  • 🟦 Shapes - Add rectangles, circles, arrows, and lines
  • 🔶 Highlights - Create highlighted areas with bounding boxes
  • 👆 Interactive Selection - Select and edit existing annotations

📱 Built with Modern Flutter

  • Uses pdfx package for high-performance PDF rendering
  • CustomPaint overlays for smooth annotation rendering
  • Gesture detection for intuitive touch interactions
  • Material Design toolbar with mode switching

💾 Data Management

  • JSON-based annotation storage
  • Export/import functionality for sharing annotations
  • Persistent local storage using path_provider
  • Structured data models for all annotation types

Getting Started

Add this package to your pubspec.yaml:

dependencies:
  pdf_marks: ^0.0.1
  pdfx: ^2.6.0  # Required peer dependency

Usage

Basic Implementation

import 'package:flutter/material.dart';
import 'package:pdfx/pdfx.dart';
import 'package:pdf_marks/pdf_marks.dart';

class MyPdfViewer extends StatefulWidget {
  @override
  State<MyPdfViewer> createState() => _MyPdfViewerState();
}

class _MyPdfViewerState extends State<MyPdfViewer> {
  late PdfDocument document;

  @override
  void initState() {
    super.initState();
    _loadDocument();
  }

  Future<void> _loadDocument() async {
    // Load from assets
    document = await PdfDocument.openAsset('assets/sample.pdf');
    
    // Or load from file
    // document = await PdfDocument.openFile('/path/to/file.pdf');
    
    // Or load from URL
    // document = await PdfDocument.openUrl('https://example.com/file.pdf');
    
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: PdfAnnotator(
        document: document,
        onAnnotationsChanged: (annotations) {
          // Handle annotation changes
          print('Annotations updated: ${annotations.keys.length} pages');
        },
      ),
    );
  }

  @override
  void dispose() {
    document.dispose();
    super.dispose();
  }
}

Advanced Usage

// Custom toolbar and annotation handling
PdfAnnotator(
  document: document,
  showToolbar: true,
  backgroundColor: Colors.grey[100]!,
  onAnnotationsChanged: (annotations) {
    // Save to backend, local storage, etc.
    _saveAnnotationsToDatabase(annotations);
  },
  initialAnnotations: _loadInitialAnnotations(),
)

// Custom toolbar
PdfAnnotator(
  document: document,
  showToolbar: false, // Hide default toolbar
  customToolbar: MyCustomToolbar(), // Use your own
)

Annotation Types

The package supports four types of annotations:

  1. Drawing Annotations - Freehand paths with customizable colors and stroke widths
  2. Note Annotations - Text-based sticky notes positioned on the page
  3. Shape Annotations - Geometric shapes (rectangles, circles, arrows, lines)
  4. Highlight Annotations - Semi-transparent overlays for highlighting content

Data Format

Annotations are stored in a structured JSON format:

{
  "1": [
    {
      "id": "1640995200000",
      "type": "AnnotationType.drawing",
      "pageNumber": 1,
      "createdAt": "2021-12-31T23:00:00.000Z",
      "modifiedAt": "2021-12-31T23:00:00.000Z",
      "path": [[10, 10], [15, 20], [20, 25]],
      "color": 4294901760,
      "strokeWidth": 2.0,
      "strokeCap": "StrokeCap.round"
    },
    {
      "id": "1640995201000",
      "type": "AnnotationType.note",
      "pageNumber": 1,
      "createdAt": "2021-12-31T23:00:01.000Z",
      "modifiedAt": "2021-12-31T23:00:01.000Z",
      "position": [100, 150],
      "text": "Important note here",
      "backgroundColor": 4294967193,
      "textColor": 4278190080,
      "fontSize": 14.0
    }
  ]
}

Export/Import

final storage = AnnotationStorage();

// Export annotations
await storage.exportAnnotations(
  annotations, 
  '/path/to/export.json'
);

// Import annotations
final importedAnnotations = await storage.importAnnotations(
  '/path/to/import.json'
);

Customization

Toolbar Customization

AnnotationToolbar(
  currentMode: AnnotationMode.draw,
  currentColor: Colors.red,
  currentStrokeWidth: 3.0,
  onModeChanged: (mode) => setState(() => _mode = mode),
  onColorChanged: (color) => setState(() => _color = color),
  // ... other callbacks
)

Canvas Customization

The annotation overlay can be customized by extending AnnotationPainter and AnnotationOverlay classes.

Requirements

  • Flutter SDK >=3.8.1
  • Dart SDK >=3.8.1
  • iOS 9.0+ / Android API 16+

Dependencies

  • pdfx: ^2.6.0 - PDF rendering
  • path_provider: ^2.1.0 - Local storage access

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

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