JavaScript XPM image loading script

スラドの、この記事で:

テーブルアートなるものが紹介されていました:

Gimpを使えばHTML表を吐き出せ、そこで上記ページにあるようにセルなどを設定すれば、HTMLでイメージをかけたりするのですが、ファイルサイズはものすごくでかくなります。
そこでテキスト(Cソース)であるXPM形式にしておき、それをJavaScriptで読み込んで解析し、上記テーブルへ展開するスクリプトを書いてみました。

xpmloader.js

function loadXpm(url) {
  document.write("<div id='" + url + "'></div>");
  loadXpmAt(url, url);
}

function loadXpmAt(url, parentId) {
  var xmlhttp = createXmlHttp();
  xmlhttp.open("GET", url, true);
  xmlhttp.onreadystatechange = function () {
    handleResponse(xmlhttp, parentId);
  };
  xmlhttp.send(null);
}

function createXmlHttp(){
  if (window.ActiveXObject) {
    return new ActiveXObject("Microsoft.XMLHTTP");
  } else if (window.XMLHttpRequest) {
    return new XMLHttpRequest();
  } else {
    return null;
  }
}

function handleResponse(xmlhttp, parentId) {
  if (xmlhttp.readyState == 4) {
    if (xmlhttp.status == 200) {
      writeXpm(parentId, xmlhttp.responseText);
      //dumpError(parentId, xmlhttp.responseText);
    }
  }
}

function writeXpm(parentId, source) {
  var src = source;
  var infoLinePattern = new RegExp('"([^"]+)"');
  var width = 0;
  var height = 0;
  var colorNum = 0;
  var colorSize = 0;
  
  if (src.match(infoLinePattern)) {
    var line = RegExp.lastParen;
    src = RegExp.rightContext;
    var nums = line.split(" ");
    width = parseInt(nums[0]);
    height = parseInt(nums[1]);
    colorNum = parseInt(nums[2]);
    colorSize = parseInt(nums[3]);
  } else {
    dumpError(parentId, "Could not read metadata line");
    return;
  }
  
  var colors = new Array(colorNum);
  var colorNo = 0;
  while (colorNo < colorNum) {
    if (src.match(infoLinePattern)) {
      var line = RegExp.lastParen;
      src = RegExp.rightContext;
      var colorId = line.substring(0, colorSize);
      var color = line.substring(colorSize + 1 + 2);
      colors[colorId] = color;
      colorNo += 1;
    } else {
      dumpError(parentId, "Could not read color line");
      return;
    }
  }
  
  var lineNo = 0;
  var imageRoot = createImageRoot();
  document.getElementById(parentId).appendChild(imageRoot);
  while (lineNo < height) {
    if (src.match(infoLinePattern)) {
      var line = RegExp.lastParen;
      src = RegExp.rightContext;
      var imageLine = addImageLine(imageRoot);
      for (var i = 0;  i < width; i++) {
        var colorId = line.substring(i * colorSize, (i + 1) * colorSize);
        var color = colors[colorId];
        addImageCell(imageLine, color);
      }
      lineNo += 1;
    } else {
      dumpError(parentId, "Could not read data line");
      return;
    }
  }
}

function dumpError(parentId, message) {
  var textNode = document.createTextNode(message);
  document.getElementById(parentId).appendChild(textNode);
}

function createImageRoot() {
  var table = document.createElement("TABLE");
  table.border = "0";
  table.cellPadding = "0";
  table.cellSpacing = "0";
  return table;
}

function addImageLine(imageRoot) {
  var tr = imageRoot.insertRow(imageRoot.rows.length);
  return tr;
}

function addImageCell(imageLine, color) {
  var cell = imageLine.insertCell(imageLine.cells.length);
  cell.bgColor = color;
  
  var table = document.createElement("TABLE");
  table.border = "0";
  table.cellPadding = "0";
  table.cellSpacing = "0";
  var tr = table.insertRow(table.rows.length);
  var td = tr.insertCell(tr.cells.length);
  td.width = "1";
  td.height = "1";
  
  cell.appendChild(table);
  return cell;
}

XmlHttpRequestを使っているので、動かすにはHTMLとXPMファイルはWebサーバ上におく必要があると思います。読み込む側のHTMLは以下のような感じです:

<html>
<body>
<script src="xpmloader.js">
</script>
<script language="JavaScript">
  loadXpm("test.xpm");
</script>
</body>
</html>

こんな感じでいけます。loadXpmはこの位置に埋め込みますが、loadXpmAt(url, parentId)を使えば、任意の要素の下に置けます。
とても重たいです。100x100だと固まったようになります。表示完了時間はIE6よりfirefoxのほうが早く終わると感じました。

おまけxpm

/* XPM */
static char * test2_xpm[] = {
"32 32 227 2",
"  	c #FFFFFF",
". 	c #F5F5F5",
"+ 	c #D1D1D1",
"@ 	c #A5A5A5",
"# 	c #818181",
"$ 	c #696969",
"% 	c #616161",
"& 	c #5E5E5E",
"* 	c #606060",
"= 	c #5F5F5F",
"- 	c #646464",
"; 	c #6C6C6C",
"> 	c #767676",
", 	c #8D8D8D",
"' 	c #AEAEAE",
") 	c #D6D6D6",
"! 	c #F6F6F6",
"~ 	c #EBEBEB",
"{ 	c #A7A7A7",
"] 	c #5B5B5B",
"^ 	c #2C2C2C",
"/ 	c #1C1C1C",
"( 	c #1D1D1D",
"_ 	c #202020",
": 	c #222222",
"< 	c #252525",
"[ 	c #272727",
"} 	c #292929",
"| 	c #2B2B2B",
"1 	c #2E2E2E",
"2 	c #303030",
"3 	c #393939",
"4 	c #565656",
"5 	c #979797",
"6 	c #E5E5E5",
"7 	c #9D9D9D",
"8 	c #171717",
"9 	c #1A1A1A",
"0 	c #2D2D2D",
"a 	c #2F2F2F",
"b 	c #313131",
"c 	c #323232",
"d 	c #3B3B3B",
"e 	c #B7B7B7",
"f 	c #353535",
"g 	c #161616",
"h 	c #191919",
"i 	c #1E1E1E",
"j 	c #242424",
"k 	c #262626",
"l 	c #282828",
"m 	c #333333",
"n 	c #3C3C3C",
"o 	c #989898",
"p 	c #EFEFEF",
"q 	c #5D5D5D",
"r 	c #1B1B1B",
"s 	c #212121",
"t 	c #373737",
"u 	c #383838",
"v 	c #585858",
"w 	c #D7D7D7",
"x 	c #C0C0C0",
"y 	c #2A2A2A",
"z 	c #363636",
"A 	c #3D3D3D",
"B 	c #B0B0B0",
"C 	c #959595",
"D 	c #2B2125",
"E 	c #4D2133",
"F 	c #711D3F",
"G 	c #861C46",
"H 	c #891F4A",
"I 	c #7B2648",
"J 	c #5B2F41",
"K 	c #42383C",
"L 	c #3E3E3E",
"M 	c #3A3A3A",
"N 	c #919191",
"O 	c #727272",
"P 	c #141414",
"Q 	c #151515",
"R 	c #331F27",
"S 	c #6E1A3C",
"T 	c #AF1452",
"U 	c #D40F5E",
"V 	c #E70D64",
"W 	c #E70D65",
"X 	c #D61160",
"Y 	c #B61B59",
"Z 	c #802B4D",
"` 	c #4D3A41",
" .	c #7C7C7C",
"..	c #131313",
"+.	c #251B1F",
"@.	c #6C1739",
"#.	c #CC105B",
"$.	c #EC0C66",
"%.	c #EC0D66",
"&.	c #EC0D67",
"*.	c #D01560",
"=.	c #812D4F",
"-.	c #494044",
";.	c #424242",
">.	c #414141",
",.	c #404040",
"'.	c #757575",
").	c #626262",
"!.	c #111111",
"~.	c #431729",
"{.	c #AE1150",
"].	c #EC0F68",
"^.	c #EC1068",
"/.	c #EC1169",
"(.	c #BA1D5B",
"_.	c #64384A",
":.	c #434343",
"<.	c #7B7B7B",
"[.	c #691336",
"}.	c #DA0F61",
"|.	c #EC136A",
"1.	c #EC146A",
"2.	c #EC126A",
"3.	c #DD1364",
"4.	c #863052",
"5.	c #464646",
"6.	c #454545",
"7.	c #444444",
"8.	c #747474",
"9.	c #A1A1A1",
"0.	c #232323",
"a.	c #0F0F0F",
"b.	c #151213",
"c.	c #9E124A",
"d.	c #EC156B",
"e.	c #ED186D",
"f.	c #ED196E",
"g.	c #ED166C",
"h.	c #ED156B",
"i.	c #EC1269",
"j.	c #EA1068",
"k.	c #A12959",
"l.	c #494949",
"m.	c #484848",
"n.	c #474747",
"o.	c #CFCFCF",
"p.	c #545454",
"q.	c #0C0C0C",
"r.	c #271019",
"s.	c #801741",
"t.	c #E31D6C",
"u.	c #ED1E71",
"v.	c #ED1C70",
"w.	c #ED1B6F",
"x.	c #ED1A6E",
"y.	c #EB1168",
"z.	c #B3235D",
"A.	c #787878",
"B.	c #F4F4F4",
"C.	c #A3A3A3",
"D.	c #401B2A",
"E.	c #A21950",
"F.	c #E41F6E",
"G.	c #EE2173",
"H.	c #EE2072",
"I.	c #EE1F72",
"J.	c #ED1D71",
"K.	c #ED176C",
"L.	c #EB126A",
"M.	c #B5235E",
"N.	c #797979",
"O.	c #EAD9E0",
"P.	c #CF417A",
"Q.	c #ED1B70",
"R.	c #ED196D",
"S.	c #A9275C",
"T.	c #7F7F7F",
"U.	c #F8A9C9",
"V.	c #E81569",
"W.	c #913057",
"X.	c #4A4A4A",
"Y.	c #888888",
"Z.	c #F25896",
"`.	c #DA1A67",
" +	c #743A51",
".+	c #4B4B4B",
"++	c #9C9C9C",
"@+	c #EF2C7A",
"#+	c #EC176B",
"$+	c #BA2560",
"%+	c #54454B",
"&+	c #595959",
"*+	c #B9B9B9",
"=+	c #D71D67",
"-+	c #7B3953",
";+	c #DBDBDB",
">+	c #E31F6D",
",+	c #8E3457",
"'+	c #50474B",
")+	c #666666",
"!+	c #BABABA",
"~+	c #F7F7F7",
"{+	c #ED1F72",
"]+	c #ED3780",
"^+	c #CF779A",
"/+	c #8A787F",
"(+	c #4D4D4D",
"_+	c #FEEDF3",
":+	c #F46AA1",
"<+	c #EE2978",
"[+	c #F25D99",
"}+	c #F9B9D2",
"|+	c #F7EDF1",
"1+	c #A9A9A9",
"2+	c #FCDAE7",
"3+	c #F57DAD",
"4+	c #F14C8E",
"5+	c #EF2B79",
"6+	c #EE2777",
"7+	c #F03781",
"8+	c #F25694",
"9+	c #F8A8C8",
"0+	c #FEF0F5",
"a+	c #FEECF3",
"b+	c #FABBD4",
"c+	c #F79BC0",
"d+	c #F690B9",
"                                                                ",
"                                                                ",
"                                                                ",
"                                                                ",
"            . + @ # $ % & * = - - ; > , ' ) !                   ",
"          ~ { ] ^ / ( _ : < [ } | 1 2 2 3 4 5 6                 ",
"        . 7 2 8 9 / _ : < [ } 0 a 2 b c c b d # 6               ",
"        e f g h / i : j k l | a b c m m m m c n o !             ",
"      p q 8 8 r / s : < [ } 0 2 m f t u u t f m v w             ",
"      x a g 8 / / : : k [ y a m z u u u u u u z A B             ",
"      C h g 8 / / : D E F G H I J K A L L A M u t N             ",
"      O P Q 8 r / R S T U V W X Y Z ` L L L L n 3  .            ",
"      * ..P g h +.@.#.$.%.&.&.%.$.*.=.-.;.>.,.L n '.            ",
"      ).!...Q 8 ~.{.&.].^././.^.].&.(._.:.:.;.>.L O             ",
"      <.!.!...P [.}./.|.1.1.|.2./.^.3.4.5.6.7.:.>.8.            ",
"      9.0.a.!.b.c.d.e.f.f.e.g.h.|.i.j.k.l.m.n.6.:.8.            ",
"      o.p.q.r.s.t.u.u.u.v.w.x.e.g.|.y.z.l.l.l.m.6.A.            ",
"      B.C.D.E.F.G.G.G.H.I.J.v.x.K.h.L.M.l.l.l.l.n.N.            ",
"        O.P.G.G.G.G.G.G.G.I.v.Q.R.g.|.S.l.l.l.l.l.T.            ",
"        U.G.G.G.G.G.G.G.G.G.u.v.x.K.V.W.l.l.l.l.X.Y.            ",
"        Z.G.G.G.G.G.G.G.G.G.H.v.w.K.`. +l.l.l.l..+++            ",
"        @+G.G.G.G.G.G.G.G.G.G.v.w.#+$+%+l.l.l.l.&+*+            ",
"        @+G.G.G.G.G.G.G.G.G.G.v.x.=+-+l.l.l.l.l.T.;+            ",
"        Z.G.G.G.G.G.G.G.G.G.H.Q.>+,+'+l.l.l.l.)+!+~+            ",
"        U.G.G.G.G.G.G.G.G.G.{+]+^+/+= (+(+= # !+p               ",
"        _+:+G.G.G.G.G.G.G.<+[+}+|+;+!+1+1+!+;+~+                ",
"          2+3+4+5+G.6+7+8+9+0+                                  ",
"            a+b+c+d+c+b+a+                                      ",
"                                                                ",
"                                                                ",
"                                                                ",
"                                                                "};