Skip to content

erykkruk/camera_extensions

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

camera_extended

pub package likes popularity License: BSD-3

Extended Flutter camera plugin with native aspect ratio support (16:9, 4:3, 1:1).

Fork of the official camera package with sensor-level aspect ratio configuration for both iOS and Android.

Android iOS
Support SDK 24+ iOS 13.0+

What's New vs Original Camera Package

Feature camera camera_extended
Aspect Ratio Control No Yes (16:9, 4:3, 1:1)
Native 1:1 Square No Yes (Android)
Sensor-Level Config No Yes
In-Memory Capture No Yes (takePictureAsBytes())
Video Stabilization No Yes (VideoStabilizationMode)

Features

  • Native Aspect Ratio Selection - Configure camera aspect ratio at the sensor level
  • 1:1 Square Format - Native 1:1 on Android (1088x1088), falls back to 4:3 on iOS
  • 4:3 Standard Format - Classic aspect ratio with wider field of view
  • 16:9 Widescreen Format - Modern widescreen ratio
  • In-Memory Capture - takePictureAsBytes() returns raw Uint8List without saving to disk
  • Video Stabilization - Query and set stabilization modes per-device
  • Full compatibility with original camera package API

Why This Package?

The standard camera package doesn't allow you to configure the aspect ratio at the native level. This package extends it to:

  1. Request specific aspect ratios from the camera sensor
  2. Get wider field of view with 4:3 or 1:1 vs 16:9
  3. Capture square photos/videos natively on supported devices

Aspect Ratio Comparison

Ratio Field of View Use Case
16:9 Narrowest Video, Widescreen
4:3 Wider Photos, Standard
1:1 Square Social Media, Profile Photos

Installation

Add to your pubspec.yaml:

dependencies:
  camera_extended: ^1.2.0

Usage

Basic Setup

import 'package:camera_extended/camera_extended.dart';

late List<CameraDescription> cameras;

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  cameras = await availableCameras();
  runApp(MyApp());
}

Initialize with Aspect Ratio

final controller = CameraController(
  cameras.first,
  ResolutionPreset.high,
  enableAudio: false,
  aspectRatio: CameraAspectRatio.ratio4x3, // NEW: aspect ratio parameter
);

await controller.initialize();

Available Aspect Ratios

enum CameraAspectRatio {
  ratio16x9,    // 16:9 widescreen
  ratio4x3,     // 4:3 standard
  ratio1x1,     // 1:1 square
  ratioDefault, // Camera's default ratio
}

Complete Example

import 'package:camera_extended/camera_extended.dart';
import 'package:flutter/material.dart';

late List<CameraDescription> cameras;

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  cameras = await availableCameras();
  runApp(const CameraApp());
}

class CameraApp extends StatefulWidget {
  const CameraApp({super.key});

  @override
  State<CameraApp> createState() => _CameraAppState();
}

class _CameraAppState extends State<CameraApp> {
  CameraController? _controller;
  CameraAspectRatio _aspectRatio = CameraAspectRatio.ratio4x3;

  @override
  void initState() {
    super.initState();
    _initCamera();
  }

  Future<void> _initCamera() async {
    await _controller?.dispose();

    _controller = CameraController(
      cameras.first,
      ResolutionPreset.high,
      aspectRatio: _aspectRatio, // Set aspect ratio here
    );

    await _controller!.initialize();
    if (mounted) setState(() {});
  }

  void _changeAspectRatio(CameraAspectRatio ratio) {
    setState(() => _aspectRatio = ratio);
    _initCamera(); // Reinitialize camera with new ratio
  }

  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Column(
          children: [
            Expanded(
              child: _controller?.value.isInitialized == true
                  ? CameraPreview(_controller!)
                  : const Center(child: CircularProgressIndicator()),
            ),
            Padding(
              padding: const EdgeInsets.all(16),
              child: SegmentedButton<CameraAspectRatio>(
                segments: const [
                  ButtonSegment(value: CameraAspectRatio.ratio16x9, label: Text('16:9')),
                  ButtonSegment(value: CameraAspectRatio.ratio4x3, label: Text('4:3')),
                  ButtonSegment(value: CameraAspectRatio.ratio1x1, label: Text('1:1')),
                ],
                selected: {_aspectRatio},
                onSelectionChanged: (selected) => _changeAspectRatio(selected.first),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

In-Memory Capture

Capture an image directly as bytes without writing to disk — ideal for ML pipelines, image processing, or uploading:

final Uint8List bytes = await controller.takePictureAsBytes();
// Use bytes directly — no file I/O needed

Video Stabilization

Query supported stabilization modes and apply one:

// Check supported modes
final modes = await controller.getSupportedVideoStabilizationModes();

// Apply stabilization
await controller.setVideoStabilizationMode(VideoStabilizationMode.standard);

Available modes: off, standard, cinematic, cinematicExtended (availability depends on device).

Platform Support

Platform 16:9 4:3 1:1
Android Native Native Native (1088x1088)
iOS Native Native Fallback to 4:3

Android

Uses CameraX with ResolutionSelector to request specific aspect ratios. Many Android devices support native 1:1 formats (e.g., 1088x1088, 720x720).

iOS

Uses AVFoundation with format selection based on aspect ratio. iOS cameras typically don't offer native 1:1 formats, so 1:1 falls back to 4:3.

Permissions

Android

Add to AndroidManifest.xml:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

iOS

Add to Info.plist:

<key>NSCameraUsageDescription</key>
<string>Camera access is required for taking photos.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Microphone access is required for recording video.</string>

Migration from camera Package

This package is API-compatible with the original camera package. To migrate:

  1. Replace camera with camera_extended in pubspec.yaml
  2. Update imports: import 'package:camera_extended/camera_extended.dart'
  3. Optionally add aspectRatio parameter to CameraController
// Before (camera package)
import 'package:camera/camera.dart';
CameraController(camera, ResolutionPreset.high);

// After (camera_extended)
import 'package:camera_extended/camera_extended.dart';
CameraController(camera, ResolutionPreset.high, aspectRatio: CameraAspectRatio.ratio4x3);

Handling Lifecycle States

Same as the original camera package - you need to handle lifecycle changes:

@override
void didChangeAppLifecycleState(AppLifecycleState state) {
  final CameraController? cameraController = controller;

  if (cameraController == null || !cameraController.value.isInitialized) {
    return;
  }

  if (state == AppLifecycleState.inactive) {
    cameraController.dispose();
  } else if (state == AppLifecycleState.resumed) {
    _initCamera();
  }
}

Requirements

  • Flutter: >=3.35.0
  • Dart SDK: ^3.9.0

Related Packages

Package Description
camera_extended Main plugin (this package)
camera_extended_android Android implementation
camera_extended_ios iOS implementation
camera_extended_platform_interface Platform interface

License

BSD 3-Clause License - same as the original Flutter camera package.

Credits

Based on the official Flutter camera plugin by the Flutter team.

Extended with native aspect ratio support.


Made with love by Codigee

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors