Suche…
Bemerkungen
In diesem Thema werden die verschiedenen Medientypen und deren Verwendung mit der Leinwand in der 2D-Oberfläche behandelt.
Medientypen haben generische und formatspezifische Kategorien
Medientypen
- Animationen
- Videos
- Bilder
- HD-Bilder
- Vektorbild
- Animierte Bilder
Medienformate
- Jpg / Jpeg
- Png
- Gif
- SVG
- M-JPEG
- Webm
- Webp
Bilder
Es gibt eine Vielzahl von Bildformaten, die von Browsern unterstützt werden, aber kein Browser unterstützt sie alle. Wenn Sie über bestimmte Bildformate verfügen, die Wiki-Browser verwenden möchten, bieten unterstützte Bildformate einen guten Überblick.
Die beste Unterstützung gilt für die 3 Hauptformate "jpeg", "png" und "gif", wobei alle gängigen Browser Unterstützung bieten.
JPEG
JPEG-Bilder eignen sich am besten für Fotos und Fotos wie Bilder. Sie eignen sich nicht gut für Diagramme, Diagramme und Texte. JPEG-Bilder unterstützen keine Transparenz.
Canvas kann JPEG-Bilder über canvas.toDataURL
und canvas.toBlob
und bietet eine Qualitätseinstellung. Da JPEG keine Transparenz unterstützt, werden transparente Pixel für das endgültige Ausgabe-JPG mit Schwarz gemischt. Das resultierende Bild ist keine perfekte Kopie der Leinwand.
PNG
PNG-Bilder sind Bilder von höchster Qualität und können auch einen Alphakanal für transparente Pixel enthalten. Die Bilddaten sind komprimiert, erzeugen jedoch keine Artefakte wie JPG-Bilder.
Aufgrund der verlustfreien Komprimierung und der Unterstützung des Alphakanals werden PNGs für Spiele, Komponentenbilder, Diagramme, Diagramme und Text verwendet. Wenn Sie sie für Fotos und Fotos wie Bilder verwenden, kann ihre Dateigröße viel größer als bei JPEG sein. .
Das PNG-Format bietet auch Animationsunterstützung, obwohl die Browserunterstützung begrenzt ist und der Zugriff auf die Animation zur Verwendung auf der Zeichenfläche nur über Javascript-APIs und -Bibliotheken möglich ist
Die Leinwand kann zum Kodieren von PNG-Bildern über canvas.toDataURL
und canvas.toBlob
das Ausgabeformat ist jedoch auf komprimiertes canvas.toDataURL
canvas.toBlob
RGBA-Format beschränkt. Das PNG liefert eine pixelgenaue Kopie der Leinwand.
GIF
GIFs werden für kurze Animationen verwendet, können aber auch verwendet werden, um Diagramme, Diagramme und Bilder in hoher Qualität bereitzustellen. GIFs verfügen über eine sehr begrenzte Farbunterstützung mit maximal 256 Farben pro Bild. Mit der Bildverarbeitung von Cleatern können GIF-Bilder besonders in der Animation überraschend gute Ergebnisse erzielen. Gifs bieten auch Transparenz, obwohl dies auf Ein oder Aus beschränkt ist
Wie bei PNG sind GIF-Animationen nicht direkt für die Verwendung auf der Leinwand zugänglich. Sie benötigen eine Javascript-API oder -Bibliothek, um Zugriff zu erhalten. GIF kann nicht über die Leinwand gespeichert werden und erfordert dazu eine API oder Bibliothek.
Ein Bild laden und anzeigen
So laden Sie ein Bild und platzieren es auf der Leinwand
var image = new Image(); // see note on creating an image
image.src = "imageURL";
image.onload = function(){
ctx.drawImage(this,0,0);
}
Bild erstellen
Es gibt verschiedene Möglichkeiten, ein Bild zu erstellen
-
new Image()
-
document.createElement("img")
-
<img src = 'imageUrl' id='myImage'>
Als Teil des HTMLdocument.getElementById('myImage')
und mitdocument.getElementById('myImage')
abgerufen.
Das Bild ist ein HTMLImageElement
Image.src-Eigenschaft
Die Image- src
kann eine beliebige gültige Image-URL oder eine codierte dataURL sein. Weitere Informationen zu Bildformaten und zur Unterstützung finden Sie in den Anmerkungen zu diesem Thema.
-
image.src = "http://my.domain.com/images/myImage.jpg"
-
image.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="
*
* Die dataURL ist ein 1 x 1 Pixel Gif-Bild, das Schwarz enthält
Hinweise zum Laden und Fehler
Das Bild wird geladen, wenn die src -Eigenschaft festgelegt ist. Das Laden ist synchron, aber das onload
Ereignis wird nicht aufgerufen, bis die Funktion oder der Code beendet / zurückgegeben wurde.
Wenn Sie ein Bild von der Seite erhalten (z. B. document.getElementById("myImage")
) und dessen src
ist, wurde es möglicherweise nicht geladen. Sie können den Status des Bildes mit HTMLImageElement.complete
überprüfen. HTMLImageElement.complete
der HTMLImageElement.complete
der HTMLImageElement.complete
true
. Dies bedeutet nicht, dass das Bild geladen wurde, sondern auch, dass das Bild geladen wurde
- geladen
- Es gab einen Fehler
- Die src-Eigenschaft wurde nicht festgelegt und entspricht der leeren Zeichenfolge
""
Wenn das Bild aus einer unzuverlässigen Quelle stammt und möglicherweise aus verschiedenen Gründen nicht verfügbar ist, wird ein Fehlerereignis generiert. In diesem Fall befindet sich das Bild in einem fehlerhaften Zustand. Wenn Sie dann versuchen, es auf die Leinwand zu zeichnen, wird der folgende Fehler ausgegeben
Uncaught DOMException: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state.
Mit dem image.onerror = myImgErrorHandler
können Sie geeignete Maßnahmen ergreifen, um Fehler zu vermeiden.
Zeichnen eines SVG-Bildes
Um ein Vektor-SVG-Bild zu zeichnen, unterscheidet sich die Operation nicht von einem Rasterbild:
Sie müssen zuerst Ihr SVG-Bild in ein HTMLImage-Element laden und dann die drawImage()
-Methode verwenden.
var image = new Image();
image.onload = function(){
ctx.drawImage(this, 0,0);
}
image.src = "someFile.SVG";
SVG-Bilder haben gegenüber Rastern einige Vorteile, da Sie nicht an Qualität verlieren, unabhängig von der Skalierung, die Sie auf Ihre Leinwand zeichnen. Aber Vorsicht, es kann auch etwas langsamer sein, als ein Rasterbild zu zeichnen.
Für SVG-Bilder gelten jedoch mehr Einschränkungen als für Rasterbilder.
Aus Sicherheitsgründen kann kein externer Inhalt aus einem SVG-Bild geladen werden, auf das in einem HTMLImageElement verwiesen wird (
<img>
).
Kein externes Stylesheet, kein externes Bild, auf das in SVGImage (<image/>
) - Elementen verwiesen wird, kein externer Filter oder Element, das mit dem Attributxlink:href
(<use xlink:href="anImage.SVG#anElement"/>
) oder dem funcIRI verknüpft ist (url()
) Attributmethode usw.
Außerdem haben im Hauptdokument angefügte Stylesheets keine Auswirkungen auf das SVG-Dokument, wenn es in einem HTMLImage-Element referenziert wird.
Schließlich wird im SVG-Image kein Skript ausgeführt.
Umgehung: Sie müssen alle externen Elemente in der SVG-Datei selbst anhängen, bevor Sie auf das HTMLImage-Element verweisen. (Für Bilder oder Schriftarten müssen Sie eine dataURI-Version Ihrer externen Ressourcen hinzufügen).Für das Wurzelelement (
<svg>
) müssen die Attribute width und height auf einen absoluten Wert gesetzt sein.
Wenn Sie die relative Länge (z. B.%
) verwenden, kann der Browser nicht wissen, um welche relative Länge es sich handelt. Einige Browser (Blink) versuchen, eine Vermutung zu treffen, aber die meisten ignorieren einfach Ihr Bild und zeichnen ohne Vorwarnung nichts.Einige Browser färben die Leinwand, wenn ein SVG-Bild darauf gezeichnet wurde.
Insbesondere Internet-Explorer <Edge auf jeden Fall und Safari 9, wenn ein<foreignObject>
im SVG-Image vorhanden ist.
Grundlegendes Laden und Abspielen eines Videos auf der Leinwand.
Die Leinwand kann verwendet werden, um Videos aus verschiedenen Quellen anzuzeigen. In diesem Beispiel wird gezeigt, wie Sie ein Video als Dateiressource laden, anzeigen und einen einfachen Klick auf den Wiedergabe / Pause-Schalter auf dem Bildschirm hinzufügen.
Diese selbst beantwortete Frage zu stackoverflow Wie zeige ich ein Video mithilfe des HTML5- Zeichenbereichs an, so wird der folgende Beispielcode in Aktion gezeigt.
Nur ein Bild
Ein Video ist nur ein Bild, was die Leinwand angeht. Sie können es wie jedes Bild zeichnen. Der Unterschied besteht darin, dass das Video abgespielt werden kann und Ton hat.
Holen Sie sich Leinwand und Grundeinstellungen
// It is assumed you know how to add a canvas and correctly size it.
var canvas = document.getElementById("myCanvas"); // get the canvas from the page
var ctx = canvas.getContext("2d");
var videoContainer; // object to hold video and associated info
Video erstellen und laden
var video = document.createElement("video"); // create a video element
video.src = "urlOffVideo.webm";
// the video will now begin to load.
// As some additional info is needed we will place the video in a
// containing object for convenience
video.autoPlay = false; // ensure that the video does not auto play
video.loop = true; // set the video to loop.
videoContainer = { // we will add properties as needed
video : video,
ready : false,
};
Im Gegensatz zu Bildelementen müssen Videos nicht vollständig geladen werden, um auf der Leinwand angezeigt zu werden. Videos bieten auch eine Vielzahl zusätzlicher Ereignisse, mit denen der Status des Videos überwacht werden kann.
In diesem Fall möchten wir wissen, wann das Video abspielbereit ist. oncanplay
bedeutet, dass genug Video geladen wurde, um etwas davon abzuspielen, aber es reicht nicht aus, um bis zum Ende abzuspielen.
video.oncanplay = readyToPlayVideo; // set the event to the play function that
// can be found below
Alternativ können Sie oncanplaythrough
das oncanplaythrough
wird, wenn genug Video geladen ist, damit es bis zum Ende abgespielt werden kann.
video.oncanplaythrough = readyToPlayVideo; // set the event to the play function that
// can be found below
Verwenden Sie nur eines der canPlay-Ereignisse und nicht beide.
Das kann Ereignis abspielen (entspricht Image Onload)
function readyToPlayVideo(event){ // this is a referance to the video
// the video may not match the canvas size so find a scale to fit
videoContainer.scale = Math.min(
canvas.width / this.videoWidth,
canvas.height / this.videoHeight);
videoContainer.ready = true;
// the video can be played so hand it off to the display function
requestAnimationFrame(undateCanvas);
}
Anzeige
Das Video wird nicht selbst auf der Leinwand abgespielt. Sie müssen es für jeden neuen Rahmen zeichnen. Da es schwierig ist, die genaue Bildrate zu kennen, und wenn sie auftreten, ist es am besten, das Video so anzuzeigen, als würde es mit 60 Bildern pro Sekunde laufen. Wenn die Bildrate niedriger ist, rendern wir dasselbe Bild nur zweimal. Wenn die Framerate höher ist, können die zusätzlichen Frames nicht angezeigt werden, so dass wir sie einfach ignorieren.
Das Videoelement ist nur ein Bildelement und kann wie jedes Bild gezeichnet werden. Sie können das Video skalieren, drehen, schwenken, spiegeln, einblenden, ausschneiden, nur Teile anzeigen und zweimal im zweiten zusammengesetzten Modus mit einem globalen Mischmodus zeichnen Effekte wie Aufhellen, Bildschirm usw. hinzufügen.
function updateCanvas(){
ctx.clearRect(0,0,canvas.width,canvas.height); // Though not always needed
// you may get bad pixels from
// previous videos so clear to be
// safe
// only draw if loaded and ready
if(videoContainer !== undefined && videoContainer.ready){
// find the top left of the video on the canvas
var scale = videoContainer.scale;
var vidH = videoContainer.video.videoHeight;
var vidW = videoContainer.video.videoWidth;
var top = canvas.height / 2 - (vidH /2 ) * scale;
var left = canvas.width / 2 - (vidW /2 ) * scale;
// now just draw the video the correct size
ctx.drawImage(videoContainer.video, left, top, vidW * scale, vidH * scale);
if(videoContainer.video.paused){ // if not playing show the paused screen
drawPayIcon();
}
}
// all done for display
// request the next frame in 1/60th of a second
requestAnimationFrame(updateCanvas);
}
Grundlegende Steuerung der Wiedergabepause
Jetzt haben wir das Video geladen und angezeigt. Alles, was wir brauchen, ist die Wiedergabesteuerung. Wir werden es als Klick-Umschaltfunktion auf dem Bildschirm machen. Wenn das Video abgespielt wird und der Benutzer klickt, wird das Video angehalten. Bei Pause wird der Klick fortgesetzt. Wir werden eine Funktion hinzufügen, um das Video abzudunkeln und ein Wiedergabesymbol (Dreieck) zu zeichnen.
function drawPayIcon(){
ctx.fillStyle = "black"; // darken display
ctx.globalAlpha = 0.5;
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = "#DDD"; // colour of play icon
ctx.globalAlpha = 0.75; // partly transparent
ctx.beginPath(); // create the path for the icon
var size = (canvas.height / 2) * 0.5; // the size of the icon
ctx.moveTo(canvas.width/2 + size/2, canvas.height / 2); // start at the pointy end
ctx.lineTo(canvas.width/2 - size/2, canvas.height / 2 + size);
ctx.lineTo(canvas.width/2 - size/2, canvas.height / 2 - size);
ctx.closePath();
ctx.fill();
ctx.globalAlpha = 1; // restore alpha
}
Nun das Play-Pause-Event
function playPauseClick(){
if(videoContainer !== undefined && videoContainer.ready){
if(videoContainer.video.paused){
videoContainer.video.play();
}else{
videoContainer.video.pause();
}
}
}
// register the event
canvas.addEventListener("click",playPauseClick);
Zusammenfassung
Die Wiedergabe eines Videos ist sehr einfach über die Leinwand, das Hinzufügen von Effekten in Echtzeit ist ebenfalls einfach. Es gibt jedoch einige Einschränkungen bei den Formaten, wie Sie spielen und suchen können. MDN HTMLMediaElement ist der Ort, an dem die vollständige Referenz auf das Videoobjekt abgerufen wird.
Nachdem das Bild auf der Leinwand gezeichnet wurde, können Sie mit ctx.getImageData
auf die darin enthaltenen Pixel zugreifen. Oder Sie können canvas.toDataURL
um ein canvas.toDataURL
zu schnappen und herunterzuladen. (Nur wenn das Video aus einer vertrauenswürdigen Quelle stammt und die Leinwand nicht verfälscht).
Beachten Sie, wenn das Video bei der Wiedergabe einen Ton hat, wird auch der Ton wiedergegeben.
Viel Spaß beim Video.
Erfassen Sie die Leinwand und speichern Sie sie als webM-Video
Erstellen eines WebM-Videos aus Leinwandrahmen und Wiedergabe als Leinwand oder Hochladen oder Herunterladen.
Beispiel Capture und Play Canvas
name = "CanvasCapture"; // Placed into the Mux and Write Application Name fields of the WebM header
quality = 0.7; // good quality 1 Best < 0.7 ok to poor
fps = 30; // I have tried all sorts of frame rates and all seem to work
// Do some test to workout what your machine can handle as there
// is a lot of variation between machines.
var video = new Groover.Video(fps,quality,name)
function capture(){
if(video.timecode < 5000){ // 5 seconds
setTimeout(capture,video.frameDelay);
}else{
var videoElement = document.createElement("video");
videoElement.src = URL.createObjectURL(video.toBlob());
document.body.appendChild(videoElement);
video = undefined; // DeReference as it is memory hungry.
return;
}
// first frame sets the video size
video.addFrame(canvas); // Add current canvas frame
}
capture(); // start capture
Anstatt große Anstrengungen zu unternehmen, nur um abgelehnt zu werden, ist dies eine schnelle Einfügung, um zu sehen, ob dies akzeptabel ist. Wird alle Details angeben, wenn akzeptiert. Zusätzliche Aufnahmeoptionen für bessere HD-Aufnahmeraten (von dieser Version entfernt, kann HD 1080 mit 50 Bildern pro Sekunde auf guten Computern aufnehmen.)
Dies wurde von Wammy inspiriert, ist jedoch eine vollständige Umschreibung mit der Kodierungsmethode, die den während der Aufnahme erforderlichen Speicherplatz erheblich reduziert. Kann mehr als 30 Sekunden bessere Daten erfassen und Algorithmen verarbeiten.
Hinweis Rahmen werden in webp Bilder codiert. Nur Chrome unterstützt die WebP-Zeichenkodierung. Für andere Browser (Firefox und Edge) müssen Sie einen Drittanbieter-WebP-Encoder wie Libwebp-Javascript verwenden. Das Codieren von WebP-Bildern über Javascript ist langsam. (wird die Unterstützung für unformatierte Webp-Bilder einschließen, wenn dies akzeptiert wird).
Der von Whammy inspirierte webM-Encoder : Ein Echtzeit-Javascript-WebM
var Groover = (function(){
// ensure webp is supported
function canEncode(){
var canvas = document.createElement("canvas");
canvas.width = 8;
canvas.height = 8;
return canvas.toDataURL("image/webp",0.1).indexOf("image/webp") > -1;
}
if(!canEncode()){
return undefined;
}
var webmData = null;
var clusterTimecode = 0;
var clusterCounter = 0;
var CLUSTER_MAX_DURATION = 30000;
var frameNumber = 0;
var width;
var height;
var frameDelay;
var quality;
var name;
const videoMimeType = "video/webm"; // the only one.
const frameMimeType = 'image/webp'; // can be no other
const S = String.fromCharCode;
const dataTypes = {
object : function(data){ return toBlob(data);},
number : function(data){ return stream.num(data);},
string : function(data){ return stream.str(data);},
array : function(data){ return data;},
double2Str : function(num){
var c = new Uint8Array((new Float64Array([num])).buffer);
return S(c[7]) + S(c[6]) + S(c[5]) + S(c[4]) + S(c[3]) + S(c[2]) + S(c[1]) + S(c[0]);
}
};
const stream = {
num : function(num){ // writes int
var parts = [];
while(num > 0){ parts.push(num & 0xff); num = num >> 8; }
return new Uint8Array(parts.reverse());
},
str : function(str){ // writes string
var i, len, arr;
len = str.length;
arr = new Uint8Array(len);
for(i = 0; i < len; i++){arr[i] = str.charCodeAt(i);}
return arr;
},
compInt : function(num){ // could not find full details so bit of a guess
if(num < 128){ // number is prefixed with a bit (1000 is on byte 0100 two, 0010 three and so on)
num += 0x80;
return new Uint8Array([num]);
}else
if(num < 0x4000){
num += 0x4000;
return new Uint8Array([num>>8, num])
}else
if(num < 0x200000){
num += 0x200000;
return new Uint8Array([num>>16, num>>8, num])
}else
if(num < 0x10000000){
num += 0x10000000;
return new Uint8Array([num>>24, num>>16, num>>8, num])
}
}
}
const ids = { // header names and values
videoData : 0x1a45dfa3,
Version : 0x4286,
ReadVersion : 0x42f7,
MaxIDLength : 0x42f2,
MaxSizeLength : 0x42f3,
DocType : 0x4282,
DocTypeVersion : 0x4287,
DocTypeReadVersion : 0x4285,
Segment : 0x18538067,
Info : 0x1549a966,
TimecodeScale : 0x2ad7b1,
MuxingApp : 0x4d80,
WritingApp : 0x5741,
Duration : 0x4489,
Tracks : 0x1654ae6b,
TrackEntry : 0xae,
TrackNumber : 0xd7,
TrackUID : 0x63c5,
FlagLacing : 0x9c,
Language : 0x22b59c,
CodecID : 0x86,
CodecName : 0x258688,
TrackType : 0x83,
Video : 0xe0,
PixelWidth : 0xb0,
PixelHeight : 0xba,
Cluster : 0x1f43b675,
Timecode : 0xe7,
Frame : 0xa3,
Keyframe : 0x9d012a,
FrameBlock : 0x81,
};
const keyframeD64Header = '\x9d\x01\x2a'; //VP8 keyframe header 0x9d012a
const videoDataPos = 1; // data pos of frame data header
const defaultDelay = dataTypes.double2Str(1000/25);
const header = [ // structure of webM header/chunks what ever they are called.
ids.videoData,[
ids.Version, 1,
ids.ReadVersion, 1,
ids.MaxIDLength, 4,
ids.MaxSizeLength, 8,
ids.DocType, 'webm',
ids.DocTypeVersion, 2,
ids.DocTypeReadVersion, 2
],
ids.Segment, [
ids.Info, [
ids.TimecodeScale, 1000000,
ids.MuxingApp, 'Groover',
ids.WritingApp, 'Groover',
ids.Duration, 0
],
ids.Tracks,[
ids.TrackEntry,[
ids.TrackNumber, 1,
ids.TrackUID, 1,
ids.FlagLacing, 0, // always o
ids.Language, 'und', // undefined I think this means
ids.CodecID, 'V_VP8', // These I think must not change
ids.CodecName, 'VP8', // These I think must not change
ids.TrackType, 1,
ids.Video, [
ids.PixelWidth, 0,
ids.PixelHeight, 0
]
]
]
]
];
function getHeader(){
header[3][2][3] = name;
header[3][2][5] = name;
header[3][2][7] = dataTypes.double2Str(frameDelay);
header[3][3][1][15][1] = width;
header[3][3][1][15][3] = height;
function create(dat){
var i,kv,data;
data = [];
for(i = 0; i < dat.length; i += 2){
kv = {i : dat[i]};
if(Array.isArray(dat[i + 1])){
kv.d = create(dat[i + 1]);
}else{
kv.d = dat[i + 1];
}
data.push(kv);
}
return data;
}
return create(header);
}
function addCluster(){
webmData[videoDataPos].d.push({ i: ids.Cluster,d: [{ i: ids.Timecode, d: Math.round(clusterTimecode)}]}); // Fixed bug with Round
clusterCounter = 0;
}
function addFrame(frame){
var VP8, kfS,riff;
riff = getWebPChunks(atob(frame.toDataURL(frameMimeType, quality).slice(23)));
VP8 = riff.RIFF[0].WEBP[0];
kfS = VP8.indexOf(keyframeD64Header) + 3;
frame = {
width: ((VP8.charCodeAt(kfS + 1) << 8) | VP8.charCodeAt(kfS)) & 0x3FFF,
height: ((VP8.charCodeAt(kfS + 3) << 8) | VP8.charCodeAt(kfS + 2)) & 0x3FFF,
data: VP8,
riff: riff
};
if(clusterCounter > CLUSTER_MAX_DURATION){
addCluster();
}
webmData[videoDataPos].d[webmData[videoDataPos].d.length-1].d.push({
i: ids.Frame,
d: S(ids.FrameBlock) + S( Math.round(clusterCounter) >> 8) + S( Math.round(clusterCounter) & 0xff) + S(128) + frame.data.slice(4),
});
clusterCounter += frameDelay;
clusterTimecode += frameDelay;
webmData[videoDataPos].d[0].d[3].d = dataTypes.double2Str(clusterTimecode);
}
function startEncoding(){
frameNumber = clusterCounter = clusterTimecode = 0;
webmData = getHeader();
addCluster();
}
function toBlob(vidData){
var data,i,vData, len;
vData = [];
for(i = 0; i < vidData.length; i++){
data = dataTypes[typeof vidData[i].d](vidData[i].d);
len = data.size || data.byteLength || data.length;
vData.push(stream.num(vidData[i].i));
vData.push(stream.compInt(len));
vData.push(data)
}
return new Blob(vData, {type: videoMimeType});
}
function getWebPChunks(str){
var offset, chunks, id, len, data;
offset = 0;
chunks = {};
while (offset < str.length) {
id = str.substr(offset, 4);
// value will have top bit on (bit 32) so not simply a bitwise operation
// Warning little endian (Will not work on big endian systems)
len = new Uint32Array(
new Uint8Array([
str.charCodeAt(offset + 7),
str.charCodeAt(offset + 6),
str.charCodeAt(offset + 5),
str.charCodeAt(offset + 4)
]).buffer)[0];
id = str.substr(offset, 4);
chunks[id] = chunks[id] === undefined ? [] : chunks[id];
if (id === 'RIFF' || id === 'LIST') {
chunks[id].push(getWebPChunks(str.substr(offset + 8, len)));
offset += 8 + len;
} else if (id === 'WEBP') {
chunks[id].push(str.substr(offset + 8));
break;
} else {
chunks[id].push(str.substr(offset + 4));
break;
}
}
return chunks;
}
function Encoder(fps, _quality = 0.8, _name = "Groover"){
this.fps = fps;
this.quality = quality = _quality;
this.frameDelay = frameDelay = 1000 / fps;
this.frame = 0;
this.width = width = null;
this.timecode = 0;
this.name = name = _name;
}
Encoder.prototype = {
addFrame : function(frame){
if('canvas' in frame){
frame = frame.canvas;
}
if(width === null){
this.width = width = frame.width,
this.height = height = frame.height
startEncoding();
}else
if(width !== frame.width || height !== frame.height){
throw RangeError("Frame size error. Frames must be the same size.");
}
addFrame(frame);
this.frame += 1;
this.timecode = clusterTimecode;
},
toBlob : function(){
return toBlob(webmData);
}
}
return {
Video: Encoder,
}
})()