Source: Media/Image/AxImage.js

/**
 * Creates an instance of AxImage
 * @param {!AxImage} source Source image to copy
 * @param {!AxPixelFormat} pixelFormat Pixel format for the new image
 * @constructor
 */
function AxImage(source, pixelFormat)
{
    AxMedia.call(this);
    
    this.Init();
    
    if (!AxUtils.IsUndefinedOrNull(source))
        this.Copy(source);
    
    if (!AxUtils.IsUndefinedOrNull(pixelFormat))
	this.SetPixelFormat(pixelFormat);
}

AxImage.prototype = Object.create(AxMedia.prototype);



/**
 * Gets fired when an image gets loaded
 * @callback AxImageLoadedCallback
 * @param {*} caller The image object, which was loaded
 * @param {*} context An object holding the context for the callback. It is the object passed to the Load method
 * @param {Boolean} succeeded True if the loading was successful, false otherwise
 */


/**
 * Disposes resources
 */
AxImage.prototype.Dispose = function()
{
    this.SetSize(0, 0, 0);
};

AxImage.prototype.Init = function()
{
    this.width = 0;
    this.height = 0;
    this.depth = 0;

    this.pixelData = null;
    this.pixelFormat = new AxPixelFormat(4, 4, 8, 8, 8, 8, AxPixelFormat.ChannelIdRed, AxPixelFormat.ChannelIdGreen, AxPixelFormat.ChannelIdBlue, AxPixelFormat.ChannelIdAlpha);
};

/**
 * Sets the pixel format of the image data and performs dithering if required
 * @param {AxPixelFormat} pixelFormat If true, dithering is performed on matching channels which have their bit count reduced
 * @param {!Boolean} dither If true, dithering is performed on matching channels which have their bit count reduced. If omitted, a value of true is assumed
 */
AxImage.prototype.SetPixelFormat = function(pixelFormat, dither)
{
    /*TODO
    if (this.pixelFormat.Equals(pixelFormat))
        return;
    
    if (AxUtils.IsUndefinedOrNull(dither))
        dither = true;

    // perform dithering on matching channels, if required
    if (dither)
    {
        var lineSize = this.width * this.pixelFormat.sizeInBytes;
        var bitOffset = 0;
        for (var channelIndex = 0; channelIndex < this.pixelFormat.numChannels; channelIndex++)
        {
            var newChannelIndex = pixelFormat.FindChannelIdIndex(this.pixelFormat.channelId[channelIndex]);
            if (newChannelIndex !== -1)
            {
                var channelBitDifference = this.pixelFormat.channelBitCount[channelIndex] - pixelFormat.channelBitCount[newChannelIndex];
                if (channelBitDifference > 0)
                {
                    var channelMax = ((1 << this.pixelFormat.channelBitCount[channelIndex]) - 1);
                    var mask = channelMax << bitOffset;
                    var pixelIndex = 0;

                    for (var z = 0; z < this.depth; z++)
                    {
                        for (var y = 0; y < this.height - 1; y++)
                        {
                            pixelIndex += this.pixelFormat.sizeInBytes;
                            for (var x = 1; x < this.width - 1; x++)
                            {
                                var channelOldValue = (*(unsigned int*)pixel & mask) >> bitOffset;
                                var channelNewValue = (channelOldValue >> channelBitDifference) << channelBitDifference;
                                var error = channelOldValue - channelNewValue;

                                *(unsigned int*)pixel = ((*(unsigned int*)pixel) & (~mask)) | (channelNewValue << bitOffset);

                                unsigned int *neighbour = (unsigned int*)(pixel + this.pixelFormat.sizeInBytes);
                                *neighbour = ((*neighbour) & (~mask)) | (AxMath.Min(((*neighbour & mask) >> bitOffset) + 7 * error / 16, channelMax) << bitOffset);
                                neighbour = (unsigned int*)(pixel + lineSize - this.pixelFormat.sizeInBytes);
                                *neighbour = ((*neighbour) & (~mask)) | (AxMath.Min(((*neighbour & mask) >> bitOffset) + 3 * error / 16, channelMax) << bitOffset);
                                neighbour = (unsigned int*)(pixel + lineSize);
                                *neighbour = ((*neighbour) & (~mask)) | (AxMath.Min(((*neighbour & mask) >> bitOffset) + 5 * error / 16, channelMax) << bitOffset);
                                neighbour = (unsigned int*)(pixel + lineSize + this.pixelFormat.sizeInBytes);
                                *neighbour = ((*neighbour) & (~mask)) | (AxMath.Min(((*neighbour & mask) >> bitOffset) + error / 16, channelMax) << bitOffset);

                                pixel += this.pixelFormat.sizeInBytes;
                            }
                            pixel += this.pixelFormat.sizeInBytes;
                        }
                        pixel += lineSize;
                    }
                }
            }

            bitOffset += this.pixelFormat.channelBitCount[channelIndex];
        }
    }


	// create and fill the new channels
	unsigned char *newData = 0;
	int newDataSize = this.width * this.height * this.depth * pixelFormat.sizeInBytes;
	if (newDataSize != 0)
	{
		newData = new unsigned char[newDataSize];

		int bitOffset = 0;
		for (int channelIndex = 0; channelIndex < pixelFormat.numChannels; channelIndex++)
		{
			int channelBitDifference = 0;

			//int oldChannelIndex = pixelFormat.FindChannelIdIndex(this.pixelFormat.channelId[channelIndex]);
			int oldChannelIndex = this.pixelFormat.FindChannelIdIndex(pixelFormat.channelId[channelIndex]);
			int oldChannelBitOffset;
			unsigned int channelOldValue = 0;
			unsigned int oldChannelMax;
			unsigned int oldChannelMask;
			unsigned char *oldChannelPixel = this.pixelData;
			if (oldChannelIndex != -1)
			{
				channelBitDifference = this.pixelFormat.channelBitCount[oldChannelIndex] - pixelFormat.channelBitCount[channelIndex];
				oldChannelBitOffset = this.pixelFormat.FindChannelIdBitOffset(this.pixelFormat.channelId[oldChannelIndex]);
				oldChannelMax = (1 << this.pixelFormat.channelBitCount[oldChannelIndex]) - 1;
				oldChannelMask = oldChannelMax << oldChannelBitOffset;
			}

			
			unsigned int channelNewValue = 0;
			unsigned int newChannelMax = (1 << pixelFormat.channelBitCount[channelIndex]) - 1;
			unsigned int mask = newChannelMax << bitOffset;
			unsigned char *pixel = newData;

			for (int z = 0; z < this.depth; z++)
			{
				for (int y = 0; y < this.height; y++)
				{
					for (int x = 0; x < this.width; x++)
					{
						if ((oldChannelIndex != -1) && (oldChannelMax > 0))
						{
							channelOldValue = (*(unsigned int*)oldChannelPixel & oldChannelMask) >> oldChannelBitOffset;
							channelNewValue = channelBitDifference >= 0 ? channelOldValue >> channelBitDifference : (channelOldValue  * newChannelMax) / oldChannelMax;
						}

						*(unsigned int*)pixel = ((*(unsigned int*)pixel) & (~mask)) | (channelNewValue << bitOffset);

						pixel += pixelFormat.sizeInBytes;
						oldChannelPixel += this.pixelFormat.sizeInBytes;
					}
				}
			}

			bitOffset += pixelFormat.channelBitCount[channelIndex];
		}
	}

	if (this.pixelData != 0)
		delete[] this.pixelData;

	this.pixelData = newData;

	this.pixelFormat = pixelFormat;
        */
};

/**
 * Gets the pixel format of the image
 * @return {AxPixelFormat} The pixel format of the image
 */
AxImage.prototype.GetPixelFormat = function()
{
    return this.pixelFormat;
};

/**
 * Sets the size of the image, allocating the required amount of memory according to the given size and the pixel format of the image
 * @param {Integer} width The width in pixels for the new size of the image
 * @param {Integer} height The height in pixels for the new size of the image
 * @param {Integer} depth The depth in pixels for the new size of the image
 */
AxImage.prototype.SetSize = function(width, height, depth)
{
    this.width = width;
    this.height = height;
    this.depth = depth;

    this.pixelData = null;

    var dataSize = this.width * this.height * this.depth * this.pixelFormat.sizeInBytes;
    if (dataSize !== 0)
        this.pixelData = new Uint8Array(dataSize);
};

/**
 * Copies pixels from a specified region of another image to a specified region.
 * Image size and pixel format are not changed and no pixel format conversion is performed
 * @param {AxImage} source The source image to copy pixels from
 * @param {Integer} srcX The X coordinate of the starting point of the region to copy from the source
 * @param {Integer} srcY The Y coordinate of the starting point of the region to copy from the source
 * @param {Integer} srcZ The Z coordinate of the starting point of the region to copy from the source
 * @param {Integer} destX The X coordinate of the starting point of the region to copy to
 * @param {Integer} destY The Y coordinate of the starting point of the region to copy to
 * @param {Integer} destZ The Z coordinate of the starting point of the region to copy to
 * @param {Integer} width The width of the region to copy
 * @param {Integer} height The height of the region to copy
 * @param {Integer} depth The depth of the region to copy
 */
AxImage.prototype.CopyPixels = function(source, srcX, srcY, srcZ, destX, destY, destZ, width, height, depth)
{
    /*TODO
    if ((source.height == height) && (this.height == height) && (source.width == width) && (this.width == width))
    {
        if ((source.depth == depth) && (this.depth == depth))
        {
            AxMem.Copy(this.pixelData, source.pixelData, width * height * depth * source.pixelFormat.sizeInBytes);
        }
        else
        {
            int planeSize = width * height * 4;
            int dest = *(int*)this.pixelData + destZ * planeSize;
            int src = *(int*)source.pixelData + srcZ * planeSize;
            for (int z = 0; z < depth; z++)
            {
                AxMem.Copy((void*)dest, (void*)src, planeSize); 
                dest += planeSize;
                src += planeSize;
            }
        }
    }
    else
    {
        int lineSize = width * 4;
        int destLineSize = this.width * 4;
        int destPlaneSize = destLineSize * this.height;
        int srcLineSize = source.width * 4;
        int srcPlaneSize = srcLineSize * source.height;
        int dest = *(int*)this.pixelData + destZ * destPlaneSize + destY * destLineSize + destX * 4;
        int src = *(int*)source.pixelData + srcZ * srcPlaneSize + srcY * srcLineSize + srcX * 4;
        for (int z = 0; z < depth; z++)
        {
            int d = dest;
            int s = src;
            for (int y = 0; y < height; y++)
            {
                AxMem.Copy((void*)d, (void*)s, lineSize); 
                d += destLineSize;
                s += srcLineSize;
            }

            dest += destPlaneSize;
            src += srcPlaneSize;
        }
    }
    */
};

/**
 * Copies pixels from a specified region of another image
 * Image size and pixel format are not changed and no pixel format conversion is performed
 * @param {AxImage} source The source image to copy pixels from
 * @param {Integer} srcX The X coordinate of the starting point of the region to copy from the source
 * @param {Integer} srcY The Y coordinate of the starting point of the region to copy from the source
 * @param {Integer} srcZ The Z coordinate of the starting point of the region to copy from the source
 * @param {Integer} width The width of the region to copy
 * @param {Integer} height The height of the region to copy
 * @param {Integer} depth The depth of the region to copy
 */
AxImage.prototype.CopyPixels_2 = function(source, srcX, srcY, srcZ, width, height, depth)
{
    this.CopyPixels(source, srcX, srcY, srcZ, 0, 0, 0, width, height, depth);
};

/**
 * Copies pixels from another image
 * Image size and pixel format are not changed and no pixel format conversion is performed
 * @param {AxImage} source The source image to copy pixels from
 */
AxImage.prototype.CopyPixels_3 = function(source)
{
    this.CopyPixels(source, 0, 0, 0, 0, 0, 0, AxMath.Min(source.width, this.width), AxMath.Min(source.height, this.height), AxMath.Min(source.depth, this.depth));
};

/**
 * Copies another image and sets the pixel format and size accordingly
 * @param {AxImage} source The image to copy from
 */
AxImage.prototype.Copy = function(source)
{
    this.pixelFormat = source.pixelFormat;
    this.SetSize(source.width, source.height, source.depth);
    this.CopyPixels(source);
};

/**
 * Sets a pixel to the given coordinates of the image
 * No pixel format conversion is performed
 * @param {Integer} x The X coordinate of the pixel to set
 * @param {Integer} y The Y coordinate of the pixel to set
 * @param {Integer} z The Z coordinate of the pixel to set
 * @param {Integer} value The color value of the pixel to be set. Contains all the channels, encoded in the pixel format of the image
 */
AxImage.prototype.SetPixel = function(x, y, z, value)
{
    /*TODO
    AxMem.Copy(&this.pixelData[(z * this.width * this.height + y * this.width + x) * this.pixelFormat.sizeInBytes], &value, this.pixelFormat.sizeInBytes);
    */
};

/**
 * Gets the pixel at the given coordinates of the image
 * No pixel format conversion is performed
 * @param {Integer} x The X coordinate of the pixel to get
 * @param {Integer} y The Y coordinate of the pixel to get
 * @param {Integer} z The Z coordinate of the pixel to get
 * @return {Integer} The color value of the pixel at the given coordinates. Contains all the channels, encoded in the pixel format of the image
 */
AxImage.prototype.GetPixel = function(x, y, z)
{
    /*TODO
    unsigned int result = 0;
    AxMem.Copy(&result, &this.pixelData[z * this.width * this.height + y * this.width + x], this.pixelFormat.sizeInBytes);
    return result;
    */
};

/**
 * Gets a sample color from a given Z-layer at given coordinates ranging from 0 to 1
 * The sampling uses linear interpolation
 * @param {Number} u The X coordinate to get a sample at
 * @param {Number} v The Y coordinate to get a sample at
 * @param {Integer} z The Z coordinate of the layer to get the sample from
 * @return {Integer} A color value sampled at the the given coordinates. Contains all the channels, encoded in the pixel format of the image
 */
AxImage.prototype.GetSample = function(u, v, z)
{
    var x = u * this.width;
    var y = v * this.height;

    var x1 = AxMath.Trunc(x);
    var y1 = AxMath.Trunc(y);

    x -= x1;
    y -= y1;

    x1 %= this.width;
    y1 %= this.height;

    var x2 = (x1 + 1) % this.width;
    var y2 = (y1 + 1) % this.height;

    var planeOffset = z * this.width * this.height;

    var intPixelData = new Uint32Array(this.pixelData.buffer);
    
    var p11 = intPixelData[((planeOffset + y1 * this.width + x1) * 4) / this.pixelFormat.sizeInBytes];
    var p12 = intPixelData[((planeOffset + y1 * this.width + x2) * 4) / this.pixelFormat.sizeInBytes];
    var p21 = intPixelData[((planeOffset + y2 * this.width + x1) * 4) / this.pixelFormat.sizeInBytes];
    var p22 = intPixelData[((planeOffset + y2 * this.width + x2) * 4) / this.pixelFormat.sizeInBytes];

    var result = 0;
    var bitShift = 0;

    for (var channelIndex = 0; channelIndex < this.pixelFormat.numChannels; channelIndex++)
    {
        var channelBitCount = this.pixelFormat.channelBitCount[channelIndex];
        var channelLimit = 1 << channelBitCount;
        var channelMax = channelLimit - 1;
        var fx = AxMath.Trunc(x * channelLimit);
        var fy = AxMath.Trunc(y * channelLimit);

        var c11 = p11 & channelMax;
        var c12 = p12 & channelMax;
        var c21 = p21 & channelMax;
        var c22 = p22 & channelMax;

        var c1 = c11 + (((c12 - c11) * fx) >> channelBitCount);
        var c2 = c21 + (((c22 - c21) * fx) >> channelBitCount);
        var c = c1 + (((c2 - c1) * fy) >> channelBitCount);

        result |= c << bitShift;
        bitShift += channelBitCount;

        p11 = p11 >> channelBitCount;
        p12 = p12 >> channelBitCount;
        p21 = p21 >> channelBitCount;
        p22 = p22 >> channelBitCount;
    }

    return result;
};

/**
 * Gets a sample color at a given coordinates ranging from 0 to 1
 * The sampling uses linear interpolation
 * @param {Number} u The X coordinate to get a sample at
 * @param {Number} v The Y coordinate to get a sample at
 * @param {Number} w The Z coordinate to get a sample at
 * @return {Integer} A color value sampled at the the given coordinates. Contains all the channels, encoded in the pixel format of the image
 */
AxImage.prototype.GetSample_2 = function(u, v, w)
{
    /*TODO
	float x = u * this.width;
	float y = v * this.height;
	float z = w * this.depth;

	int x1 = (int)x;
	int y1 = (int)y;
	int z1 = (int)z;

	x -= x1;
	y -= y1;
	z -= z1;

	x1 %= this.width;
	y1 %= this.height;
	z1 %= this.depth;

	int x2 = (x1 + 1) % this.width;
	int y2 = (y1 + 1) % this.height;
	int z2 = (z1 + 1) % this.depth;

	int planeSize = this.width * this.height;
	int plane1Offset = z1 * planeSize;
	int plane2Offset = z2 * planeSize;

	unsigned int p111 = *(unsigned int*)&this.pixelData[(plane1Offset + y1 * this.width + x1) * this.pixelFormat.sizeInBytes];
	unsigned int p112 = *(unsigned int*)&this.pixelData[(plane1Offset + y1 * this.width + x2) * this.pixelFormat.sizeInBytes];
	unsigned int p121 = *(unsigned int*)&this.pixelData[(plane1Offset + y2 * this.width + x1) * this.pixelFormat.sizeInBytes];
	unsigned int p122 = *(unsigned int*)&this.pixelData[(plane1Offset + y2 * this.width + x2) * this.pixelFormat.sizeInBytes];
	unsigned int p211 = *(unsigned int*)&this.pixelData[(plane2Offset + y1 * this.width + x1) * this.pixelFormat.sizeInBytes];
	unsigned int p212 = *(unsigned int*)&this.pixelData[(plane2Offset + y1 * this.width + x2) * this.pixelFormat.sizeInBytes];
	unsigned int p221 = *(unsigned int*)&this.pixelData[(plane2Offset + y2 * this.width + x1) * this.pixelFormat.sizeInBytes];
	unsigned int p222 = *(unsigned int*)&this.pixelData[(plane2Offset + y2 * this.width + x2) * this.pixelFormat.sizeInBytes];

	unsigned int result = 0;
	int bitShift = 0;

	for (int channelIndex = 0; channelIndex < this.pixelFormat.numChannels; channelIndex++)
	{
		int channelBitCount = this.pixelFormat.channelBitCount[channelIndex];
		int channelLimit = 1 << channelBitCount;
		int channelMax = channelLimit - 1;
		int fx = (int)(x * channelLimit);
		int fy = (int)(y * channelLimit);
		int fz = (int)(z * channelLimit);

		int c11 = p111 & channelMax;
		int c12 = p112 & channelMax;
		int c21 = p121 & channelMax;
		int c22 = p122 & channelMax;

		int c1 = c11 + (((c12 - c11) * fx) >> channelBitCount);
		int c2 = c21 + (((c22 - c21) * fx) >> channelBitCount);
		int p1c = c1 + (((c2 - c1) * fy) >> channelBitCount);

		c11 = p211 & channelMax;
		c12 = p212 & channelMax;
		c21 = p221 & channelMax;
		c22 = p222 & channelMax;

		c1 = c11 + (((c12 - c11) * fx) >> channelBitCount);
		c2 = c21 + (((c22 - c21) * fx) >> channelBitCount);
		int p2c = c1 + (((c2 - c1) * fy) >> channelBitCount);

		int pc = p1c + (((p2c - p1c) * fy) >> 8);

		result |= pc << bitShift;
		bitShift += channelBitCount;

		p111 = p111 >> channelBitCount;
		p112 = p112 >> channelBitCount;
		p121 = p121 >> channelBitCount;
		p122 = p122 >> channelBitCount;

		p211 = p211 >> channelBitCount;
		p212 = p212 >> channelBitCount;
		p221 = p221 >> channelBitCount;
		p222 = p222 >> channelBitCount;
	}

	return result;
        */
};

/**
 * Loads the image from a given stream
 * If the particular implementation of AxImage does not support the format in which the source data is encoded, it should return false
 * Different implementations of AxImage can load differently encoded images
 * @param {AxStream} source Stream containing the image encoded in its particular format
 * @param {*} callbackContext An object which is to be passed to the callback. It can be used to serve as a context for the callback or just to pass any relevant data
 * @param {AxImageLoadedCallback} callback A callback method which is to be called when the loading has finished
 */
AxImage.prototype.Load = function(source, callbackContext, callback) { callback(this, callbackContext, false); };

/**
 * Saves the image to the given stream in the given encoding format
 * If the particular implementation of AxImage does not support the requested encoding format, it should return false and shouldn't write anything to the stream
 * Different implementations of AxImage can save images in different encodings
 * @param {AxStream} destination Stream to which the image will be written in the requested format
 * @param {String} format Format in which to encode the image. For example, such as 'jpg', 'png' and etc. 
 * @return {Boolean} True if the image was successfully saved to the given stream in the given encoding format
 */
AxImage.prototype.Save = function(destination, format) { return false; };

Documentation generated by JSDoc 3.5.3 on Mon Feb 19 2018 20:39:26 GMT+0200 (FLE Standard Time)