TCPDF に嵌ってしまった

今日の投稿は短いです。

PHP を使って HTML から PDF を作成するツール TCPDF を使っているときに嵌ってしまった。以下のような HTML を書くと、class 指定しているにもかかわらず、それが反映されません。

<table class='tbl'>
  <tr>
    <th class='name'>Name</th>
    <th class='title'>Title</th>
  </tr>
</table>

<style>
.tbl {
  width: 100%;
}
.tbl .name {
  width: 20%;
}
.tbl .title {
  width: 80%;
}
</style>

4時間くらい原因が分からず右往左往していたのですが、お手本とにらめっこを繰り返してようやく原因が判明。反映されない原因は class 指定時にシングルクォート(‘)を使っていたためでした。ダブルクォート(“)にすると問題なく反映されます。

<table class="tbl">
  <tr>
    <th class="name">Name</th>
    <th class="title">Title</th>
  </tr>
</table>

<style>
.tbl {
  width: 100%;
}
.tbl .name {
  width: 20%;
}
.tbl .title {
  width: 80%;
}
</style>

HTML 上ではどちらも許されるはずなんですが…。

MySQL から完全にforkしてしまったmariaDB

最近のリレーショナル DB は geometry とか json とか使えるようになりましたが、MySQL と mariaDB でかなり仕様差があり、互換性がないという事態に陥ったので記録しておきます。

問題となるのは① geometry で2地点間の距離を求める場合。
MySQL v7.0 以降は ST_Distance_Sphere 関数があるが、mariaDBにはない。
地球楕円体から自分で計算するか、ST_Glength を使って度を算出し、それから km に直す必要がある。

②JSON カラムの初期値を MySQL は設定できないように見えるが、mariaDB は自由に設定できる。例えば

colmn json not null default '[]'

という構文を、mariaDB は許可するが、MySQL は許可しない。

そのうち統一されるのでしょうか、差異があるまま成長してしまうのか、注目しています。

Windows のシステムロケールではまる

MariaDB を utf8mb4 で使用しているにもかかわらず、

mysql -u user db <data.sql

という構文で cp932 エラーが発生。なんで??

Google 先生に聞いても良く分からなかったが、どうも CMD が CP932 になっているせいではないかということに思い当たり、

https://kuluna.github.io/blog/post/20180512/

を参考にして、CMD を UTF-8 にしてみたらうまく動いていた。

ファイルをオープンする時にコードチェックするなんて、Windows10、何て仕様なんだ…。

PC入れ替え

今使っているデスクトップ機が4年を経過して古くなったため、入れ替えることにしました。
前回はまだ個人事業主ではなかったので経費で落とせませんでしたが、今回は経費で落とすことにしました。

と言っても減価償却させるので今年の分は2か月分しかない訳ですが。

スペックはネットでの評価が高い Ryzen 5950X、GPU は RTX3090 をチョイスしました。
メモリは RAM 128GB、SSD 2TB + HDD 4TB と前回とほぼ同じ構成。
インタフェースに PCIe Gen4 が使えるのがうれしいです。
電源が 1000W 超えになるのがやや頭が痛い点です。コンセントを選ぶ…。
物が来るのは来週ですが、numpy や cupy がどのくらい速くなるのか楽しみです。

(AMD は AVX系の命令は得意でないようなのであまり差がつかないかもしれませんが)

Ubuntu 18.04 で WiFi ホットスポットを作成する

インターネット上に乗っている情報が今一古かったりしたので、18.04 用に集めた情報をまとめておきます。

パッケージのインストール

必要なパッケージをインストールする。Destop だと自動で入るようだが、server だと入らないようなので、手動で入れる。

sudo apt-get install wireless-tools wpasupplicant

WiFi ホットスポット情報の作成

ifconfig などで WiFi デバイス名を取得する。仮に wlan0 とする。

nmcli コマンドで WiFi ホットスポットを作成する。

sudo nmcli device wifi hotspot ifname wlan0 con-name 'hostspot' ssid 'MyHotspot' band 'bg' password 'password1234'

/etc/NetworkManager/system-connections/hotspot を編集する。以下の行を [ipv4] 以下に追加する。

address1=192.168.0.1/24,192.168.0.1

意味としてはホストアドレス、プレフィクス、デフォルトゲートウェイとなる。

DHCP サーバのインストール

isc-dhcp-server をインストールする。

sudo apt-get install isc-dhcp-server

/etc/dhcp/dhcpd.conf を編集する。接続性のみ確認したいので、とりあえず domain-name, domain-name-server をコメントアウトし、subnet を定義する。

subnet 192.168.0.0 netmask 255.255.255.0 {
        range 192.168.0.100 192.168.0.131;
}


host myhostname {
        hardware ethernet xx:xx:xx:xx:xx:xx;
        fixed-address 192.168.0.1;
}

ここでは 192.168.0.x/24 に割り当てることとした。

/etc/default/isc-dhcp-server を編集する。INTERFACES に wlan0 を追加し、DHCPDv4_CONF, DHCPDv4_PID のコメントを外す。

wlan0 を念のために落とす。

sudo nmcli con down wlan0

DHCP サーバを再起動する。

sudo systemctl stop isc-dhcp-server
sudo systemctl start isc-dhcp-server

systemctl status isc-dhcp-server を実行して起動していることを確認する。よくあるエラーは PID や config ファイルの指定がコメントされたままになっていること。

WiFi の再起動

nmcli コマンドで WiFi を再起動する。

sudo nmcli con up hotspot

これで WiFi をホストモードで起動できたはず。

sudo nmcli device wifi

とすると現在使用しているプロファイルが表示される。

/etc/rc.local への追加

次回起動時に WiFi ホットスポットが自動で起動するように /etc/rc.local に以下の行を追加する。

nmcli con up hotspot
systemctl restart isc-dhcp-server

なお、デフォルトでは rc.local は存在しないが、作成して chmod +x /etc/rc.local することで利用可能になる。

darknet(本家)を OpenCV 4.2.0 でコンパイル

既に darknet は OpenCV 4.x 用に fork されていますが、そうとは知らず OpenCV 4.2.0 でコンパイルして躓いたところのメモです。OS は x86_64 Ubuntu 18.02.3 です。なお、CUDA 10.0, cuDNN 7.5 がインストール済みになっています。

OpenCV をインストールする前に ffmpeg 関連のファイルをインストールしておきます。apt-get によるインストールで問題ありません。

OpenCV は WITH_V4L, OPENCV_GENERATE_PKGCONFIG を ON にしておきます。Cmake を使って Makefile を生成し、make -j 4 などでコンパイルは普通に行います。出来たら make install で /usr/local 以下などにインストールします。

次に darknet をコンパイルする訳ですが、実行してみればわかりますが、image_to_ipl, ipl_to_image で使用されなくなった OpenCV API を使おうとしてコンパイルが停止します。直接 cv::Mat API を使用することにして image_opencv.cpp に以下のような修正をかけました。

Mat image_to_mat(image im) {
         Mat m = Mat(im.h, im.w, CV_8UC(im.c));
         if (im.c == 1) {
                 for (int row = 0; row < im.h; ++row) {
                         uchar *dst = m.ptr(row);
                         float *src = &im.data[row * im.w];
                         for (int col = 0; col < im.w; ++col) {
                                 dst[col] = (uchar)(src[col] * 255);
                         }
                 }
         } else {
                 for (int row = 0; row < im.h; ++row) {
                         Vec3b *dst = m.ptr(row);
                         float *src = &im.data[row * im.w];
                         for (int c = 0; c < im.c; ++c) {
                                 for (int col = 0; col < im.w; ++col) {
                                         dst[col][2 - c] = (uchar)(src[c * im.h * im.w + col] * 255);
                                 }
                         }
                 }
         }
         return m;
}

 image mat_to_image(Mat mat) {
         image im = make_image(mat.cols, mat.rows, mat.channels());
         float *data = im.data;
         if (mat.channels() == 1) {
                 for (int row = 0; row < im.h; ++row) {
                         uchar *src = mat.ptr(row);
                         for (int col = 0; col < im.w; ++col) {
                                 data[row * im.w + col] = (float)(src[col] / 255.0);
                         }
                 }
         } else {
                 for (int row = 0; row < im.h; ++row) {
                         Vec3b *src = mat.ptr(row);
                         for (int c = 0; c < im.c; ++c) {
                                 for (int col = 0; col < im.w; ++col) {
                                         data[c * im.w * im.h + row * im.w + col] = (float)(src[col][2 - c] / 255.0);
                                 }
                         }
                 }
         }
         return im;
} 

更に、CV_CAP_PROP_ などと CV_ が付いているパラメータについて、CV_ を削除します。これでコンパイルが通るはず。

おまけ: Anaconda は外しておいた方がよいようです。カメラを使う場合はユーザを video グループに参加させるのを忘れずに。