JavaScript Canvas Bit Manipulation
Written by Ian Elliot   
Monday, 09 August 2021
Article Index
JavaScript Canvas Bit Manipulation
Beyond 32 Bits

largecover360

Beyond 32 Bits

So what exactly happens if you try to work with bitwise operators on values that aren't representable as 32-bit integers? To do this the JavaScript interpreter calls the internal ToInt32 function, which you can't use in your programs. This performs an "intelligent" conversion to a 32-bit integer with the following restrictions:

  • It truncates all fractional parts.

  • If the value is larger than what a 32-bit integer can store then the result is 32 bits all set to 1, i.e. -1 in two’s complement.

  • If the value is a fraction smaller than 1 then the result is 0.

  • If the value is infinity (plus or minus) or NaN, (Not a Number) then the result is 0.

You will also be pleased to learn that, as true evaluates to 1 and false to 0, you can use the bitwise logical operators on Boolean values as long as you remember that true is 1 and false 0. For example:

var c = 0xF & (1===1);

is 1 as (1===1) evaluates to 0x01. However, notice that due to JavaScript’s use of the idea of truthy or falsey, values that are considered to be true can be any non-zero value.

The only real problem with JavaScript's bitwise operators is that, due to the restriction to 32 bits, they are not especially fast because of the need to be converted from floating point double precision to 32-bit integer and then back again.

Masks

So what do you use the bitwise logical operators for?

You often encounter the problem of setting or clearing particular bits in a value. The value is usually stored in a variable that is usually regarded as a status variable or flag. You can set and unset bits in a flag using another value usually called a mask that defines the bits to be changed. For example, if you only want to change the first (least significant) bit then the mask would be 0x01. If you wanted to change the first and second bits the mask would be 0x03 and so on.

To work out the correct hexadecimal value needed for any particular mask, you can use the parseInt function with a radix of 2. For example:

a=parseInt("1",2);

sets a to 0x01 and:

a=parseInt("11",2);

sets a to 0x03 and so on.

In general, just write down a string of 0s and 1s with a 1 in the positions you want to change and use parseInt to convert it to a mask value.

Now that you have a mask what do you do with it?

Suppose the mask contains a value that in binary has a 1 at each bit location you want to change. Then:

flag | mask;

returns a bit pattern with the bits that the mask specifies set to 1. Notice that the bits that the mask doesn't specify are left at their original values. This is often expressed as the mask sets the bits it specifies.

For example:

var mask=parseInt("11",2);
var flag = 0xFFF0;
var result = flag | mask;

sets result to 0xFFF3, i.e. it sets the first (least significant) two bits.

If you use:

flag & ~mask;

then the bits specified in the mask are set to 0 - or unset if you prefer. Notice that you have to apply a NOT operator to the mask.

For example:

var mask=parseInt("11",2);
var flag = 0xFFFF;
var result = flag & ~mask;

sets result to 0xFFFC, i.e. it unsets the first two bits.

As well as setting and unsetting particular bits, you might also want to "flip" specified bits, i.e. negate them so that if the bit was a 1 it is changed to a 0 and vice versa. You can do this using the XOR operator, so:

flag ^ mask

flips the bits specified by the mask.

For example:

var mask=parseInt("11",2);
var flag = 0xFFFF;
var result = flag ^ mask;
alert(result.toString(16));

sets result to 0xFFFC because it changes the lower two bits from 1s to 0s. Again, bits not specified by the mask are unaffected.

Of course, in each case you don't have to use a variable to specify the mask, you could just use a numeric literal.

For example, instead of:

var flag = 0xFFFF;
var result = flag ^ mask;

you can write:

var result = flag ^ 0xFFFF;

Also if you want to update the flag rather than derive a new result, you can use &=, |= and ^= to perform the update directly.

For example, instead of:

flag = flag | mask;

you can use: 

flag |= mask;

Using Masks

What sorts of things do you use masking operations for?

Often a low level API will require that particular bits in a status word are set or unset to make it operate in a particular way. However, this is unusual in JavaScript because it generally doesn't access lower level APIs. However, new developments like Canvas, WebGL and so on are changing this.

One of the best known uses of bit manipulation predates HTML5 - extracting the color codes from an RGB color value. For example:

var RGBcolor=0x010203;
var B=RGBcolor & 0x0000FF;
var G=RGBcolor & 0x00FF00;
var R=RGBcolor & 0xFF0000;

This takes an RGB value and splits it up into its components using appropriate masks.

The result is that you end up with 0x010000 stored in R, 0x000200 in G and 0x000003 in B. Notice that while the value of B is correct, R and G are incorrect and the bits need shifting to the right. This brings us to the use of the shift operators.

In Chapter but not in this extract

  • Shifting values
  • Testing a bit

Summary

  • As well as the usual logical operators, &&, ||, and !, there are also three bitwise operators, &, | and ~. These operate on each bit in a 32-bit word.

  • If you try to work with values outside of the range of 32-bits then you might get results you don’t expect.

  • Setting and unsetting bits is best thought of in terms of using a mask to specify which bits to change.

  • You can use parseInt to convert binary to a 32-bit value.

  • Masking is a common operating when trying to extract color values and other data from bitmaps.

  • The shift operators, >>, << and >>>, also allow you to move bits to a new location before further use.

  • The >> operator is an arithmetic shift right and it maintains the sign of the value shifted. The >>> is a logical shift right and it always shifts a 0 into the high order bit and doesn’t maintain the sign of the value.

  • You can use a mask to test if the specified bits are set or unset. There are a number of ways of doing this and it can be confusing. When testing bits it is very easy to make a mistake – always check your results.

Now available as a paperback or ebook from Amazon.

JavaScript Bitmap Graphics
With Canvas

largecover360

 

Contents

  1. JavaScript Graphics
  2. Getting Started With Canvas
  3. Drawing Paths
      Extract: Basic Paths
      Extract: SVG Paths
      Extract: Bezier Curves
  4. Stroke and Fill
      Extract: Stroke Properties 
      Extract: Fill and Holes
      Extract: Gradient & Pattern Fills
  5. Transformations
      Extract: Transformations
      Extract: Custom Coordinates 
      Extract  Graphics State
  6. Text
      Extract: Text, Typography & SVG 
      Extract: Unicode
  7. Clipping, Compositing and Effects
      Extract: Clipping & Basic Compositing
  8. Generating Bitmaps
      Extract:  Introduction To Bitmaps
      Extract :  Animation 
  9. WebWorkers & OffscreenCanvas
      Extract: Web Workers
      Extract: OffscreenCanvas
  10. Bit Manipulation In JavaScript
      Extract: Bit Manipulation
  11. Typed Arrays
      Extract: Typed Arrays 
  12. Files, blobs, URLs & Fetch
      Extract: Blobs & Files
      Extract: Read/Writing Local Files
      Extract: Fetch API **NEW!
  13. Image Processing
      Extract: ImageData
      Extract:The Filter API
  14. 3D WebGL
      Extract: WebGL 3D
  15. 2D WebGL
    Extract: WebGL Convolutions

<ASIN:B07XJQDS4Z>

<ASIN:1871962579>

<ASIN:1871962560>

To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.

espbook

 

Comments




or email your comment to: comments@i-programmer.info



Last Updated ( Monday, 09 August 2021 )