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.
Artikel ini menjelaskan cara memuat dan menyimpan file gambar menggunakan BitmapDecoder dan BitmapEncoder dan cara menggunakan objek SoftwareBitmap untuk mewakili gambar bitmap.
Kelas SoftwareBitmap adalah API serbaguna yang dapat dibuat dari beberapa sumber termasuk file gambar, objek WriteableBitmap , permukaan Direct3D, dan kode. SoftwareBitmap memungkinkan Anda untuk dengan mudah mengonversi antara format piksel dan mode alfa yang berbeda, dan memungkinkan akses tingkat rendah ke data piksel. Selain itu, SoftwareBitmap adalah antarmuka umum yang digunakan oleh beberapa fitur Windows, termasuk:
CapturedFrame memungkinkan Anda mendapatkan bingkai yang diambil oleh kamera sebagai SoftwareBitmap.
VideoFrame memungkinkan Anda mendapatkan SoftwareBitmap representasi VideoFrame.
FaceDetector memungkinkan Anda mendeteksi wajah dalam SoftwareBitmap.
Kode sampel dalam artikel ini menggunakan API dari namespace berikut.
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.Storage.Streams;
using Windows.Graphics.Imaging;
using Microsoft.UI.Xaml.Media.Imaging;
using System.Runtime.InteropServices.WindowsRuntime;
Membuat SoftwareBitmap dari file gambar dengan BitmapDecoder
Untuk membuat SoftwareBitmap dari file, dapatkan instans StorageFile yang berisi data gambar. Contoh ini menggunakan FileOpenPicker untuk memungkinkan pengguna memilih file gambar.
private async Task<StorageFile?> PickInputFileAsync()
{
var picker = new FileOpenPicker();
// Initialize the picker with the window handle (required for WinUI 3).
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);
WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd);
picker.ViewMode = PickerViewMode.Thumbnail;
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
picker.FileTypeFilter.Add(".jpg");
picker.FileTypeFilter.Add(".jpeg");
picker.FileTypeFilter.Add(".png");
picker.FileTypeFilter.Add(".bmp");
return await picker.PickSingleFileAsync();
}
Panggil metode OpenAsync objek StorageFile untuk mendapatkan aliran akses acak yang berisi data gambar. Panggil metode statis BitmapDecoder.CreateAsync untuk mendapatkan instance kelas BitmapDecoder untuk stream yang ditentukan. Panggil GetSoftwareBitmapAsync untuk mendapatkan objek SoftwareBitmap yang berisi gambar.
private async Task<SoftwareBitmap> CreateSoftwareBitmapFromFileAsync(StorageFile file)
{
using IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read);
// Create a decoder from the image file.
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
// Get the SoftwareBitmap representation of the file.
SoftwareBitmap softwareBitmap = await decoder.GetSoftwareBitmapAsync();
return softwareBitmap;
}
Menyimpan SoftwareBitmap ke file dengan BitmapEncoder
Untuk menyimpan SoftwareBitmap ke file, dapatkan instans StorageFile tempat gambar akan disimpan. Contoh ini menggunakan FileSavePicker untuk memungkinkan pengguna memilih file output.
private async Task<StorageFile?> PickOutputFileAsync()
{
var picker = new FileSavePicker();
// Initialize the picker with the window handle (required for WinUI 3).
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);
WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd);
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
picker.SuggestedFileName = "output";
picker.FileTypeChoices.Add("JPEG Image", new List<string> { ".jpg" });
picker.FileTypeChoices.Add("PNG Image", new List<string> { ".png" });
return await picker.PickSaveFileAsync();
}
Panggil metode OpenAsync objek StorageFile untuk mendapatkan aliran akses acak tempat gambar akan ditulis. Panggil metode statis BitmapEncoder.CreateAsync untuk mendapatkan instans kelas BitmapEncoder untuk aliran yang ditentukan. Parameter pertama untuk CreateAsync adalah GUID yang mewakili codec yang harus digunakan untuk mengodekan gambar. Kelas BitmapEncoder mengekspos properti yang berisi ID untuk setiap codec yang didukung oleh encoder, seperti JpegEncoderId.
Gunakan metode SetSoftwareBitmap untuk mengatur gambar yang akan dikodekan. Anda dapat mengatur nilai properti BitmapTransform untuk menerapkan transformasi dasar ke gambar saat sedang dikodekan. Properti IsThumbnailGenerated menentukan apakah gambar mini dihasilkan oleh enkoder. Perhatikan bahwa tidak semua format file mendukung gambar mini, jadi jika Anda menggunakan fitur ini, Anda harus menangani error operasi yang tidak didukung yang akan muncul jika gambar mini tidak didukung.
Panggil FlushAsync untuk menyebabkan encoder menulis data gambar ke file yang ditentukan.
private async Task SaveSoftwareBitmapToFileAsync(SoftwareBitmap softwareBitmap, StorageFile outputFile)
{
using IRandomAccessStream stream = await outputFile.OpenAsync(FileAccessMode.ReadWrite);
// Create an encoder with the desired format.
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
// Set the software bitmap.
encoder.SetSoftwareBitmap(softwareBitmap);
// Set additional encoding parameters (optional).
encoder.BitmapTransform.ScaledWidth = (uint)softwareBitmap.PixelWidth;
encoder.BitmapTransform.ScaledHeight = (uint)softwareBitmap.PixelHeight;
encoder.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Fant;
encoder.IsThumbnailGenerated = true;
try
{
await encoder.FlushAsync();
}
catch (Exception ex)
{
const int WINCODEC_ERR_UNSUPPORTEDOPERATION = unchecked((int)0x88982F81);
switch (ex.HResult)
{
case WINCODEC_ERR_UNSUPPORTEDOPERATION:
// If the encoder does not support thumbnail generation,
// disable it and try again.
encoder.IsThumbnailGenerated = false;
break;
default:
throw;
}
}
if (!encoder.IsThumbnailGenerated)
{
await encoder.FlushAsync();
}
}
Anda dapat menentukan opsi pengodean tambahan saat membuat BitmapEncoder dengan membuat objek BitmapPropertySet baru dan mengisinya dengan satu atau beberapa objek BitmapTypedValue yang mewakili pengaturan enkoder. Untuk daftar opsi encoder yang didukung, lihat Referensi opsi BitmapEncoder.
private async Task SaveWithEncodingOptionsAsync(SoftwareBitmap softwareBitmap, StorageFile outputFile)
{
using IRandomAccessStream stream = await outputFile.OpenAsync(FileAccessMode.ReadWrite);
// Create encoding options with a specific image quality.
var propertySet = new BitmapPropertySet();
var qualityValue = new BitmapTypedValue(0.9, Windows.Foundation.PropertyType.Single);
propertySet.Add("ImageQuality", qualityValue);
// Create the encoder with the encoding options.
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(
BitmapEncoder.JpegEncoderId, stream, propertySet);
encoder.SetSoftwareBitmap(softwareBitmap);
await encoder.FlushAsync();
}
Menggunakan SoftwareBitmap dengan kontrol Gambar XAML
Untuk menampilkan gambar dalam halaman XAML menggunakan kontrol Gambar , pertama-tama tentukan kontrol Gambar di halaman XAML Anda.
<Image x:Name="imageControl"
Grid.Row="2"
Stretch="Uniform"/>
Saat ini, kontrol Gambar hanya mendukung gambar yang menggunakan pengodean BGRA8 dan dikalikan sebelumnya atau tanpa saluran alfa. Sebelum mencoba menampilkan gambar, uji untuk memastikan gambar memiliki format yang benar, dan jika tidak, gunakan metode Konversi statis SoftwareBitmap untuk mengonversi gambar ke format yang didukung.
Buat objek SoftwareBitmapSource baru. Atur konten objek sumber dengan memanggil SetBitmapAsync, meneruskan SoftwareBitmap. Kemudian Anda dapat mengatur properti Sumber kontrol Gambar ke SoftwareBitmapSource yang baru dibuat.
private async Task DisplaySoftwareBitmapAsync(SoftwareBitmap softwareBitmap)
{
// SoftwareBitmap must be Bgra8 with premultiplied or no alpha
// to display in a XAML Image control.
if (softwareBitmap.BitmapPixelFormat != BitmapPixelFormat.Bgra8 ||
softwareBitmap.BitmapAlphaMode == BitmapAlphaMode.Straight)
{
softwareBitmap = SoftwareBitmap.Convert(
softwareBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
}
// In WinUI 3, SoftwareBitmapSource is in Microsoft.UI.Xaml.Media.Imaging.
var source = new SoftwareBitmapSource();
await source.SetBitmapAsync(softwareBitmap);
// Set the source of the Image control.
imageControl.Source = source;
}
Anda juga dapat menggunakan SoftwareBitmapSource untuk mengatur SoftwareBitmap sebagai ImageSource untuk ImageBrush.
Membuat SoftwareBitmap dari WriteableBitmap
Anda dapat membuat SoftwareBitmap dari WriteableBitmap yang ada dengan memanggil SoftwareBitmap.CreateCopyFromBuffer dan menyediakan properti PixelBuffer dari WriteableBitmap untuk mengatur data piksel. Argumen kedua memungkinkan Anda menentukan format piksel untuk SoftwareBitmap yang baru dibuat. Anda dapat menggunakan properti PixelWidth dan PixelHeight dari WriteableBitmap untuk menentukan dimensi gambar baru.
private SoftwareBitmap ConvertWriteableBitmapToSoftwareBitmap(WriteableBitmap writeableBitmap)
{
// Create a SoftwareBitmap from the WriteableBitmap's pixel buffer.
SoftwareBitmap softwareBitmap = SoftwareBitmap.CreateCopyFromBuffer(
writeableBitmap.PixelBuffer,
BitmapPixelFormat.Bgra8,
writeableBitmap.PixelWidth,
writeableBitmap.PixelHeight);
return softwareBitmap;
}
Membuat atau mengedit SoftwareBitmap secara terprogram
Sejauh ini topik ini telah membahas bekerja dengan file gambar. Anda juga dapat membuat SoftwareBitmap baru secara terprogram dalam kode dan menggunakan teknik yang sama untuk mengakses dan memodifikasi data piksel SoftwareBitmap.
Gunakan metode CopyFromBuffer untuk mengisi SoftwareBitmap dari array byte, dan CopyToBuffer untuk menyalin data piksel ke array byte untuk membaca atau memodifikasi. Untuk menggunakan metode ekstensi AsBuffer untuk membungkus array byte sebagai IBuffer, sertakan namespace System.Runtime.InteropServices.WindowsRuntime (ini termasuk dalam SnippetNamespaces menggunakan pernyataan di bagian atas artikel ini).
Buat SoftwareBitmap baru dengan format dan ukuran piksel yang Anda inginkan. Alokasikan array byte yang cukup besar untuk menyimpan data piksel, mengisinya dengan nilai yang diinginkan, lalu panggil CopyFromBuffer untuk menulis data ke bitmap.
private SoftwareBitmap CreateGradientBitmap(int width, int height)
{
// Create a new SoftwareBitmap programmatically.
var softwareBitmap = new SoftwareBitmap(
BitmapPixelFormat.Bgra8, width, height, BitmapAlphaMode.Premultiplied);
// Allocate a byte array for the pixel data.
int bytesPerPixel = 4; // BGRA8
byte[] pixelData = new byte[width * height * bytesPerPixel];
// Fill the bitmap with a gradient pattern.
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
int pixelIndex = (row * width + col) * bytesPerPixel;
// Blue channel: gradient left to right.
pixelData[pixelIndex + 0] = (byte)((double)col / width * 255);
// Green channel: gradient top to bottom.
pixelData[pixelIndex + 1] = (byte)((double)row / height * 255);
// Red channel: inverse diagonal gradient.
pixelData[pixelIndex + 2] = (byte)(255 - (((double)(col + row)
/ (width + height)) * 255));
// Alpha channel: fully opaque.
pixelData[pixelIndex + 3] = 255;
}
}
// Copy the pixel data into the SoftwareBitmap.
softwareBitmap.CopyFromBuffer(pixelData.AsBuffer());
return softwareBitmap;
}
Buat SoftwareBitmap dari permukaan Direct3D
Untuk membuat objek SoftwareBitmap dari permukaan Direct3D, Anda harus menyertakan Windows. Graphics.DirectX.Direct3D11 namespace dalam proyek Anda.
using Windows.Graphics.DirectX.Direct3D11;
Panggil CreateCopyFromSurfaceAsync untuk membuat SoftwareBitmap baru dari permukaan. Seperti namanya, SoftwareBitmap baru memiliki salinan terpisah dari data gambar. Modifikasi pada SoftwareBitmap tidak akan berpengaruh pada permukaan Direct3D.
private async Task<SoftwareBitmap> CreateBitmapFromSurfaceAsync(IDirect3DSurface surface)
{
// Create a SoftwareBitmap from a Direct3D surface.
SoftwareBitmap softwareBitmap =
await SoftwareBitmap.CreateCopyFromSurfaceAsync(surface);
return softwareBitmap;
}
Mengonversi SoftwareBitmap ke format piksel yang berbeda
Kelas SoftwareBitmap menyediakan metode statis, Convert, yang memungkinkan Anda untuk dengan mudah membuat SoftwareBitmap baru yang menggunakan format piksel dan mode alfa yang Anda tentukan dari SoftwareBitmap yang ada. Perhatikan bahwa bitmap yang baru dibuat memiliki salinan terpisah dari data gambar. Modifikasi pada bitmap baru tidak akan memengaruhi bitmap sumber.
private SoftwareBitmap ConvertBitmapPixelFormat(SoftwareBitmap softwareBitmap)
{
// Convert the pixel format and alpha mode of the SoftwareBitmap.
SoftwareBitmap convertedBitmap = SoftwareBitmap.Convert(
softwareBitmap,
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied);
return convertedBitmap;
}
Transkode file gambar
Anda dapat mengodekan file gambar langsung dari BitmapDecoder ke BitmapEncoder. Buat IRandomAccessStream dari file yang akan ditranskodekan. Buat BitmapDecoder baru dari aliran input. Buat InMemoryRandomAccessStream baru untuk ditulisi encoder, lalu panggil BitmapEncoder.CreateForTranscodingAsync dengan meneruskan stream dalam memori tersebut dan objek dekoder. Opsi enkode tidak didukung saat transcoding; sebagai gantinya, Anda harus menggunakan CreateAsync. Properti apa pun dalam file gambar input yang tidak Anda atur secara khusus pada encoder, akan ditulis ke file output yang tidak berubah. Panggil FlushAsync untuk membuat encoder melakukan pengodean ke stream dalam memori. Terakhir, cari aliran file dan aliran dalam memori ke awal dan panggil CopyAsync untuk menulis aliran dalam memori ke aliran file.
private async Task TranscodeImageFileAsync(StorageFile inputFile, StorageFile outputFile)
{
using IRandomAccessStream inputStream =
await inputFile.OpenAsync(FileAccessMode.Read);
using IRandomAccessStream outputStream =
await outputFile.OpenAsync(FileAccessMode.ReadWrite);
// Create a decoder for the input file.
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(inputStream);
// Create an encoder for transcoding to the output file.
BitmapEncoder encoder =
await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder);
// Optionally apply transforms during transcoding.
encoder.BitmapTransform.ScaledWidth = decoder.PixelWidth / 2;
encoder.BitmapTransform.ScaledHeight = decoder.PixelHeight / 2;
encoder.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Fant;
await encoder.FlushAsync();
}
Topik terkait
Windows developer