Recent

Author Topic: BGRABitmap.js  (Read 9012 times)

lainz

  • Hero Member
  • *****
  • Posts: 3313
    • Lainz
BGRABitmap.js
« on: June 12, 2016, 08:10:08 pm »
« Last Edit: June 16, 2016, 03:10:08 pm by lainz »

Phil

  • Hero Member
  • *****
  • Posts: 2750
Re: BGRABitmap.js
« Reply #1 on: June 12, 2016, 09:06:12 pm »
Have you given any thought to how the client-side JavaScript UI code will be created? For example, will some or all of it be generated automatically and/or dynamically on the server, or will all of it be written manually?

Also, would you use only the classes supplied by the browser or will you integrate one of the mature JavaScript frameworks (qooxdoo, ExtJS, etc.)?

-Phil

lainz

  • Hero Member
  • *****
  • Posts: 3313
    • Lainz
Re: BGRABitmap.js
« Reply #2 on: June 12, 2016, 09:26:43 pm »
At this stage I'm not even sure if the way I'm doing the Assign(canvas) is sufficient to incorpore all BGRABitmap methods further.

The idea about the generation is to provide the same functionallity that comes with BGRABitmap to canvas element. If I use BGRABitmap directly on a server I can generate the output bitmap with no need of this. The usage of this is in an scenario of a web app or something like that.

About the classes, I think we need only to provide BGRABitmap class and nothing more, is up to the user to use other frameworks. But is only my point of view.

I'm open to ideas since this is a draft.

Phil

  • Hero Member
  • *****
  • Posts: 2750
Re: BGRABitmap.js
« Reply #3 on: June 12, 2016, 09:39:07 pm »
The now-abandoned ExtPascal generated ExtJS-based JavaScript dynamically in response to user events, sending this JS to the browser in order to update the UI. ExtPascal also had an optional package for Lazarus that provided "design" controls for the corresponding ExtPascal classes (which in turn corresponded to the underlying ExtJS classes. This allowed the Web app UI to be visually designed to some extent in Lazarus.

The final version of ExtPascal is here:

https://github.com/farshadmohajeri/extpascal

The natural successor to ExtPascal is something like UniGui, which also uses "design" controls when laying out the page to set properties, etc. of the actual server-side controls. UniGui is Delphi and Windows only, but the on-line demos and list of controls and features might provide some food for thought:

http://www.unigui.com/

There was much to like about ExtPascal, but I think it suffered from several design problems that manifested themselves once you got apps beyond the trivial stage:

(1) You ended up still writing some JS and "emitting" it from the server-side Pascal app, meaning now you have to know when and where the dynamically generated JS is being sent.

(2) Server and client side logic gets combined, like in the worst kind of VCL/LCL app where all the UI, db and program logic is in the form classes.

(3) Because a pixel-oriented UI designer is used, apps didn't have the modern Web (and mobile) feel, where the UI elements just flow and fill in "naturally" the available space, meaning the app looks good in mobile and desktop browsers both.

-Phil

circular

  • Hero Member
  • *****
  • Posts: 3053
    • Personal webpage
Re: BGRABitmap.js
« Reply #4 on: June 12, 2016, 09:57:21 pm »
I guess it is worth exploring the idea of stored images, not necessarily drawn directly on the canvas. Also take into account that one of the feature of BGRABitmap is to allow to use another bitmap as a brush. Not sure how that would be done in javascript.
Conscience is the debugger of the mind

Phil

  • Hero Member
  • *****
  • Posts: 2750
Re: BGRABitmap.js
« Reply #5 on: June 12, 2016, 10:17:32 pm »
Most modern JS frameworks provide a way that you can easily and dynamically "bind" a UI image control to a server-side image file. All you need is a URL to the image file. Eg, with qooxdoo:

http://demo.qooxdoo.org/current/apiviewer/#qx.ui.basic.Image

-Phil

lainz

  • Hero Member
  • *****
  • Posts: 3313
    • Lainz
Re: BGRABitmap.js
« Reply #6 on: June 13, 2016, 01:05:06 am »
Hi circular, I think I understand what you say.

Now I coded this: As you can see there is an ImageData private declaration that holds the bitmap with no need of a canvas element.

Then there is a Fill function that go through the pixels and fills them with each channel.

Then there is a Draw function that will draw the content to a canvas element.

This is the typescript source:

Code: Javascript  [Select]
  1. class BGRABitmap {
  2.     private data: ImageData;
  3.  
  4.     constructor(width: number, height: number) {
  5.         this.data = new ImageData(width, height);
  6.     }
  7.    
  8.     Fill(red, green, blue, alpha) {
  9.         for (var i = 0; i < this.data.data.length; i+= 4) {
  10.             this.data.data[i] = red;
  11.             this.data.data[i + 1] = green;
  12.             this.data.data[i + 2] = blue;
  13.             this.data.data[i + 3] = alpha;
  14.         }
  15.     }
  16.    
  17.     Draw(canvas: HTMLCanvasElement, x: number, y: number) {
  18.         canvas.getContext('2d').putImageData(this.data, x, y);
  19.     }
  20. }

This is the compiled js:

Code: Text  [Select]
  1. var BGRABitmap = (function () {
  2.     function BGRABitmap(width, height) {
  3.         this.data = new ImageData(width, height);
  4.     }
  5.     BGRABitmap.prototype.Fill = function (red, green, blue, alpha) {
  6.         for (var i = 0; i < this.data.data.length; i += 4) {
  7.             this.data.data[i] = red;
  8.             this.data.data[i + 1] = green;
  9.             this.data.data[i + 2] = blue;
  10.             this.data.data[i + 3] = alpha;
  11.         }
  12.     };
  13.     BGRABitmap.prototype.Draw = function (canvas, x, y) {
  14.         canvas.getContext('2d').putImageData(this.data, x, y);
  15.     };
  16.     return BGRABitmap;
  17. }());
  18.  
  19.  

And is used as this:

Code: Text  [Select]
  1. <!DOCTYPE html>
  2. <html>
  3.     <head>
  4.         <meta charset="utf-8">
  5.         <title>BGRABitmap.js</title>
  6.         <script src="bgrabitmap.js"></script>
  7.         <script>
  8.         function draw() {
  9.             var canvas = document.getElementById('canvas');
  10.  
  11.             var bmp = new BGRABitmap(150, 150);
  12.             bmp.Fill(255, 0, 0, 255);
  13.             bmp.Draw(canvas, 0, 0);
  14.         }
  15.         </script>
  16.     </head>
  17.     <body onload="draw();">
  18.         <canvas id="canvas" width="150" height="150"></canvas>
  19.     </body>
  20. </html>

ImageData is this:
https://developer.mozilla.org/en-US/docs/Web/API/ImageData

And I think BGRAPixel should be
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray
« Last Edit: June 13, 2016, 03:01:50 am by lainz »

lainz

  • Hero Member
  • *****
  • Posts: 3313
    • Lainz
Re: BGRABitmap.js
« Reply #7 on: June 13, 2016, 04:27:59 pm »
Hi again, I've improved it adding BGRAPixel:

Edit: also added BGRA function.

TypeScript source:

Code: Javascript  [Select]
  1. class BGRAPixel {
  2.     private data: Uint8ClampedArray;
  3.  
  4.     constructor(red: number, green: number, blue: number, alpha: number) {
  5.         this.data = new Uint8ClampedArray(4);
  6.         this.red = red;
  7.         this.green = green;
  8.         this.blue = blue;
  9.         this.alpha = alpha;
  10.     }
  11.  
  12.     public get red() : number {
  13.         return this.data[0];
  14.     }
  15.    
  16.     public get green() : number {
  17.         return this.data[1];
  18.     }
  19.  
  20.     public get blue() : number {
  21.         return this.data[2];
  22.     }
  23.  
  24.     public get alpha() : number {
  25.         return this.data[3];
  26.     }
  27.    
  28.     public set red(v : number) {
  29.         this.data[0] = v;
  30.     }
  31.  
  32.     public set green(v : number) {
  33.         this.data[1] = v;
  34.     }
  35.  
  36.     public set blue(v : number) {
  37.         this.data[2] = v;
  38.     }
  39.  
  40.     public set alpha(v : number) {
  41.         this.data[3] = v;
  42.     }
  43. }
  44.  
  45. function BGRA(red: number, green: number, blue: number, alpha: number) {
  46.     return new BGRAPixel(red, green, blue, alpha);
  47. }
  48.  
  49. class BGRABitmap {
  50.     private data: ImageData;
  51.  
  52.     constructor(width: number, height: number) {
  53.         this.data = new ImageData(width, height);
  54.     }
  55.    
  56.     Fill(color: BGRAPixel) {
  57.         for (var i = 0; i < this.data.data.length; i+= 4) {
  58.             this.data.data[i] = color.red;
  59.             this.data.data[i + 1] = color.green;
  60.             this.data.data[i + 2] = color.blue;
  61.             this.data.data[i + 3] = color.alpha;
  62.         }
  63.     }
  64.    
  65.     Draw(canvas: HTMLCanvasElement, x: number, y: number) {
  66.         canvas.getContext('2d').putImageData(this.data, x, y);
  67.     }
  68. }

Compiled JavaScript:

Code: Javascript  [Select]
  1. var BGRAPixel = (function () {
  2.     function BGRAPixel(red, green, blue, alpha) {
  3.         this.data = new Uint8ClampedArray(4);
  4.         this.red = red;
  5.         this.green = green;
  6.         this.blue = blue;
  7.         this.alpha = alpha;
  8.     }
  9.     Object.defineProperty(BGRAPixel.prototype, "red", {
  10.         get: function () {
  11.             return this.data[0];
  12.         },
  13.         set: function (v) {
  14.             this.data[0] = v;
  15.         },
  16.         enumerable: true,
  17.         configurable: true
  18.     });
  19.     Object.defineProperty(BGRAPixel.prototype, "green", {
  20.         get: function () {
  21.             return this.data[1];
  22.         },
  23.         set: function (v) {
  24.             this.data[1] = v;
  25.         },
  26.         enumerable: true,
  27.         configurable: true
  28.     });
  29.     Object.defineProperty(BGRAPixel.prototype, "blue", {
  30.         get: function () {
  31.             return this.data[2];
  32.         },
  33.         set: function (v) {
  34.             this.data[2] = v;
  35.         },
  36.         enumerable: true,
  37.         configurable: true
  38.     });
  39.     Object.defineProperty(BGRAPixel.prototype, "alpha", {
  40.         get: function () {
  41.             return this.data[3];
  42.         },
  43.         set: function (v) {
  44.             this.data[3] = v;
  45.         },
  46.         enumerable: true,
  47.         configurable: true
  48.     });
  49.     return BGRAPixel;
  50. }());
  51. function BGRA(red, green, blue, alpha) {
  52.     return new BGRAPixel(red, green, blue, alpha);
  53. }
  54. var BGRABitmap = (function () {
  55.     function BGRABitmap(width, height) {
  56.         this.data = new ImageData(width, height);
  57.     }
  58.     BGRABitmap.prototype.Fill = function (color) {
  59.         for (var i = 0; i < this.data.data.length; i += 4) {
  60.             this.data.data[i] = color.red;
  61.             this.data.data[i + 1] = color.green;
  62.             this.data.data[i + 2] = color.blue;
  63.             this.data.data[i + 3] = color.alpha;
  64.         }
  65.     };
  66.     BGRABitmap.prototype.Draw = function (canvas, x, y) {
  67.         canvas.getContext('2d').putImageData(this.data, x, y);
  68.     };
  69.     return BGRABitmap;
  70. }());
  71.  

Usage:

Code: Text  [Select]
  1. <!DOCTYPE html>
  2. <html>
  3.     <head>
  4.         <meta charset="utf-8">
  5.         <title>BGRABitmap.js</title>
  6.         <script src="bgrabitmap.js"></script>
  7.         <script>
  8.         function draw() {
  9.             var canvas = document.getElementById('canvas');
  10.  
  11.             var bmp = new BGRABitmap(150, 150);
  12.             bmp.Fill(BGRA(255, 0, 0, 255));
  13.             bmp.Draw(canvas, 0, 0);
  14.         }
  15.         </script>
  16.     </head>
  17.     <body onload="draw();">
  18.         <canvas id="canvas" width="150" height="150"></canvas>
  19.     </body>
  20. </html>
« Last Edit: June 13, 2016, 05:10:15 pm by lainz »

lainz

  • Hero Member
  • *****
  • Posts: 3313
    • Lainz
Re: BGRABitmap.js
« Reply #8 on: June 13, 2016, 10:27:26 pm »
Well, I found that I must create all stuff that is used by BGRABitmap too, like TRect for example. No pointers (i'm using numbers, see the source code). Enums also must be objects holding the name and value, there is no enumeration type (OMG TypeScript has it). I think also all string functions used by this library and all LCL / RTL code that does not come with JavaScript.

So is harder than actually looks. I'll continue playing with it in a repository to keep changes at least i'm learning how BGRABitmap works.

Repository is here:
https://github.com/bgrabitmap/bgrabitmap.js

Don't worry too much about it. :)
« Last Edit: June 13, 2016, 11:08:41 pm by lainz »

circular

  • Hero Member
  • *****
  • Posts: 3053
    • Personal webpage
Re: BGRABitmap.js
« Reply #9 on: June 14, 2016, 12:11:38 am »
@lainz:

Using ImageData is indeed the idea I was thinking about.

Then we can have a Canvas as well inside the bitmap. Like this:

Typescript library
Code: Javascript  [Select]
  1.     class BGRAPixel {
  2.         private raw: Uint8ClampedArray;
  3.      
  4.         constructor(red: number, green: number, blue: number, alpha: number) {
  5.             this.raw = new Uint8ClampedArray(4);
  6.             this.red = red;
  7.             this.green = green;
  8.             this.blue = blue;
  9.             this.alpha = alpha;
  10.         }
  11.      
  12.         public get red() : number {
  13.             return this.raw[0];
  14.         }
  15.        
  16.         public get green() : number {
  17.             return this.raw[1];
  18.         }
  19.      
  20.         public get blue() : number {
  21.             return this.raw[2];
  22.         }
  23.      
  24.         public get alpha() : number {
  25.             return this.raw[3];
  26.         }
  27.        
  28.         public set red(v : number) {
  29.             this.raw[0] = v;
  30.         }
  31.      
  32.         public set green(v : number) {
  33.             this.raw[1] = v;
  34.         }
  35.      
  36.         public set blue(v : number) {
  37.             this.raw[2] = v;
  38.         }
  39.      
  40.         public set alpha(v : number) {
  41.             this.raw[3] = v;
  42.         }
  43.        
  44.         toString(): string
  45.         {
  46.             return "BGRA(" + this.red + "," + this.green + "," + this.blue + "," + this.alpha + ")";
  47.         }        
  48.        
  49.         Equals(other: BGRAPixel): boolean
  50.         {
  51.             return other === this || (other.alpha == 0 && this.alpha == 0) ||
  52.                 (other.red == this.red && other.green == this.green && other.green == this.green && other.blue == this.blue);
  53.         }
  54.     }
  55.      
  56.     function BGRA(red: number, green: number, blue: number, alpha: number) {
  57.         return new BGRAPixel(red, green, blue, alpha == undefined ? 255 : alpha);
  58.     }    
  59.    
  60.     class Rectangle {
  61.         private raw: Int32Array;
  62.      
  63.         constructor(left: number, top: number, right: number, bottom: number) {
  64.             this.raw = new Int32Array(4);
  65.             this.Left = left;
  66.             this.Top = top;
  67.             this.Right = right;
  68.             this.Bottom = bottom;
  69.         }
  70.      
  71.         public get Left() : number {
  72.             return this.raw[0];
  73.         }
  74.        
  75.         public get Top() : number {
  76.             return this.raw[1];
  77.         }
  78.      
  79.         public get Right() : number {
  80.             return this.raw[2];
  81.         }
  82.      
  83.         public get Bottom() : number {
  84.             return this.raw[3];
  85.         }
  86.        
  87.         public set Left(v : number) {
  88.             this.raw[0] = Math.floor(v);
  89.         }
  90.      
  91.         public set Top(v : number) {
  92.             this.raw[1] = Math.floor(v);
  93.         }
  94.      
  95.         public set Right(v : number) {
  96.             this.raw[2] = Math.floor(v);
  97.         }
  98.      
  99.         public set Bottom(v : number) {
  100.             this.raw[3] = Math.floor(v);
  101.         }
  102.        
  103.         public get Empty(): boolean
  104.         {
  105.             return (this.Left == this.Right && this.Top == this.Bottom);
  106.         }
  107.        
  108.         Contains(x: number, y: number): boolean
  109.         {
  110.             return x >= this.Left && y >= this.Top && x < this.Right && y < this.Bottom;
  111.         }
  112.        
  113.         toString(): string
  114.         {
  115.             return "Rect(" + this.Left + "," + this.Top + "," + this.Right + "," + this.Bottom + ")";
  116.         }
  117.        
  118.         Clone(): Rectangle
  119.         {
  120.             return new Rectangle(this.Left,this.Top,this.Right,this.Bottom);
  121.         }        
  122.        
  123.         Intersect(other: Rectangle): boolean
  124.         {
  125.             if (other.Left > this.Right ||
  126.                 other.Right < this.Left ||
  127.                 other.Top > this.Bottom ||
  128.                 other.Bottom < this.Top)
  129.             {
  130.                 this.Left = 0;
  131.                 this.Right = 0;
  132.                 this.Top = 0;
  133.                 this.Bottom = 0;
  134.                 return false;
  135.             }
  136.             else
  137.             {
  138.                 if (other.Left > this.Left) this.Left = other.Left;
  139.                 if (other.Top > this.Top) this.Top = other.Top;
  140.                 if (other.Right < this.Right) this.Right = other.Right;
  141.                 if (other.Bottom < this.Bottom) this.Bottom = other.Bottom;
  142.                 return true;
  143.             }
  144.         }
  145.        
  146.         Equals(other: Rectangle): boolean
  147.         {
  148.             return other === this || (other.Empty && this.Empty) ||
  149.                 (other.Left == this.Left && other.Top == this.Top && other.Right == this.Right && other.Bottom == this.Bottom);
  150.         }
  151.     }    
  152.    
  153.     function Rect(left: number, top: number, right: number, bottom: number) {
  154.         return new Rectangle(left,top,right,bottom);
  155.     }  
  156.  
  157.     class BGRABitmap {
  158.         private raw: ImageData;
  159.         private rawModified: boolean;
  160.         private canvas: HTMLCanvasElement;
  161.         private canvasModified: boolean;
  162.         private clipRect: Rectangle;
  163.         private rowStride: number;
  164.      
  165.         constructor(canvas: HTMLCanvasElement, width: number, height: number) {            
  166.             this.raw = canvas.getContext('2d').createImageData(width == undefined ? canvas.width : width, height == undefined ? canvas.height : height);
  167.             this.rawModified = false;
  168.             this.canvas = null;
  169.             this.canvasModified = false;
  170.             this.clipRect = Rect(0,0,this.Width,this.Height);
  171.             this.rowStride = this.Width*4;
  172.         }
  173.        
  174.         public get Width() : number {
  175.             return this.raw.width;
  176.         }
  177.  
  178.         public get Height() : number {
  179.             return this.raw.height;
  180.         }
  181.        
  182.         public get Data() : ImageData {
  183.             if (this.canvasModified&&(this.canvas!=null))
  184.             {
  185.                 this.raw = this.canvas.getContext('2d').getImageData(0,0,this.Width,this.Height);
  186.                 this.canvasModified = false;
  187.             }    
  188.             return this.raw;
  189.         }
  190.        
  191.         public get ClipRect(): Rectangle {
  192.             return this.clipRect;
  193.         }
  194.        
  195.         public set ClipRect(v : Rectangle) {
  196.             let newClip = v.Clone();
  197.             newClip.Intersect(Rect(0,0,this.Width,this.Height));
  198.             if (!newClip.Equals(this.clipRect))
  199.                 this.clipRect = newClip;                
  200.         }
  201.        
  202.         NoClip() {
  203.             this.ClipRect = Rect(0,0,this.Width,this.Height);
  204.         }
  205.        
  206.         GetDataOffset(x,y: number): number
  207.         {
  208.             return Math.floor(y)*this.rowStride + Math.floor(x)*4;
  209.         }        
  210.        
  211.         public get CanvasElement(): HTMLCanvasElement {
  212.             if (this.canvas==null)
  213.             {
  214.                 this.canvas = document.createElement("canvas");
  215.                 this.canvas.width = this.Width;
  216.                 this.canvas.height = this.Height;                
  217.             }
  218.             if (this.rawModified)
  219.             {
  220.                 let ctx = this.canvas.getContext('2d');
  221.                 ctx.clearRect(0,0,this.Width,this.Height);
  222.                 ctx.putImageData(this.raw,0,0);
  223.                 this.rawModified = false;
  224.             }
  225.             return this.canvas;
  226.         }
  227.        
  228.         public get Canvas2D(): CanvasRenderingContext2D {            
  229.             this.canvasModified = true;
  230.             return this.CanvasElement.getContext('2d');
  231.         }
  232.        
  233.         Fill(color: BGRAPixel) {
  234.             let data = this.Data;
  235.             for (var i = 0; i < data.data.length; i+= 4) {
  236.                 data.data[i] = color.red;
  237.                 data.data[i + 1] = color.green;
  238.                 data.data[i + 2] = color.blue;
  239.                 data.data[i + 3] = color.alpha;
  240.             }
  241.             this.InvalidateBitmap();
  242.         }
  243.        
  244.         SetPixel(x: number, y:number, color: BGRAPixel)
  245.         {
  246.             if (!this.clipRect.Contains(x,y)) return;
  247.             let data = this.Data;
  248.             let offset = this.GetDataOffset(x,y);
  249.             data.data[offset] = color.red;
  250.             data.data[offset+1] = color.green;
  251.             data.data[offset+2] = color.blue;
  252.             data.data[offset+3] = color.alpha;
  253.             this.InvalidateBitmap();
  254.         }
  255.        
  256.         SetHorizLine(x: number, y: number, x2: number, color: BGRAPixel)
  257.         {
  258.             if (y < this.clipRect.Top || y >= this.clipRect.Bottom+1) return;
  259.             if (x2<x)
  260.             {
  261.                 let temp = x;
  262.                 x = x2;
  263.                 x2 = temp;
  264.             }    
  265.             if (x >= this.clipRect.Right || x2 < this.clipRect.Left) return;
  266.             if (x < this.clipRect.Left) x = this.clipRect.Left;
  267.             if (x2 > this.clipRect.Right) x2 = this.clipRect.Right;
  268.             let data = this.Data;
  269.             let offset = this.GetDataOffset(x,y);
  270.             let red = color.red, green = color.green, blue = color.blue, alpha = color.alpha;
  271.             while (x<=x2)
  272.             {
  273.                 data.data[offset] = red;
  274.                 data.data[offset+1] = green;
  275.                 data.data[offset+2] = blue;
  276.                 data.data[offset+3] = alpha;    
  277.                 offset += 4;
  278.                 x += 1;
  279.             }
  280.         }
  281.        
  282.         SetVertLine(x: number, y: number, y2: number, color: BGRAPixel)
  283.         {
  284.             if (x < this.clipRect.Left || x >= this.clipRect.Right+1) return;
  285.             if (y2<y)
  286.             {
  287.                 let temp = y;
  288.                 y = y2;
  289.                 y2 = temp;
  290.             }    
  291.             if (y >= this.clipRect.Bottom || y2 < this.clipRect.Top) return;
  292.             if (y < this.clipRect.Top) y = this.clipRect.Top;
  293.             if (y2 > this.clipRect.Bottom) y2 = this.clipRect.Bottom;            
  294.             let data = this.Data;
  295.             let offset = this.GetDataOffset(x,y);
  296.             let red = color.red, green = color.green, blue = color.blue, alpha = color.alpha;
  297.             while (y<=y2)
  298.             {
  299.                 data.data[offset] = red;
  300.                 data.data[offset+1] = green;
  301.                 data.data[offset+2] = blue;
  302.                 data.data[offset+3] = alpha;    
  303.                 offset += this.rowStride;
  304.                 y += 1;
  305.             }
  306.         }
  307.        
  308.         SetRectangle(x: number, y: number, x2: number, y2: number, color: BGRAPixel)
  309.         {
  310.             if (y == y2) { this.SetHorizLine(x,y,x2,color); return; }
  311.             if (x == x2) { this.SetVertLine(x,y,y2,color); return; }
  312.             if (y>y2)
  313.             {
  314.                 let temp = y;
  315.                 y = y2;
  316.                 y2 = y;
  317.             }
  318.             this.SetHorizLine(x,y,x2,color);
  319.             this.SetHorizLine(x,y2,x2,color);
  320.             this.SetVertLine(x,y+1,y2-1,color);
  321.             this.SetVertLine(x2,y+1,y2-1,color);
  322.         }
  323.        
  324.         InvalidateBitmap() {
  325.             this.rawModified = true;
  326.         }
  327.        
  328.         Draw(canvas: HTMLCanvasElement, x: number, y: number) {
  329.             canvas.getContext('2d').putImageData(this.Data, x, y);
  330.         }
  331.     }

Test HTML
Code: Javascript  [Select]
  1. <!DOCTYPE html>
  2. <html>
  3.     <head>
  4.         <meta charset="utf-8">
  5.         <title>BGRABitmap.js</title>
  6.         <script src="bgrabitmap.js"></script>
  7.         <script>
  8.         function draw() {
  9.             var canvas = document.getElementById('canvas');
  10.  
  11.             var bmp = new BGRABitmap(canvas);
  12.            
  13.             bmp.Fill(BGRA(255, 0, 0));
  14.  
  15.             for (var x=0; x < bmp.Width; x++)
  16.               bmp.SetPixel(x,0, BGRA(x,x,x));
  17.            
  18.             var ctx = bmp.Canvas2D;
  19.             ctx.beginPath();
  20.             ctx.moveTo(20,20);
  21.             ctx.lineTo(120,20);
  22.             ctx.lineTo(120,120);
  23.             ctx.closePath();
  24.             ctx.stroke();
  25.            
  26.             bmp.ClipRect = Rect(0,0,bmp.Width/2,bmp.Height);
  27.             bmp.SetRectangle(1,1,bmp.Width-2,bmp.Height-2, BGRA(0,255,0));
  28.             bmp.NoClip();
  29.            
  30.             bmp.SetRectangle(5,5,bmp.Width-6,bmp.Height-6, BGRA(255,255,0));
  31.            
  32.             bmp.Draw(canvas, 0, 0);
  33.         }
  34.         </script>
  35.     </head>
  36.     <body onload="draw();">
  37.         <canvas id="canvas" width="150" height="150"></canvas>
  38.     </body>
  39. </html>
Conscience is the debugger of the mind

lainz

  • Hero Member
  • *****
  • Posts: 3313
    • Lainz
Re: BGRABitmap.js
« Reply #10 on: June 14, 2016, 02:23:58 am »
Thanks!
« Last Edit: June 14, 2016, 08:40:29 pm by lainz »

lainz

  • Hero Member
  • *****
  • Posts: 3313
    • Lainz
Re: BGRABitmap.js
« Reply #11 on: June 15, 2016, 07:21:54 pm »
Hi circular, please check the newest test.html I've added some code that breaks the flow of the bitmap.

I can't mix several times context and bitmap functions because all drawings are not appearing.

circular

  • Hero Member
  • *****
  • Posts: 3053
    • Personal webpage
Re: BGRABitmap.js
« Reply #12 on: June 15, 2016, 07:44:48 pm »
Ah indeed, there a was missing call to InvalidateBitmap at the end of Horiz and VertLine functions. Fixed on Git.

By the way, nice rendering of the toolbar! :)

Note that in all cases, you need to query the property Canvas2D when you want to use it after you draw with the BGRA functions. So for example, you can store a ctx variable and use it a few times, but it needs to be reloaded after you use SetHorizLine.

In your example, there is no drawing using the ctx variable after the HorizLine so it is ok.
« Last Edit: June 15, 2016, 07:47:54 pm by circular »
Conscience is the debugger of the mind

lainz

  • Hero Member
  • *****
  • Posts: 3313
    • Lainz
Re: BGRABitmap.js
« Reply #13 on: June 15, 2016, 08:15:53 pm »
Thanks.

BTW how you minified the file? Because when I minify the variable names are long, but when you minify variables are changed to single letters...

circular

  • Hero Member
  • *****
  • Posts: 3053
    • Personal webpage
Re: BGRABitmap.js
« Reply #14 on: June 15, 2016, 08:24:55 pm »
I used this website to minify:
https://marijnhaverbeke.nl/uglifyjs
Conscience is the debugger of the mind