くりーむわーかー

プログラムとか。作ってて ・試しててハマった事など。誰かのお役に立てば幸いかと。 その他、いろいろエトセトラ。。。

画像

axiosで取得した画像データを保存とか表示とかする

VueでUIを作ってて、axios使用でajaxで画像ファイルを取得した後に、

そのデータを表示したり、ローカルに保存したりしたい。

その場合のやり方。

//リクエストヘッダでコレつけた方がいいっぽ
const config = {
  responseType: 'arraybuffer'
}

//サーバに送信
this.$axios
.post('http://hogehoeg/sample.png', { data: 'somedata'}, config)
.then(response => {
  //base64でエンコードしたい場合
  let bstr = new Buffer(response.data, 'binary').toString('base64')
  
  //blobオブジェクトにしたい場合
  let blob = new Blob([response.data], { type: 'image/png' })

  //imgタグをidでとって、srcにblobのObjectURLを突っ込んで画像表示する
  let img = document.getElementById('img_tag_id')
  let url = window.URL || window.webkitURL
  img.src = url.createObjectURL(blob)
  
  //保存させたい場合(ダウンロードっぽくさせたい場合)
  let link = document.createElement('a')
  link.href = window.URL.createObjectURL(blob)
  link.download = 'download-filename.png'
  link.click()

  //Vueで別のコンポーネントにデータ渡したい場合はこんな感じ?
  this.imgdata = response.data
})

base64でやる場合は、画像サイズは32kb未満くらいで考えた方が良いのかしら。まーあんま大きい画像はやめた方がよさそうですね。

ajaxで取ってきた画像ファイルとかをダウンロードっぽく保存させたい場合は前述の感じでやるっぽ。リンク作って、ローカルのオブジェクトのURLを突っ込んで中で、Clickを発火させてる感じ?

ちょっとイレギュラーなやらせ方のような気もするんだけど、StackOverFlowとかいろいろ見てるとこのやり方しかないっぽいですかね?

で、いい感じにまとめてくれるのが↓のGitHubのリポジトリ

https://github.com/kennethjiang/js-file-download/blob/master/file-download.js

IE11だと上述のやり方じゃ上手くいかないらしく、それにも↑のリポジトリは対応してる。

これ使った方がいいと思う。車輪の再発明は控えたい。

あと、vueでaxios使う場合、下の感じで書くと、中でthisが使えない。

this.$axios
.post('http://hogehoeg/sample.png', { data: 'somedata'}, config)
.then(function(response){
  this.dataval = ''//これ無理
})

で、これをやるには呼ぶ前に「let self = this」みたいにしておくのが昔見たやり方なんだけど、

最近の書き方的にはアロー関数でやるとthisもいける。

this.$axios
.post('http://hogehoeg/sample.png', { data: 'somedata'}, config)
.then(response => {
  this.dataval = ''//これいける
})

Python 画像データ⇔文字列にする

Pythonで画像データのバイナリを文字列として取得したり、

逆にバイナリの文字列から画像データを起こしたりしたい場合。

Pillowを使用。

import io
from PIL import Image

#バイナリにしたい画像を読み込み
tmpimg = Image.open("./imgs/-.png")
with io.BytesIO() as output:
    tmpimg.save(output,format="PNG")
    contents = output.getvalue()#バイナリ取得
    print(contents)#表示
    tmpimg2 = Image.open(io.BytesIO(contents))#バイナリから画像に変換
    tmpimg2.save('image_from_str.png')

#バイナリ文字列としてやる場合はこんな感じ
imgbytes_str = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x0c\x00\x00\x00\x0c\x01\x03\x00\x00\x00l\xbb\xce\xa4\x00\x00\x00\x06PLTE\x00\x00\x00\xff\xff\xff\xa5\xd9\x9f\xdd\x00\x00\x00\x13IDATx\x9cc\xf8\xfc\x81\x01\x8e\x8c\r\x10\x08I\x1c\x00+\xcd\x10\xa5\xa0\xa1\xbf,\x00\x00\x00\x00IEND\xaeB`\x82'
img_from_str = Image.open(io.BytesIO(imgbytes_str))
img_from_str.save('image_from_str2.png')

文字が割り当てられている外字かどうかを判定する

外字かどうかを判定するというのは結構ある。まー文字のコード範囲がE000~F8FFかどうか見ればいいだけなので、割とすぐ実装できるし、調べればすぐ出てくる。

問題は、文字が割り当てられている外字かどうかを判定しようとしたとき。割り当てられてない文字なんか入ってくるわけないと思いたくなりますが、問題はデータ移行の時。

旧システム、特に他ベンダーから移行するとか、ホストから移行するみたいな場合、外字が入ってるともー発狂したくなる状況に陥りがち。

だいたい、コードの変換表とか作ったりして対応していくと思いますが、それでも変換が間違っていたり色々問題は出てくる。そーゆー時に、外字領域のコードなんだけど、字に割当たってないコードが来た時にどう見つけるかという事です。

字に割当たっていない時は外字のフォントファイルの作られ方によると思うけど、だいたい「・」になる。場合によっては「 」空白だったり、「□」だったりする。字は全部同じ形になるけど、コード的には全部違うので、例えば「”字”=”字”」みたいな比較は不可能。

文字コードで比較できないなら、変換後の字形を比較するしかない。

とゆーことで色々試した結果、↓のコードが出来上がりましたとさ。

とりあえず割り当てられてない文字コードを指定して一文字画像として描画する。あとは調べたいデータの文字を一文字ずつ画像に描画して、画像同士を比較する。比較には画像のハッシュを計算して、それを比較する方法を使用。

とりあえず、比較のベースにする1文字を画像として描画してハッシュを取得。

Encoding unicode = Encoding.GetEncoding("UTF-16");
//比較のベースにする文字コード
short baseChar = Convert.ToInt16("E123", 16);
byte[] baseCharByte = BitConverter.GetBytes(baseChar);
//UTF-16で文字に変える
string baseCharStr = unicode.GetString(baseCharByte);

Font fnt = new Font("MS 明朝", 11);
Bitmap canvasBaseChar = new Bitmap(20, 20);//画像のサイズ
Graphics g = Graphics.FromImage(canvasBaseChar);
g.FillRectangle(Brushes.White, 0, 0, canvasSize, canvasSize);//白で塗りつぶしておく
g.DrawString(baseCharStr, fnt, Brushes.Black, 0, 0);//文字を描画
g.Dispose();

//ベースの文字画像のMD5を取得
BitmapData bmpdata = canvasBaseChar.LockBits(new Rectangle(0, 0, canvasBaseChar.Width, canvasBaseChar.Height), ImageLockMode.ReadWrite, canvasBaseChar.PixelFormat);
IntPtr ptr = bmpdata.Scan0;
int bytes = bmpdata.Stride * canvasBaseChar.Height;
byte[] rgbValues = new byte[bytes];
Marshal.Copy(ptr, rgbValues, 0, bytes);
byte[] baseHash = new MD5CryptoServiceProvider().ComputeHash(rgbValues);

あとはデータの文字列を一文字ずつ同じように画像にしてハッシュを計算してベースと比較する。

Bitmap compareCanvas = new Bitmap(20, 20);
Graphics g = Graphics.FromImage(compareCanvas);
g.FillRectangle(Brushes.White, 0, 0, 20, 20);
g.DrawString(pStr, fnt, Brushes.Black, 0, 0);
g.Dispose();

BitmapData bmpdata = compareCanvas.LockBits(new Rectangle(0, 0, compareCanvas.Width, compareCanvas.Height), ImageLockMode.ReadWrite, compareCanvas.PixelFormat);
IntPtr ptr = bmpdata.Scan0;
int bytes2 = bmpdata.Stride * compareCanvas.Height;
byte[] rgbValues2 = new byte[bytes2];
Marshal.Copy(ptr, rgbValues2, 0, bytes2);
byte[] hash2 = new MD5CryptoServiceProvider().ComputeHash(rgbValues2);

bool bEqual = false;
if (hash2 != null && hash2.Length == baseHash.Length)
{
    int i = 0;
    while ((i < hash2.Length) && (hash2[i] == baseHash[i]))
    {
        i += 1;
    }
    if (i == hash2.Length)
    {
        bEqual = true;
    }
}
if (!bEqual)
{
    Console.WriteLine("違う字形");
}
else
{
    Console.WriteLine("同じ字形");
}

画像のハッシュを計算して比較するロジックはココのブログのロジックを使わせてもらいました。

問合せ