Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/camera/camera/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.12.1

* Adds `setImageQuality` for controlling JPEG compression quality.

## 0.12.0

* Adds support for video stabilization.
Expand Down
6 changes: 6 additions & 0 deletions packages/camera/camera/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,9 @@ dev_dependencies:

flutter:
uses-material-design: true
# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins
dependency_overrides:
camera_android_camerax: {path: ../../../../packages/camera/camera_android_camerax}
camera_avfoundation: {path: ../../../../packages/camera/camera_avfoundation}
camera_platform_interface: {path: ../../../../packages/camera/camera_platform_interface}
18 changes: 18 additions & 0 deletions packages/camera/camera/lib/src/camera_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,24 @@ class CameraController extends ValueNotifier<CameraValue> {
}
}

/// Sets the JPEG compression quality for still image capture.
///
/// The [quality] must be between 1 (lowest) and 100 (highest).
Future<void> setImageQuality(int quality) async {
if (quality < 1 || quality > 100) {
throw ArgumentError.value(
quality,
'quality',
'Must be between 1 and 100.',
);
}
try {
await CameraPlatform.instance.setImageQuality(_cameraId, quality);
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
}

/// Check whether the camera platform supports image streaming.
bool supportsImageStreaming() =>
CameraPlatform.instance.supportsImageStreaming();
Expand Down
14 changes: 10 additions & 4 deletions packages/camera/camera/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: A Flutter plugin for controlling the camera. Supports previewing
Dart.
repository: https://github.com/flutter/packages/tree/main/packages/camera/camera
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
version: 0.12.0
version: 0.12.1

environment:
sdk: ^3.9.0
Expand All @@ -21,9 +21,9 @@ flutter:
default_package: camera_web

dependencies:
camera_android_camerax: ^0.7.0
camera_avfoundation: ^0.10.0
camera_platform_interface: ^2.12.0
camera_android_camerax: ^0.7.1
camera_avfoundation: ^0.10.1
camera_platform_interface: ^2.13.0
camera_web: ^0.3.3
flutter:
sdk: flutter
Expand All @@ -38,3 +38,9 @@ dev_dependencies:

topics:
- camera
# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins
dependency_overrides:
camera_android_camerax: {path: ../../../packages/camera/camera_android_camerax}
camera_avfoundation: {path: ../../../packages/camera/camera_avfoundation}
camera_platform_interface: {path: ../../../packages/camera/camera_platform_interface}
3 changes: 3 additions & 0 deletions packages/camera/camera/test/camera_preview_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ class FakeController extends ValueNotifier<CameraValue>
Future<Iterable<VideoStabilizationMode>>
getSupportedVideoStabilizationModes() async => <VideoStabilizationMode>[];

@override
Future<void> setImageQuality(int quality) async {}

@override
bool supportsImageStreaming() => true;
}
Expand Down
83 changes: 83 additions & 0 deletions packages/camera/camera/test/camera_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,83 @@ void main() {
},
);

test('setImageQuality() calls $CameraPlatform', () async {
final cameraController = CameraController(
const CameraDescription(
name: 'cam',
lensDirection: CameraLensDirection.back,
sensorOrientation: 90,
),
ResolutionPreset.max,
);
await cameraController.initialize();

await cameraController.setImageQuality(50);

verify(
CameraPlatform.instance.setImageQuality(cameraController.cameraId, 50),
).called(1);
});

test(
'setImageQuality() throws $CameraException on $PlatformException',
() async {
final cameraController = CameraController(
const CameraDescription(
name: 'cam',
lensDirection: CameraLensDirection.back,
sensorOrientation: 90,
),
ResolutionPreset.max,
);
await cameraController.initialize();

when(
CameraPlatform.instance.setImageQuality(
cameraController.cameraId,
50,
),
).thenThrow(
PlatformException(
code: 'TEST_ERROR',
message: 'This is a test error message',
),
);

expect(
cameraController.setImageQuality(50),
throwsA(
isA<CameraException>().having(
(CameraException error) => error.description,
'TEST_ERROR',
'This is a test error message',
),
),
);
},
);

test('setImageQuality() throws ArgumentError for invalid values', () async {
final cameraController = CameraController(
const CameraDescription(
name: 'cam',
lensDirection: CameraLensDirection.back,
sensorOrientation: 90,
),
ResolutionPreset.max,
);
await cameraController.initialize();

expect(
() => cameraController.setImageQuality(0),
throwsA(isA<ArgumentError>()),
);
expect(
() => cameraController.setImageQuality(101),
throwsA(isA<ArgumentError>()),
);
});

test('setExposureMode() calls $CameraPlatform', () async {
final cameraController = CameraController(
const CameraDescription(
Expand Down Expand Up @@ -4152,6 +4229,12 @@ class MockCameraPlatform extends Mock
) async => super.noSuchMethod(
Invocation.method(#setVideoStabilizationMode, <Object?>[cameraId, mode]),
);

@override
Future<void> setImageQuality(int? cameraId, int? quality) async =>
super.noSuchMethod(
Invocation.method(#setImageQuality, <Object?>[cameraId, quality]),
);
}

class MockCameraDescription extends CameraDescription {
Expand Down
4 changes: 4 additions & 0 deletions packages/camera/camera_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.10.11

* Adds `setImageQuality` for controlling JPEG compression quality.

## 0.10.10+15

* Updates example to demonstrate correct exception handling for async return statements, ensuring exceptions thrown during return within try blocks are properly caught as per [dart-lang/sdk#44395](https://github.com/dart-lang/sdk/issues/44395).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import io.flutter.plugins.camera.features.flash.FlashMode;
import io.flutter.plugins.camera.features.focuspoint.FocusPointFeature;
import io.flutter.plugins.camera.features.fpsrange.FpsRangeFeature;
import io.flutter.plugins.camera.features.jpegquality.JpegQualityFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionPreset;
import io.flutter.plugins.camera.features.sensororientation.DeviceOrientationManager;
Expand Down Expand Up @@ -1407,6 +1408,20 @@ public void setDescriptionWhileRecording(CameraProperties properties) {
}
}

/**
* Sets the JPEG compression quality for still image capture.
*
* @param quality JPEG quality value between 1 and 100.
*/
public void setImageQuality(@NonNull Long quality) {
JpegQualityFeature jpegQualityFeature = cameraFeatures.getJpegQuality();
if (jpegQualityFeature == null) {
jpegQualityFeature = cameraFeatureFactory.createJpegQualityFeature(cameraProperties);
cameraFeatures.setJpegQuality(jpegQualityFeature);
}
jpegQualityFeature.setValue(quality.intValue());
}

public void dispose() {
Log.i(TAG, "dispose");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,11 @@ public void setDescriptionWhileRecording(@NonNull String cameraName) {
}
}

@Override
public void setImageQuality(@NonNull Long quality) {
camera.setImageQuality(quality);
}

@Override
public void dispose() {
if (camera != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2013 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Autogenerated from Pigeon (v26.1.0), do not edit directly.
// Autogenerated from Pigeon (v26.1.8), do not edit directly.
// See also: https://pub.dev/packages/pigeon

package io.flutter.plugins.camera;
Expand Down Expand Up @@ -1048,6 +1048,8 @@ void create(
* <p>This should be called only while video recording is active.
*/
void setDescriptionWhileRecording(@NonNull String description);
/** Sets the JPEG compression quality for still image capture. */
void setImageQuality(@NonNull Long quality);

/** The codec used by CameraApi. */
static @NonNull MessageCodec<Object> getCodec() {
Expand Down Expand Up @@ -1778,6 +1780,31 @@ public void error(Throwable error) {
channel.setMessageHandler(null);
}
}
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.camera_android.CameraApi.setImageQuality"
+ messageChannelSuffix,
getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<>();
ArrayList<Object> args = (ArrayList<Object>) message;
Long qualityArg = (Long) args.get(0);
try {
api.setImageQuality(qualityArg);
wrapped.add(0, null);
} catch (Throwable exception) {
wrapped = wrapError(exception);
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
}
}
}
}
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import io.flutter.plugins.camera.features.flash.FlashFeature;
import io.flutter.plugins.camera.features.focuspoint.FocusPointFeature;
import io.flutter.plugins.camera.features.fpsrange.FpsRangeFeature;
import io.flutter.plugins.camera.features.jpegquality.JpegQualityFeature;
import io.flutter.plugins.camera.features.noisereduction.NoiseReductionFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionPreset;
Expand Down Expand Up @@ -157,4 +158,14 @@ ExposurePointFeature createExposurePointFeature(
*/
@NonNull
NoiseReductionFeature createNoiseReductionFeature(@NonNull CameraProperties cameraProperties);

/**
* Creates a new instance of the JPEG quality feature.
*
* @param cameraProperties instance of the CameraProperties class containing information about the
* cameras features.
* @return newly created instance of the JpegQualityFeature class.
*/
@NonNull
JpegQualityFeature createJpegQualityFeature(@NonNull CameraProperties cameraProperties);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import io.flutter.plugins.camera.features.flash.FlashFeature;
import io.flutter.plugins.camera.features.focuspoint.FocusPointFeature;
import io.flutter.plugins.camera.features.fpsrange.FpsRangeFeature;
import io.flutter.plugins.camera.features.jpegquality.JpegQualityFeature;
import io.flutter.plugins.camera.features.noisereduction.NoiseReductionFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionPreset;
Expand Down Expand Up @@ -105,4 +106,10 @@ public NoiseReductionFeature createNoiseReductionFeature(
@NonNull CameraProperties cameraProperties) {
return new NoiseReductionFeature(cameraProperties);
}

@NonNull
@Override
public JpegQualityFeature createJpegQualityFeature(@NonNull CameraProperties cameraProperties) {
return new JpegQualityFeature(cameraProperties);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import android.app.Activity;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.plugins.camera.CameraProperties;
import io.flutter.plugins.camera.DartMessenger;
import io.flutter.plugins.camera.features.autofocus.AutoFocusFeature;
Expand All @@ -15,6 +16,7 @@
import io.flutter.plugins.camera.features.flash.FlashFeature;
import io.flutter.plugins.camera.features.focuspoint.FocusPointFeature;
import io.flutter.plugins.camera.features.fpsrange.FpsRangeFeature;
import io.flutter.plugins.camera.features.jpegquality.JpegQualityFeature;
import io.flutter.plugins.camera.features.noisereduction.NoiseReductionFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionPreset;
Expand All @@ -41,6 +43,7 @@ public class CameraFeatures {
private static final String REGION_BOUNDARIES = "REGION_BOUNDARIES";
private static final String RESOLUTION = "RESOLUTION";
private static final String SENSOR_ORIENTATION = "SENSOR_ORIENTATION";
private static final String JPEG_QUALITY = "JPEG_QUALITY";
private static final String ZOOM_LEVEL = "ZOOM_LEVEL";

@NonNull
Expand Down Expand Up @@ -297,4 +300,23 @@ public ZoomLevelFeature getZoomLevel() {
public void setZoomLevel(@NonNull ZoomLevelFeature zoomLevel) {
this.featureMap.put(ZOOM_LEVEL, zoomLevel);
}

/**
* Gets the JPEG quality feature if it has been set.
*
* @return the JPEG quality feature, or null if not set.
*/
@Nullable
public JpegQualityFeature getJpegQuality() {
return (JpegQualityFeature) featureMap.get(JPEG_QUALITY);
}

/**
* Sets the instance of the JPEG quality feature.
*
* @param jpegQuality the {@link JpegQualityFeature} instance to set.
*/
public void setJpegQuality(@NonNull JpegQualityFeature jpegQuality) {
this.featureMap.put(JPEG_QUALITY, jpegQuality);
}
}
Loading