Как я могу отправить div через узел js?

Контекст: я создаю веб-приложение, в котором я могу рисовать на холсте, сохранять его как изображение и отправлять другому клиенту через Node.

Что работает:

  • Рисунок (на любом клиенте. Обновляется в режиме реального времени).
  • Сохранение холста как Uint8Array
  • Сохранение холста в виде div img с изображением в кодировке base64

На чем я застрял:

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

Как я отправляю его на сервер узла в виде div:

   byId('sendHTML').onclick = SendImageHTML;  
   function SendImageHTML() {    
        var imageHTML = convertCanvasToImage(canvas); 
        socket.emit('SendImageHTML', imageHTML);
        // EMITS: <img src="data:image/png;base64, iVB9023423523345346....."
   }

Отправка в виде массива Uint8:

  /**
   * Converts canvas to bytes & emits web socket message
   * @return {Uint8Array} Bytes from canvas 
   */     
  byId('defImgBinary').onclick = DefineImageBinary;  
  function DefineImageBinary() {
        var image  = context.getImageData(0, 0, canvas.width, canvas.height);
        var buffer = new ArrayBuffer(image.data.length);
        var bytes  = new Uint8Array(buffer);

        for (var i=0; i<bytes.length; i++) {
            bytes[i] = image.data[i];
        }

        socket.emit('defImgBinary', bytes);
        // EMITS: [24, 24, 29, 255, 24, 24, 29, 255, 24, 24.......]

  }

И вот мой код сервера:

socket.on('SendImageHTML', function (html) {
    console.log("SendImageHTML called: ");
    log(html);
    // RETURNS:
    // SendImageHTML called:
    // {} 
});




socket.on('defImgBinary', function (bytes) {
    log("defImgBinary called: ");
    log(bytes);
    // RETURNS:
    // defImgBinary called:
    // '53721': 220,
    // '53722': 219,
    // '53723': 255,
    // '53724': 229,
});

В чем мне нужна помощь:

Что мне с ним делать дальше? Как я могу отобразить это как изображение на других клиентах?


person Dave Voyles    schedule 26.09.2016    source источник
comment
Просто socket.broadcast.emit эти данные с сервера. Он отправит его на все подключенные сокеты, кроме того, который отправил данные изображения. Поскольку вы отправляете <img> html, клиенты могут просто добавить его в DOM, и он будет отображаться при следующем рендеринге.   -  person nem035    schedule 27.09.2016


Ответы (1)


Будет ли это удовлетворительным для вас, если вы будете использовать getDataURL() из Canvas API, а затем отправлять изображение в кодировке base64 или визуализированный элемент DOM?

На стороне клиента:

Вы можете получить данные с холста в кодировке base64 через HTMLCanvasElement.toDataURL< /а> . Это приведет к строке, начинающейся с data:image/png;base64..., как в вашем примере кода.

Когда вы получаете строку, вы можете либо отправить ее непосредственно на сервер в виде строки, либо преобразовать ее в элемент изображения:

var image = new Image(width, height);
image.src = myBase64String;

image.addEventListener('load', function () { /* NOTE On image loaded */ });

Если вы хотите отправить обработанный элемент DOM на сервер, вы, вероятно, найдете очень полезным Element.outerHTML — это свойство вернет точное строковое представление элемента (например, "<img src="data:image/png;base64..." width="256" height="256" />").

На стороне сервера:

В обоих случаях вы можете просто отправить данные другим клиентам через их сокеты.

Со стороны других клиентов:

Если вы отправляете простую строку в кодировке base64, ее можно легко отобразить с помощью элемента Image:

var image = new Image(256, 256);
image.src = receivedBase64String;

image.addEventListener('load', function () { 
  document.appendChild(image);
});

Если вы отправляете уже отрендеренный элемент, вы можете поместить его в структуру DOM, используя document.createElement:

var image = document.createElement('div'); // NOTE Create a 'host' element
image.innerHTML = receivedRenderedElementString;

document.appendChild(image);

Пример:

См. приведенный ниже код для рабочего примера.

Сторона клиента:

<title>
  Canvas Sample
</title>
<p>
  <canvas id="sample-canvas" width="256" height="256"></canvas>
</p>
<p>
  <button id="send-canvas">
    Send canvas
  </button>
  <label for="send-as-div">
    <input type="checkbox" id="send-as-div">
      Send as div
    </input>
  </label>
</p>
<p id="output-console"></p>

<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script>
  // NOTE Simple IO console element for socket communication
  let outputConsole = document.querySelector('#output-console');
  let printToConsole = (text = '') => {
    outputConsole.innerHTML += text + '<br/>';
  };
  let renderToConsole = (element) => {
    outputConsole.appendChild(element);
    outputConsole.innerHTML += '<br/>';
  };

  // NOTE Load image (random cat image)
  let image = new Image(250, 250);
  image.src = 'http://thecatapi.com/api/images/get?format=src&size=small';
  printToConsole('Image loading.');

  // NOTE Setup canvas
  // Render the cat image when it is loaded.
  let canvas = document.querySelector('#sample-canvas');
  let context = canvas.getContext('2d');

  image.addEventListener('load', () => {
    context.drawImage(image, 0, 0);
    printToConsole('Image loaded.');
  });

  image.addEventListener('error', (error) => {
    printToConsole('Image error.' + JSON.strinfify(error));
  });

  // NOTE Setup a websocket
  // Socket will allow to send 'img' message with either a base64 encoded
  // image data, or a rendered HTML Image element.
  let socket = io('ws://localhost:8080/');

  socket.on('error', (error) => {
    printToConsole('Socket error.' + JSON.stringify(error));
  });

  socket.on('img', (image) => {
    let renderedImage = null;

    if (image.indexOf('data:image/') === 0) {

      // NOTE If we receive a base64 image, we render it as an Image
      renderedImage = new Image(250, 250);
      renderedImage.src = image;
    } else {

      // NOTE If we receive a rendered <img> element, we render it directly
      // via document.createElement
      renderedImage = document.createElement('div');
      renderedImage.innerHTML = image;
    }

    printToConsole('Received image.');
    renderToConsole(renderedImage);
  });

  // NOTE Setup button
  let sendButton = document.querySelector('#send-canvas');

  sendButton.addEventListener('click', () => {
    let encodedCanvas = canvas.toDataURL();
    let sendAsDiv = document.querySelector('#send-as-div').checked;
    let payload = null;

    if (sendAsDiv) {
      let imageElement = new Image(250, 250);
      imageElement.src = encodedCanvas;

      payload = imageElement.outerHTML;
    } else {
      payload = encodedCanvas;
    }

    socket.emit('img', payload);

    printToConsole('Image sent.');
  });
</script>

Серверная часть (требуется npm install -D express socket.io):

'use strict';

let express = require('express');
let http = require('http');
let socketIo = require('socket.io');

// NOTE Setup server
let httpServer = http.createServer(express());
let socketServer = socketIo(httpServer);
let sockets = [];
let port = 8080;

httpServer.listen(port);

// NOTE Setup socket listener

socketServer.on('connection', (socket) => {
  sockets.push(socket);

  let socketId = sockets.length;

  socket.on('img', (payload) => {
    socket.broadcast.emit('img', payload);
  });
});

Дайте мне знать, если это решит вашу проблему ????

person Maciek Jurczyk    schedule 27.09.2016
comment
Проголосовал за упоминание представления изображения base64 для подключенных клиентов. - person Alex; 27.09.2016
comment
Работал как шарм! Я делал этот путь более сложным, чем нужно. Спасибо за исчерпывающий ответ и за предложение двух решений! - person Dave Voyles; 27.09.2016