Как повернуть изображение на холсте? - PullRequest
0 голосов
/ 31 марта 2020

Я пытаюсь нарисовать изображение с помощью d3 из файла json. Эти данные изображения затем помещаются в контекст холста, чтобы фактически нарисовать изображение. Я хотел бы повернуть полученное изображение, но не могу найти, как. Код, который я на самом деле использую

$(document).ready(function() {
    d3.json("resources/image.json").then(function(image) {
        var canvas = d3.select("colorImage")
                       .append("canvas")
                       .attr("width", 200)
                       .attr("height", 200);


        var context = canvas.node().getContext("2d");
        var image_data = context.createImageData(200, 200);

        image_data.data.set(image);
        context.rotate(60); 
        context.putImageData(image_data, 0, 0);  // <---- image not rotated
        context.fillRect( 100, 100, 20, 20 );  // <--- rectangle rotated
    }).catch(function(error){
        if (error) throw error;
    });
})

1 Ответ

2 голосов
/ 31 марта 2020

putImageData() и getImageData() не зависят от матрицы преобразования контекста.

Чтобы повернуть ее, проще всего создать ImageBitmap из него и для рисования этого ImageBitmap используйте drawImage():

(async () => {
  const canvas = document.getElementById( 'canvas' );
  const context = canvas.getContext( '2d' );
  // make some noise
  const image = new Uint8Array( Uint32Array.from(
      { length: 200 * 200 },
      _ => (Math.random() * 0xFFFFFFFF)
    ).buffer );

  const image_data = context.createImageData( 200, 200 );
  image_data.data.set( image );
  
  const center_w = canvas.width / 2;
  const center_h = canvas.height / 2;
  const bitmap = await createImageBitmap( image_data );
  context.translate( center_w, center_h ); 
  context.rotate( 60 );
  context.translate( -center_w, -center_h ); 
  context.drawImage( bitmap, center_w-100, center_h-100 );  // <---- image rotated
  context.lineWidth = 4;
  context.strokeStyle = 'green';
  context.strokeRect( center_w-100, center_h-100, 200, 200 );  // <--- rectangle rotated
})().catch( console.error );
<canvas id="canvas" height="300" width="300"></canvas>

А для браузеров, которые не поддерживают метод createImageBitmap(), вы можете довольно легко исправить это точное использование с помощью HTMLCanvasElement:

/* if( !window.createImageBitmap ) { */ // for demo we force monkey-patch
 monkeyPatchCreateImageBitmap();
/*} */

(async () => {
  const canvas = document.getElementById( 'canvas' );
  const context = canvas.getContext( '2d' );
  // make some noise
  const image = new Uint8Array( Uint32Array.from(
      { length: 200 * 200 },
      _ => (Math.random() * 0xFFFFFFFF)
    ).buffer );

  const image_data = context.createImageData( 200, 200 );
  image_data.data.set( image );
  
  const center_w = canvas.width / 2;
  const center_h = canvas.height / 2;
  const bitmap = await createImageBitmap( image_data );
  context.translate( center_w, center_h ); 
  context.rotate( 60 );
  context.translate( -center_w, -center_h ); 
  context.drawImage( bitmap, center_w-100, center_h-100 );  // <---- image rotated
  context.lineWidth = 4;
  context.strokeStyle = 'green';
  context.strokeRect( center_w-100, center_h-100, 200, 200 );  // <--- rectangle rotated
})().catch( console.error );


// minimalistic version that only accepts ImageData, and no clipping
function monkeyPatchCreateImageBitmap() {
  window.createImageBitmap = function( source ) {
    if( source instanceof ImageData ) {
      const dest = document.createElement( 'canvas' );
      dest.width = source.width;
      dest.height = source.height;
      dest.getContext( '2d' ).putImageData( source, 0, 0 );
      return Promise.resolve( dest );
    }
  };
}
<canvas id="canvas" height="300" width="300"></canvas>
...