はじめに
Wio Terminal を購入しまして。画像を表示させるチュートリアルをやってみようと思ったのですが...
- Wio Terminal (seeed: en)
- Wio Terminal (seeed: ja)
- LCD | Wio | Terminal | Platform | Loading Image (seeed)
画像表示
画像を表示させるためにはチュートリアルの通りやればいいのですが、画像は 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 で書く事にしました。
ソースコード
書きました。
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:
ソースコード (高速化版)
ピクセルの取得に ScanLine を使い、動的配列の領域確保回数を最小限に抑えた高速化版です。
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)
- 動的配列 (DocWiki)
- bmp_converter - Win32 コンパイル済バイナリ (ht-deko.com)