spice-html5-rails 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +674 -0
- data/COPYING.LESSER +165 -0
- data/LICENSE.txt +15 -0
- data/README.md +35 -0
- data/lib/spice-html5-rails/version.rb +7 -0
- data/lib/spice-html5-rails.rb +10 -0
- data/vendor/assets/javascripts/spice-html5.js +25 -0
- data/vendor/assets/javascripts/spiceHTML5/atKeynames.js +183 -0
- data/vendor/assets/javascripts/spiceHTML5/bitmap.js +51 -0
- data/vendor/assets/javascripts/spiceHTML5/cursor.js +92 -0
- data/vendor/assets/javascripts/spiceHTML5/display.js +806 -0
- data/vendor/assets/javascripts/spiceHTML5/enums.js +282 -0
- data/vendor/assets/javascripts/spiceHTML5/inputs.js +271 -0
- data/vendor/assets/javascripts/spiceHTML5/lz.js +166 -0
- data/vendor/assets/javascripts/spiceHTML5/main.js +177 -0
- data/vendor/assets/javascripts/spiceHTML5/png.js +256 -0
- data/vendor/assets/javascripts/spiceHTML5/quic.js +1335 -0
- data/vendor/assets/javascripts/spiceHTML5/spiceconn.js +455 -0
- data/vendor/assets/javascripts/spiceHTML5/spicedataview.js +96 -0
- data/vendor/assets/javascripts/spiceHTML5/spicemsg.js +883 -0
- data/vendor/assets/javascripts/spiceHTML5/spicetype.js +480 -0
- data/vendor/assets/javascripts/spiceHTML5/thirdparty/jsbn.js +589 -0
- data/vendor/assets/javascripts/spiceHTML5/thirdparty/prng4.js +79 -0
- data/vendor/assets/javascripts/spiceHTML5/thirdparty/rng.js +102 -0
- data/vendor/assets/javascripts/spiceHTML5/thirdparty/rsa.js +146 -0
- data/vendor/assets/javascripts/spiceHTML5/thirdparty/sha1.js +346 -0
- data/vendor/assets/javascripts/spiceHTML5/ticket.js +250 -0
- data/vendor/assets/javascripts/spiceHTML5/utils.js +261 -0
- data/vendor/assets/javascripts/spiceHTML5/wire.js +123 -0
- metadata +108 -0
@@ -0,0 +1,166 @@
|
|
1
|
+
"use strict";
|
2
|
+
/*
|
3
|
+
Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
|
4
|
+
|
5
|
+
This file is part of spice-html5.
|
6
|
+
|
7
|
+
spice-html5 is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the GNU Lesser General Public License as published by
|
9
|
+
the Free Software Foundation, either version 3 of the License, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
spice-html5 is distributed in the hope that it will be useful,
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
GNU Lesser General Public License for more details.
|
16
|
+
|
17
|
+
You should have received a copy of the GNU Lesser General Public License
|
18
|
+
along with spice-html5. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
*/
|
20
|
+
|
21
|
+
|
22
|
+
/*----------------------------------------------------------------------------
|
23
|
+
** lz.js
|
24
|
+
** Functions for handling SPICE_IMAGE_TYPE_LZ_RGB
|
25
|
+
** Adapted from lz.c .
|
26
|
+
**--------------------------------------------------------------------------*/
|
27
|
+
function lz_rgb32_decompress(in_buf, at, out_buf, type, default_alpha)
|
28
|
+
{
|
29
|
+
var encoder = at;
|
30
|
+
var op = 0;
|
31
|
+
var ctrl;
|
32
|
+
var ctr = 0;
|
33
|
+
|
34
|
+
for (ctrl = in_buf[encoder++]; (op * 4) < out_buf.length; ctrl = in_buf[encoder++])
|
35
|
+
{
|
36
|
+
var ref = op;
|
37
|
+
var len = ctrl >> 5;
|
38
|
+
var ofs = (ctrl & 31) << 8;
|
39
|
+
|
40
|
+
//if (type == LZ_IMAGE_TYPE_RGBA)
|
41
|
+
//console.log(ctr++ + ": from " + (encoder + 28) + ", ctrl " + ctrl + ", len " + len + ", ofs " + ofs + ", op " + op);
|
42
|
+
if (ctrl >= 32) {
|
43
|
+
|
44
|
+
var code;
|
45
|
+
len--;
|
46
|
+
|
47
|
+
if (len == 7 - 1) {
|
48
|
+
do {
|
49
|
+
code = in_buf[encoder++];
|
50
|
+
len += code;
|
51
|
+
} while (code == 255);
|
52
|
+
}
|
53
|
+
code = in_buf[encoder++];
|
54
|
+
ofs += code;
|
55
|
+
|
56
|
+
|
57
|
+
if (code == 255) {
|
58
|
+
if ((ofs - code) == (31 << 8)) {
|
59
|
+
ofs = in_buf[encoder++] << 8;
|
60
|
+
ofs += in_buf[encoder++];
|
61
|
+
ofs += 8191;
|
62
|
+
}
|
63
|
+
}
|
64
|
+
len += 1;
|
65
|
+
if (type == LZ_IMAGE_TYPE_RGBA)
|
66
|
+
len += 2;
|
67
|
+
|
68
|
+
ofs += 1;
|
69
|
+
|
70
|
+
ref -= ofs;
|
71
|
+
if (ref == (op - 1)) {
|
72
|
+
var b = ref;
|
73
|
+
//if (type == LZ_IMAGE_TYPE_RGBA) console.log("alpha " + out_buf[(b*4)+3] + " dupped into pixel " + op + " through pixel " + (op + len));
|
74
|
+
for (; len; --len) {
|
75
|
+
if (type == LZ_IMAGE_TYPE_RGBA)
|
76
|
+
{
|
77
|
+
out_buf[(op*4) + 3] = out_buf[(b*4)+3];
|
78
|
+
}
|
79
|
+
else
|
80
|
+
{
|
81
|
+
for (i = 0; i < 4; i++)
|
82
|
+
out_buf[(op*4) + i] = out_buf[(b*4)+i];
|
83
|
+
}
|
84
|
+
op++;
|
85
|
+
}
|
86
|
+
} else {
|
87
|
+
//if (type == LZ_IMAGE_TYPE_RGBA) console.log("alpha copied to pixel " + op + " through " + (op + len) + " from " + ref);
|
88
|
+
for (; len; --len) {
|
89
|
+
if (type == LZ_IMAGE_TYPE_RGBA)
|
90
|
+
{
|
91
|
+
out_buf[(op*4) + 3] = out_buf[(ref*4)+3];
|
92
|
+
}
|
93
|
+
else
|
94
|
+
{
|
95
|
+
for (i = 0; i < 4; i++)
|
96
|
+
out_buf[(op*4) + i] = out_buf[(ref*4)+i];
|
97
|
+
}
|
98
|
+
op++; ref++;
|
99
|
+
}
|
100
|
+
}
|
101
|
+
} else {
|
102
|
+
ctrl++;
|
103
|
+
|
104
|
+
if (type == LZ_IMAGE_TYPE_RGBA)
|
105
|
+
{
|
106
|
+
//console.log("alpha " + in_buf[encoder] + " set into pixel " + op);
|
107
|
+
out_buf[(op*4) + 3] = in_buf[encoder++];
|
108
|
+
}
|
109
|
+
else
|
110
|
+
{
|
111
|
+
out_buf[(op*4) + 0] = in_buf[encoder + 2];
|
112
|
+
out_buf[(op*4) + 1] = in_buf[encoder + 1];
|
113
|
+
out_buf[(op*4) + 2] = in_buf[encoder + 0];
|
114
|
+
if (default_alpha)
|
115
|
+
out_buf[(op*4) + 3] = 255;
|
116
|
+
encoder += 3;
|
117
|
+
}
|
118
|
+
op++;
|
119
|
+
|
120
|
+
|
121
|
+
for (--ctrl; ctrl; ctrl--) {
|
122
|
+
if (type == LZ_IMAGE_TYPE_RGBA)
|
123
|
+
{
|
124
|
+
//console.log("alpha " + in_buf[encoder] + " set into pixel " + op);
|
125
|
+
out_buf[(op*4) + 3] = in_buf[encoder++];
|
126
|
+
}
|
127
|
+
else
|
128
|
+
{
|
129
|
+
out_buf[(op*4) + 0] = in_buf[encoder + 2];
|
130
|
+
out_buf[(op*4) + 1] = in_buf[encoder + 1];
|
131
|
+
out_buf[(op*4) + 2] = in_buf[encoder + 0];
|
132
|
+
if (default_alpha)
|
133
|
+
out_buf[(op*4) + 3] = 255;
|
134
|
+
encoder += 3;
|
135
|
+
}
|
136
|
+
op++;
|
137
|
+
}
|
138
|
+
}
|
139
|
+
|
140
|
+
}
|
141
|
+
return encoder - 1;
|
142
|
+
}
|
143
|
+
|
144
|
+
function convert_spice_lz_to_web(context, lz_image)
|
145
|
+
{
|
146
|
+
var at;
|
147
|
+
if (lz_image.type === LZ_IMAGE_TYPE_RGB32 || lz_image.type === LZ_IMAGE_TYPE_RGBA)
|
148
|
+
{
|
149
|
+
var u8 = new Uint8Array(lz_image.data);
|
150
|
+
var ret = context.createImageData(lz_image.width, lz_image.height);
|
151
|
+
|
152
|
+
at = lz_rgb32_decompress(u8, 0, ret.data, LZ_IMAGE_TYPE_RGB32, lz_image.type != LZ_IMAGE_TYPE_RGBA);
|
153
|
+
if (lz_image.type == LZ_IMAGE_TYPE_RGBA)
|
154
|
+
lz_rgb32_decompress(u8, at, ret.data, LZ_IMAGE_TYPE_RGBA, false);
|
155
|
+
}
|
156
|
+
else if (lz_image.type === LZ_IMAGE_TYPE_XXXA)
|
157
|
+
{
|
158
|
+
var u8 = new Uint8Array(lz_image.data);
|
159
|
+
var ret = context.createImageData(lz_image.width, lz_image.height);
|
160
|
+
lz_rgb32_decompress(u8, 0, ret.data, LZ_IMAGE_TYPE_RGBA, false);
|
161
|
+
}
|
162
|
+
else
|
163
|
+
return undefined;
|
164
|
+
|
165
|
+
return ret;
|
166
|
+
}
|
@@ -0,0 +1,177 @@
|
|
1
|
+
"use strict";
|
2
|
+
/*
|
3
|
+
Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
|
4
|
+
|
5
|
+
This file is part of spice-html5.
|
6
|
+
|
7
|
+
spice-html5 is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the GNU Lesser General Public License as published by
|
9
|
+
the Free Software Foundation, either version 3 of the License, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
spice-html5 is distributed in the hope that it will be useful,
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
GNU Lesser General Public License for more details.
|
16
|
+
|
17
|
+
You should have received a copy of the GNU Lesser General Public License
|
18
|
+
along with spice-html5. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
*/
|
20
|
+
|
21
|
+
/*----------------------------------------------------------------------------
|
22
|
+
** SpiceMainConn
|
23
|
+
** This is the master Javascript class for establishing and
|
24
|
+
** managing a connection to a Spice Server.
|
25
|
+
**
|
26
|
+
** Invocation: You must pass an object with properties as follows:
|
27
|
+
** uri (required) Uri of a WebSocket listener that is
|
28
|
+
** connected to a spice server.
|
29
|
+
** password (required) Password to send to the spice server
|
30
|
+
** message_id (optional) Identifier of an element in the DOM
|
31
|
+
** where SpiceConn will write messages.
|
32
|
+
** It will use classes spice-messages-x,
|
33
|
+
** where x is one of info, warning, or error.
|
34
|
+
** screen_id (optional) Identifier of an element in the DOM
|
35
|
+
** where SpiceConn will create any new
|
36
|
+
** client screens. This is the main UI.
|
37
|
+
** dump_id (optional) If given, an element to use for
|
38
|
+
** dumping every single image + canvas drawn.
|
39
|
+
** Sometimes useful for debugging.
|
40
|
+
** onerror (optional) If given, a function to receive async
|
41
|
+
** errors. Note that you should also catch
|
42
|
+
** errors for ones that occur inline
|
43
|
+
**
|
44
|
+
** Throws error if there are troubles. Requires a modern (by 2012 standards)
|
45
|
+
** browser, including WebSocket and WebSocket.binaryType == arraybuffer
|
46
|
+
**
|
47
|
+
**--------------------------------------------------------------------------*/
|
48
|
+
function SpiceMainConn()
|
49
|
+
{
|
50
|
+
if (typeof WebSocket === "undefined")
|
51
|
+
throw new Error("WebSocket unavailable. You need to use a different browser.");
|
52
|
+
|
53
|
+
SpiceConn.apply(this, arguments);
|
54
|
+
|
55
|
+
}
|
56
|
+
|
57
|
+
SpiceMainConn.prototype = Object.create(SpiceConn.prototype);
|
58
|
+
SpiceMainConn.prototype.process_channel_message = function(msg)
|
59
|
+
{
|
60
|
+
if (msg.type == SPICE_MSG_MAIN_INIT)
|
61
|
+
{
|
62
|
+
this.log_info("Connected to " + this.ws.url);
|
63
|
+
this.report_success("Connected")
|
64
|
+
this.main_init = new SpiceMsgMainInit(msg.data);
|
65
|
+
this.connection_id = this.main_init.session_id;
|
66
|
+
|
67
|
+
if (DEBUG > 0)
|
68
|
+
{
|
69
|
+
// FIXME - there is a lot here we don't handle; mouse modes, agent,
|
70
|
+
// ram_hint, multi_media_time
|
71
|
+
this.log_info("session id " + this.main_init.session_id +
|
72
|
+
" ; display_channels_hint " + this.main_init.display_channels_hint +
|
73
|
+
" ; supported_mouse_modes " + this.main_init.supported_mouse_modes +
|
74
|
+
" ; current_mouse_mode " + this.main_init.current_mouse_mode +
|
75
|
+
" ; agent_connected " + this.main_init.agent_connected +
|
76
|
+
" ; agent_tokens " + this.main_init.agent_tokens +
|
77
|
+
" ; multi_media_time " + this.main_init.multi_media_time +
|
78
|
+
" ; ram_hint " + this.main_init.ram_hint);
|
79
|
+
}
|
80
|
+
|
81
|
+
this.mouse_mode = this.main_init.current_mouse_mode;
|
82
|
+
if (this.main_init.current_mouse_mode != SPICE_MOUSE_MODE_CLIENT &&
|
83
|
+
(this.main_init.supported_mouse_modes & SPICE_MOUSE_MODE_CLIENT))
|
84
|
+
{
|
85
|
+
var mode_request = new SpiceMsgcMainMouseModeRequest(SPICE_MOUSE_MODE_CLIENT);
|
86
|
+
var mr = new SpiceMiniData();
|
87
|
+
mr.build_msg(SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST, mode_request);
|
88
|
+
this.send_msg(mr);
|
89
|
+
}
|
90
|
+
|
91
|
+
var attach = new SpiceMiniData;
|
92
|
+
attach.type = SPICE_MSGC_MAIN_ATTACH_CHANNELS;
|
93
|
+
attach.size = attach.buffer_size();
|
94
|
+
this.send_msg(attach);
|
95
|
+
return true;
|
96
|
+
}
|
97
|
+
|
98
|
+
if (msg.type == SPICE_MSG_MAIN_MOUSE_MODE)
|
99
|
+
{
|
100
|
+
var mode = new SpiceMsgMainMouseMode(msg.data);
|
101
|
+
DEBUG > 0 && this.log_info("Mouse supported modes " + mode.supported_modes + "; current " + mode.current_mode);
|
102
|
+
this.mouse_mode = mode.current_mode;
|
103
|
+
if (this.inputs)
|
104
|
+
this.inputs.mouse_mode = mode.current_mode;
|
105
|
+
return true;
|
106
|
+
}
|
107
|
+
|
108
|
+
if (msg.type == SPICE_MSG_MAIN_CHANNELS_LIST)
|
109
|
+
{
|
110
|
+
var i;
|
111
|
+
var chans;
|
112
|
+
DEBUG > 0 && console.log("channels");
|
113
|
+
chans = new SpiceMsgChannels(msg.data);
|
114
|
+
for (i = 0; i < chans.channels.length; i++)
|
115
|
+
{
|
116
|
+
var conn = {
|
117
|
+
uri: this.ws.url,
|
118
|
+
parent: this,
|
119
|
+
connection_id : this.connection_id,
|
120
|
+
type : chans.channels[i].type,
|
121
|
+
chan_id : chans.channels[i].id
|
122
|
+
};
|
123
|
+
if (chans.channels[i].type == SPICE_CHANNEL_DISPLAY)
|
124
|
+
this.display = new SpiceDisplayConn(conn);
|
125
|
+
else if (chans.channels[i].type == SPICE_CHANNEL_INPUTS)
|
126
|
+
{
|
127
|
+
this.inputs = new SpiceInputsConn(conn);
|
128
|
+
this.inputs.mouse_mode = this.mouse_mode;
|
129
|
+
}
|
130
|
+
else if (chans.channels[i].type == SPICE_CHANNEL_CURSOR)
|
131
|
+
this.cursor = new SpiceCursorConn(conn);
|
132
|
+
else
|
133
|
+
{
|
134
|
+
this.log_err("Channel type " + chans.channels[i].type + " unknown.");
|
135
|
+
if (! ("extra_channels" in this))
|
136
|
+
this.extra_channels = [];
|
137
|
+
this.extra_channels[i] = new SpiceConn(conn);
|
138
|
+
}
|
139
|
+
|
140
|
+
}
|
141
|
+
|
142
|
+
return true;
|
143
|
+
}
|
144
|
+
|
145
|
+
return false;
|
146
|
+
}
|
147
|
+
|
148
|
+
SpiceMainConn.prototype.stop = function(msg)
|
149
|
+
{
|
150
|
+
this.state = "closing";
|
151
|
+
|
152
|
+
if (this.inputs)
|
153
|
+
{
|
154
|
+
this.inputs.cleanup();
|
155
|
+
this.inputs = undefined;
|
156
|
+
}
|
157
|
+
|
158
|
+
if (this.cursor)
|
159
|
+
{
|
160
|
+
this.cursor.cleanup();
|
161
|
+
this.cursor = undefined;
|
162
|
+
}
|
163
|
+
|
164
|
+
if (this.display)
|
165
|
+
{
|
166
|
+
this.display.cleanup();
|
167
|
+
this.display.destroy_surfaces();
|
168
|
+
this.display = undefined;
|
169
|
+
}
|
170
|
+
|
171
|
+
this.cleanup();
|
172
|
+
|
173
|
+
if ("extra_channels" in this)
|
174
|
+
for (var e in this.extra_channels)
|
175
|
+
this.extra_channels[e].cleanup();
|
176
|
+
this.extra_channels = undefined;
|
177
|
+
}
|
@@ -0,0 +1,256 @@
|
|
1
|
+
"use strict";
|
2
|
+
/*
|
3
|
+
Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
|
4
|
+
|
5
|
+
This file is part of spice-html5.
|
6
|
+
|
7
|
+
spice-html5 is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the GNU Lesser General Public License as published by
|
9
|
+
the Free Software Foundation, either version 3 of the License, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
spice-html5 is distributed in the hope that it will be useful,
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
GNU Lesser General Public License for more details.
|
16
|
+
|
17
|
+
You should have received a copy of the GNU Lesser General Public License
|
18
|
+
along with spice-html5. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
*/
|
20
|
+
|
21
|
+
/*----------------------------------------------------------------------------
|
22
|
+
** crc logic from rfc2083 ported to Javascript
|
23
|
+
**--------------------------------------------------------------------------*/
|
24
|
+
|
25
|
+
var rfc2083_crc_table = Array(256);
|
26
|
+
var rfc2083_crc_table_computed = 0;
|
27
|
+
/* Make the table for a fast CRC. */
|
28
|
+
function rfc2083_make_crc_table()
|
29
|
+
{
|
30
|
+
var c;
|
31
|
+
var n, k;
|
32
|
+
for (n = 0; n < 256; n++)
|
33
|
+
{
|
34
|
+
c = n;
|
35
|
+
for (k = 0; k < 8; k++)
|
36
|
+
{
|
37
|
+
if (c & 1)
|
38
|
+
c = ((0xedb88320 ^ (c >>> 1)) >>> 0) & 0xffffffff;
|
39
|
+
else
|
40
|
+
c = c >>> 1;
|
41
|
+
}
|
42
|
+
rfc2083_crc_table[n] = c;
|
43
|
+
}
|
44
|
+
|
45
|
+
rfc2083_crc_table_computed = 1;
|
46
|
+
}
|
47
|
+
|
48
|
+
/* Update a running CRC with the bytes buf[0..len-1]--the CRC
|
49
|
+
should be initialized to all 1's, and the transmitted value
|
50
|
+
is the 1's complement of the final running CRC (see the
|
51
|
+
crc() routine below)). */
|
52
|
+
|
53
|
+
function rfc2083_update_crc(crc, u8buf, at, len)
|
54
|
+
{
|
55
|
+
var c = crc;
|
56
|
+
var n;
|
57
|
+
|
58
|
+
if (!rfc2083_crc_table_computed)
|
59
|
+
rfc2083_make_crc_table();
|
60
|
+
|
61
|
+
for (n = 0; n < len; n++)
|
62
|
+
{
|
63
|
+
c = rfc2083_crc_table[(c ^ u8buf[at + n]) & 0xff] ^ (c >>> 8);
|
64
|
+
}
|
65
|
+
|
66
|
+
return c;
|
67
|
+
}
|
68
|
+
|
69
|
+
function rfc2083_crc(u8buf, at, len)
|
70
|
+
{
|
71
|
+
return rfc2083_update_crc(0xffffffff, u8buf, at, len) ^ 0xffffffff;
|
72
|
+
}
|
73
|
+
|
74
|
+
function crc32(mb, at, len)
|
75
|
+
{
|
76
|
+
var u8 = new Uint8Array(mb);
|
77
|
+
return rfc2083_crc(u8, at, len);
|
78
|
+
}
|
79
|
+
|
80
|
+
function PngIHDR(width, height)
|
81
|
+
{
|
82
|
+
this.width = width;
|
83
|
+
this.height = height;
|
84
|
+
this.depth = 8;
|
85
|
+
this.type = 6;
|
86
|
+
this.compression = 0;
|
87
|
+
this.filter = 0;
|
88
|
+
this.interlace = 0;
|
89
|
+
}
|
90
|
+
|
91
|
+
PngIHDR.prototype =
|
92
|
+
{
|
93
|
+
to_buffer: function(a, at)
|
94
|
+
{
|
95
|
+
at = at || 0;
|
96
|
+
var orig = at;
|
97
|
+
var dv = new SpiceDataView(a);
|
98
|
+
dv.setUint32(at, this.buffer_size() - 12); at += 4;
|
99
|
+
dv.setUint8(at, 'I'.charCodeAt(0)); at++;
|
100
|
+
dv.setUint8(at, 'H'.charCodeAt(0)); at++;
|
101
|
+
dv.setUint8(at, 'D'.charCodeAt(0)); at++;
|
102
|
+
dv.setUint8(at, 'R'.charCodeAt(0)); at++;
|
103
|
+
dv.setUint32(at, this.width); at += 4;
|
104
|
+
dv.setUint32(at, this.height); at += 4;
|
105
|
+
dv.setUint8(at, this.depth); at++;
|
106
|
+
dv.setUint8(at, this.type); at++;
|
107
|
+
dv.setUint8(at, this.compression); at++;
|
108
|
+
dv.setUint8(at, this.filter); at++;
|
109
|
+
dv.setUint8(at, this.interlace); at++;
|
110
|
+
dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4;
|
111
|
+
return at;
|
112
|
+
},
|
113
|
+
buffer_size: function()
|
114
|
+
{
|
115
|
+
return 12 + 13;
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
|
120
|
+
function adler()
|
121
|
+
{
|
122
|
+
this.s1 = 1;
|
123
|
+
this.s2 = 0;
|
124
|
+
}
|
125
|
+
|
126
|
+
adler.prototype.update = function(b)
|
127
|
+
{
|
128
|
+
this.s1 += b;
|
129
|
+
this.s1 %= 65521;
|
130
|
+
this.s2 += this.s1;
|
131
|
+
this.s2 %= 65521;
|
132
|
+
}
|
133
|
+
|
134
|
+
function PngIDAT(width, height, bytes)
|
135
|
+
{
|
136
|
+
if (bytes.byteLength > 65535)
|
137
|
+
{
|
138
|
+
throw new Error("Cannot handle more than 64K");
|
139
|
+
}
|
140
|
+
this.data = bytes;
|
141
|
+
this.width = width;
|
142
|
+
this.height = height;
|
143
|
+
}
|
144
|
+
|
145
|
+
PngIDAT.prototype =
|
146
|
+
{
|
147
|
+
to_buffer: function(a, at)
|
148
|
+
{
|
149
|
+
at = at || 0;
|
150
|
+
var orig = at;
|
151
|
+
var x, y, i, j;
|
152
|
+
var dv = new SpiceDataView(a);
|
153
|
+
var zsum = new adler();
|
154
|
+
dv.setUint32(at, this.buffer_size() - 12); at += 4;
|
155
|
+
dv.setUint8(at, 'I'.charCodeAt(0)); at++;
|
156
|
+
dv.setUint8(at, 'D'.charCodeAt(0)); at++;
|
157
|
+
dv.setUint8(at, 'A'.charCodeAt(0)); at++;
|
158
|
+
dv.setUint8(at, 'T'.charCodeAt(0)); at++;
|
159
|
+
|
160
|
+
/* zlib header. */
|
161
|
+
dv.setUint8(at, 0x78); at++;
|
162
|
+
dv.setUint8(at, 0x01); at++;
|
163
|
+
|
164
|
+
/* Deflate header. Specifies uncompressed, final bit */
|
165
|
+
dv.setUint8(at, 0x80); at++;
|
166
|
+
dv.setUint16(at, this.data.byteLength + this.height); at += 2;
|
167
|
+
dv.setUint16(at, ~(this.data.byteLength + this.height)); at += 2;
|
168
|
+
var u8 = new Uint8Array(this.data);
|
169
|
+
for (i = 0, y = 0; y < this.height; y++)
|
170
|
+
{
|
171
|
+
/* Filter type 0 - uncompressed */
|
172
|
+
dv.setUint8(at, 0); at++;
|
173
|
+
zsum.update(0);
|
174
|
+
for (x = 0; x < this.width && i < this.data.byteLength; x++)
|
175
|
+
{
|
176
|
+
zsum.update(u8[i]);
|
177
|
+
dv.setUint8(at, u8[i++]); at++;
|
178
|
+
zsum.update(u8[i]);
|
179
|
+
dv.setUint8(at, u8[i++]); at++;
|
180
|
+
zsum.update(u8[i]);
|
181
|
+
dv.setUint8(at, u8[i++]); at++;
|
182
|
+
zsum.update(u8[i]);
|
183
|
+
dv.setUint8(at, u8[i++]); at++;
|
184
|
+
}
|
185
|
+
}
|
186
|
+
|
187
|
+
/* zlib checksum. */
|
188
|
+
dv.setUint16(at, zsum.s2); at+=2;
|
189
|
+
dv.setUint16(at, zsum.s1); at+=2;
|
190
|
+
|
191
|
+
/* FIXME - something is not quite right with the zlib code;
|
192
|
+
you get an error from libpng if you open the image in
|
193
|
+
gimp. But it works, so it's good enough for now... */
|
194
|
+
|
195
|
+
dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4;
|
196
|
+
return at;
|
197
|
+
},
|
198
|
+
buffer_size: function()
|
199
|
+
{
|
200
|
+
return 12 + this.data.byteLength + this.height + 4 + 2 + 1 + 2 + 2;
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
204
|
+
|
205
|
+
function PngIEND()
|
206
|
+
{
|
207
|
+
}
|
208
|
+
|
209
|
+
PngIEND.prototype =
|
210
|
+
{
|
211
|
+
to_buffer: function(a, at)
|
212
|
+
{
|
213
|
+
at = at || 0;
|
214
|
+
var orig = at;
|
215
|
+
var i;
|
216
|
+
var dv = new SpiceDataView(a);
|
217
|
+
dv.setUint32(at, this.buffer_size() - 12); at += 4;
|
218
|
+
dv.setUint8(at, 'I'.charCodeAt(0)); at++;
|
219
|
+
dv.setUint8(at, 'E'.charCodeAt(0)); at++;
|
220
|
+
dv.setUint8(at, 'N'.charCodeAt(0)); at++;
|
221
|
+
dv.setUint8(at, 'D'.charCodeAt(0)); at++;
|
222
|
+
dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4;
|
223
|
+
return at;
|
224
|
+
},
|
225
|
+
buffer_size: function()
|
226
|
+
{
|
227
|
+
return 12;
|
228
|
+
}
|
229
|
+
}
|
230
|
+
|
231
|
+
|
232
|
+
function create_rgba_png(width, height, bytes)
|
233
|
+
{
|
234
|
+
var i;
|
235
|
+
var ihdr = new PngIHDR(width, height);
|
236
|
+
var idat = new PngIDAT(width, height, bytes);
|
237
|
+
var iend = new PngIEND;
|
238
|
+
|
239
|
+
var mb = new ArrayBuffer(ihdr.buffer_size() + idat.buffer_size() + iend.buffer_size());
|
240
|
+
var at = ihdr.to_buffer(mb);
|
241
|
+
at = idat.to_buffer(mb, at);
|
242
|
+
at = iend.to_buffer(mb, at);
|
243
|
+
|
244
|
+
var u8 = new Uint8Array(mb);
|
245
|
+
var str = "";
|
246
|
+
for (i = 0; i < at; i++)
|
247
|
+
{
|
248
|
+
str += "%";
|
249
|
+
if (u8[i] < 16)
|
250
|
+
str += "0";
|
251
|
+
str += u8[i].toString(16);
|
252
|
+
}
|
253
|
+
|
254
|
+
|
255
|
+
return "%89PNG%0D%0A%1A%0A" + str;
|
256
|
+
}
|