Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Saat aplikasi Anda mengambil foto atau video untuk digunakan di luar aplikasi, seperti menyimpan ke file atau berbagi, Anda perlu mengodekan gambar dengan metadata orientasi yang benar sehingga konten ditampilkan dengan benar di aplikasi dan perangkat lain. Artikel ini memperlihatkan cara menggunakan kelas pembantu untuk mengelola orientasi kamera di aplikasi desktop WinUI 3.
Prasyarat
Sebelum mulai, pastikan bahwa Anda memiliki:
- Proyek desktop WinUI 3 (dikemas atau tidak dikemas).
- Kamera yang kompatibel tersambung ke perangkat Anda.
- Akses kamera dideklarasikan untuk aplikasi Anda:
Aplikasi paket
webcam: Tambahkan kemampuan perangkat kePackage.appxmanifest:<Capabilities> <DeviceCapability Name="webcam" /> </Capabilities>Aplikasi yang tidak dikemas: Tidak ada kemampuan manifes untuk dideklarasikan. Akses kamera dikontrol oleh pengaturan Izinkan aplikasi desktop mengakses kamera Anda di bawah Pengaturan>Privasi &keamanan>Kamera pada perangkat pengguna.
Pengguna masih dapat menolak akses kamera di tingkat OS dalam kedua kasus. Periksa akses sebelum Anda menginisialisasi kamera dan menangani kasus yang ditolak dengan baik, seperti yang dijelaskan dalam Menangani pengaturan privasi kamera Windows.
Konsep orientasi
Aplikasi desktop biasanya berjalan di perangkat dengan layar tetap, sehingga Anda tidak perlu menangani rotasi berkelanjutan seperti yang dilakukan aplikasi seluler. Namun, Anda masih perlu memperhitungkan:
- Orientasi sensor kamera — Sudut pemasangan fisik sensor kamera, yang bervariasi menurut perangkat.
- Rotasi kamera eksternal — Webcam eksternal dapat diputar oleh pengguna.
Ide utamanya adalah menerapkan koreksi rotasi saat mengodekan foto atau video yang diambil sehingga output cocok dengan apa yang dilihat pengguna dalam pratinjau.
Membuat kelas CameraRotationHelper
Kelas pembantu berikut mengelola nilai rotasi berdasarkan orientasi sensor kamera dan sensor orientasi perangkat:
using Windows.Devices.Enumeration;
using Windows.Devices.Sensors;
using Windows.Media.Capture;
using Windows.Storage.FileProperties;
public class CameraRotationHelper
{
private readonly EnclosureLocation _cameraEnclosureLocation;
private readonly SimpleOrientationSensor _orientationSensor;
private SimpleOrientation _deviceOrientation =
SimpleOrientation.NotRotated;
public event EventHandler<bool> OrientationChanged;
public CameraRotationHelper(
EnclosureLocation cameraEnclosureLocation)
{
_cameraEnclosureLocation = cameraEnclosureLocation;
_orientationSensor =
SimpleOrientationSensor.GetDefault();
if (_orientationSensor != null)
{
_orientationSensor.OrientationChanged +=
OrientationSensor_OrientationChanged;
}
}
private void OrientationSensor_OrientationChanged(
SimpleOrientationSensor sender,
SimpleOrientationSensorOrientationChangedEventArgs args)
{
if (args.Orientation != SimpleOrientation.Faceup &&
args.Orientation != SimpleOrientation.Facedown)
{
_deviceOrientation = args.Orientation;
OrientationChanged?.Invoke(this, true);
}
}
public static bool IsEnclosureLocationExternal(
EnclosureLocation enclosureLocation)
{
return enclosureLocation == null ||
enclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Unknown;
}
private bool IsCameraMirrored()
{
// Front panel cameras are mirrored by convention
return _cameraEnclosureLocation?.Panel == Windows.Devices.Enumeration.Panel.Front;
}
private SimpleOrientation GetCameraOrientation()
{
if (IsEnclosureLocationExternal(_cameraEnclosureLocation))
{
return SimpleOrientation.NotRotated;
}
// Get the sensor orientation from the device
return _deviceOrientation;
}
/// <summary>
/// Gets the rotation to apply to the camera preview stream.
/// </summary>
public VideoRotation GetCameraPreviewOrientation()
{
if (IsEnclosureLocationExternal(_cameraEnclosureLocation))
{
return VideoRotation.None;
}
return ConvertSimpleOrientationToVideoRotation(
GetCameraOrientation());
}
/// <summary>
/// Gets the rotation to apply when encoding a photo.
/// </summary>
public PhotoOrientation GetCapturePhotoOrientation()
{
if (IsEnclosureLocationExternal(_cameraEnclosureLocation))
{
return PhotoOrientation.Normal;
}
int encodingRotation = ConvertDeviceOrientationToDegrees(
GetCameraOrientation());
if (IsCameraMirrored())
{
encodingRotation = (360 - encodingRotation) % 360;
}
return ConvertDegreesToPhotoOrientation(encodingRotation);
}
/// <summary>
/// Gets the clockwise rotation to apply when encoding a video.
/// </summary>
public int GetCaptureVideoOrientation()
{
if (IsEnclosureLocationExternal(_cameraEnclosureLocation))
{
return 0;
}
int rotation = ConvertDeviceOrientationToDegrees(
GetCameraOrientation());
if (IsCameraMirrored())
{
rotation = (360 - rotation) % 360;
}
return rotation;
}
public void Dispose()
{
if (_orientationSensor != null)
{
_orientationSensor.OrientationChanged -=
OrientationSensor_OrientationChanged;
}
}
private static int ConvertDeviceOrientationToDegrees(
SimpleOrientation orientation)
{
// TODO: This mapping from counterclockwise SimpleOrientation values
// to clockwise degree values (for example, mapping
// Rotated90DegreesCounterclockwise to 90) was carried over from the
// original UWP sample this article is based on. Verify this mapping
// against physical devices before relying on it in production; do
// not change these values without hardware verification.
return orientation switch
{
SimpleOrientation.Rotated90DegreesCounterclockwise => 90,
SimpleOrientation.Rotated180DegreesCounterclockwise => 180,
SimpleOrientation.Rotated270DegreesCounterclockwise => 270,
_ => 0,
};
}
private static VideoRotation ConvertSimpleOrientationToVideoRotation(
SimpleOrientation orientation)
{
// TODO: See the verification note on ConvertDeviceOrientationToDegrees
// above — this CCW-to-CW mapping needs the same device verification
// before the values are changed.
return orientation switch
{
SimpleOrientation.Rotated90DegreesCounterclockwise =>
VideoRotation.Clockwise90Degrees,
SimpleOrientation.Rotated180DegreesCounterclockwise =>
VideoRotation.Clockwise180Degrees,
SimpleOrientation.Rotated270DegreesCounterclockwise =>
VideoRotation.Clockwise270Degrees,
_ => VideoRotation.None,
};
}
private static PhotoOrientation ConvertDegreesToPhotoOrientation(
int degrees)
{
return degrees switch
{
90 => PhotoOrientation.Rotate90,
180 => PhotoOrientation.Rotate180,
270 => PhotoOrientation.Rotate270,
_ => PhotoOrientation.Normal,
};
}
}
Gunakan kelas pembantu
Inisialisasi helper setelah Anda membuat instans MediaCapture dan mengetahui lokasi casing kamera:
private CameraRotationHelper _rotationHelper;
private MediaCapture _mediaCapture;
private async Task InitializeCameraAsync()
{
_mediaCapture = new MediaCapture();
await _mediaCapture.InitializeAsync();
var cameraDevice = _mediaCapture.MediaCaptureSettings;
// Find the camera device info to get enclosure location
var devices = await DeviceInformation.FindAllAsync(
DeviceClass.VideoCapture);
var deviceInfo = devices.FirstOrDefault(
d => d.Id == cameraDevice.VideoDeviceId);
_rotationHelper = new CameraRotationHelper(
deviceInfo?.EnclosureLocation);
_rotationHelper.OrientationChanged += (s, e) =>
{
// Update preview rotation when device orientation changes
DispatcherQueue.TryEnqueue(UpdatePreviewRotation);
};
}
Terapkan rotasi pada pratinjau
Atur rotasi pratinjau pada instans MediaCapture Anda saat orientasi berubah:
private void UpdatePreviewRotation()
{
var rotation = _rotationHelper.GetCameraPreviewOrientation();
_mediaCapture.SetPreviewRotation(rotation);
}
Menerapkan rotasi saat mengambil foto
Atur metadata orientasi saat Anda menyimpan foto yang diambil:
using System.Collections.Generic;
using Windows.Storage;
using Windows.Storage.FileProperties;
private async Task CapturePhotoWithOrientationAsync()
{
var file = await ApplicationData.Current.LocalFolder
.CreateFileAsync("photo.jpg",
CreationCollisionOption.GenerateUniqueName);
await _mediaCapture.CapturePhotoToStorageFileAsync(
ImageEncodingProperties.CreateJpeg(), file);
// Set the orientation metadata. ImageProperties.Orientation is
// read-only, so save the EXIF orientation value directly through
// the file's property store instead.
var photoOrientation =
_rotationHelper.GetCapturePhotoOrientation();
var propertiesToSave = new List<KeyValuePair<string, object>>
{
new KeyValuePair<string, object>(
"System.Photo.Orientation", photoOrientation)
};
await file.Properties.SavePropertiesAsync(propertiesToSave);
}
Important
ApplicationData.Current.LocalFolder memerlukan identitas paket (MSIX). Aplikasi yang tidak dikemas tidak dapat digunakan ApplicationData tanpa identitas paket. Untuk aplikasi yang tidak dikemas, gunakan Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) atau jalur file Win32 lainnya sebagai gantinya.
Note
SimpleOrientationSensor tidak tersedia di semua perangkat desktop.
null Periksa pengembalian dari SimpleOrientationSensor.GetDefault() dan tangani kasus di mana tidak ada sensor orientasi. Untuk kamera eksternal, rotasinya biasanya NotRotated.
Konten terkait
Windows developer