ぬの部屋(仮)
nu-no-he-ya
  •      12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
         12
    3456789
    10111213141516
    17181920212223
    2425262728  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
       1234
    567891011
    12131415161718
    19202122232425
    26272829   
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28      
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
    1234567
    891011121314
    15161718192021
    22232425262728
           
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
         12
    3456789
    10111213141516
    17181920212223
    242526272829 
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
        123
    45678910
    11121314151617
    18192021222324
    25262728   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    15161718192021
    293031    
           
         12
    3456789
    10111213141516
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
          1
    2345678
    9101112131415
    16171819202122
    232425262728 
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
  • skiaで画像ファイルの読み込みとクロッピング

    ファイルから画像を読み込む方法。それから矩形で画像を切り出す方法。表示はwxWidgetsに出力している。

    // https://docs.wxwidgets.org/3.0/overview_helloworld.html
    
    // プリプロセッサに以下二つを追加
    // __WXMSW__
    // WXUSINGDLL
    
    // サブシステムをWindowsに設定(WinMainで呼び出すので)
    // Windows (/SUBSYSTEM:WINDOWS)
    
    #ifndef WX_PRECOMP
    #include <wx/wx.h>
    #endif
    
    #include <wx/gdicmn.h> // wxPointに必要
    #include <wx/frame.h>  // wxFrameに必要
    
    #pragma comment(lib,"skia.dll.lib")
    
    #include "skia/include/core/SkCanvas.h"
    #include "skia/include/core/SkBitmap.h"
    #include "skia/include/core/SkImage.h"
    
    // 画像読み込み
    #include "skia/include/core/SkStream.h"
    #include "skia/include/codec/SkCodec.h"
    
    
    /////////////////////////////////////
    /////////////////////////////////////
    /////////////////////////////////////
    
    #include <string>
    
    
    void getPixelRGB(std::vector<std::uint8_t>& rgb,const SkBitmap& bitmap) {
      if (!bitmap.readyToDraw()) {
        return;
      }
    
      if (bitmap.colorType() != kRGBA_8888_SkColorType && bitmap.colorType() != kBGRA_8888_SkColorType) {
        return; // Unsupported format
      }
    
      int Width = bitmap.width();
      int Height = bitmap.height();
    
      size_t rowBytes = bitmap.rowBytes();
      const auto& info = bitmap.info();
      int channels = info.bytesPerPixel();
      std::uint8_t* pixels = (std::uint8_t*)bitmap.getPixels();
    
      rgb.resize(Width * Height * 3);
      for (int i = 0; i < Height; i++) {
        for (int j = 0; j < Width; j++) {
          size_t pos_ppm = (i * Width + j) * 3;
          size_t pos_sk = (i * rowBytes + j * channels);
          rgb[pos_ppm + 0] = pixels[pos_sk + 2];
          rgb[pos_ppm + 1] = pixels[pos_sk + 1];
          rgb[pos_ppm + 2] = pixels[pos_sk + 0];
        }
      }
    }
    
    //////////////////////////////////////////////////////////////////
     
    //! @brief 画像読み込み関数
    //! @param path 画像ファイルのパス
    //! @param bitmap 読み込んだ画像を格納するビットマップ
    //! @return 読み込みに成功したらtrue
    bool LoadImageToBitmap(const std::string& path, SkBitmap* bitmap) {
      // ファイルからデータを読み込む
    
    sk_sp<SkData> data = SkData::MakeFromFileName(path.c_str()); if (!data) { return false; // データの読み込みに失敗 } // データからSkCodecを作成 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(data)); if (!codec) { return false; // コーデックの作成に失敗 } // ロード先のビットマップの情報を設定 SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); // ロード先のメモリ確保 if (!bitmap->tryAllocPixels(info)) { return false; // メモリ確保に失敗 } // ロード先へ画像をデコード SkCodec::Result ret = codec->getPixels( info, // 画像の情報 bitmap->getPixels(), // ロード先のメモリ bitmap->rowBytes() // ロード先の1行のバイト数 ); if (ret != SkCodec::kSuccess) { return false; // 画像のデコードに失敗 } return true; }
    //////////////////////////////////////////////////////////////////
    
    
    //! @brief 画像の一部を切り出す
    //! @param dst 切り出した画像を格納するビットマップ
    //! @param src 元画像
    //! @param croprect 切り出す範囲
    //! @return なし
    void CropImage(SkBitmap* dst, const SkBitmap& src, const SkIRect croprect) {
    
      sk_sp<SkImage> src_bmp_img = src.asImage();// SkBitmapをSkImageに変換
      SkCanvas canv(src);
    
      dst->allocN32Pixels(croprect.width(), croprect.height());// 画像のメモリ確保
    
      SkCanvas croppedCanvas(*dst);// 結果のSkBitmapからSkCanvas作成
      SkIRect dstRect = SkIRect::MakeWH(croprect.width(), croprect.height());// 結果の書き込み範囲作成
    
      SkSamplingOptions samplingOptions(SkFilterMode::kLinear);
      croppedCanvas.drawImageRect(
        src_bmp_img,            // 元画像
        SkRect::Make(croprect), // 切り取り範囲
        SkRect::Make(dstRect),  // 描画範囲
        samplingOptions,        // サンプリングオプション
        nullptr,
        SkCanvas::kStrict_SrcRectConstraint // 切り取り範囲を超えた描画を禁止
      );
    }
    
    // ウィンドウ作成
    class MyFrame : public wxFrame
    {
      SkBitmap _bmp;
    public:
    
      void PostCreate() {
        
    // 画像をファイルから読み込む LoadImageToBitmap("test.png", &_bmp); Bind(wxEVT_PAINT, &MyFrame::OnPaint, this); this->Layout(); // レイアウトの更新 } MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(NULL, wxID_ANY, title, pos, size) { // CallAfter : 現在処理中のイベントが終わったらPostCreateを実行 // コンストラクタはウィンドウ生成イベント扱い CallAfter(&MyFrame::PostCreate); } void OnPaint(wxPaintEvent& event) { // 切り出したい範囲をSkIRectで定義 SkIRect cropRect = SkIRect::MakeXYWH(300, 300, 400, 200); // 切り出した画像を格納する画像 SkBitmap croppedBitmap; // 切り出し処理 CropImage(&croppedBitmap, _bmp, cropRect); ////////////////////////////////////////// SkBitmap* dispbmp = &croppedBitmap; std::vector<std::uint8_t> rgb; getPixelRGB(rgb,*dispbmp); wxImage img(dispbmp->width(), dispbmp->height(), (unsigned char*)rgb.data(), true); wxBitmap wxbitmap(img); wxPaintDC dc(this); dc.DrawBitmap(wxbitmap, 0, 0, true); } private: }; ///////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// // wxWidgetsのアプリケーション作成 class MyApp : public wxApp { public: virtual bool OnInit() { MyFrame* frame = new MyFrame("Hello World", wxPoint(50, 50), wxSize(450, 340)); frame->Show(true); return true; } }; ///////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// // WinMainをマクロで定義 wxIMPLEMENT_APP(MyApp);

    Skia(4)SkBitmapをwxWidgetsで表示

    SkiaのSkBitmapをwxWidgetsのwxBitmapに変換して表示する。

    wxWidgetsがRGBなのに対して、SkiaはRGBをサポートしていないので、32bit→24bitへの変換が必要になる。変換関数らしきものを見つけたがどうしてもうまく動かなかったので手動で変換している。

    // https://docs.wxwidgets.org/3.0/overview_helloworld.html
    
    // プリプロセッサに以下二つを追加
    // __WXMSW__
    // WXUSINGDLL
    
    // サブシステムをWindowsに設定(WinMainで呼び出すので)
    // Windows (/SUBSYSTEM:WINDOWS)
    
    #ifndef WX_PRECOMP
    #include <wx/wx.h>
    #endif
    
    #include <wx/gdicmn.h> // wxPointに必要
    #include <wx/frame.h>  // wxFrameに必要
    
    #ifdef _DEBUG
    #pragma comment(lib,"wxbase32ud.lib")
    #pragma comment(lib,"wxbase32ud_net.lib")
    #pragma comment(lib,"wxbase32ud_xml.lib")
    #pragma comment(lib,"wxmsw32ud_adv.lib")
    #pragma comment(lib,"wxmsw32ud_aui.lib")
    #pragma comment(lib,"wxmsw32ud_core.lib")
    #pragma comment(lib,"wxmsw32ud_gl.lib")
    #pragma comment(lib,"wxmsw32ud_html.lib")
    #pragma comment(lib,"wxmsw32ud_media.lib")
    #pragma comment(lib,"wxmsw32ud_propgrid.lib")
    #pragma comment(lib,"wxmsw32ud_qa.lib")
    #pragma comment(lib,"wxmsw32ud_ribbon.lib")
    #pragma comment(lib,"wxmsw32ud_richtext.lib")
    #pragma comment(lib,"wxmsw32ud_stc.lib")
    #pragma comment(lib,"wxmsw32ud_webview.lib")
    #pragma comment(lib,"wxmsw32ud_xrc.lib")
    
    #else
    
    #pragma comment(lib,"wxbase32u.lib")
    #pragma comment(lib,"wxbase32u_net.lib")
    #pragma comment(lib,"wxbase32u_xml.lib")
    #pragma comment(lib,"wxmsw32u_adv.lib")
    #pragma comment(lib,"wxmsw32u_aui.lib")
    #pragma comment(lib,"wxmsw32u_core.lib")
    #pragma comment(lib,"wxmsw32u_gl.lib")
    #pragma comment(lib,"wxmsw32u_html.lib")
    #pragma comment(lib,"wxmsw32u_media.lib")
    #pragma comment(lib,"wxmsw32u_propgrid.lib")
    #pragma comment(lib,"wxmsw32u_qa.lib")
    #pragma comment(lib,"wxmsw32u_ribbon.lib")
    #pragma comment(lib,"wxmsw32u_richtext.lib")
    #pragma comment(lib,"wxmsw32u_stc.lib")
    #pragma comment(lib,"wxmsw32u_webview.lib")
    #pragma comment(lib,"wxmsw32u_xrc.lib")
    
    #endif
    
    #pragma comment(lib,"skia.dll.lib")
    
    /////////////////////////////////////
    
    #include "skia/include/core/SkCanvas.h"
    #include "skia/include/core/SkBitmap.h"
    
    
    /////////////////////////////////////
    /////////////////////////////////////
    /////////////////////////////////////
    
    #include <string>
    
    
    // SkBitmapをRGBの配列に変換
    void
    PixelRGB(std::vector<std::uint8_t>& rgb,const SkBitmap& skbmp) { if (!skbmp.readyToDraw()) { return; } if (skbmp.colorType() != kRGBA_8888_SkColorType && skbmp.colorType() != kBGRA_8888_SkColorType) { return; } rgb.clear(); int Width = skbmp.width(); int Height = skbmp.height(); size_t rowBytes = skbmp.rowBytes(); const SkImageInfo& info = skbmp.info(); int channels = info.bytesPerPixel(); std::uint8_t* pixels = (std::uint8_t*)skbmp.getPixels(); rgb.resize(Width * Height * 3); for (int i = 0; i < Height; i++) { for (int j = 0; j < Width; j++) { size_t pos_ppm = (i * Width + j) * 3; size_t pos_sk = (i * rowBytes + j * channels); rgb[pos_ppm + 0] = pixels[pos_sk + 2]; rgb[pos_ppm + 1] = pixels[pos_sk + 1]; rgb[pos_ppm + 2] = pixels[pos_sk + 0]; } } }
    // ウィンドウ作成
    class MyFrame : public wxFrame
    {
      SkBitmap my_bitmap;
    public:
    
        void PostCreate() {
    
    
          // 画像の作成・描画
          my_bitmap.setInfo(SkImageInfo::Make(400, 400, kBGRA_8888_SkColorType, kPremul_SkAlphaType));
          my_bitmap.allocPixels();
          SkCanvas canvas(my_bitmap);
          // 背景を白にクリア
          canvas.clear(SK_ColorWHITE);
          // 図形の描画
          SkPaint paint;
          paint.setStyle(SkPaint::kStroke_Style);
          paint.setStrokeWidth(5);
          paint.setColor(SK_ColorRED);
          canvas.drawCircle(200, 200, 100, paint);
    
          // OnPaintイベントを設定
          Bind(wxEVT_PAINT, &MyFrame::OnPaint, this);
    
          this->Layout(); // レイアウトの更新
        }
    
    
        MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
            : wxFrame(NULL, wxID_ANY, title, pos, size)
        
        {
          // CallAfter : 現在処理中のイベントが終わったらPostCreateを実行
          // コンストラクタはウィンドウ生成イベント扱い
          CallAfter(&MyFrame::PostCreate);
        }
    
        // OnPaintイベント
        void OnPaint(wxPaintEvent& event) {
    
    
          // SkBitmapをRGBへ変換
          int width = my_bitmap.width();
          int height = my_bitmap.height();
          std::vector<std::uint8_t> rgb;
          rgb.resize(width * height * 3);
    
          // 変換関数(自作)呼び出し
          PixelRGB(rgb, my_bitmap);
    
          // RGBをwxImageへ変換
          wxImage img(width,height, (unsigned char*)rgb.data(), true);
          wxBitmap wxbitmap(img);
    
          // wxWidgetsのウィンドウに表示
          wxPaintDC dc(this);
          dc.DrawBitmap(wxbitmap, 0, 0, true);
    
        }
    
    };
    
    /////////////////////////////////////
    /////////////////////////////////////
    /////////////////////////////////////
    
    // wxWidgetsのアプリケーション作成
    class MyApp : public wxApp {
    public:
    
      virtual bool OnInit() {
        MyFrame* frame = new MyFrame("Hello World", wxPoint(50, 50), wxSize(550, 550));
        frame->Show(true);
    
        return true;
      }
    
    };
    
    /////////////////////////////////////
    /////////////////////////////////////
    /////////////////////////////////////
    
    // WinMainをマクロで定義
    wxIMPLEMENT_APP(MyApp);
    

    skia(3)Skiaで色々な線を描いてみる

    普通の線・破線

    // SkDashPathEffectに必要
    #include "skia/include/core/SkPathEffect.h"
    #include "skia/include/effects/SkDashPathEffect.h"
    
    void draw(SkCanvas& canvas) {
      // 背景を白にクリア
      canvas.clear(SK_ColorWHITE);
    
      SkPaint paint;
      paint.setStrokeWidth(5);               // 線の太さ
      paint.setColor(SK_ColorRED);           // 線の色
    
      paint.setStyle(SkPaint::kStroke_Style);// 直線を描画
      canvas.drawLine(50, 50, 300, 300, paint);
    
      // #include "skia/include/effects/SkDashPathEffect.h"    
      const float intervals[] = { 10, 10 };  // 破線で描画
    
      paint.setPathEffect(SkDashPathEffect::Make(intervals,2, 0));
      canvas.drawLine(50, 80, 300, 330, paint);
    
    }
    

    ジグザグな線

    //SkDiscretePathEffect
    #include "skia/include/core/SkPath.h"
    #include "include/effects/SkDiscretePathEffect.h"
    
    void draw(SkCanvas& canvas) {
        // 背景を白にクリア
        canvas.clear(SK_ColorWHITE);
    
        SkPaint paint;
        paint.setStrokeWidth(5);                // 線の太さ
        paint.setColor(SK_ColorRED);
    
        paint.setStyle(SkPaint::kStroke_Style); // 直線を描画
    
        auto pathEffect = SkDiscretePathEffect::Make(5.0f, 4.0f); // 乱数シード
        paint.setPathEffect(pathEffect);
    
        SkPath path;
        path.moveTo(50, 50);   // 開始点
        path.lineTo(300, 300); // 終了点
    
        // パスを描画
        canvas.drawPath(path, paint);
    }
    

    線分の両端を丸くする

    void draw(SkCanvas& canvas) {
        // 背景を白にクリア
        canvas.clear(SK_ColorWHITE);
    
        SkPaint paint;
        paint.setColor(SK_ColorRED); // 線の色を設定
        paint.setStrokeWidth(40);    // 線の幅を設定
        paint.setStyle(SkPaint::kStroke_Style); // 描画スタイルをストロークに設定
    
        paint.setStrokeCap(SkPaint::kButt_Cap); // デフォルト
        canvas.drawLine(50, 50-20, 300, 300-20, paint);
    
        paint.setStrokeCap(SkPaint::kRound_Cap); // 両端を丸くする
        canvas.drawLine(50, 110, 300, 360, paint);
    
    }
    

    skia(2)Skiaでpng保存。あとJpeg,webp。

    SkiaでPng保存するには、SkPngEncorder.hとSkStream.hをインクルードし、SkPngEncoder::Optionsで圧縮などの設定、SkFILEWStream でファイルストリーム作成、SkPngEncoder::Encodeで書き込みを行う。

    #pragma comment(lib,"skia.dll.lib")
    
    #include "skia/include/core/SkCanvas.h"
    
    // SkBitmap
    #include "skia/include/core/SkBitmap.h"
    
    // Png保存に必要
    #include "skia/include/encode/SkPngEncoder.h"
    #include "skia/include/core/SkStream.h"
    
    #include <cstdio>
    #include <vector>
    
    // 必要なDLL
    // skia.dll
    // jpeg62.dll
    // zlib1.dll
    
    
    #pragma warning(disable:4996)
    
    
    int main()
    {
        
        //////////////////////////////////////////////////////
        SkBitmap bitmap;
        bitmap.setInfo(SkImageInfo::MakeN32Premul(400, 400));
        bitmap.allocPixels();
        SkCanvas canvas(bitmap);
        // 背景を白にクリア
        canvas.clear(SK_ColorWHITE);
        // 図形の描画
        SkPaint paint;
        paint.setStyle(SkPaint::kStroke_Style);
        paint.setStrokeWidth(5);
        paint.setColor(SK_ColorRED);
        canvas.drawCircle(200, 200, 100, paint);
        //////////////////////////////////////////////////////
    
        // optionsの設定
        SkPngEncoder::Options options;
        options.fZLibLevel = 9; // 圧縮レベル
        options.fFilterFlags = SkPngEncoder::FilterFlag::kAll; // フィルタの種類
    
    
        SkImageInfo info = bitmap.info();
        unsigned char* pixels = (unsigned char*)bitmap.getPixels(); // 画像データの先頭アドレス
        size_t rowBytes = bitmap.rowBytes(); // 1行のバイト数
    
        // bitmapをファイル保存
        SkPixmap pixmap(info, pixels, rowBytes);
        SkFILEWStream stream("output.png");
        SkPngEncoder::Encode(& stream, pixmap, options);
    
        return 0;
    }
    

    Jpeg

    Jpegの場合はSkJpegEncoder.hをインクルードする。

    #include "skia/include/encode/SkJpegEncoder.h"
    

    後はほぼ同じ。ただしoptionsの指定内容はJpeg用になっている。

        SkJpegEncoder::Options options;
        options.fQuality = 100; // 画質
        SkImageInfo info = bitmap.info();
        unsigned char* pixels = (unsigned char*)bitmap.getPixels(); // 画像データの先頭アドレス
        size_t rowBytes = bitmap.rowBytes(); // 1行のバイト数
    
        // bitmapをファイル保存
        SkPixmap pixmap(info, pixels, rowBytes);
        SkFILEWStream stream("output.jpg");
        SkJpegEncoder::Encode(&stream, pixmap, options);
    

    Webp

    Webpの場合はSkWebpEncoder.hをインクルードする。

    #include "skia/include/encode/SkWebpEncoder.h"
    

    Webpは非可逆圧縮なのでjpegと同じようにfQualityがある。

        SkWebpEncoder::Options options;
        options.fQuality = 100; // 画質
        SkImageInfo info = bitmap.info();
        unsigned char* pixels = (unsigned char*)bitmap.getPixels(); // 画像データの先頭アドレス
        size_t rowBytes = bitmap.rowBytes(); // 1行のバイト数
    
        // bitmapをファイル保存
        SkPixmap pixmap(info, pixels, rowBytes);
        SkFILEWStream stream("output.jpg");
        SkWebpEncoder::Encode(&stream, pixmap, options);
    

    skia(1) vcpkgで導入して試す

    skiaを使いたいがビルドに失敗するので妥協してvcpkgで導入してとにかく使う。

    vcpkg

    適当なディレクトリからgit cloneした後、bootstrap-vcpkg.batを実行。

    git clone https://github.com/microsoft/vcpkg
    cd vcpkg
    bootstrap-vcpkg.bat

    skiaの導入

    導入はinstallコマンドで行う。ビルド等が行われた後、includeディレクトリなどが packages\skia_x64-windows\ に入っている。

    vcpkg install skia
    vcpkg\packages\skia_x64-windows\

    サンプルコード

    #pragma comment(lib,"skia.dll.lib")
    
    #include "skia/include/core/SkCanvas.h"
    // SkBitmap
    #include "skia/include/core/SkBitmap.h"
    
    #include <cstdio>
    #include <vector>
    
    // 必要なDLL
    // skia.dll
    // jpeg62.dll
    // zlib1.dll
    
    
    #pragma warning(disable:4996)
    
    //! @brief PPM(RGB各1byte,カラー,テキスト)を書き込む
    //! @param [in] fname ファイル名
    //! @param [in] vmax 全てのRGBの中の最大値
    //! @param [in] width 画像の幅
    //! @param [in] height 画像の高さ
    //! @param [in] p 画像のメモリへのアドレス
    //! @details RGBRGBRGB....のメモリを渡すと、RGBテキストでファイル名fnameで書き込む
    void pnmP3_Write(const char* const fname, const int width, const int height, const unsigned char* const p) { // PPM ASCII
    
        FILE* fp = fopen(fname, "wb");
        fprintf(fp, "P3\n%d %d\n%d\n", width, height, 255);
    
        size_t k = 0;
        for (size_t i = 0; i < (size_t)height; i++) {
            for (size_t j = 0; j < (size_t)width; j++) {
                fprintf(fp, "%d %d %d ", p[k * 3 + 0], p[k * 3 + 1], p[k * 3 + 2]);
                k++;
            }
            fprintf(fp, "\n");
        }
    
        fclose(fp);
    }
    
    int main()
    {
        
    
        // skiaの設定
    SkBitmap bitmap; bitmap.setInfo(SkImageInfo::MakeN32Premul(400, 400)); bitmap.allocPixels(); SkCanvas canvas(bitmap); // 図形の描画 SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(5); paint.setColor(SK_ColorRED); canvas.drawCircle(200, 200, 100, paint);

        // canvasのバッファへアクセス
        SkImageInfo info = bitmap.info();
        unsigned char* pixels = (unsigned char* )bitmap.getPixels(); // 画像データの先頭アドレス
        size_t rowBytes = bitmap.rowBytes(); // 1行のバイト数
        // チャンネル数
        int channels = info.bytesPerPixel();
        // 画像サイズ
        int width = info.width();
        int height = info.height();
    

    printf("channels %d\n", channels);
     
    
          
        // PPMへ出力
    std::vector<unsigned char> ppm(width * height * 3); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { size_t pos_ppm = (i * width + j) * 3; size_t pos_sk = (i * rowBytes + j * channels); ppm[pos_ppm + 0] = pixels[pos_sk + 2]; ppm[pos_ppm + 1] = pixels[pos_sk + 1]; ppm[pos_ppm + 2] = pixels[pos_sk + 0]; } } pnmP3_Write("output.ppm", width, height, ppm.data());
    
    }
    

    結果

    雑談

    実は一年くらい公式のビルド方法を試して失敗している。もういい。

    Windows 11にDocker Desktopを導入(5)(不完全メモ)Windows 11上、WSL2(Ubuntu)のDockerコンテナのUbuntuからCUDAを使う

    できるようにはなったが、想定した手順の再現が思ったようにできていない(環境の初期化に自信がない)。(いつもそうだが今回はいつのも増して)自分用のメモなので、参考にされる方は注意。

    登場人物

    ・Windows 11  ... いつも使っている Windows 11

    ・WSL2 ... Windowsの上で動かしているUbuntu

    ・コンテナ ... docker内で動いている環境。今回はUbuntu。

    ・Docker ... WSL2の中でコンテナを動かす。導入済みとする。

    手順1 windows 11にNVIDIA ドライバのインストール

    CGとかゲームやってる人ならすでに入っていると思う。Windows 11 に、自分のグラフィックボード用のドライバを入れた記憶があるなら次の手順へ。

    よく注意されるのは、ドライバのインストールはあくまで普通の「Windowsへドライバを入れる作業(公式から.exeを落としてマウスでアイコンをポイントしダブルクリックしインストール画面を開きウィザードに従って次へを押していく)」として行わなければならず「WSL2でLinuxを使っているからと言ってaptコマンドで入れないように」という所。

    公式: https://www.nvidia.co.jp/Download/index.aspx?lang=jp

    動作チェック

    WSL2上で以下のコマンドを打って、ドライバのバージョンの表記が出れば成功。

    なおここでCUDAバージョンが表示されるが、これはこのドライバが対応しているCUDAドライバの最大バージョンとなる。これより新しいCUDAは入れられないという意味。

    nvidia-smi

    手順2 WSL2へnvidia-container-toolkitのインストール

    公式のインストール方法に従って、WSL2上に、aptを使ってインストールする。

    公式: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html

    以下を写経

    
    curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
      && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
        sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
        sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
    
    sudo apt-get update
    sudo apt-get install -y nvidia-container-toolkit

    手順3 WSL2へCUDA Toolkitを導入

    Docker内のUbuntuは、WSL2にインストールされたCUDA Toolkitを参照する形で使用する。

    CUDA Toolkitのインストールコマンドを入手

    公式へ行く。例えばCUDA 11.8を導入したい場合、以下。

    https://developer.nvidia.com/cuda-11-8-0-download-archive

    Linux → x86_64 → WSL-Ubuntu → 2.0 → deb(local)

    の順で選択するとコマンドが表示されるのでそれをWSL2で実行する。

    
    wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-wsl-ubuntu.pin
    sudo mv cuda-wsl-ubuntu.pin /etc/apt/preferences.d/cuda-repository-pin-600
    wget https://developer.download.nvidia.com/compute/cuda/11.8.0/local_installers/cuda-repo-wsl-ubuntu-11-8-local_11.8.0-1_amd64.deb
    sudo dpkg -i cuda-repo-wsl-ubuntu-11-8-local_11.8.0-1_amd64.deb
    sudo cp /var/cuda-repo-wsl-ubuntu-11-8-local/cuda-*-keyring.gpg /usr/share/keyrings/
    sudo apt-get update
    sudo apt-get -y install cuda
    

    手順4 コンテナを作成

    CUDAを使うためには -v と --gpusを指定しなければいけない。

    -v ... WSL2側のディレクトリをコンテナにマウントする。これにより、WSL2側にインストールしたcudart.so.11.0等をコンテナ側から使えるようになる。

    --gpus ... コンテナからGPUを使う設定。allを指定する

    docker create -it -v /usr/local/cuda-11.8/:/usr/local/cuda-11.8/ --gpus all --name cuda_test ubuntu:latest

    -vオプションでは、WSL2側のCUDAのインストールディレクトリを、コンテナ側の指定したパスでアクセスできるようにしている。

    手順5 確認

    まずはコンテナを起動し、

    docker start -ai cuda_test

    ドライバが読めていることを確認

    nvidia-smi

    CUDA Toolkitが使えることを確認

    ls /usr/local/cuda-11.8/lib64/

    Windows 11にDocker Desktopを導入(4)windows上のdocker内のUbuntuからmatplotlibのshow()が表示できない問題を解決

    問題

    Python環境

    まず、以下のようにpython環境を整えておく。

    apt install python3
    apt install -y python3-pip
    apt install python-is-python3

    サンプルコード

    必須

    pip install numpy
    pip install matplotlib

    test.py

    import numpy as np
    import matplotlib.pyplot as plt
    
    def plot_sample(start, end, step):
        x = np.arange(start, end, step)
        y = np.sin(x)
    
        plt.plot(x, y)
        plt.title('Sine Curve')
        plt.xlabel('x')
        plt.ylabel('sin(x)')
        plt.grid(True)
        plt.show()
    
    if __name__ == "__main__":
        plot_sample(0, 2*np.pi, 0.01)
    

    実行

    python test.py

    症状

    上記コードを実行しても何も起こらない

    解決手順

    ホストのwindowsにVcXsrvをインストール

    VcXsrvはXサーバーで、windows上でLinuxのGUIを表示するのに必要。以下からダウンロード

    https://sourceforge.net/projects/vcxsrv/

    設定は以下のサイトがとても端的にまとまっている。

    https://qiita.com/ryoi084/items/0dff11134592d0bb895c

    以下のように設定。Native openglを外す。

    最後にSave Configurationで設定ファイル(拡張子.xlaunch)を出力。これを開くとサーバーが起動する。

    docker内の~/.bashrcに追記

    GUIを表示したいUbuntuに、Xserverがあることを教える設定をする。

    vim ~/.bashrc などで、.bashrcを開き、末尾に以下を追記

    export DISPLAY=MY-HOST-NAME.mshome.net:0.0

    ここで、MY-HOST-NAMEは自分のパソコンのホスト名を記述。自分のホスト名はPowerShellなどを起動して、ipconfig /all をすると出てくる。

    ここで一度実行

    ここで一度、test.pyを実行すると、以下のエラーが出た。

    UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
    plt.show()

    これはtkinterがインストールされていないために起こるらしい。なので以下を実行。

    tkinterは、インストール途中、エリアを聞かれるのでAsia、Tokyoを指定。

    apt install python3-tk

    他に、PySide2が(も)要求されるかもしれない。

    pip install PySide2

    あるいはPyQt5が(も)必要かもしれない。

    pip install PyQt5

    参考

    https://qiita.com/ryoi084/items/0dff11134592d0bb895c

    https://and-engineer.com/articles/YWjayhIAACEAEjeC

    Windows 11にDocker Desktopを導入(3)docker内のubuntuにsudoなどを入れて環境づくり(Linux復習)。あとイメージを作る

    なんと、docker内に作ったubuntu環境にはsudoが入っていない。

    というかそもそも気分的にrootで作業したくない。ユーザの追加をしたい。

    というわけでLinuxコマンドの復習と再学習を始めたい。

    sudo

    入れ方:

    apt update
    apt install sudo

    vimを入れる

    ユーザーを追加した後 visudo コマンドを使いたいが vim がインストールされていないと使えないのでvimを入れておく。

    apt install vim

    ユーザ追加

    adduser myusername

    ユーザー切替は

    su myusername

    これだけだと、sudoを使おうとしたときに

    myusername is not in the sudoers file. This incident will be reported.

    と言われるので、sudoersファイルを編集しなければならない。

    whoamiを実行すると現在のユーザがわかるので、rootであることを確認する

    root@08181b08ec3d:/# whoami
    root

    そしてvisudoで/etc/sudoersを編集

    visudo /etc/sudoers

    下のほうにある、# User privilege specification のrootの下に、使いたいユーザを入れる

    # User privilege specification
    root ALL=(ALL:ALL) ALL
    myusername ALL=(ALL:ALL) ALL # new user

    wq;でviから出ると追加したユーザでsudoが使えるようになっている。

    設定したコンテナのdockerイメージを作る

    毎度この設定をするのも面倒なので、今回の設定をしたUbuntuをdockerイメージとして作成し、いつでもコンテナを作れるようにしておく。なおイメージ名は小文字でないといけない

    docker commit 元になるコンテナ名 作成したいイメージ名

    docker ps -a でコンテナ名を確認してから、 docker commitを行う。

    docker commit u2204base my_image_ubuntu_2204

    Windows 11にDocker Desktopを導入(1)

    はじめに

    投稿順序を間違えた。こっちが先。

    Docker Desktopについて

    Docker Desktopを導入した。正直色々調べながらどうにか入れたので理解しきれていない部分もある。ヒント程度の意味でまとめている。

    Windows上でDockerを使うには

    ・WSL2 (Windows上でUbuntuを使う仕組み)

    ・Ubuntu (Windows上にMicrosoft Storeからインストール)

    ・Docker Desktop (本体)

    の三つが必要。

    概要

    順番は前後してもいい(私がやった順番は3124だがちゃんと動いた)。

    1. PowerShellなどからwslの設定をする
    2. Microsoft Storeへ行ってUbuntuをインストールする
    3. Docker Desktopをダウンロードしてインストール
    4. Ubuntuを起動してDockerの動作確認

    WSL2の導入

    wslはWindows上でLinuxを動かすための仕組みのこと。

    コマンドプロンプトまたはPowerShellを開き、以下を実行する

    そもそもwslが入っていない場合、インストールする必要がある。

    wsl --install

    wslにはバージョン1と2がある。基本的に2のほうが優れているので、Ubuntu環境を使うときにデフォルトで2を使うように設定しておく

    wsl --set-default-version 2

    Ubuntuを入れたあと、Ubuntuを実行しようとするとエラーが出る場合がある。これはupdateで解決する

    wsl --update

    WindowsにUbuntuの導入

    WSLのおかげでWindows上でUbuntuを実行できる。Microsoft Storeへ行ってUbuntuを検索。バージョン違いが複数出てくる。特にこだわりがなければバージョン未表記のものを選べば最新版が入る。

    インストール後、「開く」でUbuntuの設定が走る。Ubuntu上で使うユーザ名とパスワードを入力する。

    もしここで以下のエラーが出るようなら上に書いたように wsl --updateを実行。

     

    Installing, this may take a few minutes...
    WslRegisterDistribution failed with error: 0x800701bc
    Error: 0x800701bc WSL 2 ???????????? ??????????????????????? https://aka.ms/wsl2kernel ?????????

    Press any key to continue...

     

    うまくいけばUbuntuのターミナルが使えるようになる。

    Docker Desktop

    以下へ行き、Docker Hub からダウンロード からダウンロード・インストールする。

    https://docs.docker.jp/docker-for-windows/install.html

    注意:インストール後、docker subscription service agreement という、利用規約に合意しろという意味のウィンドウが出てくるので、Acceptする。これをしないでCloseするとDockerが動かない

    Dockerの動作確認

    コマンドプロンプト、PowerShell、Ubuntuのターミナルのどれでもいいのでdockerコマンドを実行

    なお、私はここで

     

    The command 'docker' could not be found in this WSL 2 distro.
    We recommend to activate the WSL integration in Docker Desktop settings.

    For details about using Docker Desktop with WSL 2, visit:

    https://docs.docker.com/go/wsl2/

     

    に苦しめられた。調べるとDocker Desktopの設定から

    [Resoures] → [WSL integration] → [Enable integration with additional distros:]

    でUbuntuをOnにすれば解決、と言われるのだがその項目すらない。

    私の場合は上で書いたように、docker subscription service agreementでAcceptしていなかったのでDockerが動いていなかった。

    参考

    https://ascii.jp/elem/000/004/127/4127643/

    https://owlcamp.jp/wsl-ubuntu20-04/

    https://chigusa-web.com/blog/windows%E3%81%ABdocker%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%97%E3%81%A6python%E7%92%B0%E5%A2%83%E3%82%92%E6%A7%8B%E7%AF%89/

    Windows 11にDocker Desktopを導入(2)dockerで開発環境を作る

    docker  ... 仮想環境作成ソフト

    イメージ ... 仮想環境のひな型

    コンテナ ... イメージから作った実際に動く仮想環境

    という関係になっている。環境構築の手順としてはまずイメージをダウンロードし、それを元にコンテナを作る。今回はubuntuの環境を作る。

    イメージのダウンロード

    現在使用できるイメージの列挙

    ダウンロードの前に、いまどのイメージを使えるのかを確認する。

    docker images

    結果。まだ何もないのでイメージ一覧には何も出てこない。

    イメージのダウンロード

    次にイメージを取得。ネットにつながっていれば、docker pullでイメージをダウンロードできる。

    これは

    docker pull OS名:バージョン

    の順番で記述する。例えばバージョン18.04が欲しければ、 docker pull ubuntu:18.04 と記述する。最新版が欲しい場合は docker pull ubuntu:latest と、latest指定をする。

    docker pull ubuntu:latest

    もう一度docker imagesをしてみると、イメージ一覧にubuntuのlatestが追加されている。

    仮想環境の作成

    イメージがダウンロードできたので、このubuntu:latestを元にコンテナ(=仮想環境)を作る。

    コンテナを作るには、docker create を使う。

    docker create オプション --name 作成するコンテナ名 元になるイメージ

    オプションは、-t,-i両方を指定しておいたほうがいい。一応個別に設定できるが(詳しくないのに)つけないでいると仮想環境が動かなかったりI/Oができなかったりする。

    -tオプション ... 仮想環境で仮想ターミナルを使う。

    -iオプション ... 仮想環境と標準入出力を繋げる。コマンドラインが使用可能になる

    docker create -t -i --name my_ubuntu_env ubuntu:latest

    仮想環境の起動

    起動

    作った仮想環境を動かすにはdocker startを使う。

    docker start オプション コンテナ名

    -a ... 標準出力,エラー出力を接続

    -i ... コンテナと対話できるようにする

    -aはコンテナの出力を見ることができる(こちらから入力できない)

    -aだけで接続してしまった場合、こちらから入力できないので、Ctrl+Cで帰ってくる以外に何もできなくなる。

    docker start -a -i my_ubuntu_env

    終了

    終了する場合は、exitすれば自動的に終了する。

    docker psは、何もつけないと現在動作しているコンテナしか表示されないので、-aをつけて停止中のコンテナも表示する

    docker ps -a

    ただし、Ctrl+Cでコンテナから出た場合、終了していないので docker stop 環境名 をする必要がある。

    docker runを使った場合

    docker run は、コンテナを作成し、その後起動まで行う。便利といえば便利だが、docker runする度に新たなコンテナが新規作成されるので注意が必要。

    docker run でただ起動すると名前が勝手に付けられる(NAMES)。名前を付けたいときは --nameを指定。

    docker run -i -t ubuntu:latest

    コンテナの削除

    docker rm コンテナ名
    docker rm my_ubuntu_env

    イメージの削除

    コンテナにイメージが使われている場合削除できないので、先にdocker rm で、削除したいイメージから作成したコンテナをすべて削除しておく必要がある。

    docker rmi ubuntu:latest