如何使用 Javascript 将 Gif 转换为 spritesheet

how to convert Gif to spritesheet using Javascript

我正在使用 Libgif 从 gif 中获取帧。 然后我将这些帧附加到 div 中,Id = frames。 然后我正在拍摄这些帧并尝试在 canvas 中一个接一个地添加每个帧以制作一个 spritesheet。

最后,我在 canvas 中得到了一张图片,但我在 spritesheet 中得到了相同的图片,而不是不同的帧。 请帮我找出问题。

假设 gif 的帧数不会超过 100,我已采用 canvas 宽度 10000。

c = document.getElementById("myCanvas");
ctx = c.getContext("2d");
ctx.clearRect(0, 0, ctx.width, ctx.height);
ctx.beginPath();
var imageGiF = "";
var total = 0;
let canvasWidth = 0;
let canvasHeight = 0;
$('div.gifimage img').each(function(idx, img_tag) {
  var total = 0;
  if (/^.+\.gif$/.test($(img_tag).prop("src"))) {
    var rub = new SuperGif({
      gif: img_tag,
      progressbar_height: 0
    });
    rub.load(function() {
      for (let i = 0; i < rub.get_length(); i++) {
        total += 1;
        rub.move_to(i);
        // var canvas = cloneCanvas(rub.get_canvas());
        var canvas = rub.get_canvas().toDataURL("image/png");
        img = $('<img id = "gifframe' + i + '"src= "' + canvas + '" class= frameimages>');

        $("#frames").append(img);

      }
      var frameimages = document.getElementById("frames").querySelectorAll(".frameimages");
      var totalimages = frameimages.length;

      x = 0;
      y = 0;
      for (let i = 0; i < frameimages.length; i++) {
        img = document.getElementById("gifframe" + i + "");
        img.onload = function() {
          ctx.drawImage(img, i * 100, 0, 100, 100);
          total++;
          console.log(total);
        }
      }
      totalwidth = (total) * 100;
      c.width = totalwidth;
      c.height = 100;
      setTimeout(() => {
        imageGiF = c.toDataURL("image/png");
        console.log(imageGiF);
        // addBgimg(imageGiF)
      }, 10);
    });
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/buzzfeed/libgif-js/master/libgif.js"></script>
<div class="gifimage" id="placehere">
  <img src="https://media1.giphy.com/media/bzUwzbxcvJ3XQlcnoi/giphy.gif" alt="">

</div>
<div id="frames" class="classGIF"></div>
<canvas id='myCanvas' width="10000" height="300"></canvas>

您在事件处理程序中使用 img 循环浏览图像。 但是,外部作用域中的这个变量 img 被每次循环覆盖,直到它完成所有循环,然后 img 卡在最后添加的帧上。
然后,当事件处理程序触发时,它会在每个实例中添加最后一帧,因为那是当时 img 的值。循环在图像加载之前完成。

通过将其包装在一个函数中,将其添加到它自己的 scope 中,变量得以保留。

我还修改了您的代码,将 DOM img 元素存储在一个数组中,因此您不需要昂贵的 DOM 查找,这让您的代码稍微快了一点。

我在代码中添加了注释来解释我的更改。

c = document.getElementById("myCanvas");
ctx = c.getContext("2d");
ctx.clearRect(0, 0, ctx.width, ctx.height);
ctx.beginPath();
var imageGiF = "";
var total = 0;
let canvasWidth = 0;
let canvasHeight = 0;
$('div.gifimage img').each(function(idx, img_tag) {
  var total = 0;
  if (/^.+\.gif$/.test($(img_tag).prop("src"))) {
    var rub = new SuperGif({
      gif: img_tag,
      progressbar_height: 0
    });
    rub.load(function() {
      // An array for the image references
      let images = [];
      // Keep the reference to save on expensive DOM lookups every iteration.
      let frames = $("#frames");
      for (let i = 0; i < rub.get_length(); i++) {
        total += 1;
        rub.move_to(i);
        // var canvas = cloneCanvas(rub.get_canvas());
        var canvas = rub.get_canvas().toDataURL("image/png");
        img = $('<img id = "gifframe' + i + '"src= "' + canvas + '" class="frameimages">');
        
        // Use the reference to append the image.
        frames.append(img);
        
        // Add image to images array with the current index as the array index.
        // Use the jQuery get method to get the actual DOM element.
        images[i] = img.get(0);
      }
      var frameimages = document.getElementById("frames").querySelectorAll(".frameimages");
      var totalimages = frameimages.length;

      x = 0;
      y = 0;
      
      // Loop through all the images in the image array
      // Using a scope so the reference to img won't be overridden.
      images.forEach((img, index) => {
        img.onload = () => {
          ctx.drawImage(img, index * 100, 0, 100, 100);
          total++;
          console.log(total);
        } 
      })
      
      
      totalwidth = (total) * 100;
      c.width = totalwidth;
      c.height = 100;
      setTimeout(() => {
        imageGiF = c.toDataURL("image/png");
        console.log(imageGiF);
        // addBgimg(imageGiF)
      }, 10);
    });
  }
});
#frames { display:none;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/buzzfeed/libgif-js/master/libgif.js"></script>
<div class="gifimage" id="placehere">
  <img src="https://media1.giphy.com/media/bzUwzbxcvJ3XQlcnoi/giphy.gif" alt="">

</div>
<div id="frames" class="classGIF"></div>
<canvas id='myCanvas' width="10000" height="300"></canvas>