optimizeToFile method
Future<CPDFOptimizeResult>
optimizeToFile(
- String outputPath, {
- CPDFOptimizeOptions? options,
- bool fontSubset = false,
- void onProgress(
- int pageIndex
Optimizes the document and writes the result to outputPath, leaving the
file the document was opened from untouched.
outputPathmust be writable, its parent directory must exist, and it must differ from the path of the current document.- When
optionsis null the options currently held by the native document are used. fontSubsetembeds only the glyphs the document actually uses.- The native SDK leaves the opened document unusable once the copy is
written. This method reopens it from its original source before
returning, so a mounted reader keeps working. Unsaved changes are lost
in the process: call save first if they must be kept. If the reopen
fails the call throws with code
OPTIMIZE_RESTORE_FAILED; the output file is still valid, but the in memory document must be closed and reopened rather than saved. - Call cancelOptimize to stop a run early. A cancelled run resolves
normally with CPDFOptimizeResult.cancelled set to
true. - Only one optimization run per document may be in flight. A second call
throws with code
OPTIMIZE_ALREADY_RUNNING. - The default flag set is lossy: it removes every bookmark and every JavaScript action. See CPDFOptimizeFlag.defaults.
Since v3.2.0
Platform differences:
- iOS ignores
fontSubset; the native SDK always writes without font subsetting. - iOS allows one optimization run at a time across all documents, Android
one run per document. A second run fails with
OPTIMIZE_ALREADY_RUNNING.
example:
final result = await document.optimizeToFile(
'/path/to/optimized.pdf',
onProgress: (pageIndex) => debugPrint('page $pageIndex'),
);
Implementation
Future<CPDFOptimizeResult> optimizeToFile(
String outputPath, {
CPDFOptimizeOptions? options,
bool fontSubset = false,
void Function(int pageIndex)? onProgress,
}) async {
// The trimmed value is both validated and forwarded, so the path the native
// side resolves is exactly the one that passed this check.
final trimmedOutputPath = outputPath.trim();
if (trimmedOutputPath.isEmpty) {
throw const CPDFOptimizeException(
'INVALID_OUTPUT_PATH',
'outputPath must not be empty.',
);
}
// Only the call that actually installed the listener may replace or clear
// it. The native side allows a single run per document, so a second,
// overlapping call is rejected anyway; letting it touch the listener would
// silently stop the progress of the run that is still in flight. The
// listener is always torn down afterwards, so a failed run cannot leave a
// stale listener behind.
final ownsListener =
onProgress != null && _optimizeProgressListener == null;
if (ownsListener) {
_ensureNativeCallHandler();
_optimizeProgressListener = onProgress;
}
try {
final result = await _channel.invokeMethod('optimize_document_to_file', {
'output_path': trimmedOutputPath,
'font_subset': fontSubset,
if (options != null) 'options': options.toJson(),
});
if (result is Map) {
return CPDFOptimizeResult.fromJson(result);
}
throw const CPDFOptimizeException(
'OPTIMIZE_FAILED',
'The native side returned no optimize result.',
);
} on PlatformException catch (e) {
throw CPDFOptimizeException(e.code, e.message ?? '');
} finally {
if (ownsListener) {
_optimizeProgressListener = null;
}
}
}