1entryの容量を超えたので分割。その2からの続き。
00:25
Wassr経由で教えてもらった情報を忘れていた。
リモートの画像をdata schemeな形で取得したいのなら、Canvas使うのが簡単
var cx=Canvas.getContext(...);
var img=new Image();
img.src="..";
cx.drawImage(img, ...);
cx.toDataURL();
var img=new Image();
img.src="..";
cx.drawImage(img, ...);
cx.toDataURL();
こっちもこっちで凄い。グリモンの例では、GM_xmlhttpRequestを使ってクロスドメインでデータを取得している。しかし、Canvasを使った方法では、画像に限定されるけどURLを直接指定しているので同一出身ポリシーを気にする必要はない。これは凄いわ。
2009/04/15 追記
クロスドメインは不可能でした。これについて続きを書きました。
00:39
Base64関数をbtoaに置き換えた。
// ==UserScript==
// @name getFileByDataScheme
// @namespace http://www.kanasansoft.com/
// @include *
// ==/UserScript==
(
function(){
var parseHTTPHeader=function(responseHeader){
var headers=responseHeader.split("\n");
var len=headers.length;
var parsing=[];
for(var i=0;i<len;i++){
if(/^$/.test(headers[i])){
}else if(/^[\x09\x20]/.test(headers[i])){
if(parsing.length==0){
throw "SyntaxError:HTTPHeader (first line) "+headers[i];
}
parsing[parsing.length-1]+="\n"+headers[i];
}else{
parsing.push(headers[i]);
}
}
var len=parsing.length;
var parsed={};
for(var i=0;i<len;i++){
var pair=parsing[i].split(": ",2);
if(pair.length!=2){
throw "SyntaxError:HTTPHeader (format) "+parsing[i];
}
if(pair[0] in parsed){
throw "SyntaxError:HTTPHeader (repetition) "+pair[0];
}
parsed[pair[0]]=pair[1];
}
return parsed;
}
var loadDataMethod=function(res){
var headers=parseHTTPHeader(res.responseHeaders);
if(res.status!=200){
throw "RequestError"+
":status="+res.status+
":statusText="+res.statusText+
":responseHeaders="+res.responseHeaders;
}
var contentType=("Content-Type" in headers)?
headers["Content-Type"]:
"application/octet−stream";
var dataScheme="data:"+contentType+
";base64,"+btoa(
res.responseText.replace(
/[\u0100-\uffff]/g,
function(c){
return String.fromCharCode(c.charCodeAt(0)&0xff);
}
)
);
data.callback(dataScheme);
}
var getData=function(url){
data.url=url;
GM_xmlhttpRequest(
{
"method":"GET",
"url":data.url,
"onload":loadDataMethod,
"onerror":loadDataMethod,
"overrideMimeType":"text/plain; charset=x-user-defined"
}
);
}
var data={};
var getFileByDataScheme=function(url,callback){
data.callback=callback;
getData(url);
}
if(window.self==window.top){
var url=prompt("image url","");
if(url==null||url==""){
return;
}
var handler=function(url,callback){
return function(){
getFileByDataScheme(url,callback);
}
}
var callback=function(dataScheme){
var elem=document.createElement("img");
elem.src=dataScheme;
document.body.appendChild(elem);
}
window.addEventListener(
"load",
handler(url,callback),
false
);
}
}
)();
// @name getFileByDataScheme
// @namespace http://www.kanasansoft.com/
// @include *
// ==/UserScript==
(
function(){
var parseHTTPHeader=function(responseHeader){
var headers=responseHeader.split("\n");
var len=headers.length;
var parsing=[];
for(var i=0;i<len;i++){
if(/^$/.test(headers[i])){
}else if(/^[\x09\x20]/.test(headers[i])){
if(parsing.length==0){
throw "SyntaxError:HTTPHeader (first line) "+headers[i];
}
parsing[parsing.length-1]+="\n"+headers[i];
}else{
parsing.push(headers[i]);
}
}
var len=parsing.length;
var parsed={};
for(var i=0;i<len;i++){
var pair=parsing[i].split(": ",2);
if(pair.length!=2){
throw "SyntaxError:HTTPHeader (format) "+parsing[i];
}
if(pair[0] in parsed){
throw "SyntaxError:HTTPHeader (repetition) "+pair[0];
}
parsed[pair[0]]=pair[1];
}
return parsed;
}
var loadDataMethod=function(res){
var headers=parseHTTPHeader(res.responseHeaders);
if(res.status!=200){
throw "RequestError"+
":status="+res.status+
":statusText="+res.statusText+
":responseHeaders="+res.responseHeaders;
}
var contentType=("Content-Type" in headers)?
headers["Content-Type"]:
"application/octet−stream";
var dataScheme="data:"+contentType+
";base64,"+btoa(
res.responseText.replace(
/[\u0100-\uffff]/g,
function(c){
return String.fromCharCode(c.charCodeAt(0)&0xff);
}
)
);
data.callback(dataScheme);
}
var getData=function(url){
data.url=url;
GM_xmlhttpRequest(
{
"method":"GET",
"url":data.url,
"onload":loadDataMethod,
"onerror":loadDataMethod,
"overrideMimeType":"text/plain; charset=x-user-defined"
}
);
}
var data={};
var getFileByDataScheme=function(url,callback){
data.callback=callback;
getData(url);
}
if(window.self==window.top){
var url=prompt("image url","");
if(url==null||url==""){
return;
}
var handler=function(url,callback){
return function(){
getFileByDataScheme(url,callback);
}
}
var callback=function(dataScheme){
var elem=document.createElement("img");
elem.src=dataScheme;
document.body.appendChild(elem);
}
window.addEventListener(
"load",
handler(url,callback),
false
);
}
}
)();
実際に動作させるために無駄な処理が入っているけど、データ取得からBase64化までだともの凄く短い。
まとめ
XMLHttpRequestやGM_xmlhttpRequestでは文字列だけではなく、binaryを取得することができる。JavaScriptでBase64化することも可能。GreasemonkeyのGM_xmlhttpRequestではサーバが異なってもデータを取得できる。Greasemonkeyは、文字列を保存することが可能なのでBase64化しさえすれば、容量の問題はあるけど保持し続けることもできる。UserScript内でなくても、画像ファイルであればサーバを超えてBase64で取得することが可能。
感想
知らなかったけど、これは非常に応用範囲が広いと思う。binaryを扱うことができるので、画像であればJPEGやPNGの変換もJavaScriptで可能になるし、複数のファイルを指定してzipで圧縮なんかも可能になる。多分すでにあるんだろうけど今の段階でもJavaScriptだけでいろんなことができる。後はアイディア次第だと感じた。
謝辞
名前をだすことの了承を得ていないのでHNは出していませんが、色々なところで支援を頂いた皆様、ありがとうございました。
2009/04/15 追記
ここで終わるつもりだったのですが続きます。