591 lines
17 KiB
JavaScript
591 lines
17 KiB
JavaScript
/*
|
|
* Test for APNG encoding in ImageLib
|
|
*
|
|
*/
|
|
|
|
const { AppConstants } = ChromeUtils.importESModule(
|
|
"resource://gre/modules/AppConstants.sys.mjs"
|
|
);
|
|
|
|
// 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,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAAA9JREFUCFtj/M8ABYxYWAA5IQMBD9nE1QAAABpmY1RMAAAAAQAAAAMAAAADAAAAAAAAAAAB9APoAADuZcrMAAAAFGZkQVQAAAACCFtjZPjPAAGMWFgANiQDAVBdoI8AAAAaZmNUTAAAAAMAAAADAAAAAwAAAAAAAAAAAfQD6AAAA/MZJQAAABVmZEFUAAAABAhbY2Rg+M8ABoxYWAAzJwMBWk5KPwAAAABJRU5ErkJggg==",
|
|
};
|
|
|
|
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: AppConstants.USE_LIBZ_RS
|
|
? "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABJJREFUCFtj/M/A8J8BChhxcgCM6AX+QVLIVQAAABpmY1RMAAAAAQAAAAMAAAADAAAAAAAAAAAB9APoAADuZcrMAAAAFmZkQVQAAAACCFtjZPjP8J8BChhxcgCJ6wX+aU5KcgAAABpmY1RMAAAAAwAAAAMAAAADAAAAAAAAAAAB9APoAAAD8xklAAAAFmZkQVQAAAAECFtjZGD4/58BChhxcgCG7gX+dDwqYgAAAABJRU5ErkJggg=="
|
|
: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABJJREFUCFtj/M/AAEQQwIiTAwCM6AX+t+X3FQAAABpmY1RMAAAAAQAAAAMAAAADAAAAAAAAAAAB9APoAADuZcrMAAAAFWZkQVQAAAACCFtjZPgPhFDAiJMDAInrBf4Q0nfOAAAAGmZjVEwAAAADAAAAAwAAAAMAAAAAAAAAAAH0A+gAAAPzGSUAAAAWZmRBVAAAAAQIW2NkYPj/nwEKGHFyAIbuBf50PCpiAAAAAElFTkSuQmCC",
|
|
};
|
|
|
|
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: AppConstants.USE_LIBZ_RS
|
|
? "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAACAAAAAPONk3AAAAASSURBVAhbY/zPwPCfAQoYcXIAjOgF/kFSyFUAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABZmZEFUAAAAAQhbY2T4z/CfAQoYcXIAiesF/soYzNsAAAAaZmNUTAAAAAIAAAADAAAAAwAAAAAAAAAAAfQD6AAAmIDz8QAAABZmZEFUAAAAAwhbY2Rg+P+fAQoYcXIAhu4F/j4CoSkAAAAASUVORK5CYII="
|
|
: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAACAAAAAPONk3AAAAASSURBVAhbY/zPwABEEMCIkwMAjOgF/rfl9xUAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABVmZEFUAAAAAQhbY2T4D4RQwIiTAwCJ6wX++lSqrAAAABpmY1RMAAAAAgAAAAMAAAADAAAAAAAAAAAB9APoAACYgPPxAAAAFmZkQVQAAAADCFtjZGD4/58BChhxcgCG7gX+PgKhKQAAAABJRU5ErkJggg==",
|
|
};
|
|
|
|
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: AppConstants.USE_LIBZ_RS
|
|
? "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABJJREFUCFtj/M/A8J8BChhxcgCM6AX+QVLIVQAAABpmY1RMAAAAAQAAAAMAAAADAAAAAAAAAAAB9APoAAGZYvpaAAAAHGZkQVQAAAACCFtjZPjP8J+BgWErAwPDdEacHADI3wnivbhTBAAAABpmY1RMAAAAAwAAAAMAAAADAAAAAAAAAAAB9APoAAF09CmzAAAAHWZkQVQAAAAECFtjZGD4780ABYwMDP+3IHP+wzgAZ+AE/9iH+yoAAAAASUVORK5CYII="
|
|
: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABJJREFUCFtj/M/AAEQQwIiTAwCM6AX+t+X3FQAAABpmY1RMAAAAAQAAAAMAAAADAAAAAAAAAAAB9APoAAGZYvpaAAAAGWZkQVQAAAACCFtjZPgPhAwMW4F4OiNODgDI3wnis0vjTAAAABpmY1RMAAAAAwAAAAMAAAADAAAAAAAAAAAB9APoAAF09CmzAAAAHGZkQVQAAAAECFtjZGD4780ABYxAzhZkzn8YBwBn4AT/ernr+wAAAABJRU5ErkJggg==",
|
|
};
|
|
|
|
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: AppConstants.USE_LIBZ_RS
|
|
? "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AEAbA0RWQAAABJJREFUCFtj/M/A8J8BChhxcgCM6AX+QVLIVQAAABpmY1RMAAAAAQAAAAMAAAADAAAAAAAAAAAB9APoAQGAecsbAAAAHGZkQVQAAAACCFtjZPjP8J+BgWErAwPDdEacHADI3wnivbhTBAAAABpmY1RMAAAAAwAAAAMAAAADAAAAAAAAAAAB9APoAQFt7xjyAAAAHWZkQVQAAAAECFtjZGD4780ABYwMDP+3IHP+wzgAZ+AE/9iH+yoAAAAASUVORK5CYII="
|
|
: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AEAbA0RWQAAABJJREFUCFtj/M/AAEQQwIiTAwCM6AX+t+X3FQAAABpmY1RMAAAAAQAAAAMAAAADAAAAAAAAAAAB9APoAQGAecsbAAAAGWZkQVQAAAACCFtjZPgPhAwMW4F4OiNODgDI3wnis0vjTAAAABpmY1RMAAAAAwAAAAMAAAADAAAAAAAAAAAB9APoAQFt7xjyAAAAHGZkQVQAAAAECFtjZGD4780ABYxAzhZkzn8YBwBn4AT/ernr+wAAAABJRU5ErkJggg==",
|
|
};
|
|
|
|
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: AppConstants.USE_LIBZ_RS
|
|
? "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAAEAAAAAHzNZtAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABNJREFUCFtj/P///38GKGDEyQEAGWoL+Bp453UAAAAaZmNUTAAAAAEAAAABAAAAAQAAAAAAAAAAAfQD6AAAMld9rAAAABFmZEFUAAAAAghbY2BgYPgPAAEEAQDSISApAAAAGmZjVEwAAAADAAAAAQAAAAEAAAABAAAAAQH0A+gAALg4ejEAAAARZmRBVAAAAAQIW2NgYGD4DwABBAEAKuNrnwAAABpmY1RMAAAABQAAAAEAAAABAAAAAgAAAAIB9APoAAD9+HTXAAAAEWZkQVQAAAAGCFtjYGBg+A8AAQQBAMuNrzIAAAAASUVORK5CYII="
|
|
: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAAEAAAAAHzNZtAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABFJREFUCFtj/A8EDFDAiJMDABlqC/jamhxvAAAAGmZjVEwAAAABAAAAAQAAAAEAAAAAAAAAAAH0A+gAADJXfawAAAARZmRBVAAAAAIIW2NgYGD4DwABBAEA0iEgKQAAABpmY1RMAAAAAwAAAAEAAAABAAAAAQAAAAEB9APoAAC4OHoxAAAAEWZkQVQAAAAECFtjYGBg+A8AAQQBACrja58AAAAaZmNUTAAAAAUAAAABAAAAAQAAAAIAAAACAfQD6AAA/fh01wAAABFmZEFUAAAABghbY2BgYPgPAAEEAQDLja8yAAAAAElFTkSuQmCC",
|
|
};
|
|
|
|
// 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");
|
|
Assert.equal(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 =
|
|
// eslint-disable-next-line no-useless-concat
|
|
"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;
|
|
}
|