# Delphi で Wio Terminal 用画像コンバータを作ってみる --- tags: Arduino Delphi programming objectpascal WioTerminal created_at: 2020-05-21 updated_at: 2020-05-23 --- # はじめに **Wio Terminal** を購入しまして。画像を表示させるチュートリアルをやってみようと思ったのですが... - [Wio Terminal (seeed: en)](https://wiki.seeedstudio.com/Wio-Terminal-Getting-Started/) - [Wio Terminal (seeed: ja)](https://wiki.seeedstudio.com/jp/Wio-Terminal-Getting-Started/) - [LCD \| Wio \| Terminal \| Platform \| Loading Image (seeed)](https://wiki.seeedstudio.com/Wio-Terminal-LCD-Loading-Image/) # 画像表示 画像を表示させるためにはチュートリアルの通りやればいいのですが、画像は 24bit Bitmap から、独自の 8bit / 16bit ビットマップへ変換しなくてはなりません。 | 色深度 | フォーマット | |:---:|:---:| | 8bit | rgb332 | | 16bit | rgb565 | 変換ための Python スクリプト (bmp_converter.py) が用意されているのですが、 ``` ImportError: No module named PIL ``` だの、 ``` ModuleNotFoundError: No module named 'PIL' ``` だの言われて難儀しました。結局、チュートリアルページに書いてある `pip` では解決せず、`Anaconda` をインストールする必要がありました。その `Anaconda` を動作させるためには環境変数に... ## 面倒くさい... チュートリアルを試したいだけなのに...。 `Linux を常用している人` or `Python を常用している人` にはなんてことはないのでしょうけど、僕にとっては面倒くさかったので、変換ツールを **Delphi 10.3 Rio** で書く事にしました。 ### ソースコード 書きました。 ```pascal:bmp_converter.dpr program bmp_converter; {$APPTYPE CONSOLE} uses System.Classes, System.SysUtils, System.IOUtils, System.UITypes, Vcl.Graphics; type TRGBType = (rgb8bit, rgb16bit); const SUBDIR: array [TRGBType] of string = ('rgb332', 'rgb565'); function ConvertToRGB332(aColor: TColorRec): Byte; begin with aColor do begin R := R shr 5; G := G shr 5; B := B shr 6; Result := (R shl 5) or (G shl 2) or B; end; end; { ConvertToRGB332 } function ConvertToRGB565(aColor: TColorRec): Word; begin with aColor do begin R := R shr 3; G := G shr 2; B := B shr 3; Result := (R shl 11) or (G shl 5) or B; end; end; { ConvertToRGB565 } begin // 色深度の選択 Writeln('Enter (1) for 8-bit colour convert, Enter (2) for 16-bit colour convert'); var c: Char; while True do begin Readln(c); if CharInSet(c, ['1'..'2']) then Break; Writeln('Invalid input!'); end; var RGBType := TRGBType(Ord(c) - Ord('1')); // 入出力フォルダ var SrcDir := TPath.Combine(TPath.GetDirectoryName(ParamStr(0)), 'bmp'); var DstDir := TPath.Combine(SrcDir, SUBDIR[RGBType]); if not TDirectory.Exists(DstDir) then TDirectory.CreateDirectory(DstDir); // bmp フォルダにある *.bmp を処理 var im: TBitmap := TBitmap.Create; try for var FileName in TDirectory.GetFiles(SrcDir, '*.bmp', TSearchOption.soTopDirectoryOnly) do begin // 画像をロードして強制的に 24bit ビットマップに変換 im.LoadFromFile(FileName); im.PixelFormat := TPixelFormat.pf24bit; // データの生成 var v: TBytes := [im.Width and $00FF, im.Width shr 8, im.Height and $00FF, im.Height shr 8]; for var y := 0 to Pred(im.Height) do for var x := 0 to Pred(im.Width) do begin var Color: TColorRec; Color.Color := im.Canvas.Pixels[x, y]; case RGBType of rgb8bit: v := v + [ConvertToRGB332(Color)]; rgb16bit: begin var value := ConvertToRGB565(Color); v := v + [value shr 8, value and $00FF]; end; end; end; // バイト列をファイルに保存 var bs := TBytesStream.Create(v); try bs.SaveToFile(TPath.Combine(DstDir, TPath.GetFileName(FileName))); finally bs.Free end; end; finally im.Free; end; end. ``` Delphi 10.3 Rio さえインストールされていれば、上記ファイルを `bmp_converter.dpr` という名前で保存し、[ファイル | プロジェクトを開く] で開いてコンパイルするだけのお手軽さです。 - 外部ライブラリや特別な設定は必要ありません。 - 仕様は bmp_converter.py 準拠です (bmp サブフォルダにある *.bmp を変換します)。 **See also:** - [Vcl.Graphics.TCustomCanvas.Pixels (DocWiki)](http://docwiki.embarcadero.com/Libraries/ja/Vcl.Graphics.TCustomCanvas.Pixels) ### ソースコード (高速化版) ピクセルの取得に **ScanLine** を使い、動的配列の領域確保回数を最小限に抑えた高速化版です。 ```pascal:bmp_converter.dpr program bmp_converter; {$APPTYPE CONSOLE} uses System.Classes, System.SysUtils, System.IOUtils, System.UITypes, Winapi.Windows, Vcl.Graphics; type TRGBType = (rgb8bit, rgb16bit); const SUBDIR: array [TRGBType] of string = ('rgb332', 'rgb565'); function ConvertToRGB332(aColor: TRGBTriple): Byte; begin with aColor do begin rgbtRed := rgbtRed shr 5; rgbtGreen := rgbtGreen shr 5; rgbtBlue := rgbtBlue shr 6; Result := (rgbtRed shl 5) or (rgbtGreen shl 2) or rgbtBlue; end; end; { ConvertToRGB332 } function ConvertToRGB565(aColor: TRGBTriple): Word; begin with aColor do begin rgbtRed := rgbtRed shr 3; rgbtGreen := rgbtGreen shr 2; rgbtBlue := rgbtBlue shr 3; Result := (rgbtRed shl 11) or (rgbtGreen shl 5) or rgbtBlue; end; end; { ConvertToRGB565 } begin // 色深度の選択 Writeln('Enter (1) for 8-bit colour convert, Enter (2) for 16-bit colour convert'); var c: Char; while True do begin Readln(c); if CharInSet(c, ['1'..'2']) then Break; Writeln('Invalid input!'); end; var RGBType := TRGBType(Ord(c) - Ord('1')); // 入出力フォルダ var SrcDir := TPath.Combine(TPath.GetDirectoryName(ParamStr(0)), 'bmp'); var DstDir := TPath.Combine(SrcDir, SUBDIR[RGBType]); if not TDirectory.Exists(DstDir) then TDirectory.CreateDirectory(DstDir); // bmp フォルダにある *.bmp を処理 var im: TBitmap := TBitmap.Create; try for var FileName in TDirectory.GetFiles(SrcDir, '*.bmp', TSearchOption.soTopDirectoryOnly) do begin // 画像をロードして強制的に 24bit ビットマップに変換 im.LoadFromFile(FileName); im.PixelFormat := TPixelFormat.pf24bit; // データの生成 var v: TBytes := [im.Width and $00FF, im.Width shr 8, im.Height and $00FF, im.Height shr 8]; var i := Length(v); SetLength(v, im.Width * im.Height * Succ(Ord(RGBType)) + Length(v)); for var y := 0 to Pred(im.Height) do begin var Lines: PRGBTriple := im.ScanLine[y]; for var x := 0 to Pred(im.Width) do begin case RGBType of rgb8bit: v[i] := ConvertToRGB332(Lines^); rgb16bit: begin var value := ConvertToRGB565(Lines^); v[i] := value shr 8; Inc(i); v[i] := value and $00FF; end; end; Inc(i); Inc(Lines); end; end; // バイト列をファイルに保存 var bs := TBytesStream.Create(v); try bs.SaveToFile(TPath.Combine(DstDir, TPath.GetFileName(FileName))); finally bs.Free end; end; finally im.Free; end; end. ``` 多くのファイルを一括置換するならこちらの方がオススメです。 **See also:** - [Vcl.Graphics.TBitmap.ScanLine (DocWiki)](http://docwiki.embarcadero.com/Libraries/ja/Vcl.Graphics.TBitmap.ScanLine) - [動的配列 (DocWiki)](http://docwiki.embarcadero.com/RADStudio/ja/%E6%A7%8B%E9%80%A0%E5%8C%96%E5%9E%8B%EF%BC%88Delphi%EF%BC%89#.E5.8B.95.E7.9A.84.E9.85.8D.E5.88.97) - [bmp_converter - Win32 コンパイル済バイナリ (ht-deko.com)](https://ht-deko.com/delphiforum/?vasthtmlaction=viewtopic&t=2268.0) # おわりに FireMonkey に移植すると macOS や Linux で使えて便利かもしれません。 ![image.png](./images/e3714a70-e33a-574d-6081-441708070e16.png) - [Delphi (Embarcadero)](https://www.embarcadero.com/jp/products/delphi) - [Delphi Community Edition (Embarcadero)](https://www.embarcadero.com/jp/products/delphi/starter)