image/test/unit/test_encoder_png.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /*
michael@0 2 * Test for PNG encoding in libpr0n
michael@0 3 *
michael@0 4 */
michael@0 5
michael@0 6 const Ci = Components.interfaces;
michael@0 7 const Cc = Components.classes;
michael@0 8
michael@0 9 var png1A = {
michael@0 10 // A 3x3 image, rows are red, green, blue.
michael@0 11 // RGB format, transparency defaults.
michael@0 12
michael@0 13 transparency : null,
michael@0 14
michael@0 15 frames : [
michael@0 16 {
michael@0 17 width : 3, height : 3,
michael@0 18
michael@0 19 format : Ci.imgIEncoder.INPUT_FORMAT_RGB, stride : 9,
michael@0 20
michael@0 21 pixels : [
michael@0 22 255,0,0, 255,0,0, 255,0,0,
michael@0 23 0,255,0, 0,255,0, 0,255,0,
michael@0 24 0,0,255, 0,0,255, 0,0,255,
michael@0 25 ]
michael@0 26 }
michael@0 27
michael@0 28 ],
michael@0 29 expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII="
michael@0 30 };
michael@0 31
michael@0 32 var png1B = {
michael@0 33 // A 3x3 image, rows are red, green, blue.
michael@0 34 // RGB format, transparency=none.
michael@0 35
michael@0 36 transparency : "none",
michael@0 37
michael@0 38 frames : [
michael@0 39 {
michael@0 40 width : 3, height : 3,
michael@0 41
michael@0 42 format : Ci.imgIEncoder.INPUT_FORMAT_RGB, stride : 9,
michael@0 43
michael@0 44 pixels : [
michael@0 45 255,0,0, 255,0,0, 255,0,0,
michael@0 46 0,255,0, 0,255,0, 0,255,0,
michael@0 47 0,0,255, 0,0,255, 0,0,255,
michael@0 48 ]
michael@0 49 }
michael@0 50
michael@0 51 ],
michael@0 52 expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII="
michael@0 53 };
michael@0 54
michael@0 55 var png2A = {
michael@0 56 // A 3x3 image, rows are: red, green, blue. Columns are: 0%, 33%, 66% transparent.
michael@0 57
michael@0 58 transparency : null,
michael@0 59
michael@0 60 frames : [
michael@0 61 {
michael@0 62 width : 3, height : 3,
michael@0 63
michael@0 64 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
michael@0 65
michael@0 66 pixels : [
michael@0 67 255,0,0,255, 255,0,0,170, 255,0,0,85,
michael@0 68 0,255,0,255, 0,255,0,170, 0,255,0,85,
michael@0 69 0,0,255,255, 0,0,255,170, 0,0,255,85
michael@0 70 ]
michael@0 71 }
michael@0 72
michael@0 73 ],
michael@0 74 expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAAIElEQVQImSXJMQEAMAwEIUy+yZi8DmVFFBcjycn86GgPJw4O8v9DkkEAAAAASUVORK5CYII="
michael@0 75 };
michael@0 76
michael@0 77 var png2B = {
michael@0 78 // A 3x3 image, rows are: red, green, blue. Columns are: 0%, 33%, 66% transparent,
michael@0 79 // but transparency will be ignored.
michael@0 80
michael@0 81 transparency : "none",
michael@0 82
michael@0 83 frames : [
michael@0 84 {
michael@0 85 width : 3, height : 3,
michael@0 86
michael@0 87 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
michael@0 88
michael@0 89 pixels : [
michael@0 90 255,0,0,255, 255,0,0,170, 255,0,0,85,
michael@0 91 0,255,0,255, 0,255,0,170, 0,255,0,85,
michael@0 92 0,0,255,255, 0,0,255,170, 0,0,255,85
michael@0 93 ]
michael@0 94 }
michael@0 95
michael@0 96 ],
michael@0 97 expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII="
michael@0 98 };
michael@0 99
michael@0 100 // Main test entry point.
michael@0 101 function run_test() {
michael@0 102 dump("Checking png1A...\n")
michael@0 103 run_test_for(png1A);
michael@0 104 dump("Checking png1B...\n")
michael@0 105 run_test_for(png1B);
michael@0 106 dump("Checking png2A...\n")
michael@0 107 run_test_for(png2A);
michael@0 108 dump("Checking png2B...\n")
michael@0 109 run_test_for(png2B);
michael@0 110 };
michael@0 111
michael@0 112
michael@0 113 function run_test_for(input) {
michael@0 114 var encoder, dataURL;
michael@0 115
michael@0 116 encoder = encodeImage(input);
michael@0 117 dataURL = makeDataURL(encoder, "image/png");
michael@0 118 do_check_eq(dataURL, input.expected);
michael@0 119
michael@0 120 encoder = encodeImageAsync(input);
michael@0 121 dataURL = makeDataURLFromAsync(encoder, "image/png", input.expected);
michael@0 122 };
michael@0 123
michael@0 124
michael@0 125 function encodeImage(input) {
michael@0 126 var encoder = Cc["@mozilla.org/image/encoder;2?type=image/png"].createInstance();
michael@0 127 encoder.QueryInterface(Ci.imgIEncoder);
michael@0 128
michael@0 129 var options = "";
michael@0 130 if (input.transparency) {
michael@0 131 options += "transparency=" + input.transparency;
michael@0 132 }
michael@0 133
michael@0 134 var frame = input.frames[0];
michael@0 135 encoder.initFromData(frame.pixels, frame.pixels.length,
michael@0 136 frame.width, frame.height, frame.stride,
michael@0 137 frame.format, options);
michael@0 138 return encoder;
michael@0 139 }
michael@0 140
michael@0 141 function _encodeImageAsyncFactory(frame, options, encoder)
michael@0 142 {
michael@0 143 function finishEncode() {
michael@0 144 encoder.addImageFrame(frame.pixels, frame.pixels.length,
michael@0 145 frame.width, frame.height, frame.stride,
michael@0 146 frame.format, options);
michael@0 147 encoder.endImageEncode();
michael@0 148 }
michael@0 149 return finishEncode;
michael@0 150 }
michael@0 151
michael@0 152 function encodeImageAsync(input)
michael@0 153 {
michael@0 154 var encoder = Cc["@mozilla.org/image/encoder;2?type=image/png"].createInstance();
michael@0 155 encoder.QueryInterface(Ci.imgIEncoder);
michael@0 156
michael@0 157 var options = "";
michael@0 158 if (input.transparency) {
michael@0 159 options += "transparency=" + input.transparency;
michael@0 160 }
michael@0 161
michael@0 162 var frame = input.frames[0];
michael@0 163 encoder.startImageEncode(frame.width, frame.height,
michael@0 164 frame.format, options);
michael@0 165
michael@0 166 do_timeout(50, _encodeImageAsyncFactory(frame, options, encoder));
michael@0 167 return encoder;
michael@0 168 }
michael@0 169
michael@0 170
michael@0 171 function makeDataURL(encoder, mimetype) {
michael@0 172 var rawStream = encoder.QueryInterface(Ci.nsIInputStream);
michael@0 173
michael@0 174 var stream = Cc["@mozilla.org/binaryinputstream;1"].createInstance();
michael@0 175 stream.QueryInterface(Ci.nsIBinaryInputStream);
michael@0 176
michael@0 177 stream.setInputStream(rawStream);
michael@0 178
michael@0 179 var bytes = stream.readByteArray(stream.available()); // returns int[]
michael@0 180
michael@0 181 var base64String = toBase64(bytes);
michael@0 182
michael@0 183 return "data:" + mimetype + ";base64," + base64String;
michael@0 184 }
michael@0 185
michael@0 186 function makeDataURLFromAsync(encoder, mimetype, expected) {
michael@0 187 do_test_pending();
michael@0 188 var rawStream = encoder.QueryInterface(Ci.nsIAsyncInputStream);
michael@0 189
michael@0 190 var currentThread = Cc["@mozilla.org/thread-manager;1"].getService().currentThread;
michael@0 191
michael@0 192 var bytes = [];
michael@0 193
michael@0 194 var binarystream = Cc["@mozilla.org/binaryinputstream;1"].createInstance();
michael@0 195 binarystream.QueryInterface(Ci.nsIBinaryInputStream);
michael@0 196
michael@0 197 var asyncReader =
michael@0 198 {
michael@0 199 onInputStreamReady: function(stream)
michael@0 200 {
michael@0 201 binarystream.setInputStream(stream);
michael@0 202 var available = 0;
michael@0 203 try {
michael@0 204 available = stream.available();
michael@0 205 } catch(e) { }
michael@0 206
michael@0 207 if (available > 0)
michael@0 208 {
michael@0 209 bytes = bytes.concat(binarystream.readByteArray(available));
michael@0 210 stream.asyncWait(this, 0, 0, currentThread);
michael@0 211 } else {
michael@0 212 var base64String = toBase64(bytes);
michael@0 213 var dataURL = "data:" + mimetype + ";base64," + base64String;
michael@0 214 do_check_eq(dataURL, expected);
michael@0 215 do_test_finished();
michael@0 216 }
michael@0 217
michael@0 218 }
michael@0 219 };
michael@0 220 rawStream.asyncWait(asyncReader, 0, 0, currentThread);
michael@0 221 }
michael@0 222
michael@0 223 /* toBase64 copied from extensions/xml-rpc/src/nsXmlRpcClient.js */
michael@0 224
michael@0 225 /* Convert data (an array of integers) to a Base64 string. */
michael@0 226 const toBase64Table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' +
michael@0 227 '0123456789+/';
michael@0 228 const base64Pad = '=';
michael@0 229 function toBase64(data) {
michael@0 230 var result = '';
michael@0 231 var length = data.length;
michael@0 232 var i;
michael@0 233 // Convert every three bytes to 4 ascii characters.
michael@0 234 for (i = 0; i < (length - 2); i += 3) {
michael@0 235 result += toBase64Table[data[i] >> 2];
michael@0 236 result += toBase64Table[((data[i] & 0x03) << 4) + (data[i+1] >> 4)];
michael@0 237 result += toBase64Table[((data[i+1] & 0x0f) << 2) + (data[i+2] >> 6)];
michael@0 238 result += toBase64Table[data[i+2] & 0x3f];
michael@0 239 }
michael@0 240
michael@0 241 // Convert the remaining 1 or 2 bytes, pad out to 4 characters.
michael@0 242 if (length%3) {
michael@0 243 i = length - (length%3);
michael@0 244 result += toBase64Table[data[i] >> 2];
michael@0 245 if ((length%3) == 2) {
michael@0 246 result += toBase64Table[((data[i] & 0x03) << 4) + (data[i+1] >> 4)];
michael@0 247 result += toBase64Table[(data[i+1] & 0x0f) << 2];
michael@0 248 result += base64Pad;
michael@0 249 } else {
michael@0 250 result += toBase64Table[(data[i] & 0x03) << 4];
michael@0 251 result += base64Pad + base64Pad;
michael@0 252 }
michael@0 253 }
michael@0 254
michael@0 255 return result;
michael@0 256 }

mercurial