4-2-2. Copilotにコードレビューしてもらおう

# 1.今回やること
・GitHub Copilotを使用してコードレビューをしてもらいました。
・お願いしたことは、「コードレビューをお願いできますか？」
<br>
![20-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131051/7a607c06-141e-8392-b150-59d22820275e.png)

```cpp:MainWindow.xaml.cpp-copilotの提案

// エラーハンドリングとリソース解放を追加した MatToBitmapAsync 関数
winrt::Windows::Foundation::IAsyncOperation<winrt::Microsoft::UI::Xaml::Media::Imaging::BitmapImage>
winrt::WinUI_OpenCV::implementation::MainWindow::MatToBitmapAsync(const cv::Mat& mat)
{
    if (mat.empty())
    {
        co_return nullptr;
    }

    try
    {
        // ① imencode を使用してバイト配列へエンコード
        std::vector<uchar> imagebuf;
        if (!cv::imencode(".bmp", mat, imagebuf))
        {
            co_return nullptr;
        }

        // ② InMemoryRandomAccessStream を作成
        winrt::Windows::Storage::Streams::InMemoryRandomAccessStream rcstream;

        // ③ DataWriter を使用してストリームへデータを書き込む
        {
            auto outputstream = rcstream.GetOutputStreamAt(0);
            winrt::Windows::Storage::Streams::DataWriter writer(outputstream);

            writer.WriteBytes(winrt::array_view<const uint8_t>(imagebuf));
            co_await writer.StoreAsync();
            co_await outputstream.FlushAsync();

            // リソースを解放
            writer.Close();
            outputstream.Close();
        }

        // ④ ストリームの位置を先頭に戻す
        rcstream.Seek(0);

        // ⑤ BitmapImage を作成
        winrt::Microsoft::UI::Xaml::Media::Imaging::BitmapImage bitmap;
        co_await bitmap.SetSourceAsync(rcstream);

        // ストリームを解放
        rcstream.Close();

        co_return bitmap;
    }
    catch (const std::exception& ex)
    {
        // エラーのログ出力（必要に応じて）
        OutputDebugStringA(ex.what());
        co_return nullptr;
    }
}

// 共通処理をまとめた ResizeAndDisplayImage 関数
winrt::Windows::Foundation::IAsyncAction
winrt::WinUI_OpenCV::implementation::MainWindow::ResizeAndDisplayImage(double scale)
{
    if (_loadImg.empty())
    {
        co_return;
    }

    // 画像のリサイズ
    ResizeImage(scale);

    // 画像を BitmapImage に変換
    auto bitmap = co_await MatToBitmapAsync(_loadImg);
    if (!bitmap)
    {
        co_return;
    }

    // ウィンドウサイズを画像サイズに合わせる
    ResizeWindowToImage(bitmap);

    // 画像を表示
    _showImage().Source(bitmap);
}

// Enlarge2Times_Click と Reduce2Times_Click の修正
winrt::Windows::Foundation::IAsyncAction
winrt::WinUI_OpenCV::implementation::MainWindow::Enlarge2Times_Click(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&)
{
    // 面積を2倍に拡大（1辺を √2 倍）
    co_await ResizeAndDisplayImage(std::sqrt(2.0));
}

winrt::Windows::Foundation::IAsyncAction
winrt::WinUI_OpenCV::implementation::MainWindow::Reduce2Times_Click(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&)
{
    // 面積を1/2に縮小（1辺を 1/√2 倍）
    co_await ResizeAndDisplayImage(1.0 / std::sqrt(2.0));
}


```

![20-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131051/02fa8a5d-fb6e-c1e8-935e-8b295712f82c.png)


・確かに良い提案をしてくれていますね。
・素晴らしいと褒めてもくれてるし（単純なのでそれだけでも嬉しい）
・全面的にこの提案を受け入れて、もう少し良いコードへ変更しましょう。

```cpp:MainWindow.xaml.h

#pragma once

#include "MainWindow.g.h"

//6-2で追加。OpenCVのヘッダーをインクルード
#include <opencv2/opencv.hpp>

namespace winrt::WinUI_OpenCV::implementation
{
    struct MainWindow : MainWindowT<MainWindow>
    {
        MainWindow()
        {
            //6-1で追加。タイトル変更
			Title(L"WinUI_OpenCV");
        }

        //6-1で追加。ウインドウハンドルの取得
        HWND GetHWND();

		//6-2で追加。wstringからstringへの変換
		std::string WStringToString(const std::wstring& utf16);
		//6-2で追加。stringからwstringへの変換
		std::wstring StringToWString(const std::string& jisstr);

		//6-3で追加。MatからBitmapImageへの変換
        winrt::Windows::Foundation::IAsyncOperation<winrt::Microsoft::UI::Xaml::Media::Imaging::BitmapImage> MatToBitmapAsync(const cv::Mat& mat);

		//6-3で追加。ウインドウサイズを画像サイズに合わせる
        void ResizeWindowToImage(const winrt::Microsoft::UI::Xaml::Media::Imaging::BitmapImage& bitmap);

        //6-4で追加。画像サイズを変更
        void ResizeImage(const double scale);

        //4-2-2で追加。ウインドウサイズ変更の共通処理
        winrt::Windows::Foundation::IAsyncAction ResizeAndDisplayImage(double scale);

        //イベントハンドラ
        
		//6-1で変更。非同期化
        winrt::Windows::Foundation::IAsyncAction Open_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);

        void Exit_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);

        //6-4で変更。非同期化
        winrt::Windows::Foundation::IAsyncAction Enlarge2Times_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);

        //6-4で変更。非同期化
        winrt::Windows::Foundation::IAsyncAction Reduce2Times_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);

	private:
		//6-2で追加。画像データ保存メンバ
        cv::Mat _loadImg;

    };
}

namespace winrt::WinUI_OpenCV::factory_implementation
{
    struct MainWindow : MainWindowT<MainWindow, implementation::MainWindow>
    {
    };
}

```

```cpp:MainWindow.xaml.cpp

#include "pch.h"
#include "MainWindow.xaml.h"
#if __has_include("MainWindow.g.cpp")
#include "MainWindow.g.cpp"
#endif

using namespace winrt;
using namespace Microsoft::UI::Xaml;

//6-1で追加。::IWindowNativeと::IInitializeWithWindowを使うのにmicrosoft.ui.xaml.window.h、Shobjidl.hが必要
#include <microsoft.ui.xaml.window.h>
#include <Shobjidl.h>

//6-1で追加。FilePickerを使用するのにwinrt/Windows.Storage.Pickers.hが必要
#include <winrt/Windows.Storage.Pickers.h>

//6-3で追加。InMemoryRandomAccessStreamを使用するのにwinrt/Windows.Storage.Streams.hが必要
#include <winrt/Windows.Storage.Streams.h>

//6-3で追加。BitmapImageを使用するのにwinrt/Microsoft.UI.Xaml.Media.Imaging.hが必要
#include <winrt/Microsoft.UI.Xaml.Media.Imaging.h>

//6-3で追加GetWindowIdFromWindowを使用するのにwinrt/Microsoft.ui.interop.hとwinrt/Microsoft.UI.Windowing.hが必要
#include <winrt/Microsoft.UI.Interop.h>
#include <winrt/Microsoft.UI.Windowing.h>

//6-3で追加。Windows.Graphics.SizeInt32を使用するのにwinrt/Windows.Graphics.hが必要
#include <winrt/Windows.Gaming.Input.h>


namespace winrt::WinUI_OpenCV::implementation
{

}

//6-1で追加。ウインドウハンドルの取得
HWND winrt::WinUI_OpenCV::implementation::MainWindow::GetHWND()
{
	auto windowNative{ this->m_inner.as<::IWindowNative>() };
	HWND hWnd{ 0 };
	windowNative->get_WindowHandle(&hWnd);

	return hWnd;
}

//6-2で追加。wstringからstringへの変換
std::string winrt::WinUI_OpenCV::implementation::MainWindow::WStringToString(const std::wstring& utf16)
{
	std::string jisstr;
	int jissize = WideCharToMultiByte(CP_ACP, 0, utf16.c_str(), -1, nullptr, 0, nullptr, nullptr);
	if (jissize > 0)
	{
		jisstr.resize(jissize);
		WideCharToMultiByte(CP_ACP, 0, utf16.c_str(), -1, jisstr.data(), jissize, nullptr, nullptr);
	}
	return jisstr;
}

//6-2で追加。stringからwstringへの変換
std::wstring winrt::WinUI_OpenCV::implementation::MainWindow::StringToWString(const std::string& jisstr)
{
	std::wstring utf16;
	int utf16size = MultiByteToWideChar(CP_ACP, 0, jisstr.c_str(), -1, nullptr, 0);
	if (utf16size > 0)
	{
		utf16.resize(utf16size);
		MultiByteToWideChar(CP_ACP, 0, jisstr.c_str(), -1, utf16.data(), utf16size);
	}
	return utf16;	
}

//6-3で追加。MatからBitmapImageへの変換
//4-2-2で変更。エラーハンドリングを追加
winrt::Windows::Foundation::IAsyncOperation<winrt::Microsoft::UI::Xaml::Media::Imaging::BitmapImage> winrt::WinUI_OpenCV::implementation::MainWindow::MatToBitmapAsync(const cv::Mat& mat)
{
	if (mat.empty())
	{
		co_return nullptr;
	}

	try
	{
		// ① imencode を使用してバイト配列へエンコード
		std::vector<uchar> imagebuf;
		if (!cv::imencode(".bmp", mat, imagebuf))
		{
			co_return nullptr;
		}

		// ② InMemoryRandomAccessStream を作成
		winrt::Windows::Storage::Streams::InMemoryRandomAccessStream rcstream;

		// ③ DataWriter を使用してストリームへデータを書き込む
		{
			auto outputstream = rcstream.GetOutputStreamAt(0);
			winrt::Windows::Storage::Streams::DataWriter writer(outputstream);

			writer.WriteBytes(winrt::array_view<const uint8_t>(imagebuf));
			co_await writer.StoreAsync();
			co_await outputstream.FlushAsync();

			// リソースを解放
			writer.Close();
			outputstream.Close();
		}

		// ④ ストリームの位置を先頭に戻す
		rcstream.Seek(0);

		// ⑤ BitmapImage を作成
		winrt::Microsoft::UI::Xaml::Media::Imaging::BitmapImage bitmap;
		co_await bitmap.SetSourceAsync(rcstream);

		// ストリームを解放
		rcstream.Close();

		co_return bitmap;
	}
	catch (const std::exception& ex)
	{
		// エラーのログ出力（必要に応じて）
		OutputDebugStringA(ex.what());
		co_return nullptr;
	}
}

//6-3で追加。ウインドウサイズを画像サイズに合わせる
void winrt::WinUI_OpenCV::implementation::MainWindow::ResizeWindowToImage(const winrt::Microsoft::UI::Xaml::Media::Imaging::BitmapImage& bitmap)
{
	//①ウインドウIDからAppWindowを作成。
	auto wndid = Microsoft::UI::GetWindowIdFromWindow(GetHWND());
	auto appwnd = Microsoft::UI::Windowing::AppWindow::GetFromWindowId(wndid);

	//②Bitmapのサイズを取得＋高さにはmenuの高さ
	auto menuheight = _menuBar().ActualHeight();
	winrt::Windows::Graphics::SizeInt32 imgsize;
	imgsize.Width = bitmap.PixelWidth();
	imgsize.Height = bitmap.PixelHeight() + menuheight;

	//③AppWindowのResize()を使用してウインドウサイズを変更
	appwnd.Resize(imgsize);
}

void winrt::WinUI_OpenCV::implementation::MainWindow::ResizeImage(const double scale)
{
	if (_loadImg.empty())
		return;

	//画像を拡大縮小. cv::resize()を使用
	cv::Mat resizedImg;
	cv::resize(_loadImg, resizedImg, cv::Size(), scale, scale, cv::INTER_CUBIC);

	//_loadImgをresizedImgで上書き
	_loadImg = resizedImg.clone();
}

//4-2-2で追加。ウインドウサイズ変更の共通処理
winrt::Windows::Foundation::IAsyncAction winrt::WinUI_OpenCV::implementation::MainWindow::ResizeAndDisplayImage(double scale)
{
	if (_loadImg.empty())
	{
		co_return;
	}

	// 画像のリサイズ
	ResizeImage(scale);

	// 画像を BitmapImage に変換
	auto bitmap = co_await MatToBitmapAsync(_loadImg);
	if (!bitmap)
	{
		co_return;
	}

	// ウィンドウサイズを画像サイズに合わせる
	ResizeWindowToImage(bitmap);

	// 画像を表示
	_showImage().Source(bitmap);
}

winrt::Windows::Foundation::IAsyncAction winrt::WinUI_OpenCV::implementation::MainWindow::Open_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
	//6-1で追加。FileOpenPickerを使用してファイルを開く
	winrt::Windows::Storage::Pickers::FileOpenPicker imgpicker;
	imgpicker.as<::IInitializeWithWindow>()->Initialize(this->GetHWND());
	imgpicker.FileTypeFilter().Append(L".jpg");
	imgpicker.FileTypeFilter().Append(L".png");
	imgpicker.FileTypeFilter().Append(L".bmp");
	imgpicker.FileTypeFilter().Append(L".gif");
	imgpicker.SuggestedStartLocation(winrt::Windows::Storage::Pickers::PickerLocationId::Desktop);

	auto&& imgfile = co_await imgpicker.PickSingleFileAsync();

	//6-1で追加。ファイルが選択されなかった場合はco_returnで関数を終了
	if (!imgfile)
	{
		co_return;
	}

	//6-1で追加。ファイルパスの取得
	std::wstring imgpath = imgfile.Path().c_str();

	//6-2で追加。wstringからstringへの変換
	std::string utf8path = WStringToString(imgpath);

	//6-2で追加。OpenCVで画像を読み込む
	_loadImg = cv::imread(utf8path);

	//6-2で追加。画像データを表示 6-4でコメントアウト
	//cv::imshow("Load Image", _loadImg);

	//4-2-2で変更。共通処理化。倍率は変更しないので1倍1
	co_await ResizeAndDisplayImage(1.0);
}

void winrt::WinUI_OpenCV::implementation::MainWindow::Exit_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
	//6-1で追加。アプリの終了
	Application::Current().Exit();
}

//6-4で変更。非同期化
//4-2-2で変更。共通処理化
winrt::Windows::Foundation::IAsyncAction winrt::WinUI_OpenCV::implementation::MainWindow::Enlarge2Times_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
	// 面積を2倍に拡大（1辺を √2 倍）
	co_await ResizeAndDisplayImage(std::sqrt(2.0));
}

//6-4で変更。非同期化
//4-2-2で変更。共通処理化
winrt::Windows::Foundation::IAsyncAction winrt::WinUI_OpenCV::implementation::MainWindow::Reduce2Times_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
	// 面積を1/2に縮小（1辺を 1/√2 倍）
	co_await ResizeAndDisplayImage(1.0 / std::sqrt(2.0));
}

```


・この変更はコミットしませんが、最終的にこうなりました。
・こんな感じでGitHub Copilotはコードレビューもしてくれる良いツールです。
・使っていると色々鬱陶しい部分もありますが…
・こんなに使えるツールが$10/月とお買い得になっています。

・実際にwstringとstringの変換部分はcopilotが提案してくれたままですし、お値段以上の価値がある気がしています。

[もくじへ](https://qiita.com/lilac0011/items/f53f7401ea7da31e3a0b)