Demosaicing Script (JavaScript)

In this article:
We recommend reading Scripting in Application (JavaScript) first to learn the basics of scripting.
JavaScript is by far the slowest of the 3 languages. Running the same script, it is roughly 100 times slower than C# and 5 to 10 times slower than Python. The script runs again every time the image needs to be rendered, so please consider C# for a script which processes a large image.

Demosaicing Script

There is only one script in each demosaicing script, and it will be invoked one time every time when the image needs to be rendered. The script reads the mosaic from context.inputStream and writes the demosaiced BGRA pixels into context.outputStream.
The type of returned value is DemosaicingResult. Return DemosaicingResult.default after interpolating the mosaic.
The following is sample script to write the single color component provided by each pixel of the mosaic into all of the 3 color channels of that pixel, which produces a monochrome image:
if (context.format !== BitmapFormat.bgra32)
    throw new Error("Only 32-bit BGRA is supported by this script.");
var mosaic = context.selectNextSubMosaic();
while (mosaic) {
    var width = mosaic.width;
    var height = mosaic.height;
    var rowBytes = mosaic.rowBytes;
    var colorPattern = mosaic.colorPattern;
    var row = context.createByteArray(rowBytes);
    for (var y = 0; y < height; ++y) {
        mosaic.inputStream.position = y * rowBytes;
        mosaic.inputStream.readExactly(row, 0, rowBytes);
        var components = colorPattern[y & 1];
        for (var x = 0; x < width; ++x) {
            var offset = x * 4;
            var sample = row[offset + components[x & 1]];
            row[offset] = sample;
            row[offset + 1] = sample;
            row[offset + 2] = sample;
            row[offset + 3] = 255;
        }
        mosaic.outputStream.position = y * rowBytes;
        mosaic.outputStream.write(row, 0, rowBytes);
    }
    mosaic = context.selectNextSubMosaic();
}
return DemosaicingResult.default;
Each pixel of the mosaic provides only the single color component which colorPattern reports for its position. The other color channels of that pixel are undefined and must never be read.
The sample above assumes that context.format is bgra32, so each pixel is 4 bytes. Each pixel is 8 bytes and each color channel is a 16-bit integer when the format is bgra64.

Samples

The following is sample script to interpolate the mosaic by bilinear interpolation. It supports every pattern of Bayer Filter, it interpolates the mosaic in place, and it needs an image of bgra64 format: You can import the downloaded file through the dialog of managing demosaicing scripts.

Sub Mosaics

The mosaic of a 4x4 pattern of Bayer Filter is split into the 4 mosaics of the corresponding 2x2 pattern which its sub sampling positions carry, so that a script which interpolates a 2x2 mosaic is able to interpolate a 4x4 one as well. Each call of context.selectNextSubMosaic() interleaves the sub mosaic interpolated by the previous call back into the image before it hands the next one out, and it returns null once every sub mosaic has been interpolated.
The mosaic of a 2x2 pattern is not split, the context itself is handed out once as the only sub mosaic, so the same loop interpolates every pattern without checking bayerPattern first. The following are worth noticing while interpolating the sub mosaics:
  • The view of a sub mosaic and its streams are valid only until the next call of selectNextSubMosaic().
  • The width, the height and the number of bytes of a row of each sub mosaic are different from the ones of the image and from each other, so they must be read from the view inside the loop.
  • bayerPattern and colorPattern of every sub mosaic are the ones of the corresponding 2x2 pattern.
  • Leaving the loop before it completes is allowed. The sub mosaic which was interpolated last is still interleaved back, and the rest of the image is left opaque black.
Interpolating the sub mosaics is optional. A script which declares a 4x4 pattern and never calls selectNextSubMosaic() reads and writes the whole 4x4 mosaic through the members of context itself.

Namespaces

The following namespaces are included by default:
  • System.IO

Context

The following are members of Context other than basic members:
  • bayerPattern: BayerPattern
    Pattern of Bayer Filter which the mosaic is rendered with. The following are values defined in BayerPattern:
    • bggR_2x2
    • gbrG_2x2
    • grbG_2x2
    • rggB_2x2
    • bggR_4x4
    • gbrG_4x4
    • grbG_4x4
    • rggB_4x4
  • colorPattern: Array
    Color component provided by each pixel in color block of the pattern of Bayer Filter. The 1st dimension is the position in vertical direction, the 2nd dimension is the position in horizontal direction. The array belongs to the script, modifying it affects nothing but the script itself. The following are values defined in BayerPatternColorComponent, and the value of each of them is the offset of its color channel in a BGRA pixel, so the component selects the channel of pixel directly:
    • blue
    • green
    • red
    Each component is provided to the script as a plain number, so it can be used as an index of color channel directly.
  • createByteArray(count: number): Array
    Create an array of bytes for bulk reading from or writing to the streams provided by the context.
  • createUInt16Array(count: number): Array
    Create an array of 16-bit unsigned integers for bulk reading from or writing to the streams provided by the context.
  • createUInt32Array(count: number): Array
    Create an array of 32-bit unsigned integers for bulk reading from or writing to the streams provided by the context.
  • createUInt64Array(count: number): Array
    Create an array of 64-bit unsigned integers for bulk reading from or writing to the streams provided by the context.
  • format: BitmapFormat
    Format of the buffers which the mosaic is read from and the demosaiced image is written to. The following are values defined in BitmapFormat:
    • bgra32
    • bgra64
  • height: number
    Height of image in pixels.
  • inputStream: System.IO.Stream
    Stream to read the mosaic of image. The stream is read-only and fully seekable, and it is valid only during the demosaicing call. The pixel at (x, y) starts at y * rowBytes + x * (number of bytes of a pixel of format).
  • outputStream: System.IO.Stream
    Stream to write the demosaiced image. The stream is fully seekable and readable, and it addresses its pixels exactly as inputStream does. It is valid only during the demosaicing call.
  • renderingOptions: ImageRenderingOptions
    Options of rendering the image. The following are members of ImageRenderingOptions:
    • blueGain: number
    • byteOrdering: ByteOrdering
      Byte ordering of source image data. The following are values defined in ByteOrdering:
      • bigEndian
      • littleEndian
    • greenGain: number
    • redGain: number
  • rowBytes: number
    Number of bytes of each row of the buffers.
  • selectNextSubMosaic(): IMosaicView
    Select the next sub mosaic of the image to be interpolated, or return null if every sub mosaic has been interpolated. Please refer to Sub Mosaics for more information. The following are members of IMosaicView, which report the sub mosaic instead of the image but are otherwise the same as the members of Context above:
    • bayerPattern: BayerPattern
    • colorPattern: Array
    • format: BitmapFormat
    • height: number
    • inputStream: System.IO.Stream
    • outputStream: System.IO.Stream
    • rowBytes: number
    • width: number
  • width: number
    Width of image in pixels.
  • workingBufferStream: System.IO.Stream
    Stream to read and write the buffer which the script keeps its own intermediate result in. The stream is fully seekable and it is valid only during the demosaicing call. Its length is the number of pixels of the image multiplied by the working buffer size per pixel which the algorithm defines, which is 0 unless the algorithm defines otherwise. Its content is undefined on entry and is not cleared, so every part of it has to be written before it is read, and writing past its end fails rather than growing it. The same stream is provided throughout the call, including while a sub mosaic is selected, and it is not divided between the sub mosaics.
Interacting with user is not supported inside a demosaicing script, because the script runs on a background thread every time when the image needs to be rendered.

Stream Extensions

The following members are added to System.IO.Stream for reading and writing arrays of unsigned integers, which are needed to read and write the 16-bit color channels of a bgra64 image:
  • readUInt16(buffer: Array, offset: number, count: number): number
    Read at most count 16-bit unsigned integers from the stream into the given array, and return the number of integers actually read. A returned number which is less than count means that the end of stream has been reached.
  • readUInt16Exact(buffer: Array, offset: number, count: number): void
    Read the given number of 16-bit unsigned integers from the stream into the given array, and throw an error if the end of stream is reached first.
  • readUInt32(buffer: Array, offset: number, count: number): number
  • readUInt32Exact(buffer: Array, offset: number, count: number): void
  • readUInt64(buffer: Array, offset: number, count: number): number
  • readUInt64Exact(buffer: Array, offset: number, count: number): void
    The 32-bit and 64-bit versions of the members above.
  • writeUInt16(buffer: Array, offset: number, count: number): void
    Write the given number of 16-bit unsigned integers in the given array to the stream.
  • writeUInt32(buffer: Array, offset: number, count: number): void
  • writeUInt64(buffer: Array, offset: number, count: number): void
    The 32-bit and 64-bit versions of writeUInt16.
These members are available only as members of the stream itself, for example context.inputStream.readUInt16Exact(buffer, 0, count). Calling them as StreamExtensions.readUInt16Exact(stream, buffer, 0, count) does not work in JavaScript.
Please use the arrays created by context.createUInt16Array and the other array factories with these members.