@Override
  public byte[] getTilesMergedJpeg(List<TileInfo> tileList, int tileWidth, int tileHeight) {
    int width = Math.max(tileWidth, tileWidth * tileList.size());

    BufferedImage bufferedImage =
        new BufferedImage(width, tileHeight, BufferedImage.TYPE_3BYTE_BGR);
    Graphics2D g = bufferedImage.createGraphics();

    synchronized (offlineImage) {
      int i = 0;
      for (TileInfo tile : tileList) {
        Rectangle rc = tile.getTileRect();
        g.drawImage(
            offlineImage,
            i * tileWidth,
            0,
            i * tileWidth + rc.width,
            rc.height,
            rc.x,
            rc.y,
            rc.x + rc.width,
            rc.y + rc.height,
            null);
        i++;
      }
    }

    byte[] imgBits = null;
    try {
      imgBits = ImageHelper.jpegFromImage(bufferedImage);
    } catch (IOException e) {
      s_logger.info("[ignored] read error on image tiles", e);
    }
    return imgBits;
  }
 @Override
 public void handle(HttpExchange t) throws IOException {
   try {
     Thread.currentThread()
         .setName("Cmd Thread " + Thread.currentThread().getId() + " " + t.getRemoteAddress());
     s_logger.info("CmdHandler " + t.getRequestURI());
     doHandle(t);
   } catch (Exception e) {
     s_logger.error(e.toString(), e);
     String response = "Not found";
     t.sendResponseHeaders(404, response.length());
     OutputStream os = t.getResponseBody();
     os.write(response.getBytes());
     os.close();
   } catch (OutOfMemoryError e) {
     s_logger.error("Unrecoverable OutOfMemory Error, exit and let it be re-launched");
     System.exit(1);
   } catch (Throwable e) {
     s_logger.error(e.toString(), e);
   } finally {
     t.close();
   }
 }
  public void doHandle(HttpExchange t) throws Exception {
    String path = t.getRequestURI().getPath();
    int i = path.indexOf("/", 1);
    String cmd = path.substring(i + 1);
    s_logger.info("Get CMD request for " + cmd);
    if (cmd.equals("getstatus")) {
      ConsoleProxyClientStatsCollector statsCollector = ConsoleProxy.getStatsCollector();

      Headers hds = t.getResponseHeaders();
      hds.set("Content-Type", "text/plain");
      t.sendResponseHeaders(200, 0);
      OutputStreamWriter os = new OutputStreamWriter(t.getResponseBody(), "UTF-8");
      statsCollector.getStatsReport(os);
      os.close();
    }
  }
public class ConsoleProxyCmdHandler implements HttpHandler {
  private static final Logger s_logger = Logger.getLogger(ConsoleProxyCmdHandler.class);

  @Override
  public void handle(HttpExchange t) throws IOException {
    try {
      Thread.currentThread()
          .setName("Cmd Thread " + Thread.currentThread().getId() + " " + t.getRemoteAddress());
      s_logger.info("CmdHandler " + t.getRequestURI());
      doHandle(t);
    } catch (Exception e) {
      s_logger.error(e.toString(), e);
      String response = "Not found";
      t.sendResponseHeaders(404, response.length());
      OutputStream os = t.getResponseBody();
      os.write(response.getBytes());
      os.close();
    } catch (OutOfMemoryError e) {
      s_logger.error("Unrecoverable OutOfMemory Error, exit and let it be re-launched");
      System.exit(1);
    } catch (Throwable e) {
      s_logger.error(e.toString(), e);
    } finally {
      t.close();
    }
  }

  public void doHandle(HttpExchange t) throws Exception {
    String path = t.getRequestURI().getPath();
    int i = path.indexOf("/", 1);
    String cmd = path.substring(i + 1);
    s_logger.info("Get CMD request for " + cmd);
    if (cmd.equals("getstatus")) {
      ConsoleProxyClientStatsCollector statsCollector = ConsoleProxy.getStatsCollector();

      Headers hds = t.getResponseHeaders();
      hds.set("Content-Type", "text/plain");
      t.sendResponseHeaders(200, 0);
      OutputStreamWriter os = new OutputStreamWriter(t.getResponseBody(), "UTF-8");
      statsCollector.getStatsReport(os);
      os.close();
    }
  }
}
  @Override
  public byte[] getFrameBufferJpeg() {
    int width = offlineImage.getWidth();
    int height = offlineImage.getHeight();

    BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
    Graphics2D g = bufferedImage.createGraphics();
    synchronized (offlineImage) {
      g.drawImage(offlineImage, 0, 0, width, height, 0, 0, width, height, null);
      g.dispose();
    }

    byte[] imgBits = null;
    try {
      imgBits = ImageHelper.jpegFromImage(bufferedImage);
    } catch (IOException e) {
      s_logger.info("[ignored] read error on image", e);
    }

    return imgBits;
  }
public class RdpBufferedImageCanvas extends BufferedImageCanvas implements FrameBufferCanvas {
  /** */
  private static final long serialVersionUID = 1L;

  private static final Logger s_logger = Logger.getLogger(RdpBufferedImageCanvas.class);

  private final ConsoleProxyRdpClient _rdpClient;

  public RdpBufferedImageCanvas(ConsoleProxyRdpClient client, int width, int height) {
    super(width, height);
    _rdpClient = client;
  }

  @Override
  public Image getFrameBufferScaledImage(int width, int height) {
    if (offlineImage != null)
      return offlineImage.getScaledInstance(width, height, Image.SCALE_DEFAULT);
    return null;
  }

  @Override
  public byte[] getFrameBufferJpeg() {
    int width = offlineImage.getWidth();
    int height = offlineImage.getHeight();

    BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
    Graphics2D g = bufferedImage.createGraphics();
    synchronized (offlineImage) {
      g.drawImage(offlineImage, 0, 0, width, height, 0, 0, width, height, null);
      g.dispose();
    }

    byte[] imgBits = null;
    try {
      imgBits = ImageHelper.jpegFromImage(bufferedImage);
    } catch (IOException e) {
      s_logger.info("[ignored] read error on image", e);
    }

    return imgBits;
  }

  @Override
  public byte[] getTilesMergedJpeg(List<TileInfo> tileList, int tileWidth, int tileHeight) {
    int width = Math.max(tileWidth, tileWidth * tileList.size());

    BufferedImage bufferedImage =
        new BufferedImage(width, tileHeight, BufferedImage.TYPE_3BYTE_BGR);
    Graphics2D g = bufferedImage.createGraphics();

    synchronized (offlineImage) {
      int i = 0;
      for (TileInfo tile : tileList) {
        Rectangle rc = tile.getTileRect();
        g.drawImage(
            offlineImage,
            i * tileWidth,
            0,
            i * tileWidth + rc.width,
            rc.height,
            rc.x,
            rc.y,
            rc.x + rc.width,
            rc.y + rc.height,
            null);
        i++;
      }
    }

    byte[] imgBits = null;
    try {
      imgBits = ImageHelper.jpegFromImage(bufferedImage);
    } catch (IOException e) {
      s_logger.info("[ignored] read error on image tiles", e);
    }
    return imgBits;
  }

  @Override
  public void updateFrameBuffer(int x, int y, int w, int h) {
    _rdpClient.onFramebufferUpdate(x, y, w, h);
  }
}