file_compression_plus 1.0.0 copy "file_compression_plus: ^1.0.0" to clipboard
file_compression_plus: ^1.0.0 copied to clipboard

Compress images and PDFs in Flutter. Hit an exact target file size, batch compress with progress, convert JPG PNG WebP HEIC, and shrink PDF documents.

File Compression Plus

Compress images and PDF files in Flutter.
Pick a file, get a smaller one back. No plugin registration, no platform setup, no native code.

pub version pub points pub likes downloads per month

platforms CI status license MIT open issues

final smaller = await FileCompressor.compressImage(file: photo);

Built and maintained by Tisankan Jeyakumar.

Why this package #

Most compression packages give you a quality slider and stop there. Real apps need more than that, so this one covers the jobs you actually hit:

You need to Use
Make a photo smaller compressImage
Get a file under an upload limit compressImageToTargetSize
Compress a whole gallery selection compressBatch with progress
Compress bytes you never wrote to disk compressImageBytes
Shrink a PDF compressPdf
Handle a picked file without checking its type compress
Show the user what was saved CompressionResult, formatBytes

It also refuses to hand you a file that got bigger, which is what happens when you compress an already optimised JPEG. That is on by default.

Features #

  • Images: JPG, PNG, WebP and HEIC, with quality, resizing and rotation
  • Target file size: say "under 1 MB" and it finds the best quality that fits
  • Batch compression with per-file progress and per-file error collection
  • Bytes in, bytes out for images and PDFs, no disk needed
  • PDF compression with three levels, plus optional metadata stripping
  • Never returns a larger file than it was given
  • Format conversion, for example PNG to JPG or JPG to HEIC
  • Size reporting: before, after, bytes saved, percentage saved
  • Choose the output path, or let the package use the temporary directory
  • Optionally delete the original after a successful compression

Platform support #

Platform Image PDF
Android Yes Yes
iOS Yes Yes
macOS Yes, no WebP Yes
Linux Yes, needs flutter_image_compress_linux Yes
Windows No Yes
Web No No

Image compression runs through flutter_image_compress, which uses the platform image encoders. PDF compression is pure Dart, so it works anywhere dart:io is available. This package uses dart:io, so it does not support web.

Two platform notes worth knowing before you ship:

  • macOS needs a deployment target of 10.15 or higher for image compression, and it cannot encode WebP. Use ImageFormat.jpg or ImageFormat.png there.
  • Linux image compression needs the community package flutter_image_compress_linux in your app. Without it the call throws UnimplementedError.

Install #

flutter pub add file_compression_plus

Or add it to pubspec.yaml:

dependencies:
  file_compression_plus: ^1.0.0

There is nothing else to configure. This is a plain Dart package, not a plugin.

Usage #

Compress an image #

import 'dart:io';
import 'package:file_compression_plus/file_compression_plus.dart';

final compressed = await FileCompressor.compressImage(
  file: File('/path/to/photo.jpg'),
);

print(compressed.path);

Compress an image with your own settings #

final compressed = await FileCompressor.compressImage(
  file: File('/path/to/photo.png'),
  quality: 70,              // 0 to 100, lower means smaller
  maxWidth: 1280,           // the image fits inside this box
  maxHeight: 720,
  format: ImageFormat.jpg,  // convert PNG to JPG
  rotate: 90,               // turn it clockwise while compressing
  outputPath: '/path/to/output/photo.jpg',
  keepExif: true,           // keep camera metadata
  skipIfLarger: true,       // never hand back a bigger file
  deleteOriginal: false,
);

Hit an exact file size #

The most common real requirement: the server rejects anything over 1 MB.

final result = await FileCompressor.compressImageToTargetSize(
  file: photo,
  targetBytes: 1024 * 1024,
);

if (result.compressedSize <= 1024 * 1024) {
  await upload(result.file);
} else {
  // The picture could not be squeezed that far. Tell the user.
}

It binary searches the quality range, so you keep the highest quality that still fits rather than a guessed number. If even the lowest quality is too big it halves the dimensions and searches again, up to three times by default.

This runs the encoder several times, so it is slower than a plain compressImage. Worth it when a hard limit is involved.

Compress many files with progress #

final batch = await FileCompressor.compressBatch(
  files: pickedFiles,
  quality: 75,
  outputDirectory: cacheDir.path,
  onProgress: (progress) {
    setState(() => _progress = progress.fraction);
  },
);

print('${batch.successes.length} compressed, ${batch.failures.length} failed');
print('Saved ${formatBytes(batch.totalSavedBytes)}');

for (final failure in batch.failures) {
  print('${failure.file.path} failed: ${failure.error}');
}

Each file is routed to the image or the PDF compressor by its extension. One bad file does not stop the run, it lands in failures instead. Files are processed one at a time on purpose, because running many native encoders at once is a good way to run a phone out of memory.

Work with bytes, not files #

For an image you downloaded, received from a camera stream, or are about to upload straight to a server.

final smaller = await FileCompressor.compressImageBytes(
  bytes: downloadedBytes,
  quality: 70,
  format: ImageFormat.jpg,
);

await http.post(uri, body: smaller);

The same works for PDFs with compressPdfBytes. Nothing touches the disk.

Compress a PDF #

final compressed = await FileCompressor.compressPdf(
  file: File('/path/to/document.pdf'),
  compressionLevel: PdfCompressionLevel.best,
  removeMetadata: true, // clears title, author, creator and the rest
);

Handle any picked file #

When the file comes from a picker and you do not know the type up front:

if (FileCompressor.canCompress(file)) {
  final result = await FileCompressor.compress(file: file);
  print(result); // 4.2 MB -> 380.1 KB, saved 91.2%
}

Show the user what happened #

final result = await FileCompressor.compressImageWithResult(file: photo);

Text('${result.readableOriginalSize} to ${result.readableCompressedSize}');
Text('Saved ${result.savedPercentage.toStringAsFixed(1)} percent');

if (result.wasSkipped) {
  Text('This file was already as small as it gets.');
}

API #

Image methods #

Method Returns Use it for
compressImage File The everyday case
compressImageWithResult CompressionResult When you want the sizes too
compressImageBytes Uint8List In-memory images, no disk
compressImageToTargetSize CompressionResult Upload limits

compressImage parameters:

Parameter Type Default Description
file File required The image to compress
quality int 80 0 to 100. Ignored for PNG output, PNG is lossless
maxWidth int 1920 Maximum output width, aspect ratio kept
maxHeight int 1080 Maximum output height, aspect ratio kept
format ImageFormat? source format jpg, png, webp or heic
rotate int 0 Degrees clockwise
outputPath String? temporary directory Exact output path, folders created
keepExif bool false Keep camera metadata
skipIfLarger bool true Keep the original if compression grows it
deleteOriginal bool false Delete the source after success

compressImageToTargetSize adds:

Parameter Type Default Description
targetBytes int required The size budget to fit inside
minQuality int 10 Lowest quality it will accept
maxQuality int 95 Highest quality it will try
allowDownscale bool true Halve the size when quality alone is not enough
maxDownscaleSteps int 3 How many times it may halve

PDF methods #

Method Returns Use it for
compressPdf File The everyday case
compressPdfWithResult CompressionResult When you want the sizes too
compressPdfBytes Uint8List In-memory documents, no disk
Parameter Type Default Description
file File required The PDF to compress
compressionLevel PdfCompressionLevel best none, normal or best
removeMetadata bool false Clear title, author, subject, keywords, creator, producer
outputPath String? temporary directory Exact output path, folders created
skipIfLarger bool true Keep the original if compression grows it
deleteOriginal bool false Delete the source after success

Any file #

Member Description
compress Routes to the image or PDF compressor by extension
compressBatch Compresses a list of files with progress
canCompress(file) True when the extension is supported
supportedExtensions Every extension this package handles
supportedImageExtensions Just the image extensions

CompressionResult #

Member Type Description
file File The compressed file
path String Path of the compressed file
originalSize int Source size in bytes
compressedSize int Output size in bytes
savedBytes int Bytes saved
savedPercentage double Percentage saved, 0 to 100
wasSkipped bool True when the original was kept because compression grew it
readableOriginalSize String For example 2.4 MB
readableCompressedSize String For example 310.5 KB

BatchCompressionResult #

Member Type Description
successes List<CompressionResult> Files that compressed
failures List<CompressionFailure> Files that failed, with the reason
totalFiles int Successes plus failures
totalOriginalSize int Combined source size
totalCompressedSize int Combined output size
totalSavedBytes int Combined bytes saved
savedPercentage double Percentage saved across the batch
isCompleteSuccess bool True when nothing failed

BatchProgress #

Member Type Description
completed int Files finished so far
total int Files in the batch
file File The file that just finished
result CompressionResult? Its result, or null when it failed
fraction double 0.0 to 1.0, ready for a progress bar
percentage int 0 to 100

Helpers #

formatBytes(int bytes, {int decimals = 1}) turns a byte count into something a user can read: formatBytes(2517000) gives 2.4 MB.

Errors #

Error When it is thrown
ArgumentError Quality outside 0 to 100, a size limit of zero or less, an unsupported file extension, empty bytes, or an invalid quality range
FileSystemException The file is missing, empty, not a readable PDF, or the encoder returned no data
UnsupportedError The platform cannot encode the requested format. WebP on macOS, HEIC on most devices
try {
  final compressed = await FileCompressor.compressImage(
    file: source,
    format: ImageFormat.heic,
  );
} on UnsupportedError {
  // This device cannot write HEIC. Fall back to JPEG.
  final compressed = await FileCompressor.compressImage(
    file: source,
    format: ImageFormat.jpg,
  );
} on ArgumentError catch (error) {
  // Bad settings or an unsupported file type.
} on FileSystemException catch (error) {
  // Missing file, empty file, or the encoder failed.
}

In a batch, none of these stop the run. They collect in failures.

Notes and limits #

  • Without outputPath the result goes to the temporary directory, which the operating system may clear at any time. Copy the file somewhere permanent if you need to keep it.
  • Compression cannot shrink every file. An already optimised image or PDF may come out larger. skipIfLarger is on by default, so you get the original back with wasSkipped set instead of a worse file.
  • PDF compression packs the document streams. It does not re-encode images that are already embedded in the PDF, so a PDF full of large photos will not shrink much. That needs image extraction, which the underlying PDF library does not expose.
  • quality does nothing for PNG output. PNG is lossless. To shrink a PNG, lower maxWidth and maxHeight, or convert it with format: ImageFormat.jpg.
  • HEIC output throws UnsupportedError on most devices. Always catch it and fall back to JPEG.
  • compressImageToTargetSize runs the encoder about seven times, plus once per downscale step. Do not call it in a tight loop over hundreds of files.

Example #

A runnable demo is in example/. It covers single file compression, batch compression with a progress bar, and target size compression.

Testing #

The package ships 54 tests covering argument validation, file handling, batch behaviour, PDF compression and the result models.

Image compression calls the native platform encoders, so it cannot run in a plain flutter test process. Those paths are covered by the example app on a real device rather than by a unit test that would only ever assert against a mock.

flutter test

Dependencies #

  • flutter_image_compress for image compression
  • syncfusion_flutter_pdf for PDF compression. Syncfusion is free under their community licence for small teams and paid otherwise. Check their licence before shipping a commercial app.

Documentation #

Document What is in it
Recipes Copy and paste solutions for the common jobs
Migration guide Moving from 0.0.x to 1.0.0
Changelog What changed in every release
Contributing How to report a bug or send a pull request
API reference Generated Dart docs

Contributors wanted #

This package is actively maintained and open to contributors. If you would like to help, get in touch at hello@tisankan.dev and tell me what you want to work on. New contributors are welcome, including first time open source contributors.

Areas where help is genuinely useful right now:

Area What is needed
Windows image support Wire up a Windows encoder so images work there, not only PDFs
Web support A dart:io free path so the package runs on Flutter web
PDF image downsampling Re-encode images embedded inside a PDF for much bigger savings
Integration tests Device tests for the image paths that unit tests cannot reach
Documentation More recipes, translations, and worked examples
Benchmarks Real numbers for compression time and output size per platform

Pick anything from the list, or open an issue with your own idea. Small pull requests are just as welcome as large ones.

Before opening a pull request:

flutter analyze
flutter test
dart format .

Full guide in CONTRIBUTING.md.

Support #

If this package saved you time, a like on pub.dev helps other developers find it.

Author #

Tisankan Jeyakumar Tisankan Jeyakumar
Chief Technical Officer, Yarl Ventures (PVT) Ltd
tisankan.dev  |  hello@tisankan.dev  |  GitHub

Building production Flutter and Node.js systems for education, healthcare and commerce. Available for consulting at hello@tisankan.dev.

License #

MIT. Copyright (c) Tisankan Jeyakumar. See LICENSE.

4
likes
160
points
158
downloads

Documentation

Documentation
API reference

Publisher

verified publishertisankan.dev

Weekly Downloads

Compress images and PDFs in Flutter. Hit an exact target file size, batch compress with progress, convert JPG PNG WebP HEIC, and shrink PDF documents.

Repository (GitHub)
View/report issues

Topics

#compression #image #pdf #file #optimization

License

MIT (license)

Dependencies

flutter, flutter_image_compress, path, path_provider, syncfusion_flutter_pdf

More

Packages that depend on file_compression_plus