flutter_image_quality 0.0.1
flutter_image_quality: ^0.0.1 copied to clipboard
A Flutter package for image quality analysis, blur detection, brightness detection, and smart JPEG compression.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_image_quality/flutter_image_quality.dart';
import 'package:image_picker/image_picker.dart';
void main() {
runApp(const ImageQualityExampleApp());
}
class ImageQualityExampleApp extends StatelessWidget {
const ImageQualityExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Image Quality',
theme: ThemeData(
useMaterial3: true,
),
home: const ImageQualityHomePage(),
);
}
}
class ImageQualityHomePage extends StatefulWidget {
const ImageQualityHomePage({super.key});
@override
State<ImageQualityHomePage> createState() => _ImageQualityHomePageState();
}
class _ImageQualityHomePageState
extends State<ImageQualityHomePage> {
File? selectedImage;
ImageQualityResult? qualityResult;
CompressedImageResult? compressionResult;
bool analyzing = false;
bool compressing = false;
Future<void> pickImage() async {
final picker = ImagePicker();
final result = await picker.pickImage(
source: ImageSource.gallery,
);
if (result == null) {
return;
}
setState(() {
selectedImage = File(result.path);
qualityResult = null;
compressionResult = null;
});
}
Future<void> analyzeImage() async {
final file = selectedImage;
if (file == null) {
return;
}
setState(() {
analyzing = true;
});
try {
final result =
await FlutterImageQuality.analyze(
file,
);
if (!mounted) {
return;
}
setState(() {
qualityResult = result;
});
} finally {
if (mounted) {
setState(() {
analyzing = false;
});
}
}
}
Future<void> compressImage() async {
final file = selectedImage;
if (file == null) {
return;
}
setState(() {
compressing = true;
});
try {
final result = await FlutterImageQuality.compress(
file,
maxSizeKB: 500,
);
debugPrint("======= Result ========");
debugPrint("${result.bytes }");
if (!mounted) {
return;
}
setState(() {
compressionResult = result;
});
} finally {
if (mounted) {
setState(() {
compressing = false;
});
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
'Flutter Image Quality',
),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.stretch,
children: [
ElevatedButton.icon(
onPressed: pickImage,
icon: const Icon(
Icons.photo_library,
),
label: const Text(
'Select Image',
),
),
const SizedBox(height: 20),
if (selectedImage != null)
ClipRRect(
borderRadius:
BorderRadius.circular(16),
child: Image.file(
selectedImage!,
height: 300,
fit: BoxFit.contain,
),
),
if (selectedImage != null) ...[
const SizedBox(height: 20),
FilledButton.icon(
onPressed:
analyzing ? null : analyzeImage,
icon: const Icon(
Icons.analytics,
),
label: Text(
analyzing
? 'Analyzing...'
: 'Analyze Image',
),
),
const SizedBox(height: 10),
FilledButton.icon(
onPressed:
compressing
? null
: compressImage,
icon: const Icon(
Icons.compress,
),
label: Text(
compressing
? 'Compressing...'
: 'Compress to 500 KB',
),
),
],
if (qualityResult != null) ...[
const SizedBox(height: 25),
_QualityCard(
result: qualityResult!,
),
],
if (compressionResult != null) ...[
const SizedBox(height: 20),
_CompressionCard(
result: compressionResult!,
),
],
],
),
),
);
}
}
class _QualityCard extends StatelessWidget {
final ImageQualityResult result;
const _QualityCard({
required this.result,
});
@override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.all(18),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
const Text(
'Image Quality',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 15),
Text(
'Blur Score: '
'${result.blurScore.toStringAsFixed(2)}',
),
Text(
'Brightness: '
'${result.brightness.toStringAsFixed(2)}',
),
const SizedBox(height: 12),
_ResultRow(
title: 'Blurred',
value: result.isBlurred,
),
_ResultRow(
title: 'Too Dark',
value: result.isTooDark,
),
_ResultRow(
title: 'Too Bright',
value: result.isTooBright,
),
],
),
),
);
}
}
class _CompressionCard extends StatelessWidget {
final CompressedImageResult result;
const _CompressionCard({
required this.result,
});
@override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.all(18),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
const Text(
'Compression',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 15),
Text(
'Original: '
'${_formatBytes(result.originalSize)}',
),
Text(
'Compressed: '
'${_formatBytes(result.compressedSize)}',
),
Text(
'JPEG Quality: '
'${result.quality}',
),
Text(
'Reduction: '
'${result.compressionPercentage.toStringAsFixed(1)}%',
),
],
),
),
);
}
String _formatBytes(int bytes) {
if (bytes < 1024) {
return '$bytes B';
}
if (bytes < 1024 * 1024) {
return '${(bytes / 1024).toStringAsFixed(1)} KB';
}
return '${(bytes / (1024 * 1024)).toStringAsFixed(2)} MB';
}
}
class _ResultRow extends StatelessWidget {
final String title;
final bool value;
const _ResultRow({
required this.title,
required this.value,
});
@override
Widget build(BuildContext context) {
return Row(
children: [
Icon(
value
? Icons.cancel
: Icons.check_circle,
),
const SizedBox(width: 8),
Text('$title: ${value ? "Yes" : "No"}'),
],
);
}
}