10

状況

回転可能な 144 (90px x 90px) の画像 (12x12) を含むグリッドのような順序付けられていないリストがあります。私の最終目標は、144 個の画像グリッドを取得して 1 つの画像として保存することです。

現在のソリューション

私の現在のソリューションでは、次の手順に従っています。

  1. 1 画像の幅 x 12 幅、1 画像の高さ x 12 高さのキャンバスを作成します。これは、最終製品のイメージを表すためのものです。
  2. リスト項目 (画像) をループし、項目から画像 src を抽出し、画像のサイズである独自のキャンバスに描画します。
  3. 新しい小さなキャンバスを回転しますが、画像はグリッド上で回転しています。
  4. 現在のポインターの x と y で最終結果キャンバスに新しい小さなキャンバスを描画します。

注意事項

画像をループしながら、ポインター (キャンバス上の現在の場所) を追跡します。行と列番号を維持することでこれを行います。それらは、私が描いている画像の現在の行と列を表しています。単一の画像の幅と高さを掛けて、キャンバス上の正確な x 座標と y 座標を取得し、次の画像を描画します。

現在の問題

キャンバスの base64 を作成、描画、および生成する関数を呼び出すと、次のエラー メッセージが表示されます。このエラーが 100% の確率で発生していた場合、キャンバスに描画している画像がまだ読み込まれていないか、まったく読み込まれていないためだと思いますが、このエラーは 1 回しか表示されません。私がロードするすべての新しい画像。たとえば、144 個の画像グリッド、つまり 2 つの異なる画像がそれぞれ 72 回描画されている場合、InvalidStateError を 2 回受け取り、3 回目に関数を呼び出すと成功します。

現在のコード

これは、画像の保存をテストするための単純なスパイク コードであることを覚えておいてください。リファクタリングが必要であることは承知しています。

generateThumbnail: function(){
  var builder = this,
      canvas = document.createElement('canvas'),
      content,
      row = 0,
      col = 0;

  // width is single image width (90) x number of tiles wide (usually 12)
  canvas.width = 90 * builder.grid[0];
  // height is single image height (90) x number of tiles high (usually 12)
  canvas.height = 90 * builder.grid[1];
  // get 2d context of new canvas
  context = canvas.getContext("2d");

  // loop through all of the images on the grid
  $.each($(".pattern-grid li"), function(i, tile) {
    var $tile = $(tile),
        image = new Image(),
        src = $tile.find("img").attr("src"),
        width,
        height,
        buffer,
        bufferctx,
        x,
        y;

    // set crossOrigin of image to anonymous as these images are loaded via CORS
    image.crossOrigin = "Anonymous";
  
    // increase row number by 1 if it has reached the end of the row and its not the first image being drawn
    if(i % builder.grid[0] == 0 && i != 0){
      row++;
    }
    // Set Column to 0 if it is a new row, otherwise increase column by 1 (unless it is the first image being drawn)
    if(col == builder.grid[0]-1){
      col = 0;
    }else if(i != 0){
      col++;
    }

    // determine if there was no image drawn at this location
    if(src != undefined){
      image.src = src;
      // get the width and height the image, to be used for the small canvas and where to draw it
      width = image.width;
      height = image.height;
      // create a new buffer canvas to draw the image to, this will be used to apply any rotations that may exist
      buffer = document.createElement("canvas");
      //set width and height of the buffer to the current images width and height
      buffer.width = width;
      buffer.height = height;
      bufferctx = buffer.getContext("2d");
      //Determine x and y coordinates to draw the small canvas using row and column numbers
      x = col*width;
      y = row*height;
      //Save current state of buffer canvas
      bufferctx.save();
      //translate and then rotate the buffer canvas by the image's rotation
      bufferctx.translate(width/2, height/2);
      bufferctx.rotate($tile.find("img").data("rotation")*Math.PI/180);
      bufferctx.translate(width/2*-1, height/2*-1);
      //draw image to buffer canvas and restore its context
      bufferctx.drawImage(image, 0, 0);
      bufferctx.restore();
      //draw the buffer canvas to the main canvas at predetermined x and y
      context.drawImage(buffer, x, y, width, height);
    }
  });
  return canvas.toDataURL();
}
4

2 に答える 2

4

関数の状態を保存するためのクロージャーと組み合わせて、onloadで@abiessuの提案を使用することができました。動作する私の解決策は次のとおりです。

generateThumbnail: function(){
  var builder = this,
      canvas = document.createElement('canvas'),
      content,
      row = 0,
      col = 0;
  // width is single image width (90) x number of tiles wide (usually 12)
  canvas.width = 90 * builder.grid[0];
  // height is single image height (90) x number of tiles high (usually 12)
  canvas.height = 90 * builder.grid[1];
  context = canvas.getContext("2d");
  // loop through all of the images on the grid
  $.each($(".pattern-grid li"), function(i, tile) {
    var $tile = $(tile),
        image = new Image(),
        src = $tile.find("img").attr("src");
     // set crossOrigin of image to anonymous as these images are loaded via CORS
    image.crossOrigin = "Anonymous";
    // increase row number by 1 if it has reached the end of the row and its not the first image being drawn
    if(i % builder.grid[0] == 0 && i != 0){
      row++;
    }
    // increase row number by 1 if it has reached the end of the row and its not the first image being drawn
    if(col == builder.grid[0]-1){
      col = 0;
    }else if(i != 0){
      col++;
    }
    image.onload = function(row, col){
      return function(){
        // determine if there was no image drawn at this location
        if(src != undefined){
          var width = image.width,
              height = image.height,
              buffer = document.createElement("canvas"),
              bufferctx,
              x,
              y;
          buffer.width = width;
          buffer.height = height;
          bufferctx = buffer.getContext("2d");
          x = col*width;
          y = row*height;
          bufferctx.save();
          bufferctx.translate(width/2, height/2);
          bufferctx.rotate($tile.find("img").data("rotation")*Math.PI/180);
          bufferctx.translate(width/2*-1, height/2*-1);
          bufferctx.drawImage(image, 0, 0);
          bufferctx.restore();
          context.drawImage(buffer, x, y, width, height);
        }
      }
    }(row, col);
    image.src = $tile.find("img").attr("src");
  });
  window.canvas = canvas;
}
于 2013-10-28T15:29:24.103 に答える
0

image.onloadコールバックを使用します。

image.onload = function(){
  bufferctx.drawImage(image,0,0);
}

詳細については、Mozilla のページを参照してください。このページとこの検索を使用まし

于 2013-10-28T14:52:41.047 に答える