Flutterを使ったDesktop基盤アトラス化アプリ作成

## 前置き
- Flutterを使ってデスクトップアプリケーションを作った感想です。
- 開発環境はVisual Studio Code1.80.2、Flutter3.10.0です。

## 目次
- Flutterとは？
- Flutterの特徴
- Flutterでイメージをアトラス化するアプリを作ってみた
- イメージをアトラス化するためには何が必要なのか
- Flutterを使った感想
- まとめ

## Flutterとは？
Googleは2017年に公開したmobile/web/desktopクロスプラットフォームSDKです。
一つのコードベースでandroid, ios, macOS, windowsで動作するアプリを作ることができるのが特徴です。
言語はGoogleがデザインしたDartを使います。

## Flutterの特徴
##### クロスプラットフォーム
上述のように、Flutterは一つのコードで色んなプラットフォームで使うアプリを作ることができます。
もちろん特定のプラットフォームだけ動くパッケージとかはありますが、ほとんどの機能はすべてのプラットフォームで動作するので生産性が高い部分といえます。

##### Hot Roload
Flutterはコード修正後確認のため再実行の代わりにホットリロード機能を使うことができます。
Visual Studio Code基準キーボードでrを押すことでFlutterに修正項目が自動的に反映されます。

##### pub.devの存在
https://pub.dev/

pub.devはFlutterのための公式リポジトリサイトです。
必要なパッケージを探したり、一番人気のパッケージなどを探すことができます。
Unityを使っている方にとっては、asset storeに似ているものだと思って貰えば良いと思います。

## Flutterでイメージをアトラス化するアプリを作ってみた
イメージを一つに合わせるアプリが必要だったのでFlutterを使って作ってみました。
例えば5つのpngファイルがあるとすれば、このpngを1つにまとめてアトラス化させるアプリです。

## アトラス化するためには何が必要なのか
イメージを一つに合わせるためには以下のロジックが必要でした。
- イメージ変更のためのピクセル操作
- 完成イメージサイズ、座標設定のためのnative cコードの呼び込み
- サンプル画像を見せるためのマルチウィンドウ

そのため主に使ったパッケージは以下になります。
```
image.dart // イメージファイルを操作できるようにしてくれるパッケージ
dart.ffi  //native c apiを呼び出すプラグイン
desktop_multi_window // マルチウィンドウ表示パッケージ
``` 

#### イメージのピクセル操作はimage.dartで
僕が作ろうとしたアプリはイメージの変換とか必要な時があったので画像をピクセル単位で修正する必要がある場合がありました。
そのために`image.dart`を使って画像を変形、操作しました。

https://pub.dev/packages/image

以下のコードはピクセルを操作して画像の上下左右を反転させたコードです。
```
import 'package:image/image.dart' as img;

//pngファイルのパスからbytes取得
...

var oriImage = img.decodePng(bytes) as img.Image;
Pixel pixel = oriImage.getPixel(x, y);

for (int y = 0; y < oriImage.height; y++) {
  for (int x = 0; x < oriImage.width; x++) {
    var pixel = oriImage.getPixel(x, y);
    oriImage.setPixel(oriImage.width - x, oriImage.height - y, pixel);
  }
}
```

#### Native Cコード使用のためにはffiで
アトラス化したイメージ完成画像のサイズの設定、空画像にイメージを付けるための座標計算作業がかなり複雑だったため以下のc++コードを使いました。

https://github.com/juj/RectangleBinPack

このc++コードを使うため使ったのが`dart.ffi`です。
Dart FFI (Foreign Function Interface)はDart言語内でc、c＋＋みたいなnative言語相互作用できるライブラリです。
-  Webの場合`dart.ffiが動かない`のでWebアプリ開発の場合JavaScriptなどを使って別対応をする必要があります。

↓のコードはイメージからwidth,heightをもらってw,y座標をreturnするコードです。

```
import 'dart:ffi';
class FlutterRect extends Struct {
  @Int32()
  external int x;
  @Int32()
  external int y;
  @Int32()
  external int width;
  @Int32()
  external int height;
}

typedef GetMyStructC = FlutterRect Function(Int32, Int32, Int32, Int32);
typedef GetMyStructDart = FlutterRect Function(int, int, int, int);

int _shapePadding = 10;
int _extrude = 0;

FlutterRect calcAtlasImage(int width, int height) {
  final getRect = _atlasImageLib
      .lookupFunction<GetMyStructC, GetMyStructDart>('calcAtlasImage');

  final rect = getRect(width, height, _shapePadding, _extrude);
  return rect;
}
```

#### マルチウィンドウ表示はdesktop_multi_windowで
flutterは基本的にマルチウィンドウをサポートしていません。
しかし、これを使えばmacOS、Linux環境でマルチウィンドウを表示することができます。

https://pub.dev/packages/multi_window
- windowsの場合作成日基準まだ公式的に支援しないのでマルチウィンドウを開くのは確認しましたが、色々不具合とか出る可能性があります。

```
const _defaultOffset = Offset(0, 0);
const _defaultSize = Size(1280, 720);

final window = await DesktopMultiWindow.createWindow();
window
  ..setFrame(_defaultOffset & _defaultSize) //ウィンドウフレーム設定
  ..center() //ウィンドウを中央に配置
  ..show() //ウィンドウをを見せる

...Widget作成
```

## Flutterを使った感想
このようにflutterを使ってアプリを開発してみましたが、良かった点と不便だった点を話してみようと思います。

### 良かった点
##### 1. Hot Reloadを使ったdebug効率向上
Hot Reloadの存在は思ったよりすごかったです。
他のフレームワークでは、修正確認のためにリロードに時間を費やしますが、Flutterでは`r`ボタン一つですぐリロードされたため、デバッグ時間がかなり節約されました。

##### 2. 楽なWidgetの追加
![スクリーンショット 2023-08-07 17.14.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524338/1c5108fe-81aa-d80e-7848-61c9865e66a9.png)
FlutterではVisual Studio Code基準ctrl+.を押すだけでWidgetを追加することができます。
機能をあれこれ追加すると括弧が多くなり何か追加することが困難な状況になりますが、このショートカットを利用すると簡単に管理することができます。

##### 3. 色んなパッケージの存在
Flutter自体ライブラリだけでは少し機能的に足りない部分がある可能性もありますが、これを補うためにさまざまなパッケージが存在します。
パッケージ追加自体もpubspec.yamlに書くだけで追加できるので便利です！
```
//desktop_multi_windowの追加の場合

dependencies:
  flutter:
    sdk: flutter
  desktop_multi_window: ^0.2.0
```

### 不便だった点

##### 1. デスクトップアプリには不便な部分がある
Flutterは様々な環境で使用できるクロスプラットフォームが特徴ですが、逆にこの特徴のためデスクトップアプリを作る時制限がありました。
ほとんどのデスクトップ開発ライブラリはマルチウィンドウをサポートしていますが、Flutterはサポートしておらず、別のパッケージを見つける必要がありました。
モバイル版の開発にはかなり充実した感じがありましたが、デスクトップ版の開発はすぐに使うには少し不便なことがありましたね。

##### 2. まだライブラリが多くはない
Flutterはまだ作られて間もないフレームワークなので他のフレームワークに比べて多様なライブラリが追加されているわけではありません。
時間が経てば改善する可能性はありますが、現時点では必要なライブラリがないかもしれません。

## まとめ
確かにFlutterは便利な機能も多くて作業しやすいフレームワークではありますが、まだ公開されて間もないフレームワークだからか、不便な部分も少しありました。
特にUIの管理はとても便利でしたが、デスクトップ専用アプリを作るのに少し制限があったので少し大変でしたね。

でも、しっかり活用すれば効率的なフレームワークであることは確かですから、新しいアプリを開発する際に活用してみましょう！