36
36
using Xamarin . Forms ;
37
37
using Xamarin . Forms . Platform . Android ;
38
38
using Camera = Android . Hardware . Camera ;
39
+ using Math = System . Math ;
39
40
using Rect = Android . Graphics . Rect ;
41
+ using APoint = Android . Graphics . Point ;
40
42
41
43
namespace Xamarin . CommunityToolkit . UI . Views
42
44
{
43
45
class CameraFragment : Fragment , TextureView . ISurfaceTextureListener
44
46
{
47
+ // Max preview width that is guaranteed by Camera2 API
48
+ const int MAX_PREVIEW_HEIGHT = 1080 ;
49
+ // Max preview height that is guaranteed by Camera2 API
50
+ const int MAX_PREVIEW_WIDTH = 1920 ;
51
+
45
52
CameraDevice device ;
46
53
CaptureRequest . Builder sessionBuilder ;
47
54
CameraCaptureSession session ;
@@ -222,14 +229,42 @@ public async Task RetrieveCameraDevice(bool force = false)
222
229
}
223
230
Element . MaxZoom = maxDigitalZoom = ( float ) characteristics . Get ( CameraCharacteristics . ScalerAvailableMaxDigitalZoom ) ;
224
231
activeRect = ( Rect ) characteristics . Get ( CameraCharacteristics . SensorInfoActiveArraySize ) ;
232
+ sensorOrientation = ( int ) characteristics . Get ( CameraCharacteristics . SensorOrientation ) ;
233
+
234
+ var displaySize = new APoint ( ) ;
235
+ Activity . WindowManager . DefaultDisplay . GetSize ( displaySize ) ;
236
+ var rotatedViewWidth = texture . Width ;
237
+ var rotatedViewHeight = texture . Height ;
238
+ var maxPreviewWidth = displaySize . X ;
239
+ var maxPreviewHeight = displaySize . Y ;
240
+
241
+ if ( sensorOrientation == 90 || sensorOrientation == 270 )
242
+ {
243
+ rotatedViewWidth = texture . Height ;
244
+ rotatedViewHeight = texture . Width ;
245
+ maxPreviewWidth = displaySize . Y ;
246
+ maxPreviewHeight = displaySize . X ;
247
+ }
248
+
249
+ if ( maxPreviewHeight > MAX_PREVIEW_HEIGHT )
250
+ {
251
+ maxPreviewHeight = MAX_PREVIEW_HEIGHT ;
252
+ }
253
+
254
+ if ( maxPreviewWidth > MAX_PREVIEW_WIDTH )
255
+ {
256
+ maxPreviewWidth = MAX_PREVIEW_WIDTH ;
257
+ }
258
+
225
259
photoSize = GetMaxSize ( map . GetOutputSizes ( ( int ) ImageFormatType . Jpeg ) ) ;
226
260
videoSize = GetMaxSize ( map . GetOutputSizes ( Class . FromType ( typeof ( MediaRecorder ) ) ) ) ;
227
261
previewSize = ChooseOptimalSize (
228
262
map . GetOutputSizes ( Class . FromType ( typeof ( SurfaceTexture ) ) ) ,
229
- texture . Width ,
230
- texture . Height ,
263
+ rotatedViewWidth ,
264
+ rotatedViewHeight ,
265
+ maxPreviewWidth ,
266
+ maxPreviewHeight ,
231
267
cameraTemplate == CameraTemplate . Record ? videoSize : photoSize ) ;
232
- sensorOrientation = ( int ) characteristics . Get ( CameraCharacteristics . SensorOrientation ) ;
233
268
cameraType = ( LensFacing ) ( int ) characteristics . Get ( CameraCharacteristics . LensFacing ) ;
234
269
235
270
if ( Resources . Configuration . Orientation == AOrientation . Landscape )
@@ -923,17 +958,25 @@ ASize GetMaxSize(ASize[] imageSizes)
923
958
}
924
959
925
960
// chooses the smallest one whose width and height are at least as large as the respective requested values
926
- ASize ChooseOptimalSize ( ASize [ ] choices , int width , int height , ASize aspectRatio )
961
+ ASize ChooseOptimalSize ( ASize [ ] choices , int width , int height , int maxWidth , int maxHeight , ASize aspectRatio )
927
962
{
928
963
var bigEnough = new List < ASize > ( ) ;
964
+ var notBigEnough = new List < ASize > ( ) ;
929
965
var w = aspectRatio . Width ;
930
966
var h = aspectRatio . Height ;
931
967
foreach ( var option in choices )
932
968
{
933
- if ( option . Height == option . Width * h / w &&
934
- option . Width >= width && option . Height >= height )
969
+ if ( option . Width <= maxWidth && option . Height <= maxHeight &&
970
+ option . Height == option . Width * h / w )
935
971
{
936
- bigEnough . Add ( option ) ;
972
+ if ( option . Width >= width && option . Height >= height )
973
+ {
974
+ bigEnough . Add ( option ) ;
975
+ }
976
+ else
977
+ {
978
+ notBigEnough . Add ( option ) ;
979
+ }
937
980
}
938
981
}
939
982
@@ -943,11 +986,15 @@ ASize ChooseOptimalSize(ASize[] choices, int width, int height, ASize aspectRati
943
986
var minArea = bigEnough . Min ( s => s . Width * s . Height ) ;
944
987
return bigEnough . First ( s => s . Width * s . Height == minArea ) ;
945
988
}
946
- else
989
+
990
+ if ( notBigEnough . Count > 0 )
947
991
{
948
- LogError ( "Couldn't find any suitable preview size" ) ;
949
- return choices [ 0 ] ;
992
+ var maxArea = notBigEnough . Max ( s => s . Height * s . Width ) ;
993
+ return notBigEnough . First ( s => s . Height * s . Width == maxArea ) ;
950
994
}
995
+
996
+ LogError ( "Couldn't find any suitable preview size" ) ;
997
+ return choices [ 0 ] ;
951
998
}
952
999
#endregion
953
1000
}
0 commit comments