Open In App

Flutter – Build an Image Compressor App

Last Updated : 06 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Many applications accept images of small size, to reduce image size we use different online applications to compress images while maintaining their quality. In this article, we will be creating an Image compressor app in Flutter that will compress images with the help of available libraries in Flutter.

Step-by-Step Implementation

Step 1: Create a Project

From the terminal create a flutter project using the following command:

flutter create imagecompressor

Step 2: Add package

First, we need to add all dependencies required for this project in pubspec.yaml file. This can be done using the below command:

flutter pub add flutter_image_compress file_picker gallery_saver

Step 3: Import dependencies

To use libraries, import all of them in main.dart file,

import 'package:flutter_image_compress/flutter_image_compress.dart';
import 'package:file_picker/file_picker.dart';
import 'package:gallery_saver/gallery_saver.dart';

Step 4: Add permissions

To access device files and save images after compression in gallery, we need to allow read and write permissions to device storage. In AndroidManifest.xml file, inside <manifest> add following lines:-

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Step 5: Create Basic Widget

Now, create basic view, from which user can upload image and download compressed image.

Dart




class MyApp extends StatelessWidget {
  const MyApp({super.key});
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter App',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.green),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Image Compressor'),
    );
  }
}
  
class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;
  
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}
  
class _MyHomePageState extends State<MyHomePage> {
  @override
  void initState() {
    super.initState();
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(
          widget.title,
          style: TextStyle(color: Colors.white),
        ),
      ),
      body: Center(
          child: Column(
        children: <Widget>[
          Padding(
            padding: EdgeInsets.all(20),
            child: ElevatedButton(
              onPressed: () {
                print("hello!");
              },
              child: const Text('Pick a File'),
            ),
          )
        ],
      )),
    );
  }
}


Output:

Screenshot_1697705311

Step 6: Compress Image

Create function _pickFile(), using which we will select file from device.

Dart




Future<File> _pickFile() async {
    FilePickerResult? result = await FilePicker.platform.pickFiles();
  
    if (result != null) {
      PlatformFile file = result.files.first;
       File pickedFile = File(file.path!);
      await compressImage(pickedFile);
      return File(compressedImage!.path);
    } else {
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("No file picked!")));
      
      throw Exception('No file picked');
    }
  }


Create another function compressImage() which takes file as input, and then compress it.

Dart




Future<void>  compressImage(File file) async {
     
    final filePath = file.absolute.path;
    final lastIndex = filePath.lastIndexOf(RegExp(r'.jp'));
    final splitted = filePath.substring(0, (lastIndex));
    final outPath = "${splitted}_out${filePath.substring(lastIndex)}";
  
     compressedImage = await FlutterImageCompress.compressAndGetFile(
          filePath, 
          outPath,
          minWidth: 1000,
          minHeight: 1000,
          quality: 70);
}


Create _saveLocalImage() function, which will be invoked when user clicks on download button. It will save the compressed image in device gallery.

Full Source Code

Dart




import 'dart:io';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
import 'package:file_picker/file_picker.dart';
import 'package:gallery_saver/gallery_saver.dart';
  
void main() {
  runApp(const MyApp());
}
  
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.green),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Image Compressor'),
    );
  }
}
  
class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
   final String title;
  
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}
  
class _MyHomePageState extends State<MyHomePage> {
var key = GlobalKey();
    XFile? compressedImage;
     File? image;
      
  Future<void>  compressImage(File file) async {
     
    final filePath = file.absolute.path;
    final lastIndex = filePath.lastIndexOf(RegExp(r'.jp'));
    final splitted = filePath.substring(0, (lastIndex));
    final outPath = "${splitted}_out${filePath.substring(lastIndex)}";
  
     compressedImage = await FlutterImageCompress.compressAndGetFile(
          filePath, 
          outPath,
          minWidth: 1000,
          minHeight: 1000,
          quality: 70);
}
  
Future<void> _saveLocalImage() async {
  
    try {
     GallerySaver.saveImage(compressedImage!.path);
     ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Image Saved to Galery!")));
     print(compressedImage!.path);
    } catch (e) {
      print('Error: $e');
       ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Error ocurred. Try again!")));
      
    }
  }
    
  Future<File> _pickFile() async {
    FilePickerResult? result = await FilePicker.platform.pickFiles();
  
    if (result != null) {
      PlatformFile file = result.files.first;
       File pickedFile = File(file.path!);
      await compressImage(pickedFile);
      return File(compressedImage!.path);
    } else {
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("No file picked!")));
      
      throw Exception('No file picked');
    }
  }
  
  @override
  void initState() {
    super.initState();
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
      backgroundColor: Theme.of(context).colorScheme.inversePrimary,
       title: Text(widget.title,style: TextStyle(color: Colors.white),),
      ),
      body: Center(
        child:  Column(
          children: <Widget>[
             ElevatedButton(
          onPressed:() {
                _pickFile().then((compressedFile) {
                  setState(() {
                    image = compressedFile;
                  });
                }).catchError((error) {
                  print('Error: $error');
                });
              },
          child: const Text('Pick a File'),
        ),
        Container(
          height: 450,
          width: 300,
        child: image != null
                ? Column(
                  children:[
                    Image.file(image!,width: 300,height: 400,)
                    ,
                    ElevatedButton(
                      onPressed:_saveLocalImage,
                      child:const Text("Download")
                    )
                  ]
                )
                : const Center(child: Text('No image selected')),
        )
          ],
        )),
    );
  }
}


Output Video:



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads