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
12 changes: 7 additions & 5 deletions BigIslandBarcode/MainPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
x:Name="barcodeView"
BarcodesDetected="BarcodesDetected"
/>

<Grid
<Grid Grid.Row="1" VerticalOptions="End" HorizontalOptions="Fill" BackgroundColor="#aa000000">
<Slider Minimum="0" Maximum="1" ValueChanged="ZoomFactorChanged" />
</Grid>
<Grid
Grid.Row="0"
BackgroundColor="#aa000000">
<Label x:Name="ResultLabel" Grid.Row="2" Text="Top text..." HorizontalOptions="Center" VerticalOptions="Center" TextColor="White" />
</Grid>

<Grid
Grid.Row="3"
BackgroundColor="#aa000000"
Expand All @@ -27,8 +29,8 @@
<Button Text="🔄️" Grid.Column="0" BackgroundColor="#aa000000" CornerRadius="8" BorderColor="Black" Clicked="SwitchCameraButton_Clicked" />

<Button Text="📷" Grid.Column="1" BackgroundColor="#aa000000" CornerRadius="8" BorderColor="Black" Clicked="SelectCameraButton_Clicked" />

<zxing:BarcodeGeneratorView
<zxing:BarcodeGeneratorView
x:Name="barcodeGenerator"
Grid.Column="2"
HorizontalOptions="Center"
Expand Down
9 changes: 8 additions & 1 deletion BigIslandBarcode/MainPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,12 @@ void TorchButton_Clicked(object sender, EventArgs e)
{
barcodeView.IsTorchOn = !barcodeView.IsTorchOn;
}
}

private void ZoomFactorChanged(object sender, ValueChangedEventArgs e)
{
var slider = (Slider)sender;
barcodeView.ZoomFactor = (float)e.NewValue;

}
}
}
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,18 @@ Toggle Torch
cameraBarcodeReaderView.IsTorchOn = !cameraBarcodeReaderView.IsTorchOn;
```

Set zoom (normalized 0..1)
```csharp
// 0 = minimum, 1 = maximum (values outside the range are clamped)
cameraBarcodeReaderView.ZoomFactor = 0.5f;
```

Notes on zoom behavior:
- The zoom factor is normalized (0..1) across platforms.
- iOS maps 0..1 to the device zoom range [1, max], where max is capped to the maximum optical zoom (currently min of `ActiveFormat.VideoMaxZoomFactor` and `5x`) to avoid degraded digital zoom.
- Android uses linear zoom via CameraX.
- Windows maps the normalized value to the device `ZoomControl` range when supported.

Flip between Rear/Front cameras
```csharp
cameraBarcodeReaderView.CameraLocation
Expand Down Expand Up @@ -175,4 +187,3 @@ The `CharacterSet` property defaults to "UTF-8" if not specified. Other common v




9 changes: 9 additions & 0 deletions ZXing.Net.MAUI.Controls/Controls/CameraBarcodeReaderView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ public CameraInfo SelectedCamera
set => SetValue(SelectedCameraProperty, value);
}

public static readonly BindableProperty ZoomFactorProperty =
BindableProperty.Create(nameof(ZoomFactor), typeof(float), typeof(CameraBarcodeReaderView), defaultValue: 0f);

public float ZoomFactor
{
get => (float)GetValue(ZoomFactorProperty);
set => SetValue(ZoomFactorProperty, value);
}

public void AutoFocus()
=> StrongHandler?.Invoke(nameof(AutoFocus), null);

Expand Down
9 changes: 9 additions & 0 deletions ZXing.Net.MAUI.Controls/Controls/CameraView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ public CameraInfo SelectedCamera
set => SetValue(SelectedCameraProperty, value);
}

public static readonly BindableProperty ZoomFactorProperty =
BindableProperty.Create(nameof(ZoomFactor), typeof(float), typeof(CameraView), defaultValue: 0f);

public float ZoomFactor
{
get => (float)GetValue(ZoomFactorProperty);
set => SetValue(ZoomFactorProperty, value);
}

public void AutoFocus()
=> StrongHandler?.Invoke(nameof(AutoFocus), null);

Expand Down
22 changes: 22 additions & 0 deletions ZXing.Net.MAUI/Apple/CameraManager.ios.maccatalyst.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ public void UpdateCamera()
captureSession.AddInput(captureInput);

captureSession.StartRunning();

}
}

Expand Down Expand Up @@ -269,6 +270,27 @@ public void UpdateTorch(bool on)
}
}

partial void ApplyZoomFactor()
{
if (captureDevice == null)
return;

var minZoomFactor = 1f;
// Cap zoom to the max optical range (higher values can engage digital zoom and degrade clarity).
var maxZoomFactor = Math.Min((float)captureDevice.ActiveFormat.VideoMaxZoomFactor, 5.0f);
if (maxZoomFactor < minZoomFactor)
maxZoomFactor = minZoomFactor;

var normalizedZoomFactor = ZoomFactor * (maxZoomFactor - minZoomFactor) + minZoomFactor;
if (normalizedZoomFactor < minZoomFactor)
normalizedZoomFactor = minZoomFactor;
else if (normalizedZoomFactor > maxZoomFactor)
normalizedZoomFactor = maxZoomFactor;

CaptureDevicePerformWithLockedConfiguration(() =>
captureDevice.VideoZoomFactor = normalizedZoomFactor);
}

public void Focus(Microsoft.Maui.Graphics.Point point)
{
if (captureDevice == null)
Expand Down
1 change: 1 addition & 0 deletions ZXing.Net.MAUI/CameraBarcodeReaderViewHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public partial class CameraBarcodeReaderViewHandler : ViewHandler<ICameraBarcode
[nameof(ICameraBarcodeReaderView.IsTorchOn)] = (handler, virtualView) => handler.cameraManager?.UpdateTorch(virtualView.IsTorchOn),
[nameof(ICameraBarcodeReaderView.CameraLocation)] = (handler, virtualView) => handler.cameraManager?.UpdateCameraLocation(virtualView.CameraLocation),
[nameof(ICameraBarcodeReaderView.SelectedCamera)] = (handler, virtualView) => handler.cameraManager?.UpdateSelectedCamera(virtualView.SelectedCamera),
[nameof(ICameraBarcodeReaderView.ZoomFactor)] = (handler, virtualView) => handler.cameraManager?.UpdateZoomFactor(virtualView.ZoomFactor),
[nameof(IView.Visibility)] = MapVisibility
};

Expand Down
9 changes: 9 additions & 0 deletions ZXing.Net.MAUI/CameraManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public CameraManager(IMauiContext context, CameraLocation cameraLocation)

public CameraLocation CameraLocation { get; private set; }
public CameraInfo SelectedCamera { get; private set; }
public float ZoomFactor { get; private set; }

/// <summary>
/// Gets a value indicating whether barcode scanning is supported on this device.
Expand All @@ -48,7 +49,15 @@ public void UpdateSelectedCamera(CameraInfo cameraInfo)
UpdateCamera();
}

public void UpdateZoomFactor(float zoomFactor)
{
ZoomFactor = Math.Clamp(zoomFactor, 0f, 1f);
ApplyZoomFactor();
}

public static async Task<bool> CheckPermissions()
=> (await Permissions.RequestAsync<Permissions.Camera>()) == PermissionStatus.Granted;

partial void ApplyZoomFactor();
}
}
1 change: 1 addition & 0 deletions ZXing.Net.MAUI/CameraViewHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public partial class CameraViewHandler : ViewHandler<ICameraView, NativePlatform
[nameof(ICameraView.IsTorchOn)] = (handler, virtualView) => handler.cameraManager?.UpdateTorch(virtualView.IsTorchOn),
[nameof(ICameraView.CameraLocation)] = (handler, virtualView) => handler.cameraManager?.UpdateCameraLocation(virtualView.CameraLocation),
[nameof(ICameraView.SelectedCamera)] = (handler, virtualView) => handler.cameraManager?.UpdateSelectedCamera(virtualView.SelectedCamera),
[nameof(ICameraView.ZoomFactor)] = (handler, virtualView) => handler.cameraManager?.UpdateZoomFactor(virtualView.ZoomFactor),
[nameof(IView.Visibility)] = MapVisibility
};

Expand Down
2 changes: 2 additions & 0 deletions ZXing.Net.MAUI/ICameraView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public interface ICameraView : IView, ICameraFrameAnalyzer

CameraInfo SelectedCamera { get; set; }

float ZoomFactor { get; set; }

//CameraMode Mode { get; set; }

void AutoFocus();
Expand Down
4 changes: 4 additions & 0 deletions ZXing.Net.MAUI/Net/CameraManager.net.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ public void UpdateCamera()
public void UpdateTorch(bool on)
=> LogUnsupported();

partial void ApplyZoomFactor()
{
}

public void Focus(Microsoft.Maui.Graphics.Point point)
=> LogUnsupported();

Expand Down
7 changes: 7 additions & 0 deletions ZXing.Net.MAUI/Platforms/Android/CameraManager.android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ public void UpdateCamera()
// if not, this should be sufficient as a fallback
_camera = _cameraProvider.BindToLifecycle(maLifecycleOwner, _cameraSelector, _cameraPreview, _imageAnalyzer);
}

ApplyZoomFactor();
}
}

Expand Down Expand Up @@ -223,6 +225,11 @@ public void UpdateTorch(bool on)
_camera?.CameraControl?.EnableTorch(on);
}

partial void ApplyZoomFactor()
{
_camera?.CameraControl?.SetLinearZoom(ZoomFactor);
}

public void Focus(Point point)
{

Expand Down
41 changes: 41 additions & 0 deletions ZXing.Net.MAUI/Platforms/Windows/CameraManager.windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ public NativePlatformCameraPreviewView CreateNativeView()

public void UpdateTorch(bool on) => TryEnqueueUI(async () => await UpdateTorchAsync(on));

partial void ApplyZoomFactor()
{
TryEnqueueUI(async () => await ApplyZoomFactorAsync());
}

public void Focus(Microsoft.Maui.Graphics.Point point) => TryEnqueueUI(async () => await FocusAsync(point));

public void AutoFocus() => TryEnqueueUI(async () => await AutoFocusAsync());
Expand Down Expand Up @@ -633,6 +638,42 @@ private async Task UpdateTorchAsync(bool on)
}
}

private async Task ApplyZoomFactorAsync()
{
await MediaCaptureLifeLock.WaitAsync();

try
{
var zoomControl = _mediaCapture?.VideoDeviceController?.ZoomControl;
if (zoomControl?.Supported ?? false)
{
var minZoom = (float)zoomControl.Min;
var maxZoom = (float)zoomControl.Max;
if (maxZoom < minZoom)
maxZoom = minZoom;

var normalizedZoom = ZoomFactor * (maxZoom - minZoom) + minZoom;
if (normalizedZoom < minZoom)
normalizedZoom = minZoom;
else if (normalizedZoom > maxZoom)
normalizedZoom = maxZoom;

if (Math.Abs(zoomControl.Value - normalizedZoom) > float.Epsilon)
{
zoomControl.Value = normalizedZoom;
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
MediaCaptureLifeLock.Release();
}
}

private async Task FocusAsync(Microsoft.Maui.Graphics.Point point)
{
await MediaCaptureLifeLock.WaitAsync();
Expand Down