SSブログ
JavaScript ブログトップ
前の10件 | -

0.96インチI2C OLED (SSD1306)用に画像をデータ配列に。 [JavaScript]

Aliexpressで安いI2C OLEDディスプレイとなると、0.96インチの制御チップがSSD1306のもの。

とりあえず画像を出してみたいけど、BMPファイルデータをArduinoで動的に変換する必要はないので、SSD1306に合わせて画像をデータ配列にしたほうがいい。

ssd1306_dat.png

自作のスクリプトを作った後、すでに画像変換できるサイトがあることが判明。

image2cpp
http://javl.github.io/image2cpp/

ただ、いろいろできる分、設定もたくさんある。
ぼくの作ったのは、サンプルプログラムの寄せ集めだけど、ドラッグ&ドロップでSSD1306専用のデータが瞬時にできるというのが売り。
高さが8の倍数でないときの余白部分を白にするか黒にするかの選択のみ。

ssd1306-san.png
HTMLソース
<html>
<head><meta charset="utf-8"><title>SSD1306-san</title></head>
<body style="color:#999; text-align:center;">
<h1   style="color:#666;">SSD1306-san</h1>
<div  style="display:flex; justify-content:center; align-items:center;">
    <div id="target" style="width:200px; height:100px; border:5px dashed #eee; padding:10px;">
        Drop image here !<br>
        <img    id="preview" style="max-width:200px; max-height:80px;" onLoad="ssd1306img()"><br></div>
    <div style="width: 50px; "> -&gt; </div>
    <div style="width:200px; height:100px; border:5px solid #eee; padding:10px;">
        <span   id="info" ></span><br>
        <canvas id="cvs"     style="max-width:128px; max-height:64px; border:1px dashed #ccc; display:none"></canvas></div></div>
<div>
    <p>background color : 
        <input  id="bgw" type="radio" name="bg" checked><label for="bgw">white</label>
        <input  id="bgb" type="radio" name="bg"        ><label for="bgb">black</label>
    <p><textarea id="ary" cols=100 rows=20 style="font-size:80%; padding:1em; border:1px solid #ccc;" onClick="this.select()"></textarea></div>
<script>
function $(x) { return document.getElementById(x); }
const ctx = $('cvs').getContext('2d');

$('target').addEventListener('dragover', function (e) {
    e.preventDefault();
    e.stopPropagation();
    e.dataTransfer.dropEffect = 'copy';    } );
$('target').addEventListener('drop', function (e) {
    e.stopPropagation();
    e.preventDefault();
    const reader = new FileReader();
    reader.onload = function (e) { preview.src = e.target.result; }
    reader.readAsDataURL(e.dataTransfer.files[0]);    } );

function ssd1306img() {
    const w = $('cvs').width  = $('preview').naturalWidth;
    const h = $('cvs').height = $('preview').naturalHeight;
    const H = h - (h - 1) % 8 + 7;
    $('info').innerHTML    = "W:" + w + " x H:" + h;
    $('cvs').style.display = "none";
    $('ary').textContent   = " Image size is too large! ";
    if( w > 128 || h > 64 )  return;
    $('cvs').style.display = "inline";
    $('ary').textContent   = "const uint8_t image[] = { " + w + ",   " + h + ", // px\n  ";
    ctx.fillStyle = $('bgw').checked ? '#fff' : '#000';
    ctx.fillRect(0, 0, w, H);
    ctx.drawImage($('preview'), 0, 0);
    const img = ctx.getImageData(0, 0, w, h);
    let i, d, x, y, b;
    for (i = 0; i < img.data.length; i += 4) {
        const gray = img.data[i] * 0.299 + img.data[i+1] * 0.587 + img.data[i+2] * 0.114;
        img.data[i] = img.data[i+1] = img.data[i+2] = gray > 127 ? 255 : 0;
    }
    ctx.putImageData(img, 0, 0);
    for (i = y = 0; y < H; y += 8) {
        for (x = 0; x < w; x++) {
            for (b = d = 0; b < 8; b++) d += img.data[(x+(y+b)*w)*4] ? (1<<b) : 0;
            $('ary').textContent += (d < 16 ? "0x0" : "0x") + d.toString(16) + ((++i % 16) ? ", ": ",\n  ");
        }
    }
    $('ary').textContent = $('ary').textContent.slice( 0, $('ary').textContent.lastIndexOf(',') ) + "\n};";
}
</script>
</body>
</html>


タグ:OLED SSD1306
nice!(0)  コメント(0) 

Digisparkで音楽演奏【楽譜編】 [JavaScript]

kewpie3score.jpg
以前につくった notes.h ですが、やっぱり楽譜から入力しづらい。大文字が多いこととアンダーバー('_')が入力しにくさの原因ではないかと考えました。
もうちょっと楽譜から入力しやすいようにしました。
変更点としては、小文字メインで、半音上がるシャープ(♯)がつくのを大文字にするのと、長さを数字ではなく英語での頭文字の小文字としました。
以下、再度楽譜のマイルール。

【マイコンで処理しやすい楽譜・音符情報を作ります。】
  • 音の高さ(音高、ピッチ)は、周波数(Hz)等ではなく、音階とオクターブで表す
  • 音の長さ(音価)は基準の最小音符の何倍かで表す
  • 一音で2byte(16bit)使用する
    • 上位8bitが音の高さ(音高)
      • 0xooの時は休符
      • 上位4ビットがオクターブ
        • 0-9まで
      • 次の4ビットが音階・スケール(ド~シの12音階で0-11)
        • 音名は、英語でCDEFGAB
        • 入力簡便化のため小文字とし、半音上げる際は大文字を使用
          • 'c','C','d','D','e','f','F','g','G','a','A','b'
        • 半音下げるのは、一音下げてから半音あげる対応で   
      • MIDIノート番号でいうとNo.13(C#0)~127(G9)まで網羅
      • C0は休符用に使用, A9, A#9, B9はMIDI番号にもないため除く
      • 音階とオクターブを分けることで12個の基本音階情報からシフト演算を用いて容易に算出できる
    • 下位8ビットが音の長さ(音価)
      • 96分音符を最小単位の1とする
        • 1-255までに各種音符の長さを入れるとすると32分音符(3)から倍全音符(192)まで入れることができる
        • 3連符には対応できるよう通常の音符は3の倍数
      • 音符の長さの表記は、英語訳の頭文字
        • 32分音符 thirty-second note
        • 16分音符 sixteenth note
        • 8分音符 eighth note
        • 4分音符 quarter note
        • 2分音符 half note
        • 全音符 whole note (breve)
        • 倍全音符 double whole note (longa)
        • 4倍全音符 4x whole note (maxima)
      • 入力簡便化のため小文字を使用する
      • 付点音符はさらに'd' (dotted) を付ける
      • 3連符用に三分の一の長さ(one third)には't'を付ける
        • 本来は3連符は3等分する前の音符の半分の長さの音符で書かれる   
      • タイによる音符の結合は、休符(長さ情報のみでできている)を加算することで可能
  • 楽譜としては、音符となるunsigned int(2byte)の情報を配列に羅列する
    • 先頭は、テンポ(♩=1~65535)を入れて、次に0で区切る
    • 1トラック内に和音は置けないため、必要な和音の分だけトラックを使用する
    • 各トラック内の終わりは0とし、つづけて次のトラック情報に入る
    • すべてのトラック情報のあとにさらに0を入れて楽譜データ終了とする

【楽譜定義のヘッダーファイルを作るjavascript】

前回はエクセルでしこしこ作りましたが、今回は修正もしやすいようにjavascriptを使用。
以下を「note2.html」として保存してブラウザで開く。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Musical notes 2</title>
<script>
// *** twelve-tone scale ***
//   capital letter : raise a semitone. (e.g. C means C#)
const twelveTone = ['c','C','d','D','e','f','F','g','G','a','A','b'];

// *** note value (sound length) ***
const noteValue  = [
  { note: 't' , value:   3 },   // thirty-second note
  { note: 's' , value:   6 },   // sixteenth note
  { note: 'e' , value:  12 },   // eighth note
  { note: 'q' , value:  24 },   // quarter note
  { note: 'h' , value:  48 },   // half note
  { note: 'w' , value:  96 },   // whole note (breve)
  { note: 'd' , value: 192 },   // double whole note (longa)

  { note: 'sd', value:   9 },   // dotted sixteenth note
  { note: 'ed', value:  18 },   // dotted eighth note
  { note: 'qd', value:  36 },   // dotted quarter note
  { note: 'hd', value:  72 },   // dotted half note
  { note: 'wd', value: 144 },   // dotted whole note (breve)

  { note: 'tt', value:   1 },   // 1/3 of a 32nd note
  { note: 'st', value:   2 },   // 1/3 of a 16th note
  { note: 'et', value:   4 },   // 1/3 of an eighth note
  { note: 'qt', value:   8 },   // 1/3 of a quarter note
  { note: 'ht', value:  16 },   // 1/3 of a half note
  { note: 'wt', value:  32 },   // 1/3 of a whole note (breve)
  { note: 'dt', value:  64 },   // 1/3 of a double whole note (longa)
  { note: 'mt', value: 128 },   // 1/3 of a 4x whole note (maxima)
 ];

$ = function(id) { return document.getElementById(id); }

function notes() {
    let  octave, scale;
    $('main').value  = $('explanation').value;
    $('main').value += '#define MIN_NOTE  96    // 96th note (reference note)\n';
    $('main').value += '\n// Rests of various lengths (rests are just Length, so it is also for connection by Tie)\n';
    for( let nv of noteValue ) $('main').value += '#define RS' + (nv.note + '   ').slice(0,2)  + "   "  + ('   ' + nv.value).slice(-3) + '\n';
    $('main').value += '\n// combination of pitch and length\n';
    for( octave = 0; octave < 10; octave++ ) {
        for( scale = 0; scale < 12; scale++ ) {
            if( octave == 0 && scale == 0) continue;
            if( octave == 9 && scale >  8) continue;
            for( let nv of noteValue ) {
                $('main').value += '#define ' + twelveTone[scale] + octave +  (nv.note + '  ').slice(0,2)
                                +  '   (0x' + octave + scale.toString(16) + '00 | ' +  ('   ' + nv.value).slice(-3) + ')\n';
            }
        }
    }
    $('main').style.display  = 'block';
    $('dlBtn').style.display = 'inline';
}

function downloadText(fileName) {
  const blob = new Blob([$('main').value], { type: 'text/plain' });
  const aTag = document.createElement('a');
  aTag.href = URL.createObjectURL(blob);
  aTag.target = '_blank';
  aTag.download = fileName;
  aTag.click();
  URL.revokeObjectURL(aTag.href);
}
</script>
</head>
<body>
<h1>Musical notes 2</h1>
<p>Creates musical score and note information that is easy to process with a microcomputer.
<p>
<button onClick="notes()">Create a note definition data</button>
<button onClick="downloadText('note2.h')" style="display:none;" id="dlBtn">Download the header file</button>
<p>
<textarea id="explanation" disabled style="display:none;">
// ****************************************************************
//  notes2.h
// ****************************************************************
//   upper 8 bits   : pitch of a sound (0x00 : rest)
//     upper 4 bits : octaves  [0-9]
//     next  4 bits : 12 tone scale (C,C#,D,D#,E,F,F#,G,G#,A,A#,B)
//                      ['c','C','d','D','e','f','F','g','G','a','A','b']
//   lower 8 bits   : length of the sound 
//                      Let the 96th note be 1
//                      't'  =   3   thirty-second note
//                      's'  =   6   sixteenth note
//                      'e'  =  12   eighth note
//                      'q'  =  24   quarter note
//                      'h'  =  48   half note
//                      'w'  =  96   whole note (breve)
//                      'd'  = 192   double whole note (longa)
//                      'sd' =   9   dotted sixteenth note
//                      'ed' =  18   dotted eighth note
//                      'qd' =  36   dotted quarter note
//                      'hd' =  72   dotted half note
//                      'wd' = 144   dotted whole note (breve)
//                      'tt' =   1   1/3 of a 32nd note
//                      'st' =   2   1/3 of a 16th note
//                      'et' =   4   1/3 of an eighth note
//                      'qt' =   8   1/3 of a quarter note
//                      'ht' =  16   1/3 of a half note
//                      'wt' =  32   1/3 of a whole note (breve)
//                      'dt' =  64   1/3 of a double whole note (longa)
//                      'mt' = 128   1/3 of a 4x whole note (maxima)
// ****************************************************************

</textarea>
<textarea id="main" style="display:none; width:90%; height: calc( 1.2em * 25 );  line-height: 1.2;"></textarea>
</body>
</html>

再生のスケッチは後日。
nice!(0)  コメント(0) 

ビットマップの動的作成 [JavaScript]

createbmp.png
canvas 使えば!?っていうことなんですけど。

・ビットマップをバイナリーファイルの配列として作る
・ファイルイメージ上で画像を編集
・Base64でエンコードしてテキストとしてソースを指定

というゴリゴリした処理で canvas を使うことなく画像を表示します。
ネットで拾った情報をアレンジして何とか形にしたものです。
JavaScriptのオブジェクトとか、よくわかってないので間違ってたらすみません。
HTA形式なら、ファイル保存もできます。
ソースは長いですが、フルカラー24bitとモノクロ1bitの2つと、base64エンコードと、HTA用ファイル保存などの組み合わせだけで、やってることは単純です。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ビットマップの動的作成 Dynamic creation of bitmap</title>
<script>
var Bitmap = function() {       // full color (24bit)
    // Property
    this.width     = 0;
    this.height    = 0;
    this.lineBytes = 0;
    this.fileData  = [ 66,77, 54,0,0,0, 0,0, 0,0, 54,0,0,0,     // Bitmap File Header (14 bytes)
                       40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0, 0,0,0,0, 0,0,0,0,
                        0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];    // Information Header (40 bytes)
    // Method
    this.setSize = function(w, h) {
        this.width     = w;
        this.height    = h;
        this.lineBytes = ((w * 3 + 3) >> 2) << 2;
        setArrayLong( this.fileData,  2, 54 + this.lineBytes * h );
        setArrayLong( this.fileData, 18, w );
        setArrayLong( this.fileData, 22, h );
        this.fileData.length = 54 + this.lineBytes * h;
    } 
    this.setPixel = function(x, y, r, g, b) {
        var index = (this.height - y - 1) * this.lineBytes  +  x * 3;
        this.fileData[ index + 54 ] = b;
        this.fileData[ index + 55 ] = g;
        this.fileData[ index + 56 ] = r;
    }
    this.fillRect = function(x1, y1, x2, y2, r, g, b) {
        for(var x=x1; x<=x2; x++) for(var y=y1; y<=y2; y++) this.setPixel(x, y, r, g, b);
    }
    // Local Scope Function
    function setArrayLong(arr, index, num) {
        for(var i=0; i<4; i++)  arr[index + i] = ( num >> ( i * 8 ) ) & 0xff;
    }
}

var BitmapMono = function() {   // 2color monochrome (1bit)
    // Property
    this.width     = 0;
    this.height    = 0;
    this.lineBytes = 0;
    this.fileData  = [ 66,77, 62,0,0,0, 0,0, 0,0, 62,0,0,0,     // Bitmap File Header (14 bytes)
                       40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 1,0, 0,0,0,0, 0,0,0,0,
                        0,0,0,0, 0,0,0,0, 2,0,0,0, 0,0,0,0,     // Information Header (40 bytes)
                       255,255,255,0,  0,0,0,0 ];               // Color palette       (8 bytes)
    // Method
    this.setSize = function(w, h) {
        this.width     = w;
        this.height    = h;
        this.lineBytes = ((w + 31) >> 5) << 2;
        setArrayLong( this.fileData,  2, 62 + this.lineBytes * h );
        setArrayLong( this.fileData, 18, w );
        setArrayLong( this.fileData, 22, h );
        this.fileData.length = 62 + this.lineBytes * h;
    } 
    this.setPixel = function(x, y, pal) {
        var index = (this.height - y - 1) * this.lineBytes  + (x >> 3);
        if( pal ) this.fileData[ index + 62 ] |=  (128 >> (x % 8)); // 128 = 0b10000000
        else      this.fileData[ index + 62 ] &= ~(128 >> (x % 8));
    }
    this.fillRect = function(x1, y1, x2, y2, pal) {
        for(var x=x1; x<=x2; x++) for(var y=y1; y<=y2; y++) this.setPixel(x, y, pal);
    }
    // Local Scope Function
    function setArrayLong(arr, index, num) {
        for(var i=0; i<4; i++)  arr[index + i] = ( num >> ( i * 8 ) ) & 0xff;
    }
}

function saveFile( bytes, filename ) {  // File writing (* Only for HTA)
    var stream = new ActiveXObject('ADODB.Stream'); 
    stream.Type = 2;                // 1:adTypeBinary  2:adTypeText
    stream.Charset = 'iso-8859-1';  // To get as a byte type array
    stream.Open();
    for(var i=0; i<bytes.length; i++) stream.WriteText( String.fromCharCode( bytes[i] ) );
    stream.SaveToFile( filename, 2 );
    stream.Close();
}

function encodeBase64( bytes ) {        // Encode to Base64
    var i, len, table = [], base64 = '';
    for (i=65; i< 91; i++)  table.push(String.fromCharCode(i));
    for (i=97; i<123; i++)  table.push(String.fromCharCode(i));
    for (i= 0; i< 10; i++)  table.push(i.toString(10));
    table.push('+');
    table.push('/');
    for (i=0, len=bytes.length; i<len-2; i+=3) {
        base64 += table[  (bytes[i]   & 0xfc) >> 2  ];
        base64 += table[ ((bytes[i]   & 0x03) << 4) | ((bytes[i+1] & 0xf0) >> 4) ];
        base64 += table[ ((bytes[i+1] & 0x0f) << 2) | ((bytes[i+2] & 0xc0) >> 6) ];
        base64 += table[   bytes[i+2] & 0x3f        ];
    }
    if (len === i+1) {          // last 1 byte
        base64 += table[  (bytes[i]   & 0xfc) >> 2  ];
        base64 += table[ ((bytes[i]   & 0x03) << 4) ] + '==';
    }else if (len === i+2) {    // last 2 bytes
        base64 += table[  (bytes[i]   & 0xfc) >> 2  ];
        base64 += table[ ((bytes[i]   & 0x03) << 4) | ((bytes[i+1] & 0xf0) >> 4) ];
        base64 += table[ ((bytes[i+1] & 0x0f) << 2) ] + '=';
    }
    return base64;
}

function main() {
    var bmp1 = new BitmapMono();
    var bmp2 = new Bitmap();
    bmp1.setSize( 32, 32);
    for(var i=0; i<32; i++)  bmp1.setPixel( i, i, 1);
    document.getElementById('bmp').innerHTML  = '<img src="data:image/bmp;base64,'+ encodeBase64( bmp1.fileData ) + '" >';
    bmp2.setSize( 32, 32);
    for(var i=0; i<32; i++)  bmp2.setPixel( i, i, i*8, 255-i*8, 0);
    document.getElementById('bmp').innerHTML += '<img src="data:image/bmp;base64,'+ encodeBase64( bmp2.fileData ) + '" >';
    // * Can be saved for HTA
    // saveFile(bmp1.fileData, 'test1.bmp');
    // saveFile(bmp2.fileData, 'test2.bmp');
}
</script>
</head>
<body>
<h1>ビットマップの動的作成</h1>
<p>
<ul>
  <li>ビットマップをバイナリーファイルの配列として作る
  <li>ファイルイメージ上で画像を編集
  <li>Base64でエンコードしてテキストとしてソースを指定
</ul>
<p><button onclick="main()">create Bitmap</button>
<p id="bmp"></p>
</body>
</html>

タグ:HTA
nice!(0)  コメント(0) 

画像をクリップボードコピーする [JavaScript]

ddimg.png
画像をクリップボードコピーする.js (WSH版)

タイトル通りです。画像をアプリ起動なしで、いきなりクリップボードにコピーするものです。
画像ファイルをドラッグ&ドロップ するだけ。(よく使うならSendToに入れてもいいかも)

シングルクォートとダブルクォートが混じっていますが、PowerShellではダブルクォートはいろいろ変換されてしまます。

引用符規則について - PowerShell Microsoft Docs
https://docs.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_quoting_rules?view=powershell-7.2

そこで PowerShell内でシングルクォートが使えるように、PowerShellのコマンド自体はダブルクォートで囲いました。パス・ファイル名の中のシングルクォートは、シングルクォート2個に置き換え逃げ切っています。

以下をコピーして「画像をクリップボードコピーする.js」というファイル名で保存します。
(長いので切れて見えなくなっててすみません。)
if( WScript.Arguments.Count() === 0 ) 
{ 
    WScript.createObject( 'WScript.Shell' ).Popup( 'Drag and drop the image file', 5, 'Copy Image File to Clipboard', 48);
    WScript.Quit( 1 );
} 
WScript.Quit( WScript.createObject( 'WScript.Shell' ).Run( "PowerShell -Command Add-Type -AssemblyName System.Windows.Forms;[Windows.Forms.Clipboard]::SetImage([System.Drawing.Image]::FromFile('" + WScript.Arguments.Item(0).replace("'", "''") + "'));", 0, true ) );

nice!(0)  コメント(0) 

テキストから書式をはずす [JavaScript]

plaintext.png
ブラウザなどからテキストをコピーして、他のソフトに貼り付ける際に、書式は要らないっていうときありますよね。
いちいちメモ帳に貼り付けて、またコピーして、別ソフトに貼り付けるという処理をしていました。
そこで、これをスクリプトで処理できるようにしてみました。
WScript.Quit( WScript.createObject( 'WScript.Shell' ).Run( 'PowerShell Get-Clipboard -Format Text | Set-Clipboard' , 0, true ) );

これを「テキストから書式をはずす.js」という名前で保存して起動するだけ。
PowerShellとかよくわかってないのですが、なんとかこれで書式を外せています。
WSHを使って、RunからPowerShellを呼び出すことで、ウインドウを出さないようにしています。

タグ:WSH powershell
nice!(0)  コメント(0) 

画面のスケーリングを調べる [JavaScript]

またHTAですみません。
getDPI.png
最近のブラウザは、ピクセル指定しても、dot by dotにはならず、文字の大きさに合わせてスケーリングしてくれているみたい。
でもHTAは古いので、画面のスケーリングに対応できておらず、ピクセル指定と、文字幅指定で差がでてしまいます。
でも、HTAにおけるウインドウサイズの変更はピクセル指定なので、スケーリングの倍率分をかけてあげないといけません。
エクセルのDLL呼び出しでやってみました。
以下を参考にしました。

ディスプレイの拡大率取得 -コントローパネルのディスプレイから、「デスクト- | OKWAVE
https://okwave.jp/qa/q8972028.html

DLLはよくわからず使っているので、間違っていたらごめんなさい。
解像度とかの意味合いや言葉の定義などもあいまいな理解のままで、とりあえず動けばいいという感じですみません。
<thml>
<head>
<title>ディスプレイの拡大率</title>
<script>
function getDPI() {     // 参考:https://okwave.jp/qa/q8972028.html
    var excel = new ActiveXObject('Excel.Application');         // Excelオブジェクト生成
    try {
        var hWndDesk = excel.ExecuteExcel4Macro( 'CALL("user32", "GetDesktopWindow", "J")' );
        var hDCDesk  = excel.ExecuteExcel4Macro( 'CALL("user32", "GetDC", "JJ", ' + hWndDesk + ')' );
        var logPix   = excel.ExecuteExcel4Macro( 'CALL("gdi32",  "GetDeviceCaps", "JJJ",' + hDCDesk + ',88)' );
        excel.ExecuteExcel4Macro( 'CALL("usr32",  "ReleaseDC", "JJJ",' + hWndDesk + ',' + hDCDesk + ')' );
        excel.Quit();
        excel = null;
        return logPix;
    } catch(e) {
        excel.Quit();
        excel = null;
        return -1;      // エラーの場合は、-1を返す
    }
}

function main() {
    var dpi = getDPI();
    document.getElementById('DPI').innerHTML = ' 論理解像度は' + dpi + ' DPIです。';
    window.resizeTo( 460 * dpi / 96, 320 * dpi / 96 );
}
</script>
</head>
<body>
<h1>getDPI</h1>
<p style="width:400px;background:skyblue;">width=400px</p>
<p style="width:25em; background:skyblue;">width=25em</p>
<p>通常ブラウザか96DPIなら同じ長さ(16px=1.00em)
<p><button onclick="main()">解像度に合わせウインドウサイズを変更<br>96 DPI換算で460x320</button>
<p id="DPI"></p>
</body>
</html>

タグ:HTA
nice!(0)  コメント(0) 

ワード・エクセル開いているかな? [JavaScript]

前回の「ウィンドウを検索する」でアプリケーションのclass nameを知ることができました。
(ワードやエクセルならネットで検索すれば出てきますが、、)
このclass nameをもとに、ウインドウのタイトルバーの文字列を取得して表示します。
officeinfo.png
UTF-8、拡張子は.HTAで以下のテキストを保存。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ワード・エクセル開いているかな?</title>
<script>
var excel = new ActiveXObject('Excel.Application');     // Excelオブジェクト生成

function officeInfo( className ) {
    var resultHtml = '';                                // ↓指定したクラス名の1つめのウィンドウのハンドルを取得
    var hWnd  = excel.ExecuteExcel4Macro( 'CALL("user32", "FindWindowA", "JCJ", "' + className + '", 0)' );
    if( hWnd ) {                                        // 取得できたら(0でなければ)、、
        do {                                            // ↓ウィンドウが表示状態ならば、ウィンドウハンドルからウィンドウ名を取得
            if( excel.ExecuteExcel4Macro( 'CALL("user32", "IsWindowVisible", "JJ", ' + hWnd + ')' ) ) {
                resultHtml += '<p>' + excel.ExecuteExcel4Macro( 'CALL("user32", "GetWindowTextA", "2JFJ", ' + hWnd +', 0, 64)' );
            }                                           // ↓デスクトップを親ウィンドウとし(0)、現在(hWnd)の次の子ウィンドウを検索
            hWnd = excel.ExecuteExcel4Macro( 'CALL("user32", "FindWindowExA", "JJJCJ", 0, ' + hWnd + ', "' +className + '", 0)' );
        } while( hWnd );
    }
    if( !resultHtml ) resultHtml = '<p>Not found  (' + className + ')';
    document.getElementById('result').innerHTML = resultHtml;
}
</script>
</head>
<body>
<h1>ワード・エクセル開いているかな?</h1>
<p>
<form>
<input type="button" value="Word"       onclick="officeInfo('OpusApp')"       >
<input type="button" value="Excel"      onclick="officeInfo('XLMAIN')"        >
<input type="button" value="PowerPoint" onclick="officeInfo('PPTFrameClass')" >
<input type="button" value="Access"     onclick="officeInfo('OMain')"         >
<input type="reset"  value="clear"      onclick="document.getElementById('result').innerHTML=''" >
</form>
<p><div id="result"></div>
</body>
</html>

タグ:HTA
nice!(0)  コメント(0) 

ウィンドウを検索する [JavaScript]

他のプログラムが表示しているデータを欲しいときってあるけど、まあ無理。
せめてウインドウのタイトルだけでも、、ということでまずは調査。
以下のサイトを参考というか、HTMLアプリケーション(HTA)用に書き直しました。

Win32API ウィンドウを検索する FindWindowEx - s-kita’s blog
https://s-kita.hatenablog.com/entry/20121218/1355839657

コールバック関数、、よくわからなかったので、とりあえず動けばということで作りました。

windowkensaku.jpg
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=9" >
<title>ウィンドウを検索する</title>
<style>
    table            {  width: 100%;  border-collapse: collapse;  border-spacing: 0; }
    th, td           {  padding: 0px;  text-align: left; }
    tr:nth-child(odd){  background-color: #eee; }
    tr:nth-child(1)  {  background-color: #ccc; }
</style>
<script>
var excel = new ActiveXObject( 'Excel.Application' );           // Excelオブジェクト生成
var tableHtml;                                                  // 表示する表のHTML
var depth;                                                      // ウインドウ階層の深さ

function EnumetareWindows(hWndParent) {
    var strClassName, strCaption;
    var isWinVisible  = excel.ExecuteExcel4Macro( 'CALL("user32", "IsWindowVisible", "JJ",   '  + hWndParent + ')' ) 
    if( isWinVisible || !document.getElementById( 'limitVisible' ).checked  ) {     // 可視Windowか、可視のみの指定がないなら表示する
        strClassName  = excel.ExecuteExcel4Macro( 'CALL("user32", "GetClassNameA"  , "2JFJ", '  + hWndParent +', 0, 128)' );
        strCaption    = excel.ExecuteExcel4Macro( 'CALL("user32", "GetWindowTextA" , "2JFJ", '  + hWndParent +', 0, 128)' );
        tableHtml  += ( isWinVisible ? '<tr>' : '<tr style="color:#aaa">' )         // 非可視Windowはグレーで表示
                   +  '<td style="text-indent:' + depth + 'rem">' + hWndParent + '</td><td>' + strClassName + '</td><td>' + strCaption + '</td></tr>';
    }
    
    var hWndChild     = excel.ExecuteExcel4Macro( 'CALL("user32", "FindWindowExA"  , "JJJJJ", ' + hWndParent + ', 0, 0, 0)' );
    if( !hWndChild )  return;
    if(  document.getElementById( 'limitDepth' ).checked  &&  depth ) return;
    depth++;
    do {
        EnumetareWindows(hWndChild);
        hWndChild     = excel.ExecuteExcel4Macro( 'CALL("user32", "FindWindowExA"  , "JJJJJ", ' + hWndParent + ', ' + hWndChild + ', 0, 0)' ); 
    } while ( hWndChild );
    depth--;
}

function getWindowInfo() {
    var hWndParent    = excel.ExecuteExcel4Macro( 'CALL("user32", "GetDesktopWindow", "J")' );
    tableHtml  = '<table><tr><th>window handle</th><th>class name</th><th>caption</th></tr>';
    depth = 0;
    EnumetareWindows( hWndParent );
    tableHtml += '</table>';
    document.getElementById( 'result' ).innerHTML = tableHtml;
}
</script>
</head>
<body>
<h1>ウィンドウを検索する</h1>
<p>
<form>
<input type="checkbox" id="limitVisible" checked ><label for="limitVisible">可視ウィンドウのみ</label> 
<input type="checkbox" id="limitDepth"   checked ><label for="limitDepth"  >親ウィンドウのみ</label> 
<input type="button" value="検索"   onclick="getWindowInfo()" >
<input type="reset"  value="クリア" onclick="document.getElementById('result').innerHTML=''" >
</form>
<p><div id="result"></div>
</body>
</html>

IE9モードにしたのは、表を「しましま」にするためだけです。
excel.ExecuteExcel4Macro(’CALL(~)’) でWindowsAPI関数を実行しています。
なので、エクセルがインストールされていることが前提です。
JJ、2JFJ、JJJJJとかは「CALL 関数と REGISTER 関数の使い方 - Microsoft Support」で。
タグ:HTA
nice!(0)  コメント(0) 

HTAファイルの関連付け windows11で [JavaScript]

window11を入れたPCで、HTAファイルがMicrosoft Edgeに関連付けられていました。
当然ただのHTMLファイルとしてしか表示されません。

C:\Windows\System32 にある mshta.exe に関連付けようとしましたが、
noopenwith.png
「選択したプログラムは、このファイルの種類に関連付けることはできません。他のプログラムを選択してください。」と言われてしまいました。
で、関連付けをする方法を調べてみました。

レジストリエディターを起動(メニューの検索のところにregeditと入力するなど)
  ↓
HKEY_CLASSES_ROOT\Applications\mshta.exe を選択
  ↓
NoOpenWith を削除
  ↓
HTAファイルを右クリック > プログラムから開く > 別のプログラムから開く > その他のアプリ↓ > このPCで別のアプリを探す > C:\Windows\System32\mshta.exe を指定

でOKでした。

タグ:HTA
nice!(0)  コメント(0) 

CODE128で改行入りバーコードを作る [JavaScript]

あるあるですが、端末にバーコードリーダーがあるけど、ログイン画面にはIDとパスワードの入力欄とログインボタンがあって、キーボードから、ID → [Enter] → パスワード → [Enter] でログインするシステム。
バーコードで楽々入力だと便利なのですが、CODE39やNW-7では入力できない文字があったり、IDとパスワードを1回で読み込むことができないということがあります。
それをCODE128で解決してみました。
bc128.png
HTML5ですので、以下のコードをテキストエディタにコピーして、文字コードはshift JISではなくUTF-8で、拡張子をhtmlにして保存してください。できたバーコードは右クリックで画像保存できます。(canvasのサイズ変更処理をすることでcanvasのクリアも兼ねていて、背景のリセット処理を省いているので透過画像になっています。)
スマホのバーコード、QRコード読み込みアプリで読み込めることを確認しました。
お約束ですが、ID・パスワードの管理は、印刷したものを無くさないようにするのはもちろん、上司やシステム管理の人にばれないように自己責任でおこなってください。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>バーコード128太郎</title>
<script type="text/javascript">
const BC128 = [
    "212222","222122","222221","121223","121322","131222","122213","122312",
    "132212","221213","221312","231212","112232","122132","122231","113222",
    "123122","123221","223211","221132","221231","213212","223112","312131",
    "311222","321122","321221","312212","322112","322211","212123","212321",
    "232121","111323","131123","131321","112313","132113","132311","211313",
    "231113","231311","112133","112331","132131","113123","113321","133121",
    "313121","211331","231131","213113","213311","213131","311123","311321",
    "331121","312113","312311","332111","314111","221411","431111","111224",
    "111422","121124","121421","141122","141221","112214","112412","122114",
    "122411","142112","142211","241211","221114","413111","241112","134111",
    "111242","121142","121241","114212","124112","124211","411212","421112",
    "421211","212141","214121","412121","111143","111341","131141","114113",
    "114311","411113","411311","113141","114131","311141","411131","211412",
    "211214","211232","2331112"];                           // code128パターン BSBSBS(B)

function dispCode(f) {
    let codeText, checkDigit, i, c, n, x, w;
    if( !f.txt1.value ) { f.txt1.focus();  return; }        // 入力されるまでfocusが留まる
    if( !f.txt2.value ) { f.txt2.focus();  return; }        //  → [Enter]で次のボックスへ
    // データの作成
    codeText  = BC128[ 104 ];   checkDigit = 104;  n = 0;   // STARTコード(B)設定
    for(i = 0; i < f.txt1.value.length; i++) {              // 1つ目のエンコード
        c = f.txt1.value.charCodeAt(i) - 32;                //     文字に対応する数値
        codeText += BC128[c];   checkDigit +=  c  * ++n;    //     パターン追加,check digit計算
    }
    codeText += BC128[ 101 ];   checkDigit += 101 * ++n;    // 改行:code A に変更
    codeText += BC128[  77 ];   checkDigit +=  77 * ++n;    //     :CR
    codeText += BC128[  74 ];   checkDigit +=  74 * ++n;    //     :LF
    codeText += BC128[ 100 ];   checkDigit += 100 * ++n;    //     :code B に戻す
    for(i = 0; i < f.txt2.value.length; i++) {              // 2つ目のエンコード
        c = f.txt2.value.charCodeAt(i) - 32;
        codeText += BC128[c];   checkDigit +=  c  * ++n;
    }
    codeText += BC128[ checkDigit % 103 ];                  // チェックディジット
    codeText += BC128[ 106 ];                               // STOPコード設定
    // バーコードを表示
    const ctx = document.getElementById("codeImage").getContext("2d");
    document.getElementById("codeImage").width = codeText.length * 11 / 6 + 22;
    for(i = 0, x = 10; i < codeText.length; i++) {
        w = parseInt(codeText.charAt(i));
        if( !(i%2) ) ctx.fillRect(x, 2, w, 60);
        x += w;
    }
}
</script>
</head>
<body>
<h1 style="background-color:green;padding-left:10px;color:white;">バーコード128太郎</h1>
<p>
<form method="post" name="f" onsubmit="dispCode(this); return false;">
<input type="text" name="txt1" size="10" pattern="^[¥x20-¥x7F]+$" autofocus />
<input type="text" name="txt2" size="10" pattern="^[¥x20-¥x7F]+$" />
<input type="submit" value="作成" /> 
<input type="reset" onClick="f.txt1.focus();" />
</form>
<p>
<canvas id="codeImage" height="64" style="border:solid 1px lightgray;"></canvas>
</body>
</html>

タグ:バーコード
nice!(0)  コメント(0) 
前の10件 | - JavaScript ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。