A powerful Flutter library for programmatically creating and manipulating Microsoft Word (.docx) documents. This library provides comprehensive functionality for text replacement, image insertion, table manipulation, and complex document generation.
✨ Text Manipulation
- Replace text placeholders with dynamic values using
{key}format - Replace entire paragraphs for complex content
- Support for headers and footers
🖼️ Image Handling
- Insert images with automatic aspect ratio management
- Replace image placeholders in text boxes
- Support for PNG and JPG formats
- Automatic dimension calculation and scaling
📊 Table Support
- Generate dynamic tables with custom rows
- Pre-built templates for personnel, projects, and transcripts
- Easy table row insertion and manipulation
📄 Document Structure
- Work with headers and footers independently
- Manage multiple document sections
- Create complex document layouts with text boxes
🔧 Advanced Features
- Extract and manipulate DOCX XML structure
- Add image relationships dynamically
- Support for both asset and file system documents
- Automatic temporary file management
The library uses a simple and consistent placeholder format throughout all operations:
Format: {key}
Where key is the identifier you use in your code to replace the placeholder.
Examples:
{companyName}→ Replaced with company name value{date}→ Replaced with date value{employeeList}→ Replaced with employee list content{logoImage}→ Replaced with an image
In Your Template (Word document):
Dear {customerName},
Your order #{orderNumber} has been confirmed on {orderDate}.
Thank you for your business!
In Your Code:
await docxUtil.replaceText(
textReplacements: {
'customerName': 'John Doe',
'orderNumber': '12345',
'orderDate': '2025-11-07',
}
);Result:
Dear John Doe,
Your order #12345 has been confirmed on 2025-11-07.
Thank you for your business!
The heart of the library, DocxUtil provides a comprehensive API for working with DOCX files.
Design Pattern: Builder/Facade Pattern
- Simplifies complex XML manipulation behind an easy-to-use interface
- Handles DOCX file lifecycle (extract → modify → save)
Key Responsibilities:
- DOCX file extraction and compression
- XML content manipulation
- Temporary file management
- Relationship management for embedded resources
A utility class that handles image dimension calculations while maintaining aspect ratios.
Key Features:
- Automatic original dimension detection
- Aspect ratio preservation
- EMU (English Metric Units) conversion
- Support for wanted width/height constraints
A high-level utility that demonstrates how to use DocxUtil for generating complete documents from templates.
Purpose: Provides ready-to-use methods for generating specific document types (KGB, EK-series documents, etc.)
DocxUtil docxUtil = DocxUtil(
filePath: 'template.docx', // Source template
savePath: '/path/to/output.docx', // Output path
isAsset: true // Load from assets or file system
);Internal Process:
- Validates the file has
.docxextension - Loads the file (from assets bundle or file system)
- Extracts the ZIP archive to a temporary directory
- Stores the temporary path for XML manipulation
The library uses XML manipulation to modify document content:
// Text Replacement
await docxUtil.replaceText(
textReplacements: {
'companyName': 'ACME Corp',
'date': '2025-11-07',
}
);
// Paragraph Replacement (for tables/complex content)
await docxUtil.replaceParagraph(
paragraphReplacements: {
'tableContent': generatedTableXML,
}
);
// Image Replacement
await docxUtil.replaceImage(
imageReplacements: {
'logoImage': MsImageUtil.createInstance(
image: logoFile,
wantedWidth: 300,
wantedHeight: 200,
),
}
);XML Manipulation Strategy:
- Uses regular expressions to find placeholders in
{key}format (e.g.,{companyName}) - Placeholders are case-sensitive and must match exactly
- Maintains XML structure integrity
- Caches modified XML content in memory (
xmlContentMap) - Only writes changes when
saveDocx()is called
Note: The placeholder format is always {key} where the key matches your replacement map keys.
The library provides dedicated methods for header/footer manipulation:
// Replace text in headers
await docxUtil.replaceTextHeader(
textReplacements: {'headerTitle': 'Document Title'}
);
// Replace text in footers
await docxUtil.replaceTextFooter(
textReplacements: {'footerText': 'Page Footer'}
);
// Replace images in header text boxes
await docxUtil.replaceImageInTextBoxHeader(
imageReplacements: {'headerLogo': logoFile}
);Implementation Details:
- Automatically discovers all header files (
header1.xml,header2.xml, etc.) - Automatically discovers all footer files (
footer1.xml,footer2.xml, etc.) - Applies replacements to all discovered files
DOCX files use a relationship system to link images. The library handles this automatically:
String newRid = await docxUtil.addImageRelationship(
image: imageFile,
relationshipFilePath: 'word/_rels/document.xml.rels'
);
// Returns: 'rId7' (relationship ID)Process:
- Determines the next available relationship ID
- Copies the image to the document's
mediafolder - Creates a relationship entry in the
.relsfile - Returns the relationship ID for XML reference
For images within text boxes (common in Word templates):
await docxUtil.replaceImageInTextBox(
imageReplacements: {
'logoPlaceholder': logoFile,
},
padding: 14000 // EMU padding
);Intelligent Processing:
- Locates the text box containing the placeholder
- Extracts the text box dimensions
- Calculates optimal image size (with padding)
- Maintains aspect ratio
- Generates proper XML with image reference
String textBoxXML = await docxUtil.createTextBoxImage(
3000000, // Width in EMU
2000000, // Height in EMU
imageFile,
padding: 14000
);String textXML = docxUtil.createTextParagraph(
text: 'Important Notice',
font: 'Arial',
fontSizeHalfPoints: 28, // 14pt (half-points)
bold: true,
italic: false,
underline: true,
alignment: 'center',
);String imagesXML = await docxUtil.createMultiTextBoxImages(
textBoxWidthCm: 15.0,
textBoxHeightCm: 10.0,
firstImageWidthCm: 17.0,
firstImageHeightCm: 12.0,
imageFiles: [image1, image2, image3],
);// Save the modified document
await docxUtil.saveDocx();
// Clean up temporary files
docxUtil.dispose();Save Process:
- Writes all cached XML content to their respective files
- Recursively compresses the temporary directory back into a ZIP
- Saves the archive with
.docxextension - (Optional) Cleans up temporary files with
dispose()
The library uses template DOCX files as starting points, allowing for consistent document structure while enabling dynamic content.
- XML content is loaded only when needed
- Modified content is cached in
xmlContentMap - All changes are written atomically during save
- DocxUtil: Core document manipulation
- MsImageUtil: Image dimension calculations
- CreateDocumentUtil: High-level document generation
- Constants: XML templates and configurations
// Explicit resource cleanup
void dispose() {
final tempDirFolder = Directory(tmpPath!);
tempDirFolder.deleteSync(recursive: true);
xmlContentMap.clear();
}Follows Flutter's disposal pattern for cleanup of temporary resources.
Future<void> replaceText({
required Map<String, dynamic> textReplacements
}) async { ... }
Future<void> replaceImage({
required Map<String, MsImageUtil> imageReplacements
}) async { ... }The library includes pre-built XML templates for common Word elements:
msTextTemplate- Formatted text paragraphsmsPageBreak- Page breakmsLineBreak- Line break
msImageTemplate- Inline imagesmsTextBoxImageTemplate- Images in text boxesmsRelationShipTemplate- Image relationship entries
permissionGivenPersonalTable- Personnel permission tableshareHolderPersonalTable- Shareholder information tableauthorizedPersonalTable- Authorized personnel tableprojectTable- Project listing tabletranscriptTable- Document transcript table
permissionGivenPersonalRowshareHolderPersonalRowauthorizedPersonalRowprojectRowtranscriptRow
planImageTemplate- Plan/diagram image layoutplanImageTemplateTogek- TOGEK-specific plan layout
Predefined save file names for generated documents:
const String saveKgbFileName = "KGB Üst Yazısı.docx";
const String saveEk0FileName = "Ek-0 Başvuru Yazısı.docx";
// ... more predefined namesPredefined placeholder keys:
const msPermissionGivenPeronalListKey = "permissionGivenPersonalList";
const msShareHolderPersonalKey = "shareHolderPersonalList";
const msAuthorizedPersonalKey = "authorizedPersonalList";
// ... more keysDocxUtil docxUtil = DocxUtil(
filePath: 'letter_template.docx',
savePath: '/storage/letter_output.docx',
isAsset: true,
);
await docxUtil.replaceText(
textReplacements: {
'recipientName': 'John Doe',
'date': '2025-11-07',
'subject': 'Project Proposal',
}
);
await docxUtil.saveDocx();
docxUtil.dispose();DocxUtil docxUtil = DocxUtil(
filePath: 'company_report.docx',
savePath: '/storage/report_output.docx',
isAsset: true,
);
// Replace header logo
await docxUtil.replaceImageInTextBoxHeader(
imageReplacements: {
'companyLogo': File('/path/to/logo.png'),
}
);
// Replace body text
await docxUtil.replaceText(
textReplacements: {
'reportTitle': 'Q4 Financial Report',
'year': '2025',
}
);
await docxUtil.saveDocx();
docxUtil.dispose();DocxUtil docxUtil = DocxUtil(
filePath: 'employee_list.docx',
savePath: '/storage/employees.docx',
isAsset: true,
);
// Generate table rows
String tableRows = '';
for (var employee in employees) {
tableRows += permissionGivenPersonalRow
.replaceAll('{name}', employee.name)
.replaceAll('{idNumber}', employee.id)
.replaceAll('{duty}', employee.position);
}
// Replace table placeholder
String completeTable = permissionGivenPersonalTable
.replaceAll('{insert_row}', tableRows);
await docxUtil.replaceParagraph(
paragraphReplacements: {
'employeeTable': completeTable,
}
);
await docxUtil.saveDocx();
docxUtil.dispose();DocxUtil docxUtil = DocxUtil(
filePath: 'project_report.docx',
savePath: '/storage/project_output.docx',
isAsset: true,
);
// Create image pages
String imagePages = await docxUtil.createMultiTextBoxImages(
textBoxWidthCm: 15.0,
textBoxHeightCm: 10.0,
imageFiles: [
File('photo1.jpg'),
File('photo2.jpg'),
File('photo3.jpg'),
],
);
// Add title and images
String content = await docxUtil.createTextBoxImagesWithTitle(
title: 'Project Progress Photos',
titleFontSizeHalfPoints: 28,
titleBold: true,
textBoxWidthCm: 15.0,
textBoxHeightCm: 10.0,
imageFiles: [File('photo1.jpg'), File('photo2.jpg')],
);
await docxUtil.replaceParagraph(
paragraphReplacements: {
'photoSection': content,
}
);
await docxUtil.saveDocx();
docxUtil.dispose();The library relies on the following Flutter packages:
dependencies:
flutter:
sdk: flutter
archive: ^3.0.0 # ZIP compression/decompression
path: ^1.8.0 # Path manipulation
path_provider: ^2.0.0 # Temporary directory access
xml: ^6.0.0 # XML parsing and manipulation
image: ^4.0.0 # Image dimension detection// Convert centimeters to EMU (English Metric Units)
int emu = DocxUtil.cmToEmu(10.5); // 3780000 EMUConversion Formula: EMU = CM × 360,000
bool isValid = DocxUtil.isImage(filePath);
// Returns true for .png, .jpg, .jpeg- Each
DocxUtilinstance creates a unique temporary directory - Directory name includes timestamp to prevent conflicts
- Important: Always call
dispose()to clean up temporary files
- XML content is loaded lazily
- Modified content is cached to avoid redundant file I/O
- Images are referenced, not embedded multiple times
All I/O operations are asynchronous to prevent blocking the UI thread:
await docxUtil.replaceText(...); // Async
await docxUtil.replaceImage(...); // Async
await docxUtil.saveDocx(); // Async
docxUtil.dispose(); // Sync (cleanup)Always dispose of DocxUtil instances:
DocxUtil? docxUtil;
try {
docxUtil = DocxUtil(...);
await docxUtil.replaceText(...);
await docxUtil.saveDocx();
} finally {
docxUtil?.dispose();
}Keep template DOCX files in the assets/docs/ directory:
flutter:
assets:
- assets/docs/Always use the format: {key}
Use descriptive, camelCase keys:
In Word Template:
{companyName}
{employeeList}
{reportDate}
In Code:
await docxUtil.replaceText(
textReplacements: {
'companyName': 'ACME Corp', // Note: No curly braces in code
'employeeList': tableContent,
'reportDate': '2025-11-07',
}
);Important:
- Placeholders in Word documents include curly braces:
{key} - Keys in code do NOT include curly braces:
'key' - Placeholders are case-sensitive
try {
DocxUtil docxUtil = DocxUtil(...);
await docxUtil.replaceText(...);
await docxUtil.saveDocx();
return [true, "Document created successfully"];
} catch (e) {
return [false, e.toString()];
} finally {
docxUtil?.dispose();
}- Prefer PNG format for transparency support
- Ensure images are reasonably sized (not too large)
- Use
MsImageUtilfor automatic dimension management
DOCX files are ZIP archives containing XML files:
document.docx
├── word/
│ ├── document.xml # Main document content
│ ├── header1.xml # Header content
│ ├── footer1.xml # Footer content
│ ├── _rels/
│ │ └── document.xml.rels # Relationships
│ └── media/
│ └── image1.png # Embedded images
├── docProps/
│ └── core.xml # Document properties
└── [Content_Types].xml # MIME types
You can create custom XML templates by:
- Creating a Word document with the desired layout
- Saving as
.docx - Extracting the ZIP
- Copying the relevant XML structure
- Adding placeholders using
{keyName}format
Placeholder Format in Custom Templates:
When creating custom templates, always use the {key} format:
<!-- Example XML with placeholders -->
<w:t>{companyName}</w:t>
<w:t>Order Date: {orderDate}</w:t>
<w:t>Total: ${totalAmount}</w:t>Tips:
- Place placeholders where you want dynamic content
- Keep placeholder names descriptive and meaningful
- Use camelCase for consistency (e.g.,
{firstName},{orderTotal}) - Avoid special characters in placeholder names (stick to letters and numbers)
The library automatically manages relationships for:
- Images (media files)
- Headers and footers
- Embedded content
Each relationship has:
- ID: Unique identifier (e.g.,
rId7) - Type: Resource type (image, header, etc.)
- Target: Relative path to the resource
-
Supported Document Elements:
- Text and paragraphs ✅
- Images ✅
- Tables ✅
- Headers/Footers ✅
- Charts ❌
- SmartArt ❌
- Embedded objects ❌
-
Image Formats:
- PNG ✅
- JPG/JPEG ✅
- GIF ❌
- BMP ❌
- SVG ❌
-
File Size: Best suited for documents under 50MB
-
Concurrent Operations: Each
DocxUtilinstance should be used sequentially, not concurrently
Solution: Ensure the file is listed in pubspec.yaml:
flutter:
assets:
- assets/docs/template.docxSolution: Only PNG and JPG are supported. Convert images to these formats.
Solution: Ensure placeholder format and names match exactly:
Correct Format:
- Template (Word document):
{companyName} - Code:
'companyName': 'ACME Corp'(no braces in code)
Common Mistakes:
- ❌ Template:
{{companyName}}(double braces) - ❌ Template:
[companyName](wrong brackets) - ❌ Code:
'{companyName}': 'ACME'(braces in code key) - ❌ Mismatched case: Template
{CompanyName}vs Code'companyName'
Remember: Placeholders are case-sensitive!
Solution: Ensure you're not modifying the document after calling saveDocx().
Solution: Always call dispose() to clean up temporary files.
| Location | Format | Example |
|---|---|---|
| Word Template | {key} |
{companyName} |
| Dart Code (key) | 'key' |
'companyName' |
| Dart Code (value) | String/dynamic |
'ACME Corp' |
Complete Example:
// In your Word template: Hello {userName}, welcome to {companyName}!
await docxUtil.replaceText(
textReplacements: {
'userName': 'John', // Maps to {userName}
'companyName': 'ACME', // Maps to {companyName}
}
);
// Result: Hello John, welcome to ACME!| Type | Template Placeholder | Code Example |
|---|---|---|
| Text | {customerName} |
'customerName': 'John Doe' |
| Number | {orderTotal} |
'orderTotal': '1500' |
| Date | {invoiceDate} |
'invoiceDate': '2025-11-07' |
| Table | {employeeTable} |
'employeeTable': tableXML |
| Image | {companyLogo} |
'companyLogo': MsImageUtil(...) |
This library is designed to be extensible. To add new features:
- New Templates: Add XML templates to
ms_word_constant.dart - New Operations: Add methods to
DocxUtilclass - New Helpers: Create utility classes like
MsImageUtil
This project is open-source and available under the MIT License.
Anıl Kutay Uçan
Version: 1.0.0
Last Updated: November 7, 2025