2015年4月
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
無料ブログはココログ

« 2014年3月 | トップページ | 2014年5月 »

2014年4月の4件の記事

2014年4月29日 (火)

白いシールに影を付けて見えるようにするシール

stroke の新規追加はあきらめましたが…

MOONPhase ver.2.9.0 での getStrokeJSON() では、外部ストロークの要素数を変更できない、とか…

Getstrokejson290

「じゃあ、白紙に最初にストロークを登録するときと、ストローク消去はどないせいっちゅうねん」、と言いたいところなのですが、とりあえず、既存のストロークを加工するなら問題ないと考えてよさそうです

と、いうことで、既存のストロークをいじるだけで済むシールを一つ作りました。

白くて見えないシールのストロークに影をつけて、見やすくするシール

Download : 「シールのストロークに影をつけるシール」

MOONPhase ver.2.9.0 になって画面描画周りが改修された影響で、黒背景に白いペンで書いて作ったシールが、白背景に張り付けると見えなくなってしまいました。

たとえば、清水さん謹製の「手書きで太さ変更」シール、シール台帳に貼った状態ではよく視認できます。

Screenshot_20140429022550

これを白背景のページに張り付けると…

Screenshot_20140429022631

上の画面には、シールが貼ってあるのですが、全く見えません。ver.2.8.0 以前では、い~感じに周囲に黒い縁取りがついてて見えたのですが。もっとも今の描画の方が、まっとうなのかもしれません。

Screenshot_20140429022659

そこで、「シールのストロークに影をつけるシール」を使います。

Screenshot_20140429022711

シールをタップすると、ページ上の全てのシールが強調表示されます。見えないシールがどこにあるのか、わからないままだと困りますから。

ここで、ページ上部に(見えないまま)貼りついている 「手書きで太さ変更」の部分をタップすると、このシールが操作対象として選ばれ、ストロークに影が付きます。

Screenshot_20140429022731

影のついたシールを改めてシール台帳に save すると、こんな感じです。上がオリジナル、下が影付きです。

Screenshot_20140429022754

ストロークに影を付ける部分の処理を抜去します。元のストロークの色を変えて、座標を右下に数ピクセルずらしたものを、本来のストロークの直前に描くようにデータを変更しています。

function shadowStroke( stickerID ){
    var _CONST = {
        offset: 3
    };

    function invertColor( orgColor ){
        var rgba = MOON.int2rgba( orgColor );
        return MOON.rgba2int( 255 - rgba[0], 255 - rgba[1], 255 - rgba[2], rgba[3] );
    }

    var baseExtStrokes = MOON.getStrokeJSON( stickerID );
    var shadowExtStrokes = MOON.getStrokeJSON( stickerID );
    var newExtStrokes = [];

    for ( var i = 0, eLen = baseExtStrokes.length; i < eLen; i++ ){
        var baseStrokes = baseExtStrokes[i].strokes;
        var shadowStrokes = shadowExtStrokes[i].strokes;
        var oneExtStroke = {strokes: []};

        for ( var j = 0, sLen = shadowStrokes.length; j < sLen; j++ ){
            var oneStroke = shadowStrokes[j];
            oneStroke.color = invertColor( oneStroke.color );

            for ( var k = 0, dLen = oneStroke.data.length; k < dLen; k += 3 ){
                oneStroke.data[k] += _CONST.offset;
                oneStroke.data[k +1] += _CONST.offset;
            }
            oneExtStroke.strokes.push( oneStroke, baseStrokes[j] );
        }
        newExtStrokes.push( oneExtStroke );
    }

    MOON.setStrokeJSON( stickerID, newExtStrokes );
}

役に立つのは「白くて見えないシール」の場合だけではありません。逆に、白背景に黒いペンで書いたシールの場合。

Screenshot_20140429022947

上図ページの "TEST" シールをシール台帳に save してみます。

Screenshot_20140429023035

このスクリーンショット画像では結構はっきり見えますが、実際の MOON の液晶では、この "TEST" という文字は、かなり視認性が低くなっています。

Screenshot_20140429023049

そこで、この "TEST" にも 「シールのストロークに影をつけるシール」を適用します。黒文字に白い影がつくので、ページ上では何の変化もないように見えます。

しかし、適用してからシール台帳に save すると、こうなります。

Screenshot_20140429023147

今後は、この白い影を付けたシールを原本とすれば、シール台帳上でも視認しやすいですし、もちろん黒背景のページに張り付けても一目瞭然です。

いずれ、システム側で何か対策を施すのかもしれませんが、それまでは、このシールで一時しのぎを。

Download : 「シールのストロークに影をつけるシール」

2014年4月21日 (月)

peperJSON/strokeJSON の罠? 謎? 仕様? バグ?

コピペシールがバージョンアップできません。

結局、この週末もバージョンアップに失敗しました。

コピペシールの ver.2.9.0 になって、動作しなくなった部分は以下のシーケンスなのですが・・・これ、今公開されている API で実現できなかったりするんじゃないだろうか?

  1. backing から、ペンで囲んだ範囲内の strokes 情報を拾い上げる
  2. シール背景の strokes に、拾い上げた strokes を登録する
  3. シールの x, y 座標を、ペンで囲んだ位置に移動する
  4. シール背景の有効な形状を制限する、info.json の clip 属性を変更する
  5. シール背景の範囲を指定する、info.json の width, height 属性を変更する

1~5 まで動作すれば、コピペシールのバージョンアップは終了です。

このうち、1, 3 は実現できています。3 は ver.2.9.0 より前は、システムの不備 ? のようで、実現できなかったのが、ようやく実現できるようになりました。

2 は、実現できるのですが、他の項目を動作させようとすると前後関係で動いたり動かなくなったり、まだ油断できない、よくわかりません。

4, 5 を諦めれば話は簡単なのですが、特に 5  が動作しないと実用に耐えません。

以下、個人の環境と経験でお送りします。

ちまちま書いていきますが、思いっきり勝手に失敗しているだけかもしれません。

2. のストローク操作に関して

まず、既存のシール背景のストロークを消去してみました。

var paperJSON = MOON.getPaperJSON( stickerID );
paperJSON.strokes = [];
MOON.setPaperJSON( stickerID, paperJSON );

或いは

var paperJSON = MOON.getPaperJSON( stickerID );
paperJSON.externalStrokes = [];
MOON.setPaperJSON( stickerID, paperJSON );

更には

MOON.setStrokeJSON( stickerID, [] );

の、どれでもうまくいきそうなのですが、これが、前後のコードとの組み合わせでうまくいったりいかなかったり。

また、既存のストロークを無視して、新たにストロークを登録するには

var paperJSON = MOON.getPaperJSON( stickerID );
paperJSON.strokes = newStrokes;
MOON.setPaperJSON( stickerID, paperJSON );

或いは

MOON.setStrokeJSON( stickerID, [{strokes: newStrokes}] );

のどちらでも動きます。どちらかというと、後者が正解だと思いますが。

3. のシール座標変更

これは、ver.2.9.0 になってから可能になった操作です。peperJSON.x, paperJSON.y に数値を指定すると、その座標にシールが移動します。以前はシールが移動しなかったのは、多分システム側の不備だったと認識しています。

var paperJSON = MOON.getPaperJSON( stickerID );
paperJSON.x = 100;
paperJSON.y = 100;
MOON.setPaperJSON( stickerID, paperJSON );

といった形で操作できるのですが、以前は x, y に数値こそ代入できるのですが、表示に反映されませんでした。

今回はまった罠は、「x, y に代入する値は、整数でなければならない」というものです。リテラルでも、変数経由でも、整数値だと動くのですが、小数点以下のある値を渡すと、システムコールから帰ってきません。

これは、「仕様として整数値しかうけつけない」というのでも構いませんが、そうすべき積極的な理由が思い当りませんので、本来の仕様としては非整数値でも受け付けるべきところを、整数を前提としたコードを書いてしまい、テスト時にも整数値でしかチェックしなかったのではないかと邪推します。

整数値しかうけつけないのは、width, height も同様でした。システムコール内部で Math.floor() でも使っておけばよいのではないかと思います。

4. clip 属性の操作

ver.2.9.0 より前は、

var paperJSON = MOON.getPaperJSON( stickerID );
paperJSON.clip.data = {...}
MOON.setPaperJSON( stickerID, paperJSON );

とすることで、clipping の範囲だけを、strokes.data 形式で指定できました。これにより、不定形だったり、円形だったり、任意の形状で背景を clipping できていたのです。

ver.2.9.0 では、MOON.getPaperJSON() の返り値に clip 属性が含まれていません。 info.json には存在するのに、です。MOON.getPaperJSON() が clip 属性をカットしてしまうようです。

info.json を見ると、clip 属性自体の形式は従来と変わらず、strokes 形式のようですので、強引に、以下のコードで動きます。

paperJSON = MOON.getPaperJSON( stickerID );
var newClip = { width:1.0, color:-1, type:"pen", subtype:"",
      data: [ 0, 0, 0.01, width -1, 0, 0.01,
             width -1, height -1, 0.01, 0, height -1, 0.01, 0, 0, 0.01
      ]
};
paperJSON.clip = newClip;
MOON.setPaperJSON( myStickerID, paperJSON );

この問題は上記の方法で回避できるのですが、ちょっと判然としません。MOON.getPaperJSON() が clip 属性を返すか、別の正式な API が欲しいです。

5. 背景サイズが変えられない

これ、半分以上本気で「バグ」じゃないかと疑っています。

既述のように、paperJSON.width, paperJSON.height は、整数値しか受け付けないというのもあるのですが、そもそも想定の動作をしません。

たとえば、もともとのシール背景サイズが 100×100 で、シール背景のストロークを200×300 の範囲に収まる newStrokes に書き換えようとすれば、

paperJSON = MOON.getPaperJSON( stickerID );
paperJSON.width = 200;
paperJSON.height = 300;
MOON.setPaperJSON( stickerID, paperJSON );
MOON.setStrokeJSON( stickerID, [{strokes:newStrokes}] );

ver.2.8.0 までは、こんな感じでうまくいきました。ところが ver.2.9.0 では不思議な動作をします。

上記のコードで、確かにシール背景のサイズは 200×300 になります。ところが表示内容は、100×100 の範囲のストロークが横に 2 倍、縦に 3 倍されたものになります。ストロークもガタガタとジャギーの激しいものが表示されます。あれこれためしてみましたが、どう頑張っても、もともとのシール背景のサイズからはみ出すストロークデータを表示できません。

ストロークはベクトルデータなので、2 倍や 3 倍に拡大したくらいで、ジャギーを目立たなくさせることが不可能ではないでしょうから、これは何か描画ルーチンに見落としがあるのではないかと感じました。

どうやら、しばらく

コピペシールのバージョンアップはお預けのようです。

前回・今回の記事の内容を、また地道に、Issue Tracker に上げることにします。

2014年4月15日 (火)

新規 strokes データの正式な追加登録手続きが分からない

自作シールの MOONPhase ver.2.9.0 対応を進めるために、あれこれ探っています。その中で、やはり、新しい strokes データフォーマット、あるいは新しい info.json, strokeX.json の操作方法で詰まっています。

MOONPhase ver.2.8.0 以前では、info.json の内容は以下の構造でした。

{
  version:"0.2",
  x:0, y:0,
  width:768, height:1024,
  scale:1.0,
  color ":-1,
  transparent:false,
  strokes:[
    {
      width:2.5,
      color:-16777216,
      type:"pen",
      data:[
        x0, y0, p0, x1, y1, p1, ...
      ]
    },
    {
      width:2.5,
      color:-16777216,
      type:"pen",
      data:[
        x0, y0, p0, x1, y1, p1, ...
      ]
    },
    {...}, {...}, ...
  ]
}

MOONPhase ver.2.9.0 以降では、info.json は以下のようになっています。

{
  version:"1.0",
  x:0, y:0,
  width:768, height:1024,
  scale:1.0,
  color:-1,
  externalStrokes:[
    {
      name:"stroke1.json",
      x:126, y:147,
      width:438, height:170,
      size:3399
    }
  ],
  clip:{
    width:1.0,
    color:-1,
    type:"pen",
    subtype:"",
    data:[
      x0, y0, p0, x1, y1, p1, ...
    ]
  }
}

strokeX.json の内容は、

{
  strokes:[
    {
      width:3.0,
      color:-16777216,
      type:"pen",
      subtype:"",
      data:[
        x0, y0, p0, x1, y1, p1, ...
      ]
    },
    {
      width:3.0,
      color:-16777216,
      type:"pen",
      subtype:"",
      data:[
        x0, y0, p0, x1, y1, p1, ...
      ]
    },
    {...}, {...}, ...
  ]
}

古い version の strokes 以下が外に出された形ですね。

参考にするのは、やっぱり「暗号化シール」

この、新しい形式の info.json, strokeX.json の扱い方については、プレインストールの「暗号化シール」が非常に参考になります。

旧バージョンの MOON.getPaperJSON( backingID ).strokes に相当する情報は、新バージョンでは MOON.getStrokeJSON( backingID ) で得られますが、微妙に違います。

[
  {
    strokes:[.....]
  },
  {
    strokes:[.....]
  },
  ...
]

stroke1.json, stroke2.json, stroke3.json, .... の内容を単純に並べた配列のようです。中身を全部読もうとすると、従来より一段深いループを回す必要があります。

書き込み方を知りたい

で、strokes データの読み取り方はわかったのですが、書き込み方が分かりません。暗号化シールでも strokes データの書き込みはあるのですが、「新規に」ではなくて、「既存の strokes データをいじって書き戻す」処理です。具体的には、var extStrokes = MOON.getStrokeJSON( backingID ); として、extStrokes[0].strokes.data[...] を全部書き変えて、最後に MOON.setStrokeJSON( backingID, extStrokes ); で書き戻す。

この書き戻し処理がどうして参考にならないかというと、「もし、既存のストロークがなかったらどうすればよいのか」「複数の strokeX.json があったとして、どの strokeX.json に storkes データを追加しても問題ないのか、先頭の strokeX.json に追加すべきなのか、あるいは最後の strokeX.json にすべきなのか」。指針となる情報がありません。

旧バージョンのシールと互換性保持を考えると、info.json の内容に strokes データを組み込んで、MOON.setPaperJSON( backingID, paperJSON ) で書き込むと、内部で strokes データを分離して、新フォーマットの info.json と stroke1.json に書き込んでくれるだろう、と、まず最初に、strokes:[] の追加 (つまり、全 stroke の消去ですね) を試してみました。

すると、半ば予想通り、半ば予想を超える結果になりました。

info.json については予想通りでした。strokes:[...] という属性はファイルには保存されず、代わりに、externalStrokes:[] として、外部 json ファイルへのリンクが消失していました。

で、stroke1.json 自体がなくなるか、というと、stroke1.json は存在している。では、stroke1.json の中身は空かというと、実は全く変化していませんでした。stroke1.json には手を付けずに、externalStrokes のみを操作していたわけです。リンク情報の操作と、strokes データ自体の書き変えを柔軟に組み合わせて、実作業量の削減を図っているようです。

このように、既存のストロークがなかった場合、stroke1.json に相当するデータをでっち上げて、それを要素に持つ配列を MOON.setStringJSON( backingID, extStrokes ) に渡すのが正式な手続きなのか、それとも、「たまたまうまく動作する」が、本来想定されている手続きではないのか。

正式な情報がない時点では、内部処理のオーバーヘッドはあるかもしれませんが、従来同様に MOON.setPaperJSON() を使って書き込むのが無難だろうかと考えています。

strokes だけなら逃げられるんですが

ところが・・・、これでもまだ解決しないんですねぇ。

先週からあれこれ調べているのは、当然、自作シールのバージョンアップの為です。最初に ver.2.9.0 対応したいのは (自分が使いたいこともあって) コピペシールです。

コピペシールでは、カット/コピー操作の際に、背景のストロークをシールのストロークに取り込むと同時に、取り込んだストロークに合わせてシールの clip:{} を変更しています。

ところが、この操作をしている部分のコードが動作しません。いろいろ探ってみると、info.json には clip:{} という属性が存在するのに、ver.2.9.0 で MOON.getPaperJSON() すると、返り値の属性には clip が含まれていません !!!

「なんということでしょう」

これって、MOON.getPaperJSON() の返り値に、旧バージョンと同じフォーマットで clip:{} を追加して、無理やり MOON.setPaperJSON() していいんでしょうか。シールの clip 情報を加工するには、別の正式な手順があるんでしょうか。

とりあえず動く、無理やりバージョンアップなら数日でできそうですが、本当にそれでよいのか、やはり正式な tutorial が欲しいところです。

MOONPhase 開発チームの皆さん、体を壊さない範囲で、早めに資料を準備してもらえるとうれしいです。よろしくお願いします。

というか、strokes データを書き込むサンプルシールを作ってくれれば、とりあえずそれでなんとかします。 :-)

#でも、ver.2.9.1 のリリースが優先ですかね。

2014年4月10日 (木)

世代別 JSON ?, JSON 階層化 ?

MOONPhase ver.2.9.0 に update しました。

課題が消失したわけではなないでしょうが、レスポンスの向上は純粋に素晴らしい。

それはともかく。

一から書きなおしたという内部コードを理解することはかなわないとして、趣味プロ屋としては、API の brush up と、データ・オブジェクトの構成変更が気になります。

早速手書きしたページのデータを覗いてみると、backing データは、従来 info.json だけであったところが、info.json, canvas.png, strokeX.json に分かれています。

また、ページのトップディレクトリ内に screenshot.jpg, と thumb.png が追加されています。

Genjson_2

 

つまり、従来、手書きデータは JSON 形式でのベクトルデータで全てを保持していて、それは info.json 内に含まれていました。ページを開くたびに info.json を読み込んで、ベクトルデータを解釈して描画するしかなかったわけです。

今回のファイル構成だと、info.json を開くと、その中に strokeX.json へのリンクが記録されています。これだけで、まず、問答無用で読み込まなければならない情報量が減りました。そして、状況に応じ、手書きデータの追加・削除がなければ、screenshot.jpg (あるいは backing と、全てのシールの canvas.json の積算) を表示し、ベクトルデータの編集が必要な場合だけ strokeX.json を読み書きするのでしょう。

なるほど、ページ表示だけでも明らかに速くなるはずです。

上記の構成だけ見ると、JSON ファイル (或いは、データファイル) の階層化と表現した方が分かりやすいような気もします。

但し、まだまだ情報がなくてわからないのですが、手書きで stroke1.json に格納されたベクトルデータは、必ずしも即時に *.png なラスタデータに変換されるわけでなく、スリープ時や、何も操作をしていない時に、バックグラウンドで徐々に処理されていくはずです。そうすると、タイミングによって、既にラスタライズの済んだ stroke データと、まだ処理されていない stroke データを区別する必要があるので、恐らく stroke0.json と stroke1.json のような形で、storokeX.json がいくつかできて処理が進んでいくのでしょう。

「世代別 JSON」という表現が、どこまでを含むのか分かりませんが、他のファイルの関係を見ると、この strokeX.json の範囲を差しているのだと思います。ラスタライズ済みのものから、最新の手書きされたばかりのものまで、何世代分にも分ける方法もあるでしょうが、恐らく「世代別」という言葉が「世代別ガーベジコレクション」からの流用であろうこと、世代別ガーベジコレクションで 5 世代も 10 世代も分類するようなものは聞かないことから、2 から、せいぜい 3 世代くらいでパフォーマンスが出せるのだろうと推測します。

さて、従来 strokes データ(手書きのベクトルデータ)を扱うプログラムでは、

var page = MOON.getCurrentPage();
var backing = page.backing;
var paperJSON = MOON.getPaperJSON( backing );
var strokes = paperJSON.strokes;

という形で strokes データを取得していましたが、新しい info.json には strokes オブジェクトが含まれていません。どうやって、外部リンクされている strokesX.json のデータを取得すればよいのか、と、ver.2.9.0 版の暗号化シールのコードを読んでいますと、今後はどうやら以下の形でアクセスできるようです。

var page = MOON.getCurrentPage();
var backing = page.backing;
var strokes = MOON.getStrokeJSON( backing );

という tweet を踏まえると、ver.2.9.0 で MOON.getPaperJSON( backing ) を使用すると、新しい info.json の内容に、strokeX.json の内容を組み込んだ JSON を新しく作成し、それを返すように内部で wrap しているのでしょう。同じように、MOON.setPaperJSON( backing, papaerJSON ) すると、内部で strokeX.json に書き出して、外部リンクを張るのだと思います。互換性は保たれますが、直接 MOON.getStrokeJSON(), MOON.setStrokeJSON() を call した方が、効率がよいわけですね。

ver.2.9.0 版の暗号化シールのコードには、他にも、stickerStorage.getItem(), stickerStorage.setItem() という記述も見られます。

「お、これは、Issue Tracker 148 の、シール固有データの保存 API が実装されたか」と喜んで、固有データの保存先を探したのですが、わかりません。てっきり、各シールの directory 内に、storage.json が作成されるのだと思ったのですが。これについては、技術データの公開を待つことにします。

さて、動かなくなったシールをバージョンアップすることにしましょう。すぐできればよいのですが。

« 2014年3月 | トップページ | 2014年5月 »