http://vps.will-co21.net/test/html5proxy/postMessageCrossDomain.html?/formdatapost/tmp/hoge.png
html5のpostMessageとXMLHTTPRequestとiframeを組み合わせて画像のバイナリをXMLHTTPRequestで取得して
base64エンコードしたものをiframeからpostMessageで別ドメインの親ウィンドウに送って
dataURLにして画像として表示。
親ウィンドウ
window.onload = function () {
require(["base64"], function (lib ) {
var base64 = lib.base64;
var iframe = document.createElement("iframe");
iframe.src = "http://habrashi.s351.xrea.com/htmlproxy/proxy.html?" + encodeURIComponent(window.location.search.substr(1));
iframe.setAttribute("id", "xhrframe");
document.body.appendChild(iframe);
window.addEventListener("message", function (e) {
var data = e.data;
img = document.createElement("img");
img.src = "data:image/png;base64," + data;
document.getElementById("content").appendChild(img);
});
});
}
window.onload = function () {
var target = (parent && parent.postMessage ? parent : (parent && parent.document.postMessage ? parent.document : undefined));
require(["base64"], function (lib ) {
var xhr = new XMLHttpRequest();
var base64 = lib.base64;
xhr.onreadystatechange = function () {
if(xhr.readyState == 4){
var res = xhr.responseText;
var bytes = [];
for(var i=0, len = res.length; i < len; i++) bytes.push(String.fromCharCode(res.charCodeAt(i) & 0xff));
var data = bytes.join("");
base64String = base64.encode(data);
if (typeof target != "undefined") {
target.postMessage(base64String, '*');
}
}
}
var url = decodeURIComponent(window.location.search.substr(1));
xhr.open("GET", url, true);
xhr.overrideMimeType("text/plain; charset=x-user-defined");
xhr.send(null);
});
}
子ウィンドウ
※require.jsとsmokescreenで使われてるbase64ライブラリを使用。
子ウィンドウをPHPにしてiframeをtargetとしてフォームデータをPOSTして、
POSTされたデータをJSONエンコードしてJSに渡せば、
POSTデータの中継なんかもできそう。
投稿者のアーカイブ
XMLHTTPRequestとiframeとpostMessageでクロスドメイン通信
2012年11月23日 金曜日globalCompositeOperation=”darker”が使えないブラウザ用の自前JS実装改良版
2012年11月18日 日曜日function darker(src, dst, globalAlpha)
{
var w,h;
if(src.width > dst.width)
{
w = src.width;
}
else
{
w = dst.width;
}
if(src.height > dst.height)
{
h = src.height;
}
else
{
h = dst.height;
}
var ctx1 = src.getContext("2d");
var canvas = document.createElement("canvas");
canvas.setAttribute("width", w);
canvas.setAttribute("height", h);
ctx2 = canvas.getContext("2d");
ctx2.drawImage(src, 0, 0);
var canvas2 = document.createElement("canvas");
canvas2.setAttribute("width", w);
canvas2.setAttribute("height", h);
ctx3 = canvas2.getContext("2d");
ctx3.drawImage(dst, 0, 0);
var result = ctx2.getImageData(0, 0, w, h);
var blend = ctx3.getImageData(0, 0, w, h);
var alpha;
for(var data = result.data, blend = blend.data, i = 0 ; i < data.length ; i+=4)
{
if(typeof globalAlpha !== "undefined") gA = globalAlpha * 1;
else gA = 1;
alpha = blend[i+3] * gA;
alpha = alpha / 255;
if(data[i] == 0 && data[i+1] == 0 && data[i+2] == 0 && data[i+3] == 0)
{
data[i] = blend[i], data[i+1] = blend[i+1], data[i+2] = blend[i+2], data[i+3] = alpha * 255;
}
else
{
data[i] = ((data[i]) * (1 - alpha) + -blend[i] * (alpha));
data[i+1] = ((data[i+1]) * (1 - alpha) + -blend[i+1] * (alpha));
data[i+2] = ((data[i+2]) * (1 - alpha) + -blend[i+2] * (alpha));
data[i+3] = 255;
}
}
ctx1.putImageData(result, 0, 0);
return src;
}
背景色が白以外の場合に動作がおかしかったのと、
globalAlphaへの対応を追加。
いろいろ計算式をいじっていてこれで動いたけど、
なぜこの計算式なのかは不明。
ChromeとSafariの実装にあわせたからこの式になったけど、
Firefoxと同じ結果になる式のほうが論理的に正しいのかもしれない。
globalCompositeOperation=”darker”が使えないブラウザ用の自前JS実装
2012年11月17日 土曜日function darker(src, dst)
{
var w,h;
if(src.width > dst.width)
{
w = src.width;
}
else
{
w = dst.width;
}
if(src.height > dst.height)
{
h = src.height;
}
else
{
h = dst.height;
}
var ctx1 = src.getContext("2d");
var canvas = document.createElement("canvas");
canvas.setAttribute("width", w);
canvas.setAttribute("height", h);
ctx2 = canvas.getContext("2d");
ctx2.fillStyle = "rgba(255,255,255,1)";
ctx2.fillRect(0, 0, w, h);
ctx2.drawImage(src, 0, 0);
var canvas2 = document.createElement("canvas");
canvas2.setAttribute("width", w);
canvas2.setAttribute("height", h);
ctx3 = canvas2.getContext("2d");
ctx3.fillStyle = "rgba(255,255,255,1)";
ctx3.fillRect(0, 0, w, h);
ctx3.drawImage(dst, 0, 0);
var result = ctx2.getImageData(0, 0, w, h);
var blend = ctx3.getImageData(0, 0, w, h);
var aO;
for(var data = result.data, blend = blend.data, i = 0 ; i < data.length ; i+=4)
{
aO = (data[i+3]) + (blend[i+3]);
data[i] = 255 - ((255 - data[i]) * (data[i+3]) + (255 - blend[i]) * (blend[i+3]));
data[i+1] = 255 - ((255 - data[i+1]) * (data[i+3]) + (255 - blend[i+1]) * (blend[i+3]));
data[i+2] = 255 - ((255 - data[i+2]) * (data[i+3]) + (255 - blend[i+2]) * (blend[i+3]));
}
ctx1.putImageData(result, 0, 0);
return src;
}
globalAlphaを使ったときと同じ動作にするためには、
dst側のalphaの値をglobalAlphaの値で置き換えればいけるんじゃないかと思うけどまだ未確認。
[JavaScript]ユニークIDを発行する関数を生成する
2012年11月10日 土曜日var Uuid = (function () { var i=0; return function () { return ++i; }; })();
さらにeval,String.replaceと組み合わせて
var params = ["hoge", "fuga", "aaa"];
Class = function () {};
Class.reflection = function (classname, params) {
var args = [];
for(var i=0; i < params.length; i++) args.push("params[%d]");
return eval("new " + classname + "(" + args.join(",").replace(/%d/g, (function () {
var i=0; return function () { return i++; };
})()) + ")");
}
var a = Class.reflection("Array", params);
クラス名文字列とパラメータの配列からクラスを生成するリフレクション
Function.bindを利用しても同じことはできるけど、IEなどで使えない場合にはこれが使える。