1.はじめに (特徴)
-
シンプル・イズ・ベスト。操作法が非常に簡単なキャプチャアプリ
-
共用の端末には同類のアプリが入っているが設定が端末毎にまちまちでまともに使えない
-
その為、キャプチャのみの機能に限定して簡単操作を念頭に設計
-
数時間で完成させたお手軽&簡単コード
-
改修しました。(25.07.31)
-
動作しない場合はご連絡ください。可能な限り見てみます
2.使用方法 (うな重をキャプチャする)
- 1.起動後マウスが十字型に変わり画面が暗くなる
- 2.切取りしたい適当な四隅にマウス移動
- 3.左ボタンを押したまま対角線に移動して範囲指定
- 4.左ボタンを離す
- 5.中止する場合はスペースキー等押す
- 6.デスクトップにND_SSフォルダが作られ、「日付時間.JPG」が作成
- 7.全画面を撮りたい場合は[HOME]キー
必要な時に実行。簡単に起動できるようピン留め、タイルに入れるなり要工夫。
または「WPF版 タスクトレイアプリ(TSR)のひな形」で起動するよう変更
(Process.Start()やShellExec())
https://qiita.com/inf102/items/cce5965c140d6877676e
- マルチディスプレイ未対応、プライマリ専用
- ショートカットをプライマリディスプレイのデスクトップに置いても可
- 動画のキャプチャは、「切取りしたいフレームが出た時」に起動。その後、その動画の位置を範囲指定
3.解説
同類のアプリがどう作られているか知らないので下記の手法を考案し実装- 1.画面全体のスクリーンショットを取りテンポラリファイルとして保存
- 2.少し透過させたウィンドウを全画面に張り付ける(結果画面が暗くなる)
- (透過率はXAMLを修正)
- 3. 2のウィンドウに対するマウスイベントハンドラで切取る範囲を取得
- 4. 3の範囲を元に1.のテンポラリJPGからその範囲を切り出して保存
4.WPF (C#)
/////////////////////////////////////////////////////
// ND CAP2JPG R2.00 (WPF + .Netframework)
// System.Windows.Forms 参照設定
// (c)inf102 2025. All rights reserved.
/////////////////////////////////////////////////////
using System;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace WPF_SC {
public partial class MainWindow : Window {
[DllImport("User32.dll")]
private static extern bool SetCursorPos(int X, int Y);
///////////////////////////////////////////////////////////////////////////////
const int WAKU=3; // 選択赤枠の幅
static string Desktop=""; // デスクトップ名 ex C:\Users\inf102
static int x1=0,y1,x2,y2;
static bool area_select=false; // false = 選択開始前 , true = エリア選択中
static int Y=0;
static int F=0;
static int AL=255; // 文字濃淡
///////////////////////////////////////////////////////////////////////////////
// debug
public void m(string m){
MessageBox.Show(m);
}
public MainWindow() {
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
string tmp="";
string[] cmds = System.Environment.GetCommandLineArgs();
try {
tmp=cmds[1];
}catch (IndexOutOfRangeException ){
// MessageBox.Show ("");
}
// 画面全体をスクリーンキャプチャ 一時ファイルに保存
Fsc();
// フルスクリーン オプション
if (tmp =="/F" || tmp =="/f") {
string outfile=DateTime.Now.ToString("yyMMdd-HH-mm-ss");
CropJpeg(Desktop+"\\ND_SSTMP.JPG", Desktop+"\\"+outfile+".jpg", 0,0,(int)SystemParameters.PrimaryScreenWidth-1,(int)SystemParameters.PrimaryScreenHeight-1);
File.Delete(Desktop+"\\ND_SSTMP.JPG");
Application.Current.Shutdown();
}
else{
// カーソル設定
this.Cursor = Cursors.Cross;
SetCursorPos((int)SystemParameters.PrimaryScreenWidth/2,(int)SystemParameters.PrimaryScreenHeight/2);
}
}
// 画面全体をスクリーンキャプチャ 一時ファイルに保存
public void Fsc() {
// デスクトップにND_SSフォルダ作成
Desktop=System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
Directory.CreateDirectory(Desktop+"\\ND_SS");
Desktop+="\\ND_SS";
BitmapSource bs=CopyScreen();
using (Stream stream = new FileStream (Desktop+"\\ND_SSTMP.JPG", FileMode.Create)){
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bs));
encoder.Save(stream);
}
}
// 選択前
public void Msg1(object sender) {
var canvas = sender as Canvas;
SolidColorBrush brush = new SolidColorBrush(System.Windows.Media.Color.FromArgb(255,255, 0, 0));
TextBlock text2 = new TextBlock{
Text = " ~ JPGファイル保存 ~\r\n[マウス 左] 選択開始\r\n[SPACE] キャプチャ中止(終了)\r\n[HOME] 全画面の保存&終了",
FontSize = 21,
Foreground = brush,
FontWeight= FontWeights.Bold,
};
// X軸設定 //////////////
bool FLG = false;
// 左端
if (x2 < 140) {
Canvas.SetLeft(text2,10);
FLG = true;
}
// 右端
if (x2>(int)SystemParameters.PrimaryScreenWidth -130) {
Canvas.SetLeft(text2,(int)SystemParameters.PrimaryScreenWidth-260);
FLG=true;
}
// 通常
if (FLG==false) Canvas.SetLeft(text2,x2-130 );
/////////////////////////////////////////////////////////////////////////
// Y軸設定 //////////////
// マウスが下より上
if ( Y==0 && ( y2 < (int)SystemParameters.PrimaryScreenHeight-120 ) ) Canvas.SetTop(text2,y2+15);
// マウスが下の下 は必ず上表示
if ( y2 > (int)SystemParameters.PrimaryScreenHeight-120){
Canvas.SetTop(text2,y2-100);
Y=2;
}
// マウスが上より下で上に表示中
if ( Y==2 && (y2 > 80) ) Canvas.SetTop(text2,y2-125);
// マウスが上の上
if ( y2 < 130 ) {
Canvas.SetTop(text2,y2+20);
Y=0;
}
// 下に表示中でマウスが画面より下
if ( Y==0 && y2 > (int)SystemParameters.PrimaryScreenHeight-100 ){
Canvas.SetTop(text2,y2+30);
Y=5;
}
// 文字表示
DrawCanvas.Children.Add(text2);
}
// 選択中
public void Msg2(object sender) {
if ( F!=4 && (Math.Abs(x2-x1) < 350 || Math.Abs(y2-y1) < 110 )) {
F=1;
}
else F=2;
var canvas = sender as Canvas;
SolidColorBrush brush = new SolidColorBrush(System.Windows.Media.Color.FromArgb((byte)AL,0,255 , 255));
TextBlock text = new TextBlock{
Text = " ~ 保 存 ~\r\n[ 左Up ] 保存&終了\r\n[SPACE] キャプチャ中止(終了)\r\n[HOME] 全画面の保存&終了\r\n[ENTER] 範囲指定やり直し",
FontSize = 27,
FontWeight= FontWeights.Bold,
Foreground = brush
};
if (F == 2) F=4;
if (F ==1 ) {
text.Text= "左ボタン押したままマウスを移動させ範囲指定します";
Canvas.SetLeft(text,(x2-x1)/2+x1-265);
Canvas.SetTop (text,(y2-y1)/2+y1-40 );
}
else{
Canvas.SetLeft(text,(x2-x1)/2+x1-170);
}
if (F == 4) {
Canvas.SetTop(text, (y2 - y1) / 2 + y1 - 90);
}
DrawCanvas.Children.Add(text);
}
private void Window_PreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e) {
var canvas = sender as Canvas;
System.Windows.Point position = e.GetPosition(canvas);
DrawCanvas.Children.Clear();
// MOUSE XY
x2=(int)position.X;
y2=(int)position.Y;
SolidColorBrush brush = new SolidColorBrush(System.Windows.Media.Color.FromArgb(255,255, 0, 0));
// 選択開始前の説明表示
if (area_select==false) {
Msg1(sender);
return;
}
// 範囲選択中の説明表示
Msg2(sender);
// 選択枠四角描画
Line Line1 = new Line();
Line Line2 = new Line();
Line Line3 = new Line();
Line Line4 = new Line();
// この場合、LボタンのイベントハンドラはCanvas上にあるのでそのLボタンUPを捕捉させる
Line1.MouseUp += Window_PreviewMouseLeftButtonUp;
Line2.MouseUp += Window_PreviewMouseLeftButtonUp;
Line3.MouseUp += Window_PreviewMouseLeftButtonUp;
Line4.MouseUp += Window_PreviewMouseLeftButtonUp;
Line4.Stroke = Line3.Stroke = Line2.Stroke = Line1.Stroke = System.Windows.Media.Brushes.Red;
Line4.StrokeThickness = Line3.StrokeThickness = Line2.StrokeThickness = Line1.StrokeThickness = WAKU;
// 左上から左下
Line1.X1 = x1; // 開始点X
Line1.Y1 = y1; // 開始点Y
Line1.X2 = x1; // 終了点X
Line1.Y2 = y2; // 終了点Y
DrawCanvas.Children.Add(Line1);
// 左上から右上
Line2.X1 = x1;
Line2.Y1 = y1;
Line2.X2 = x2;
Line2.Y2 = y1;
DrawCanvas.Children.Add(Line2);
//左下から右下
Line3.X1 = x1;
Line3.Y1 = y2;
Line3.X2 = x2;
Line3.Y2 = y2;
DrawCanvas.Children.Add(Line3);
//右上から右下
Line4.X1 = x2;
Line4.Y1 = y1;
Line4.X2 = x2;
Line4.Y2 = y2;
DrawCanvas.Children.Add(Line4);
// 選択範囲が狭いときは暗く表示する
/*
if (Math.Abs (x2-x1) < 350 ) {
AL=Math.Abs (x2-x1)/2;
if (AL>=254) AL=254;
if (AL<=0) AL=0;
return;
}
if (Math.Abs (x2-x1) > 350) {
AL=254;
return;
}
*/
if (F==1 ) {
AL=254;
return;
}
// 高さによって文字を薄くする
if (Math.Abs (y2-y1) < 400 ) {
AL=Math.Abs (y2-y1)/2+45;
return;
}
if (Math.Abs (y2-y1) > 400) AL=254;
}
// キャプチャ
private void Window_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e) {
DrawCanvas.Children.Clear();
int xx=x1,yy=y1,he=y2-y1,wi=x2-x1;
// FILENAME
string outfile=DateTime.Now.ToString("yyMMdd-HH-mm-ss");
// Window_PreviewMouseLeftButtonDown()により開始点がx1,y1に入る。
// それより左、または上に終点(x2,y2)とした場合、
// x1 > x2 になり、例外出るので補正。Y座標、幅等についても同じ
// 選択開始が左上から右下へ
if(x1 < x2 && y1 < y2) {
CropJpeg(Desktop+"\\ND_SSTMP.JPG", Desktop+"\\"+outfile+".jpg", xx,yy,wi,he);
File.Delete(Desktop+"\\ND_SSTMP.JPG");
Application.Current.Shutdown();
}
// 右下から左上へ
if (x1 > x2 && y1 > y2 ){
xx=x2;
yy=y2;
wi=Math.Abs(wi);
he=Math.Abs(he);
}
// 左下から右上へ
if (x1 < x2 && y1 > y2) {
wi=x2-x1;
he=y1-y2;
yy=y2;
}
// 右上から左下
if (y1 < y2 && x1 > x2){
yy=y1;
wi=x2-x1;
wi=Math.Abs(wi);
he=y2-y1;
xx=x2;
}
// 切り抜き保存
//CropJpeg(Desktop+"\\ND_SSTMP.JPG", Desktop+"\\"+outfile+".jpg", xx-10,yy-7,wi+17,he+15);
CropJpeg(Desktop+"\\ND_SSTMP.JPG", Desktop+"\\"+outfile+".jpg", xx-10,yy-7,wi+5,he+2);
// 一時ファイル削除
File.Delete(Desktop+"\\ND_SSTMP.JPG");
Application.Current.Shutdown();
}
// 全画面キャプチャ or 中止 or 撮り直し
private void print_KeyDown(object sender, System.Windows.Input.KeyEventArgs e) {
if ( (e.Key != Key.Space && e.Key != Key.Return && e.Key!= Key.Home)) return;
// 撮り直し
if (e.Key == Key.Return){
F=0;
area_select=false;
return;
}
// 全画面キャプチャ
if(e.Key == Key.Home){
string outfile=DateTime.Now.ToString("yyMMdd-HH-mm-ss");
CropJpeg(Desktop+"\\ND_SSTMP.JPG", Desktop+"\\"+outfile+".jpg", 0,0,(int)SystemParameters.PrimaryScreenWidth-1,(int)SystemParameters.PrimaryScreenHeight-1);
}
try {
File.Delete(Desktop+"\\ND_SSTMP.JPG");
}
catch{ }
Application.Current.Shutdown();
}
// 選択開始
private void Window_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) {
DrawCanvas.Children.Clear();
var canvas = sender as Canvas;
area_select=true;
// 選択開始位置
System.Windows.Point position = e.GetPosition(canvas);
x1=(int)position.X;
y1=(int)position.Y;
Msg2(sender);
}
// 全画面キャプチャ
private BitmapSource CopyScreen(){
using (var screenBmp = new Bitmap((int)SystemParameters.PrimaryScreenWidth,(int)SystemParameters.PrimaryScreenHeight,System.Drawing.Imaging.PixelFormat.Format32bppArgb)){
using (var bmpGraphics = Graphics.FromImage(screenBmp)){
bmpGraphics.CopyFromScreen(0, 0, 0, 0, screenBmp.Size);
return Imaging.CreateBitmapSourceFromHBitmap(screenBmp.GetHbitmap(),IntPtr.Zero,Int32Rect.Empty,BitmapSizeOptions.FromEmptyOptions());
}
}
}
// 指定した座標位置から画像切り出し
public void CropJpeg(string inputPath, string outputPath, int x, int y, int width, int height){
BitmapImage source = new BitmapImage();
source.BeginInit();
source.UriSource = new Uri(inputPath, UriKind.Absolute);
source.CacheOption = BitmapCacheOption.OnLoad;
source.EndInit();
var rect = new System.Drawing.Rectangle((int)this.Left, (int)this.Top, (int)this.Width, (int)this.Height);
var screen = System.Windows.Forms.Screen.FromRectangle(rect);
int w = screen.Bounds.Width;
int h = screen.Bounds.Height;
// 座標補正、例外対応
if (x+width >=w) width =w-x;
if (y+height>=h) height =h-y;
if (y<0) y=0;
if (x<0) x=0;
if (width >w) width =w;
if (height >h) height=h;
Int32Rect cropArea = new Int32Rect(x, y, width, height);
CroppedBitmap cropped=null;
try{
cropped = new CroppedBitmap(source, cropArea);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(cropped));
using (FileStream fs = new FileStream(outputPath, FileMode.Create)){
encoder.Save(fs);
fs.Close();
}
}
catch {
cropped =null;
m("範囲が狭すぎます.やり直して下さい.");
Application.Current.Shutdown();
}
}
}
}
5.WPF (XAML)
<Window x:Class="WPF_SC.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPF_SC" AllowsTransparency="True" ShowInTaskbar="False"
Background="#50000000" mc:Ignorable="d" WindowStyle="None" WindowState="Maximized"
Title="MainWindow" PreviewMouseLeftButtonDown="Window_PreviewMouseLeftButtonDown" PreviewMouseMove="Window_PreviewMouseMove" KeyDown="print_KeyDown" Loaded="Window_Loaded" >
<Grid x:Name="G1" >
<Canvas Name="DrawCanvas">
</Canvas>
</Grid>
</Window>