2018年12月29日土曜日

UTF-8文字列をUNICODE化し、絵文字判別

UTF-8で指定された文字列をUNICODE化し(32bit)、絵文字かどうかを判定する例題です。

絵文字かどうかの議論は色々あるかと思いますが、twemoji 内に格納されている絵文字を基準としています。
→ emoji-png フォルダに png として保存し、ファイルを検索してチェック

絵文字かどうかを判定した後は元のUTF-8に戻し、標準出力へ出力しています。
絵文字に対応していないフォントを用いているUI等では、絵文字が表示されない場合がありますので、絵文字の部分は twemoji 内の png で置き換えて表示したりすることができます。 実行結果

2018年9月23日日曜日

Broadcast Wave Format に対応した WAVE 音声の読み込み

Broadcast Wave Format に対応した WAVE 音声の読み込みの例題です。
Broadcast Wave Format (BWF) は、マイクロソフトのWAV音声ファイルフォーマットの拡張であり、映画やテレビで使われているノンリニアデジタルレコーダーの録音フォーマットとしてよく使われている。
WAVEファイルの読込み/再生 での例題で WAVEファイルを読み込んだ際、ヘッダ部分がうまく取得できないWAVEファイルが存在していました。
中身を見ると、フォーマット用のチャンク部分に「fmt 」ではなく、「bext」と記載されているファイル形式のファイルでした。
PCMの音声データ部分のチャンクは「data」から始まり、PCM音声部分の抜き取りは正常に動作していたのですが、元の音声の形式がどのようなものかを正常に取得できていないので困ることになります。
なので、この「bext」のチャンクが含まれる Broadcast Wave Format の WAVE 形式にも対応した形で読み込み部を修正しています。

Broadcast Wave Format(BWF)は CM 位置へのスキップ等に対応した CUE というイベント情報等を含められるようですが、今回はヘッダ部分のパースと WAVE の保存形式を正常に認識するための修正のみを行っています(CUE が入った音声サンプルが手に入らないため)。

また、4GBの壁にも対応した修正になっています(本来はWAVE64というフォーマットがありますが、WAVEに4GB以上のデータが含まれるもの)。
WAVEファイルのヘッダ構造体は32bitですのでその部分で4GBの壁となります。
WAVEで保存するICレコーダー等で4GB以上の録音となる場合にこういった不具合が発生することがあります。
data チャンクの長ささえ取得できれば音声部は正しく保存されていますので、その部分から読み込みを開始すればデータ部は正しく取得できます。 実行結果

2017年9月2日土曜日

libcurl による連続取得における排他処理

HTTPS コネクション時の libcurl による連続GET にて HTTPS への GET リクエストを行う際、curl ハンドラを初期化せずに利用した方が高速にダウンロードされると言う例題を記載しましたが、別のスレッドでタイミングがバラバラに GET したい場合、排他処理にて安全性を確保するための例題です。

libcurl 自体はスレッドセーフ化されているので、curl_easy_init にて毎回ハンドラを初期化し利用すれば何の問題もなく別のスレッドで GET リクエストを行えますが、同じハンドラを使いまわしたい場合には同じタイミングで同じハンドラが利用されないように排他処理を行っておく必要があります(今回のような特別な用途でないかぎりは全く必要のない例題です)。

pthread_mutex_lock にて排他処理を行っているので、GET リクエストが並列化されるわけではないので並列化による恩恵は受けれませんが、HTTPS への要求時における証明書の取得などの内部処理を毎回行わずに済むなどの恩恵が大きい場合に利用します(例題のweb.fc2.comはその恩恵が得られないサイトで、証明書が正しくない場合に起こるようです、別のサーバーにてお試しください)。 実行結果

2017年8月14日月曜日

libcurl-multi による並行GETリクエスト

libcurl-multi による並行GETリクエストを行う例題です。

例題では複数のURLを指定し並列にGETリクエストを行い、その結果を用意した char 型のバッファ内に格納しています。
HTTPS で連続取得を行う場合にはこちらで試した方法の方が高速な場合があります。 実行結果

2017年8月11日金曜日

HTTPS コネクション時の libcurl による連続GETリクエストの高速化の検討

HTTPS コネクション時の libcurl による連続GETリクエストを高速化するための検証用の例題です。

libcurl による GET 取得時の高速化手段として以下のサイトでまとめられています。
https://moz.com/devblog/high-performance-libcurl-tips
(c-ares/PowerDNS 等により DNSのリスポンスを良くするとか libcurl-multi による並列処理化等、上記サイトには書かれていませんが TCP FAST OPEN に対応しているサーバーであれば libcurl からオプションを指定して利用できます)

一方、HTTPS でのリクエストでは証明書の検証等で、単純なデータやり取り以外の部分で内部的に処理が食われてしまうことがあります。
下記の例題では HTTPS にてデータ取得を行うサイトが信頼のあるサイトであることを前提とし、証明書の検証を行っていません。

例題では以下の3つの手法にてサイトからのデータ取得をループし、取得時間を計測しています。
CURL_RequestText1:毎回CURLハンドラを初期化し、データ取得を行う例
CURL_RequestText2:毎回CURLハンドラを初期化し、内部的に確保されているコネクションの再利用等は行わずデータ取得を行う例(CURLOPT_FORBID_REUSE/CURLOPT_FRESH_CONNECT)
CURL_RequestText3:CURLハンドラを予め準備しておき、繰り返し利用する間は再利用する例
結果では、1/2 はサイトにより多少の変化はあるもののあまり差はなく(2の方が若干早い印象)、3 は 1 の半分程度の時間でデータ取得が行われています(この例題では記載していませんが、POST 時の応答も高速化されていました)。
TCP FAST OPEN(CURLOPT_TCP_FASTOPEN)の影響があるかどうかどうかを見てみましたが、特に影響はありませんでした。

HTTPS 接続が正常に機能しているサイトではほぼ 3 の設定で高速化される印象ですが、ブラウザ接続した際に「信頼できる運営者情報はありません」等のアラートが出るサイトでは全く変化はありませんでした(証明書の検証を行っていないにも関わらず)。
新しいサーバーでテストする際等には証明書を正しく入れてもらうようにお願いするしかない状況です(libcurl の設定では対処できない)。

今回テストしたのはサーバーからの応答を取得後に別の応答を取得する必要がある場合の処理です。
URLが異なる複数の結果を予め取得しておく場合には libcurl-multi や CURL ハンドラを複数準備して別スレッドで並行して結果を取得すれば容易に高速化することは可能かと思います(スレッドで用いる場合は CURLOPT_NOSIGNAL を指定)。 実行結果

2017年7月15日土曜日

GDによるグラフ描画(最小二乗法による直線近似)

libgd によるグラフ描画の例題です(最小二乗法による直線近似)。

文字列画像の作成 にて用意したフォントを用い、sin関数により生成したデータのグラフを作成しています。

graphInit 関数にてグラフ作成時のオプションを指定していますが、グラフの横幅(graw)、縦幅(grah)、余白(padding)、グラフ描画オプション(DrawType BASE_UNDER:最小値を基準としてグラフを作成する BASE_ORIGIN:原点を基準としてグラフを作成する)等を指定できます。
genData の type にて最大値や最小値が異なるデータを生成していますが、グラフは枠内に収まるよう自動的にスケーリングして描画され、縦横軸のラベルもそれに応じて描画されます。

データのグラフ化のついでに、最小二乗法による直線近似も行っています。グラフ化に用いるデータから傾き、切片を計算し、近似する直線を描いています。 実行結果 genData(type=0)にて原点を基準にして作成したグラフ

2017年7月2日日曜日

フォントを指定して文字列画像の作成(libgd)

libgd を利用しフォントを指定して文字列画像を作成する例題です。

OpenType のフォントが Google から配布されていますのでそれをダウンロードし、実行ファイルと同じフォルダ内に保存します(例として NotoSerifCJKjp-[weight].otf を利用)。

libgd のインストールはこのような感じです(OSX、freetype や libjpeg/libpng も予めインストール)。 例題では、余計な余白や画像サイズを手入力で計算する必要がないように、予め文字列の描画に必要な領域を計算しておき画像のサイズを決定しています。
複数行にて表示していますが、行間を広げたい場合等には一行の高さを gdImageStringFT にて予め計算しておき、その高さ+行間をインクリメントして行数分の表示を行います。 実行結果