Click here to Skip to main content
15,893,508 members
Articles / Multimedia / Image Processing

Colorspaces and Conversions

Rate me:
Please Sign up or sign in to vote.
4.98/5 (32 votes)
24 Nov 2013GPL36 min read 135.7K   4.7K   62  
A library for colormodels and spaces, correct color-conversions and color-difference calculation.
using System;

/*  This library reads version 4.3 and compatible ICC-profiles as specified by the International Color Consortium.
    Copyright (C) 2013  Johannes Bildstein

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.*/

namespace ICCReader
{
    /// <summary>
    /// An element to process data
    /// </summary>
    public abstract class MultiProcessElement
    {
        /// <summary>
        /// The signature of this element
        /// </summary>
        public abstract multiProcessElementSignature Signature { get; }
        /// <summary>
        /// Number of input channels
        /// </summary>
        public ushort InputChannelCount { get; protected set; }
        /// <summary>
        /// Number of output channels
        /// </summary>
        public ushort OutputChannelCount { get; protected set; }
        
        internal static MultiProcessElement CreateElement(int idx)
        {
            //Tag signature (byte position 0 to 3) (4 to 7 are zero)
            multiProcessElementSignature t = (multiProcessElementSignature)Helper.GetUInt32(idx);
            //Number of input channels (2 bytes)
            ushort InputChannelCount = Helper.GetUInt16(idx + 8);
            //Number of output channels (2 bytes)
            ushort OutputChannelCount = Helper.GetUInt16(idx + 10);
            return GetElement(t,  idx + 12, InputChannelCount, OutputChannelCount);
        }

        private static MultiProcessElement GetElement(multiProcessElementSignature type, int idx, ushort InputChannelCount, ushort OutputChannelCount)
        {
            switch (type)
            {
                case multiProcessElementSignature.CurveSet:
                    return new CurveSetProcessElement(idx, InputChannelCount, OutputChannelCount);
                case multiProcessElementSignature.CLUT:
                    return new CLUTProcessElement(idx, InputChannelCount, OutputChannelCount);
                case multiProcessElementSignature.Matrix:
                    return new MatrixProcessElement(idx, InputChannelCount, OutputChannelCount);
                case multiProcessElementSignature.bACS:
                    return new bACSProcessElement(idx, InputChannelCount, OutputChannelCount);
                case multiProcessElementSignature.eACS:
                    return new eACSProcessElement(idx, InputChannelCount, OutputChannelCount);

                default:
                     throw new CorruptProfileException("MultiProcessElement");
            }
        }
        
        public abstract double[] GetValue(double[] inColor);
    }

    /// <summary>
    /// A matrix element to process data
    /// </summary>
    public sealed class MatrixProcessElement : MultiProcessElement
    {
        /// <summary>
        /// The signature of this element
        /// </summary>
        public override multiProcessElementSignature Signature { get { return multiProcessElementSignature.Matrix; } }
        public double[,] MatrixIxO { get; private set; }        
        public double[] MatrixOx1 { get; private set; }

        internal MatrixProcessElement(int idx, ushort InputChannelCount, ushort OutputChannelCount)
        {
            this.InputChannelCount = InputChannelCount;
            this.OutputChannelCount = OutputChannelCount;
            //Matrix IxO (4 bytes each)
            MatrixIxO = Helper.GetMatrix(InputChannelCount, OutputChannelCount,  idx, true);
            //Matrix Ox1 (4 bytes each)
            MatrixOx1 = Helper.GetMatrix(OutputChannelCount,  idx + (4 * InputChannelCount * OutputChannelCount), true);
        }

        public override double[] GetValue(double[] inColor)
        {
            if (inColor.Length != InputChannelCount) { throw new ArgumentException("Input color channel count does not match element channel count"); }

            return Helper.AddMatrix(Helper.MultiplyMatrix(MatrixIxO, inColor), MatrixOx1);
        }
    }

    /// <summary>
    /// A set of curves to process data
    /// </summary>
    public sealed class CurveSetProcessElement : MultiProcessElement
    {
        /// <summary>
        /// The signature of this element
        /// </summary>
        public override multiProcessElementSignature Signature { get { return multiProcessElementSignature.CurveSet; } }
        /// <summary>
        /// An array with one dimensional curves
        /// </summary>
        public OneDimensionalCurve[] Curves { get; private set; }
        internal PositionNumber[] CurvePositions { get; private set; }

        internal CurveSetProcessElement(int idx, ushort InputChannelCount, ushort OutputChannelCount)
        {
            this.InputChannelCount = InputChannelCount;
            this.OutputChannelCount = OutputChannelCount;
            //Curves
            Curves = new OneDimensionalCurve[InputChannelCount]; int end = idx;
            for (int i = 0; i < InputChannelCount; i++)
            {
                Curves[i] = new OneDimensionalCurve(end);
                end = Curves[i].end + Curves[i].end % 4;
            }
        }

        public override double[] GetValue(double[] inColor)
        {
            if (inColor.Length != InputChannelCount) { throw new ArgumentException("Input color channel count does not match element channel count"); }

            double[] output = new double[InputChannelCount];
            for (int i = 0; i < InputChannelCount; i++) { output[i] = Curves[i].GetValue(inColor[i]); }
            return output;
        }
    }

    /// <summary>
    /// An CLUT (Color Look-Up-Table) element to process data
    /// </summary>
    public sealed class CLUTProcessElement : MultiProcessElement
    {
        /// <summary>
        /// The signature of this element
        /// </summary>
        public override multiProcessElementSignature Signature { get { return multiProcessElementSignature.CLUT; } }
        public CLUTf32 CLUTvalues { get; private set; }

        internal CLUTProcessElement(int idx, ushort InputChannelCount, ushort OutputChannelCount)
        {
            this.InputChannelCount = InputChannelCount;
            this.OutputChannelCount = OutputChannelCount;
            //CLUT
            CLUTvalues = (CLUTf32)CLUT.GetCLUT(idx, true, InputChannelCount, OutputChannelCount);
        }

        public override double[] GetValue(double[] inColor)
        {
            if (inColor.Length != InputChannelCount) { throw new ArgumentException("Input color channel count does not match element channel count"); }

            return CLUTvalues.GetValue(inColor);
        }
    }

    /// <summary>
    /// An empty process element for future expansion
    /// </summary>
    public sealed class bACSProcessElement : MultiProcessElement
    {
        /// <summary>
        /// The signature of this element
        /// </summary>
        public override multiProcessElementSignature Signature { get { return multiProcessElementSignature.bACS; } }

        internal bACSProcessElement(int idx, ushort InputChannelCount, ushort OutputChannelCount)
        {
            this.InputChannelCount = InputChannelCount;
            this.OutputChannelCount = OutputChannelCount;
            //Nothing (reserved for future expansion)
        }

        public override double[] GetValue(double[] inColor)
        {
            return null;
        }
    }

    /// <summary>
    /// An empty process element for future expansion
    /// </summary>
    public sealed class eACSProcessElement : MultiProcessElement
    {
        /// <summary>
        /// The signature of this element
        /// </summary>
        public override multiProcessElementSignature Signature { get { return multiProcessElementSignature.eACS; } }

        internal eACSProcessElement(int idx, ushort InputChannelCount, ushort OutputChannelCount)
        {
            this.InputChannelCount = InputChannelCount;
            this.OutputChannelCount = OutputChannelCount;
            //Nothing (reserved for future expansion)
        }

        public override double[] GetValue(double[] inColor)
        {
            return null;
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Software Developer
Austria Austria
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions