Project

General

Profile

1811o_20150807_2.txt

Sergey Ivanovskiy, 08/07/2015 04:52 PM

Download (21.9 KB)

 
1
=== modified file 'src/com/goldencode/p2j/ui/client/driver/web/res/p2j.socket.js'
2
--- src/com/goldencode/p2j/ui/client/driver/web/res/p2j.socket.js	2015-07-20 21:45:43 +0000
3
+++ src/com/goldencode/p2j/ui/client/driver/web/res/p2j.socket.js	2015-08-07 15:56:12 +0000
4
@@ -18,8 +18,9 @@
5
 ** 007 GES 20150324 Moved this class to a common resource base and made it generic (so that it
6
 **                  can be used for both ChUI and GUI web clients.
7
 ** 008 SBI 20150731 Applied "use strict" directive, fixed undeclared variables.
8
-** 009 GES 20170709 Added support for MSG_READ_CLIPBOARD (server-driven clipboard request) and
9
+** 009 GES 20150709 Added support for MSG_READ_CLIPBOARD (server-driven clipboard request) and
10
 **                  MSG_WRITE_CLIPBOARD.
11
+** 010 SBI 20150807 Fixed a network order for reading int32 from binaries message
12
 */
13
 
14
 "use strict";
15
@@ -131,7 +132,7 @@
16
 
17
       for (var i = 0; i < 4; i++)
18
       {
19
-         num |= message[offset + i] << (8 * i);
20
+         num |= message[offset + i] << (8 * (3-i));
21
       }
22
       
23
       return num;
24

    
25
=== added file 'src/com/goldencode/p2j/ui/client/gui/driver/web/DrawImageOp.java'
26
--- src/com/goldencode/p2j/ui/client/gui/driver/web/DrawImageOp.java	1970-01-01 00:00:00 +0000
27
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/DrawImageOp.java	2015-08-07 20:40:47 +0000
28
@@ -0,0 +1,114 @@
29
+/*
30
+** Module   : DrawImageOp.java
31
+** Abstract : Defines a draw image command.
32
+**
33
+** Copyright (c) 2015, Golden Code Development Corporation.
34
+** ALL RIGHTS RESERVED. Use is subject to license terms.
35
+**
36
+**         Golden Code Development Corporation
37
+**                 CONFIDENTIAL
38
+**
39
+** -#- -I- --Date-- --------------------------------Description----------------------------------
40
+** 001 SBI 20150807 First version which is a draw image command.
41
+** 
42
+** 
43
+*/
44
+
45
+package com.goldencode.p2j.ui.client.gui.driver.web;
46
+
47
+import java.awt.Image;
48
+import java.util.HashSet;
49
+
50
+import com.goldencode.p2j.ui.client.gui.driver.PaintPrimitives;
51
+import com.goldencode.p2j.ui.client.gui.driver.PaintStructure;
52
+
53
+/**
54
+ * 
55
+ * DrawImageOp performs a draw image on a virtual screen and prepares
56
+ * a draw message to transfer via networks, holds a hash map of loaded images.
57
+ *
58
+ */
59
+public class DrawImageOp
60
+{
61
+
62
+   private final VirtualScreen virtualScreen;
63
+
64
+   private final HashSet<Integer> loadedImages;
65
+   /**
66
+    * 
67
+    * @param virtualScreen
68
+    */
69
+   public DrawImageOp(VirtualScreen virtualScreen)
70
+   {
71
+      this.virtualScreen = virtualScreen;
72
+      this.loadedImages = new HashSet<Integer>();
73
+   }
74
+
75
+   /**
76
+    * Write a 32-bit integer value into a binary message at a given offset.
77
+    *
78
+    * @param    message
79
+    *           Message content as an byte array.
80
+    * @param    offset
81
+    *           Offset into the message at which the integer should be written.
82
+    * @param    value
83
+    *           The 32-bit value to write.
84
+    */
85
+   private void writeMessageInt32(byte[] message, int offset, int value)
86
+   {
87
+      message[offset]     = (byte)((value >> 24) & 0x00FF);
88
+      message[offset + 1] = (byte)((value >> 16) & 0x00FF);
89
+      message[offset + 2] = (byte)((value >> 8)  & 0x00FF);
90
+      message[offset + 3] = (byte)( value        & 0x00FF);
91
+   }
92
+
93
+   /**
94
+    * Perform a draw image on a virtual screen, the image parameters provided
95
+    * in PaintStructure. A binary message format is defined as
96
+    * DRAW_IMAGE, 1 byte, operation id
97
+    * x, 4 bytes, an image x-offset
98
+    * y, 4 bytes, an image y-offset
99
+    * width, 4 bytes, an image width
100
+    * height, 4 bytes, an image width
101
+    * encoding, 1 byte, an image encoding schema, Raw or Hash
102
+    * imageHashCode, 4 bytes, an image hash code
103
+    * image binaries, 4*width*height bytes, an encoded image, it is omitted
104
+    * if an encoding is Hash.
105
+    * @param ps PaintStructure parameters for an image drawing
106
+    * @return byte[] a drawing image prepared to transfer via network. 
107
+    */
108
+   public byte[] execute(PaintStructure ps) {
109
+      int x = ps.xOffset;//4
110
+      int y = ps.yOffset;//4
111
+      Image image = (Image) ps.img.getImage();
112
+      int width = image.getWidth(null);//4
113
+      int height = image.getHeight(null);//4
114
+      virtualScreen.drawImage(image, x, y);
115
+      int imageHash = image.hashCode();
116
+      ImageEncoding encoding;
117
+      if (!loadedImages.contains(imageHash)) {
118
+         loadedImages.add(imageHash);
119
+         encoding = ImageEncoding.RAW;
120
+      } else {
121
+         encoding = ImageEncoding.HASH;
122
+      }
123
+      final byte[] encodedImage = new RawEncoder().packToBinaries(virtualScreen, x, y, width, height);
124
+      int msgLen = 22;
125
+      if (encoding == ImageEncoding.RAW) { 
126
+         msgLen += encodedImage.length;
127
+      }
128
+      byte[] drawImageMsg = new byte[msgLen];
129
+      drawImageMsg[0] = (byte) (PaintPrimitives.DRAW_IMAGE.ordinal());
130
+      writeMessageInt32(drawImageMsg, 1, x);
131
+      writeMessageInt32(drawImageMsg, 5, y);
132
+      writeMessageInt32(drawImageMsg, 9, width);
133
+      writeMessageInt32(drawImageMsg, 13, height);
134
+      drawImageMsg[17] = (byte) encoding.getValue();
135
+      writeMessageInt32(drawImageMsg, 18, imageHash);
136
+      if (encoding == ImageEncoding.RAW) {
137
+         System.arraycopy(encodedImage, 0, drawImageMsg, 22, encodedImage.length);
138
+      }
139
+      
140
+      return drawImageMsg;
141
+   }
142
+}
143

    
144
=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebEmulatedWindow.java'
145
--- src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebEmulatedWindow.java	2015-07-30 23:09:31 +0000
146
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebEmulatedWindow.java	2015-08-07 15:18:59 +0000
147
@@ -13,6 +13,7 @@
148
 ** 002 HC  20150612 Compatibility changes related to support of paragraph layout.
149
 ** 003 HC  20150702 Improved positioning of top-level windows on systems with multiple displays.
150
 ** 004 GES 20150701 Added GUI implementation for previously stubbed-out methods.
151
+** 005 SBI 20150807 Added an images drawing operation.
152
 */
153
 
154
 package com.goldencode.p2j.ui.client.gui.driver.web;
155
@@ -378,6 +379,7 @@
156
             websock.drawRoundRect(ps.x, ps.y, ps.width, ps.height, ps.arcDiameter);
157
             break;
158
          case DRAW_IMAGE:
159
+            websock.drawImage(ps);
160
             break;
161
          case FILL_RECT:
162
             websock.fillRect(ps.x, ps.y, ps.width, ps.height);
163

    
164
=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.java'
165
--- src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.java	2015-07-30 23:09:31 +0000
166
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.java	2015-08-07 20:44:27 +0000
167
@@ -10,16 +10,19 @@
168
 **
169
 ** -#- -I- --Date-- --------------------------------Description----------------------------------
170
 ** 001 GES 20150331 First version which is a placeholder using the common parent code as ChUI.
171
-** 002 GES 20150701 Added messages for a first pass at GUI support. 
172
+** 002 GES 20150701 Added messages for a first pass at GUI support.
173
+** 003 SBI 20150807 Added an images drawing operation.
174
 */
175
 
176
 package com.goldencode.p2j.ui.client.gui.driver.web;
177
 
178
+import java.awt.color.ColorSpace;
179
+import java.awt.image.DataBuffer;
180
+import java.awt.image.DirectColorModel;
181
 import java.util.*;
182
 
183
 import com.goldencode.p2j.ui.client.driver.web.*;
184
 import com.goldencode.p2j.ui.client.*;
185
-import com.goldencode.p2j.ui.client.widget.*;
186
 import com.goldencode.p2j.ui.client.gui.driver.*;
187
 
188
 /**
189
@@ -49,6 +52,21 @@
190
    private int pendingBytes = 0;
191
    
192
    /**
193
+    * Defines a pixels model as sRGB 32bits per a pixel
194
+    */
195
+   private final DirectColorModel colorModel = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
196
+            32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000, true, DataBuffer.TYPE_INT);
197
+   /**
198
+    * TODO to get client screen width and height.
199
+    */
200
+   private final VirtualScreen virtualScreen = new VirtualScreenImpl(colorModel, 800, 600);
201
+   
202
+   /**
203
+    * Image drawing manager holds a hash map of loaded images
204
+    */
205
+   private final DrawImageOp drawImageOp = new DrawImageOp(virtualScreen);
206
+   
207
+   /**
208
     * Create a new GUI web socket instance.
209
     * 
210
     * @param    lock
211
@@ -257,7 +275,15 @@
212
    {
213
       allocateAndSend(PaintPrimitives.FILL_3D_RECT, x, y, width, height, raised);
214
    }
215
-   
216
+
217
+   /**
218
+    * Draw a given image on the virtual screen and prepare it to transfer. 
219
+    * @param imageParameters PaintStructure 
220
+    */
221
+   public void drawImage(PaintStructure imageParameters) {
222
+      addDrawingOp(drawImageOp.execute(imageParameters));
223
+   }
224
+
225
    /**
226
     * Draw a filled, closed polygon in the current color/stroke.
227
     * 
228
@@ -719,6 +745,15 @@
229
    }
230
    
231
    /**
232
+    * Add a prepared drawing to the pending operations list
233
+    * @param message byte[] prepared drawing to transfer
234
+    */
235
+   private void addDrawingOp(byte[] message) {
236
+      drawingOps.add(message);
237
+      pendingBytes += message.length;
238
+   }
239
+   
240
+   /**
241
     * Defines the possible ways that the clipboard contents can be requested.
242
     */
243
    private enum ClipboardRequest
244

    
245
=== added file 'src/com/goldencode/p2j/ui/client/gui/driver/web/ImageEncoding.java'
246
--- src/com/goldencode/p2j/ui/client/gui/driver/web/ImageEncoding.java	1970-01-01 00:00:00 +0000
247
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/ImageEncoding.java	2015-08-07 20:14:21 +0000
248
@@ -0,0 +1,44 @@
249
+/*
250
+** Module   : ImageEncoding.java
251
+** Abstract : Enumerates encoding schemas to transfer screens images via network.
252
+**
253
+** Copyright (c) 2015, Golden Code Development Corporation.
254
+** ALL RIGHTS RESERVED. Use is subject to license terms.
255
+**
256
+**         Golden Code Development Corporation
257
+**                 CONFIDENTIAL
258
+**
259
+** -#- -I- --Date-- --------------------------------Description----------------------------------
260
+** 001 SBI 20150807 First version which describes a schema for Raw encoding and MD5 hash encoding
261
+**                  that is used to transfer images md5 hashes via networks.
262
+** 
263
+*/
264
+
265
+package com.goldencode.p2j.ui.client.gui.driver.web;
266
+
267
+/**
268
+ * 
269
+ * ImageEncoding defines Raw encoding and Hash encoding
270
+ * that is used to transfer images ids instead of their binaries via networks.
271
+ * 
272
+ */
273
+public enum ImageEncoding
274
+{
275
+   RAW(0), HASH(1);
276
+
277
+   private final int value;
278
+
279
+   private ImageEncoding(int value)
280
+   {
281
+      this.value = value;
282
+   }
283
+
284
+   /**
285
+    * Returns an encoding well-known id.
286
+    * @return int an encoding id
287
+    */
288
+   public int getValue()
289
+   {
290
+      return value;
291
+   }
292
+}
293

    
294
=== added file 'src/com/goldencode/p2j/ui/client/gui/driver/web/PixelsEncoder.java'
295
--- src/com/goldencode/p2j/ui/client/gui/driver/web/PixelsEncoder.java	1970-01-01 00:00:00 +0000
296
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/PixelsEncoder.java	2015-08-07 14:49:54 +0000
297
@@ -0,0 +1,35 @@
298
+/*
299
+** Module   : PixelsEncoder.java
300
+** Abstract : Describes a functionality to encode screens rectangles to transfer via networks.
301
+**
302
+** Copyright (c) 2015, Golden Code Development Corporation.
303
+** ALL RIGHTS RESERVED. Use is subject to license terms.
304
+**
305
+**         Golden Code Development Corporation
306
+**                 CONFIDENTIAL
307
+**
308
+** -#- -I- --Date-- --------------------------------Description----------------------------------
309
+** 001 SBI 20150807 First version which describes a schema for encoding of a rectangle
310
+**                  on a provided virtual screen.
311
+*/
312
+
313
+package com.goldencode.p2j.ui.client.gui.driver.web;
314
+
315
+/**
316
+ * 
317
+ * PixelsEncoder
318
+ *
319
+ */
320
+public interface PixelsEncoder
321
+{
322
+   /**
323
+    * Encode the rectangular area on the screen to transfer.
324
+    * @param screen virtual screen with the defined color model
325
+    * @param x int a position of the left side of the target rectangle along the screen horizon
326
+    * @param y int a position of the upper side of the target rectangle along the screen's vertical
327
+    * @param w int a width of the target rectangular area
328
+    * @param h int a height of the target rectangular area
329
+    * @return
330
+    */
331
+   byte[] packToBinaries(VirtualScreen screen, int x, int y, int w, int h);
332
+}
333

    
334
=== added file 'src/com/goldencode/p2j/ui/client/gui/driver/web/RawEncoder.java'
335
--- src/com/goldencode/p2j/ui/client/gui/driver/web/RawEncoder.java	1970-01-01 00:00:00 +0000
336
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/RawEncoder.java	2015-08-07 14:49:54 +0000
337
@@ -0,0 +1,70 @@
338
+/*
339
+** Module   : RawEncoder.java
340
+** Abstract : Implements Raw encoding.
341
+**
342
+** Copyright (c) 2015, Golden Code Development Corporation.
343
+** ALL RIGHTS RESERVED. Use is subject to license terms.
344
+**
345
+**         Golden Code Development Corporation
346
+**                 CONFIDENTIAL
347
+**
348
+** -#- -I- --Date-- --------------------------------Description----------------------------------
349
+** 001 SBI 20150807 First version which describes a raw encoding of a rectangle
350
+**                  on a provided virtual screen based on sRGB model.
351
+*/
352
+
353
+
354
+package com.goldencode.p2j.ui.client.gui.driver.web;
355
+
356
+import java.awt.image.DirectColorModel;
357
+
358
+/**
359
+ * 
360
+ * RawEncoder implements Raw encoding based on RFB specification documents:
361
+ * https://www.realvnc.com/docs/rfbproto.pdf
362
+ * https://tools.ietf.org/html/rfc6143
363
+ * This implementation supports only sRGB pixels models with 32 bits per a pixel.
364
+ */
365
+class RawEncoder implements PixelsEncoder
366
+{
367
+
368
+   private final static int TRUE_COLOR_BITS_PER_PIXEL = 32;
369
+   
370
+   @Override
371
+   public byte[] packToBinaries(VirtualScreen screen, int x, int y,
372
+            int w, int h)
373
+   {
374
+      byte[] encodedRectangle = null;
375
+      int b = 0;
376
+      int i = 0;
377
+      int s = 0;
378
+      int pixel;
379
+      int numberOfPixels = w * h;
380
+      int scanline = screen.getScreenWidth();
381
+      int jump = scanline - w;
382
+      int p = y * scanline + x;
383
+      int[] pixels = screen.getPixels();
384
+      DirectColorModel colorModel = screen.getColorModel();
385
+      if (colorModel.getPixelSize() == TRUE_COLOR_BITS_PER_PIXEL) {
386
+         encodedRectangle = new byte[ numberOfPixels << 2 ];
387
+         for( ; i < numberOfPixels; i++, s++, p++ )
388
+         {
389
+            if( s == w )
390
+            {
391
+               s = 0;
392
+               p += jump;
393
+            }
394
+            pixel = pixels[p];
395
+            encodedRectangle[b++] = (byte) colorModel.getRed(pixel);
396
+            encodedRectangle[b++] = (byte) colorModel.getGreen(pixel);
397
+            encodedRectangle[b++] = (byte) colorModel.getBlue(pixel);
398
+            encodedRectangle[b++] = (byte) colorModel.getAlpha(pixel);
399
+         }
400
+      } else {
401
+         throw new UnsupportedOperationException("Supported only 32 bits per a pixel");
402
+      }
403
+      
404
+      return encodedRectangle;
405
+   }
406
+
407
+}
408

    
409
=== added file 'src/com/goldencode/p2j/ui/client/gui/driver/web/VirtualScreen.java'
410
--- src/com/goldencode/p2j/ui/client/gui/driver/web/VirtualScreen.java	1970-01-01 00:00:00 +0000
411
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/VirtualScreen.java	2015-08-07 20:10:45 +0000
412
@@ -0,0 +1,53 @@
413
+/*
414
+** Module   : VirtualScreen.java
415
+** Abstract : Define methods to work with screen
416
+**
417
+** Copyright (c) 2015, Golden Code Development Corporation.
418
+** ALL RIGHTS RESERVED. Use is subject to license terms.
419
+**
420
+**         Golden Code Development Corporation
421
+**                 CONFIDENTIAL
422
+**
423
+** -#- -I- --Date-- --------------------------------Description----------------------------------
424
+** 001 SBI 20150807 First version which describes a virtual screen based on sRGB model.
425
+*/
426
+
427
+package com.goldencode.p2j.ui.client.gui.driver.web;
428
+
429
+import java.awt.Image;
430
+import java.awt.image.DirectColorModel;
431
+
432
+/**
433
+ * VirtualScreen describes a virtual screen based on sRGB model. It provides
434
+ * an access to a screen pixel model and perform drawing operations.
435
+ */
436
+public interface VirtualScreen
437
+{
438
+   /**
439
+    * 
440
+    * @return pixels int[] RGBA model via pixels 
441
+    */
442
+   int[] getPixels();
443
+   /**
444
+    * Gets a screen width.
445
+    * @return int a screen width
446
+    */
447
+   int getScreenWidth();
448
+   /**
449
+    * Gets a screen height.
450
+    * @return height a screen height
451
+    */
452
+   int getScreenHeight();
453
+   /**
454
+    * Describes a pixel format used for drawing.
455
+    * @return DirectColorModel color model
456
+    */
457
+   DirectColorModel getColorModel();
458
+   /**
459
+    * Draw an image at the target position on the screen
460
+    * @param image Image
461
+    * @param x int x-coordinate of the target image position 
462
+    * @param y int y-coordinate of the target image position
463
+    */
464
+   void drawImage(Image image, int x, int y);
465
+}
466

    
467
=== added file 'src/com/goldencode/p2j/ui/client/gui/driver/web/VirtualScreenImpl.java'
468
--- src/com/goldencode/p2j/ui/client/gui/driver/web/VirtualScreenImpl.java	1970-01-01 00:00:00 +0000
469
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/VirtualScreenImpl.java	2015-08-07 20:11:48 +0000
470
@@ -0,0 +1,99 @@
471
+/*
472
+** Module   : VirtualScreenImpl.java
473
+** Abstract : Implements virtual screen functionalities.
474
+**
475
+** Copyright (c) 2015, Golden Code Development Corporation.
476
+** ALL RIGHTS RESERVED. Use is subject to license terms.
477
+**
478
+**         Golden Code Development Corporation
479
+**                 CONFIDENTIAL
480
+**
481
+** -#- -I- --Date-- --------------------------------Description----------------------------------
482
+** 001 SBI 20150807 First version which implements a virtual screen based on sRGB model.
483
+*/
484
+
485
+package com.goldencode.p2j.ui.client.gui.driver.web;
486
+
487
+import java.awt.Color;
488
+import java.awt.Graphics2D;
489
+import java.awt.Image;
490
+import java.awt.image.BufferedImage;
491
+import java.awt.image.DataBuffer;
492
+import java.awt.image.DataBufferInt;
493
+import java.awt.image.DirectColorModel;
494
+import java.awt.image.Raster;
495
+import java.awt.image.SampleModel;
496
+import java.awt.image.SinglePixelPackedSampleModel;
497
+import java.awt.image.WritableRaster;
498
+
499
+
500
+/**
501
+ * 
502
+ * VirtualScreenImpl is an implementation of VirtualScreen drawings operations.
503
+ *
504
+ */
505
+class VirtualScreenImpl implements VirtualScreen
506
+{
507
+
508
+   private final DirectColorModel colorModel;
509
+   private final int width;
510
+   private final int height;
511
+   private final int[] pixels;
512
+   private final BufferedImage screen;
513
+
514
+   /**
515
+    * Constructs a virtual screen of the given width and height
516
+    * based on the given pixels model.
517
+    * 
518
+    * @param colorModel DirectColorModel pixels model based on sRGB
519
+    * @param width int a screen width
520
+    * @param height int a screen height 
521
+    */
522
+   public VirtualScreenImpl(DirectColorModel colorModel, int width, int height)
523
+   {
524
+      this.colorModel = colorModel;
525
+      this.width = width;
526
+      this.height = height;
527
+      this.pixels = new int[width*height];
528
+      final DataBuffer data = new DataBufferInt(pixels, pixels.length);
529
+      final SampleModel sampleModel = new SinglePixelPackedSampleModel(
530
+               DataBuffer.TYPE_INT, width,  height, colorModel.getMasks());
531
+      final WritableRaster raster = Raster.createWritableRaster(sampleModel, data, null);
532
+      this.screen = new BufferedImage(colorModel, raster, true, null);
533
+   }
534
+
535
+   @Override
536
+   public int[] getPixels()
537
+   {
538
+      return pixels;
539
+   }
540
+
541
+   @Override
542
+   public int getScreenWidth()
543
+   {
544
+      return width;
545
+   }
546
+
547
+   @Override
548
+   public int getScreenHeight()
549
+   {
550
+      return height;
551
+   }
552
+
553
+   @Override
554
+   public DirectColorModel getColorModel()
555
+   {
556
+      return colorModel;
557
+   }
558
+
559
+   @Override
560
+   public void drawImage(Image image, int x, int y)
561
+   {
562
+      Graphics2D g2 = screen.createGraphics();
563
+      g2.setColor(new Color(0,0,0));
564
+      g2.fillRect(0, 0, getScreenWidth(), getScreenHeight());
565
+      g2.drawImage(image, x, y, null);
566
+      g2.dispose();
567
+   }
568
+
569
+}
570

    
571
=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.screen.js'
572
--- src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.screen.js	2015-07-30 23:09:31 +0000
573
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.screen.js	2015-08-07 20:31:16 +0000
574
@@ -14,6 +14,7 @@
575
 **                  ChUI). Moved some logic to common code locations.
576
 ** 002 SBI 20150731 Applied "use strict" directive, fixed undeclared variables.
577
 ** 003 GES 20150720 Total rewrite to implement a first pass at GUI support.
578
+** 004 SBI 20150807 Added a drawing image operation
579
 */
580
 
581
 "use strict";
582
@@ -32,6 +33,11 @@
583
    /** List of active windows. */
584
    var winlist = new Array();
585
 
586
+   /**
587
+    * Loaded images map
588
+    */
589
+   var loadedImages = new Map();
590
+   
591
    /** Normal canvas font. */
592
    var font;
593
 
594
@@ -352,6 +358,37 @@
595
                drawRoundRect(ctx, x, y, width, height, diameter, this.rawColor, false);
596
                break;
597
             case ops.DRAW_IMAGE:
598
+               //console.debug("drawing type: " + message[idx]);
599
+               x = p2j.socket.readInt32BinaryMessage(message, idx + 1);
600
+               y = p2j.socket.readInt32BinaryMessage(message, idx + 5);
601
+               width = p2j.socket.readInt32BinaryMessage(message, idx + 9);
602
+               height = p2j.socket.readInt32BinaryMessage(message, idx + 13);
603
+               //console.debug(x + "x" + y + ", " + width + "x" + height);
604
+               var encoding = message[idx + 17];
605
+               //console.debug("encoding type: " + encoding);
606
+               var key = p2j.socket.readInt32BinaryMessage(message, idx + 18);
607
+               console.debug("hash: " + key);
608
+               var img = ctx.createImageData(width, height);
609
+               var data = img.data;
610
+               var pixelsInBytes = width * height * 4;
611
+               var imgData;
612
+               var imgDataOffset;
613
+               if(loadedImages.has(key)) {
614
+                  imgData = loadedImages.get(key);
615
+                  imgDataOffset = 0;
616
+               } else {
617
+                  imgData = message;
618
+                  imgDataOffset = idx + 22;
619
+                  loadedImages.set(key, message.subarray(imgDataOffset, imgDataOffset + pixelsInBytes));
620
+               }
621
+               for (var i = 0, j = imgDataOffset; i < pixelsInBytes; i += 4, j += 4) {
622
+                   data[i]     = imgData[j];
623
+                   data[i + 1] = imgData[j + 1];
624
+                   data[i + 2] = imgData[j + 2];
625
+                   data[i + 3] = imgData[j + 3];
626
+               }
627
+               ctx.putImageData(img, x, y);
628
+
629
                break;
630
             case ops.FILL_RECT:
631
                x      = p2j.socket.readInt32BinaryMessage(message, idx + 1);
632