123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471 |
- /*
- * Test for APNG encoding in ImageLib
- *
- */
- var Ci = Components.interfaces;
- var Cc = Components.classes;
- // dispose=[none|background|previous]
- // blend=[source|over]
- var apng1A = {
- // A 3x3 image with 3 frames, alternating red, green, blue. RGB format.
- width : 3, height : 3, skipFirstFrame : false,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGB,
- transparency : null,
- plays : 0,
- frames : [
- { // frame #1
- width : 3, height : 3,
- x_offset : 0, y_offset : 0,
- dispose : "none", blend : "source", delay : 500,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGB, stride : 9,
- transparency : null,
- pixels : [
- 255,0,0, 255,0,0, 255,0,0,
- 255,0,0, 255,0,0, 255,0,0,
- 255,0,0, 255,0,0, 255,0,0
- ]
- },
- { // frame #2
- width : 3, height : 3,
- x_offset : 0, y_offset : 0,
- dispose : "none", blend : "source", delay : 500,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGB, stride : 9,
- transparency : null,
- pixels : [
- 0,255,0, 0,255,0, 0,255,0,
- 0,255,0, 0,255,0, 0,255,0,
- 0,255,0, 0,255,0, 0,255,0
- ]
- },
- { // frame #3
- width : 3, height : 3,
- x_offset : 0, y_offset : 0,
- dispose : "none", blend : "source", delay : 500,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGB, stride : 9,
- transparency : null,
- pixels : [
- 0,0,255, 0,0,255, 0,0,255,
- 0,0,255, 0,0,255, 0,0,255,
- 0,0,255, 0,0,255, 0,0,255
- ]
- }
- ],
- expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABBJREFUCJlj+M/AAEEMWFgAj44I+H2CySsAAAAaZmNUTAAAAAEAAAADAAAAAwAAAAAAAAAAAfQD6AAA7mXKzAAAABNmZEFUAAAAAgiZY2D4zwBFWFgAhpcI+I731VcAAAAaZmNUTAAAAAMAAAADAAAAAwAAAAAAAAAAAfQD6AAAA/MZJQAAABNmZEFUAAAABAiZY2Bg+A9DmCwAfaAI+AGmQVoAAAAASUVORK5CYII="
- };
- var apng1B = {
- // A 3x3 image with 3 frames, alternating red, green, blue. RGBA format.
- width : 3, height : 3, skipFirstFrame : false,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA,
- transparency : null,
- plays : 0,
- frames : [
- { // frame #1
- width : 3, height : 3,
- x_offset : 0, y_offset : 0,
- dispose : "none", blend : "source", delay : 500,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
- pixels : [
- 255,0,0,255, 255,0,0,255, 255,0,0,255,
- 255,0,0,255, 255,0,0,255, 255,0,0,255,
- 255,0,0,255, 255,0,0,255, 255,0,0,255
- ]
- },
- { // frame #2
- width : 3, height : 3,
- x_offset : 0, y_offset : 0,
- dispose : "none", blend : "source", delay : 500,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
- pixels : [
- 0,255,0,255, 0,255,0,255, 0,255,0,255,
- 0,255,0,255, 0,255,0,255, 0,255,0,255,
- 0,255,0,255, 0,255,0,255, 0,255,0,255
- ]
- },
- { // frame #3
- width : 3, height : 3,
- x_offset : 0, y_offset : 0,
- dispose : "none", blend : "source", delay : 500,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
- pixels : [
- 0,0,255,255, 0,0,255,255, 0,0,255,255,
- 0,0,255,255, 0,0,255,255, 0,0,255,255,
- 0,0,255,255, 0,0,255,255, 0,0,255,255
- ]
- }
- ],
- expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABFJREFUCJlj+M/A8B+GGXByAF3XEe/CoiJ1AAAAGmZjVEwAAAABAAAAAwAAAAMAAAAAAAAAAAH0A+gAAO5lyswAAAASZmRBVAAAAAIImWNg+I8EcXIAVOAR77Vyl9QAAAAaZmNUTAAAAAMAAAADAAAAAwAAAAAAAAAAAfQD6AAAA/MZJQAAABRmZEFUAAAABAiZY2Bg+P8fgXFxAEvpEe8rClxSAAAAAElFTkSuQmCC"
- };
- var apng1C = {
- // A 3x3 image with 3 frames, alternating red, green, blue. RGBA format.
- // The first frame is skipped, so it will only flash green/blue (or static red in an APNG-unaware viewer)
- width : 3, height : 3, skipFirstFrame : true,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA,
- transparency : null,
- plays : 0,
- frames : [
- { // frame #1
- width : 3, height : 3,
- x_offset : 0, y_offset : 0,
- dispose : "none", blend : "source", delay : 500,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
- pixels : [
- 255,0,0,255, 255,0,0,255, 255,0,0,255,
- 255,0,0,255, 255,0,0,255, 255,0,0,255,
- 255,0,0,255, 255,0,0,255, 255,0,0,255
- ]
- },
- { // frame #2
- width : 3, height : 3,
- x_offset : 0, y_offset : 0,
- dispose : "none", blend : "source", delay : 500,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
- pixels : [
- 0,255,0,255, 0,255,0,255, 0,255,0,255,
- 0,255,0,255, 0,255,0,255, 0,255,0,255,
- 0,255,0,255, 0,255,0,255, 0,255,0,255
- ]
- },
- { // frame #3
- width : 3, height : 3,
- x_offset : 0, y_offset : 0,
- dispose : "none", blend : "source", delay : 500,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
- pixels : [
- 0,0,255,255, 0,0,255,255, 0,0,255,255,
- 0,0,255,255, 0,0,255,255, 0,0,255,255,
- 0,0,255,255, 0,0,255,255, 0,0,255,255
- ]
- }
- ],
- expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAACAAAAAPONk3AAAAARSURBVAiZY/jPwPAfhhlwcgBd1xHvwqIidQAAABpmY1RMAAAAAAAAAAMAAAADAAAAAAAAAAAB9APoAAB1FiAYAAAAEmZkQVQAAAABCJljYPiPBHFyAFTgEe+kD/2tAAAAGmZjVEwAAAACAAAAAwAAAAMAAAAAAAAAAAH0A+gAAJiA8/EAAAAUZmRBVAAAAAMImWNgYPj/H4FxcQBL6RHvC5ggGQAAAABJRU5ErkJggg=="
- };
- var apng2A = {
- // A 3x3 image with 3 frames, alternating red, green, blue. RGBA format.
- // blend = over mode
- // (The green frame is a horizontal gradient, and the blue frame is a
- // vertical gradient. They stack as they animate.)
- width : 3, height : 3, skipFirstFrame : false,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA,
- transparency : null,
- plays : 0,
- frames : [
- { // frame #1
- width : 3, height : 3,
- x_offset : 0, y_offset : 0,
- dispose : "none", blend : "source", delay : 500,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
- pixels : [
- 255,0,0,255, 255,0,0,255, 255,0,0,255,
- 255,0,0,255, 255,0,0,255, 255,0,0,255,
- 255,0,0,255, 255,0,0,255, 255,0,0,255
- ]
- },
- { // frame #2
- width : 3, height : 3,
- x_offset : 0, y_offset : 0,
- dispose : "none", blend : "over", delay : 500,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
- pixels : [
- 0,255,0,255, 0,255,0,180, 0,255,0,75,
- 0,255,0,255, 0,255,0,180, 0,255,0,75,
- 0,255,0,255, 0,255,0,180, 0,255,0,75
- ]
- },
- { // frame #3
- width : 3, height : 3,
- x_offset : 0, y_offset : 0,
- dispose : "none", blend : "over", delay : 500,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
- pixels : [
- 0,0,255,75, 0,0,255,75, 0,0,255,75,
- 0,0,255,180, 0,0,255,180, 0,0,255,180,
- 0,0,255,255, 0,0,255,255, 0,0,255,255
- ]
- }
- ],
- expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABFJREFUCJlj+M/A8B+GGXByAF3XEe/CoiJ1AAAAGmZjVEwAAAABAAAAAwAAAAMAAAAAAAAAAAH0A+gAAZli+loAAAAcZmRBVAAAAAIImWNg+M/wn+E/wxaG/wzeDDg5ACeGDvKVa3pyAAAAGmZjVEwAAAADAAAAAwAAAAMAAAAAAAAAAAH0A+gAAXT0KbMAAAAcZmRBVAAAAAQImWNgYPjvjcAM/7cgMMP//zAMAPqkDvLn1m3SAAAAAElFTkSuQmCC"
- };
- var apng2B = {
- // A 3x3 image with 3 frames, alternating red, green, blue. RGBA format.
- // blend = over, dispose = background
- // (The green frame is a horizontal gradient, and the blue frame is a
- // vertical gradient. Each frame is displayed individually, blended to
- // whatever the background is.)
- width : 3, height : 3, skipFirstFrame : false,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA,
- transparency : null,
- plays : 0,
- frames : [
- { // frame #1
- width : 3, height : 3,
- x_offset : 0, y_offset : 0,
- dispose : "background", blend : "source", delay : 500,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
- pixels : [
- 255,0,0,255, 255,0,0,255, 255,0,0,255,
- 255,0,0,255, 255,0,0,255, 255,0,0,255,
- 255,0,0,255, 255,0,0,255, 255,0,0,255
- ]
- },
- { // frame #2
- width : 3, height : 3,
- x_offset : 0, y_offset : 0,
- dispose : "background", blend : "over", delay : 500,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
- pixels : [
- 0,255,0,255, 0,255,0,180, 0,255,0,75,
- 0,255,0,255, 0,255,0,180, 0,255,0,75,
- 0,255,0,255, 0,255,0,180, 0,255,0,75
- ]
- },
- { // frame #3
- width : 3, height : 3,
- x_offset : 0, y_offset : 0,
- dispose : "background", blend : "over", delay : 500,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
- pixels : [
- 0,0,255,75, 0,0,255,75, 0,0,255,75,
- 0,0,255,180, 0,0,255,180, 0,0,255,180,
- 0,0,255,255, 0,0,255,255, 0,0,255,255
- ]
- }
- ],
- expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AEAbA0RWQAAABFJREFUCJlj+M/A8B+GGXByAF3XEe/CoiJ1AAAAGmZjVEwAAAABAAAAAwAAAAMAAAAAAAAAAAH0A+gBAYB5yxsAAAAcZmRBVAAAAAIImWNg+M/wn+E/wxaG/wzeDDg5ACeGDvKVa3pyAAAAGmZjVEwAAAADAAAAAwAAAAMAAAAAAAAAAAH0A+gBAW3vGPIAAAAcZmRBVAAAAAQImWNgYPjvjcAM/7cgMMP//zAMAPqkDvLn1m3SAAAAAElFTkSuQmCC"
- };
- var apng3 = {
- // A 3x3 image with 4 frames. First frame is white, then 1x1 frames draw a diagonal line
- width : 3, height : 3, skipFirstFrame : false,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA,
- transparency : null,
- plays : 0,
- frames : [
- { // frame #1
- width : 3, height : 3,
- x_offset : 0, y_offset : 0,
- dispose : "none", blend : "source", delay : 500,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
- pixels : [
- 255,255,255,255, 255,255,255,255, 255,255,255,255,
- 255,255,255,255, 255,255,255,255, 255,255,255,255,
- 255,255,255,255, 255,255,255,255, 255,255,255,255
- ]
- },
- { // frame #2
- width : 1, height : 1,
- x_offset : 0, y_offset : 0,
- dispose : "none", blend : "source", delay : 500,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
- pixels : [
- 0,0,0,255
- ]
- },
- { // frame #3
- width : 1, height : 1,
- x_offset : 1, y_offset : 1,
- dispose : "none", blend : "source", delay : 500,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
- pixels : [
- 0,0,0,255
- ]
- },
- { // frame #4
- width : 1, height : 1,
- x_offset : 2, y_offset : 2,
- dispose : "none", blend : "source", delay : 500,
- format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
- pixels : [
- 0,0,0,255
- ]
- }
- ],
- expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAAEAAAAAHzNZtAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAAA5JREFUCJlj+I8EGHByALuHI91kueRqAAAAGmZjVEwAAAABAAAAAQAAAAEAAAAAAAAAAAH0A+gAADJXfawAAAARZmRBVAAAAAIImWNgYGD4DwABBAEAbr5mpgAAABpmY1RMAAAAAwAAAAEAAAABAAAAAQAAAAEB9APoAAC4OHoxAAAAEWZkQVQAAAAECJljYGBg+A8AAQQBAJZ8LRAAAAAaZmNUTAAAAAUAAAABAAAAAQAAAAIAAAACAfQD6AAA/fh01wAAABFmZEFUAAAABgiZY2BgYPgPAAEEAQB3Eum9AAAAAElFTkSuQmCC"
- };
- // Main test entry point.
- function run_test() {
- dump("Checking apng1A...\n");
- run_test_for(apng1A);
- dump("Checking apng1B...\n");
- run_test_for(apng1B);
- dump("Checking apng1C...\n");
- run_test_for(apng1C);
- dump("Checking apng2A...\n");
- run_test_for(apng2A);
- dump("Checking apng2B...\n");
- run_test_for(apng2B);
- dump("Checking apng3...\n");
- run_test_for(apng3);
- };
- function run_test_for(input) {
- var encoder, dataURL;
- encoder = encodeImage(input);
- dataURL = makeDataURL(encoder, "image/png");
- do_check_eq(dataURL, input.expected);
- };
- function encodeImage(input) {
- var encoder = Cc["@mozilla.org/image/encoder;2?type=image/png"].createInstance();
- encoder.QueryInterface(Ci.imgIEncoder);
- var options = "";
- if (input.transparency) { options += "transparency=" + input.transparency; }
- options += ";frames=" + input.frames.length;
- options += ";skipfirstframe=" + (input.skipFirstFrame ? "yes" : "no");
- options += ";plays=" + input.plays;
- encoder.startImageEncode(input.width, input.height, input.format, options);
- for (var i = 0; i < input.frames.length; i++) {
- var frame = input.frames[i];
- options = "";
- if (frame.transparency) { options += "transparency=" + input.transparency; }
- options += ";delay=" + frame.delay;
- options += ";dispose=" + frame.dispose;
- options += ";blend=" + frame.blend;
- if (frame.x_offset > 0) { options += ";xoffset=" + frame.x_offset; }
- if (frame.y_offset > 0) { options += ";yoffset=" + frame.y_offset; }
- encoder.addImageFrame(frame.pixels, frame.pixels.length,
- frame.width, frame.height, frame.stride, frame.format, options);
- }
- encoder.endImageEncode();
- return encoder;
- }
- function makeDataURL(encoder, mimetype) {
- var rawStream = encoder.QueryInterface(Ci.nsIInputStream);
- var stream = Cc["@mozilla.org/binaryinputstream;1"].createInstance();
- stream.QueryInterface(Ci.nsIBinaryInputStream);
- stream.setInputStream(rawStream);
- var bytes = stream.readByteArray(stream.available()); // returns int[]
- var base64String = toBase64(bytes);
- return "data:" + mimetype + ";base64," + base64String;
- }
- /* toBase64 copied from extensions/xml-rpc/src/nsXmlRpcClient.js */
- /* Convert data (an array of integers) to a Base64 string. */
- const toBase64Table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' +
- '0123456789+/';
- const base64Pad = '=';
- function toBase64(data) {
- var result = '';
- var length = data.length;
- var i;
- // Convert every three bytes to 4 ascii characters.
- for (i = 0; i < (length - 2); i += 3) {
- result += toBase64Table[data[i] >> 2];
- result += toBase64Table[((data[i] & 0x03) << 4) + (data[i+1] >> 4)];
- result += toBase64Table[((data[i+1] & 0x0f) << 2) + (data[i+2] >> 6)];
- result += toBase64Table[data[i+2] & 0x3f];
- }
- // Convert the remaining 1 or 2 bytes, pad out to 4 characters.
- if (length%3) {
- i = length - (length%3);
- result += toBase64Table[data[i] >> 2];
- if ((length%3) == 2) {
- result += toBase64Table[((data[i] & 0x03) << 4) + (data[i+1] >> 4)];
- result += toBase64Table[(data[i+1] & 0x0f) << 2];
- result += base64Pad;
- } else {
- result += toBase64Table[(data[i] & 0x03) << 4];
- result += base64Pad + base64Pad;
- }
- }
- return result;
- }
|