如何将 GIF 帧转换为 spritesheet

how to convert frames of GIF into spritesheet

我正在尝试合并 GIF 中的多个帧以将它们转换为 spritesheet。我以某种方式能够使用 libgif.js 提取帧 这是我的代码。 Canvas 我想放我所有图片的地方是空的,最后我不知道它有什么问题。

<img hidden src="https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif" rel:auto_play="0"
    rel:rubbable="0" />

  <div id="frames">
  </div>
  <canvas id="myCanvas" style="border:1px solid #d3d3d3;">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://unpkg.com/jsgif@1.0.2/libgif.js"></script>
<script>
  $(document).ready(function () {
    $('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 (var i = 0; i < rub.get_length(); i++) {
            total += 1;
            rub.move_to(i);
            var canvas = cloneCanvas(rub.get_canvas());

            $("#frames").append('<img id = "' + i + '"src= "' + canvas + '">');

          }
          for (var i = 0; i <= total; i++) {
            id = i.toString();
            var img = document.getElementById(id);
            window.onload = function () {

              var c = document.getElementById("myCanvas");
              var ctx = c.getContext("2d");

              ctx.drawImage(img, 10, 10);
            }
          }
        });
      }
    });
  });

  function cloneCanvas(oldCanvas) {
    var img = oldCanvas.toDataURL("image/png");
    return img;
  }
</script>

您的解决方案中的主要问题是您正在遍历所有插入的帧图像并使用 window.onload 并期望在 canvas 上绘制图像。但是,在图像元素之后,您在图像元素上分配了windows.onload,图像已经在之前的(for i = 0)迭代中附加到dom,通过$("#frames").append(...。这意味着您的 onload 处理程序在事件已经触发后注册。

我将您的代码重新排列到下面的代码片段中,以确保在将图像帧附加到文档之前注册 onload

在这个解决方案中,我通过一个接一个地垂直放置图像帧来创建“spritesheet”。相应地调整解决方案以创建您想要的“spritesheet 布局”。

棘手的部分是您需要以动态方式为 canvas 设置 widthheight,这意味着您必须等待所有图像帧完成将 loaded 放入文档中并测量它们的总宽度和高度。 算法应该是:

  1. 收集图像帧的所有宽度和高度onload
  2. 计算总数 canvas.widthcanvas.height 取决于 你想要的布局(在我的垂直其中一个解决方案中 这意味着使用最大图像宽度作为 canvas 宽度和 所有图像高度的总和作为高度。如果你需要一个不同的 spritesheet 布局然后你需要以不同的方式调整这个逻辑)
  3. 画完canvas上的所有图片,至此已经足够了 宽度和高度以适合您所有的 gif 帧图像。

在我的解决方案中我没有实现这个算法,我宁愿在为您的特定 gif 示例手动计算 max-img-width 和 total-img-height 之后硬编码 canvas 宽度和高度。

$(document).ready(function () {
    const c = document.getElementById("myCanvas");
    const ctx = c.getContext("2d");
    let canvasWidth = 0;
    let canvasHeight = 0;
    $('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());

            const img = $('<img id = "' + i + '"src= "' + canvas + '">');
            img.on('load', function() {
              // draw the image
              ctx.drawImage(this, 0, canvasHeight);
              // extend canvas width, if newly loaded image exceeds current width
              canvasWidth = $(this).width() > canvasWidth ? $(this).width() : canvasWidth;
              // add canvas height by the newly loade image height value
              canvasHeight += $(this).height();
              // resize sprite-canvas to host the new image
              canvas.width = canvasWidth;
              canvas.height = canvasHeight;
            });
            $("#frames").append(img);
          }
        });
      }
    });
  });

  function cloneCanvas(oldCanvas) {
    var img = oldCanvas.toDataURL("image/png");
    return img;
  }
Gif:
<img hidden src="https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif" rel:auto_play="0"
    rel:rubbable="0" />
<hr />
Frames:
<div id="frames">
</div>
<hr />
Canvas:
<hr />
<canvas id="myCanvas" style="border:1px solid #d3d3d3;" width="400" height="17600">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://unpkg.com/jsgif@1.0.2/libgif.js"></script>