■はじめに
今回は画面全体のスクリーンショットを撮り、jpeg画像として保存するアプリケーションを作ります。
■開発環境
- Windows 10
- Visual Studio Community 2019 (Version 16.6.5)
- .NET Framework 4.8 / .NET Core 3.1
■.NET Framework版のみの作業
新しいプロジェクトでWPFアプリ (.NET Framework) C#
を選択します。
ソリューションエクスプローラーで参照
を右クリックし、参照の追加
を選択します。
アセンブリでSystem.Drawing
のチェックボックスをチェックし、OK
ボタンを選択します。
■.NET Core版のみの作業
新しいプロジェクトでWPF App (.NET Core) C#
を選択します。
ソリューションエクスプローラーでプロジェクトを右クリック、NuGetパッケージの管理
を選択します。
System.Drawing.Common
をインストールします。
■作成(.NET Framework/.NET Core共通)
◇画面
MainWindow.xaml
<Window
x:Class="ScreenShot.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ScreenShotCore"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="キャプチャ"
Width="640"
Height="400"
ResizeMode="CanResizeWithGrip"
WindowStyle="ToolWindow"
mc:Ignorable="d">
<Window.Resources>
<!-- ボタンの既定スタイル -->
<Style TargetType="Button">
<Setter Property="Width" Value="150" />
<Setter Property="Margin" Value="10" />
<Setter Property="Padding" Value="5" />
</Style>
</Window.Resources>
<Grid Background="SlateGray">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Viewbox>
<Image x:Name="CaptureImage" Margin="5" />
</Viewbox>
<TextBlock
x:Name="SaveInfo"
Margin="10"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="60"
Text="保存しました。"
Visibility="Collapsed" />
<StackPanel
Grid.Row="1"
Background="LightSteelBlue"
Orientation="Horizontal">
<Button Click="CaptureButton_Click" Content="キャプチャ(_1)" />
<Button Click="SaveButton_Click" Content="保存(_2)" />
<Button Click="CaptureAndSaveButton_Click" Content="キャプチャして保存(_3)" />
</StackPanel>
</Grid>
</Window>
◇コード
MainWindow.xaml.cs
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using DIMG = System.Drawing.Imaging;
using DRW = System.Drawing;
using MIMG = System.Windows.Media.Imaging;
namespace ScreenShot
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
/// <summary>
/// キャプチャ時、自ウィンドウを隠すための待ち時間
/// </summary>
private static readonly int CaptureWaitMSec = 300;
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
private static extern bool DeleteObject(IntPtr objectHandle);
/// <summary>
/// コンストラクタ
/// </summary>
public MainWindow()
{
InitializeComponent();
}
/// <summary>
/// キャプチャボタン押下
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void CaptureButton_Click(object sender, RoutedEventArgs e)
{
CaptureImage.Source = null;
// ウィンドウ最小化
WindowState = WindowState.Minimized;
// ウィンドウが最小化するまで少し待つ
await Task.Delay(CaptureWaitMSec);
// キャプチャ
CaptureImage.Source = GetFullScreenImage();
// ウィンドウを元に戻す
WindowState = WindowState.Normal;
}
/// <summary>
/// 保存ボタン押下
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void SaveButton_Click(object sender, RoutedEventArgs e)
{
if (CaptureImage.Source == null)
{
MessageBox.Show("まずキャプチャしてください。", "警告", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
// 画像保存
SaveImage();
// 保存通知
await NotifySaveImage();
}
/// <summary>
/// キャプチャして保存ボタン押下
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void CaptureAndSaveButton_Click(object sender, RoutedEventArgs e)
{
// ウィンドウ最小化
WindowState = WindowState.Minimized;
// ウィンドウが最小化するまで少し待つ
await Task.Delay(CaptureWaitMSec);
// キャプチャ
CaptureImage.Source = GetFullScreenImage();
// 画像保存
SaveImage();
// ウィンドウを元に戻す
WindowState = WindowState.Normal;
// 保存通知
await NotifySaveImage();
}
/// <summary>
/// 画面全体のイメージ取得
/// </summary>
/// <returns></returns>
private MIMG.BitmapSource GetFullScreenImage()
{
int w = (int)SystemParameters.PrimaryScreenWidth;
int h = (int)SystemParameters.PrimaryScreenHeight;
using (var bmp = new DRW.Bitmap(w, h, DIMG.PixelFormat.Format32bppRgb))
using (var grph = DRW.Graphics.FromImage(bmp))
{
// スクリーンイメージをコピー
grph.CopyFromScreen(
sourceX: 0, sourceY: 0,
destinationX: 0, destinationY: 0,
bmp.Size);
IntPtr bmpHandle = bmp.GetHbitmap();
try
{
return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
bmpHandle,
IntPtr.Zero,
Int32Rect.Empty,
MIMG.BitmapSizeOptions.FromEmptyOptions());
}
finally
{
DeleteObject(bmpHandle);
}
}
}
/// <summary>
/// 画像ファイルを保存
/// </summary>
private void SaveImage()
{
// ピクチャフォルダのスクリーンショットフォルダ
string saveFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "Screenshots");
string saveFilePath = Path.Combine(saveFolder, $"スクショ{DateTime.Now:yyyyMMdd-HHmmss}.jpeg");
if (!Directory.Exists(saveFolder))
{
// 保存先フォルダが無ければ作成
Directory.CreateDirectory(saveFolder);
}
// 画像ファイル保存
using (Stream stream = new FileStream(saveFilePath, FileMode.Create))
{
var encoder = new MIMG.JpegBitmapEncoder();
encoder.Frames.Add(MIMG.BitmapFrame.Create((MIMG.BitmapSource)CaptureImage.Source));
encoder.Save(stream);
}
}
/// <summary>
/// 保存通知
/// </summary>
/// <returns></returns>
/// <remarks>
/// 画像保存メッセージを表示し、画面の画像をクリアする。
/// </remarks>
private async Task NotifySaveImage()
{
// 保存通知
SaveInfo.Visibility = Visibility.Visible;
await Task.Delay(250);
// 画像クリア
CaptureImage.Source = null;
await Task.Delay(250);
// 保存通知隠す
SaveInfo.Visibility = Visibility.Collapsed;
}
}
}
■実行してみる
キャプチャ
ボタンを押しました。
一瞬、画面が隠れて全画面のスクリーンショットが画面に表示されます。
保存
ボタンを押すと画面に表示されている画像が「ピクチャ」フォルダの「スクリーンショット」フォルダに保存されます。
おしまい