text: /*
   *
   *  Copyright (C) 2016, Pascal Getreuer, Open Connections GmbH
   *  All rights reserved.  See COPYRIGHT file for details.
   *
   *  This software and supporting documentation are maintained by
   *
   *    OFFIS e.V.
   *    R&D Division Health
   *    Escherweg 2
   *    D-26121 Oldenburg, Germany
   *
   *
   *  Module:  dcmiod
   *
   *  Author:  Pascal Getreuer, Michael Onken
   *
   *  Purpose: Static helper functionality for CIE<->RGB color conversions
   *
   */
  
  #ifndef CIELABUTIL_H
  #define CIELABUTIL_H
  
  #include "dcmtk/config/osconfig.h"
  #define INCLUDE_CMATH                // for pow() function
  #include "dcmtk/ofstd/ofstdinc.h"
  #include "dcmtk/dcmiod/ioddef.h"
  
  
  /** Class supporting color space conversions from and to CIELab. In some IODs
   *  DICOM stores CIELab color values which must often be converted to RGB for
   *  display or other purposes. This is supported by the functions dicomLab2RGB()
   *  and rgb2DicomLab(). The CIELab value range in DICOM is [0,65535] for all
   *  three values. The RGB value range in this class is [0;1]. Further functions
   *  are available in order to convert between RGB, "normal" CIELab value range
   *  as well as CIEXYZ. The class uses double floating point precision for
   *  calculations.
   */
  class DCMTK_DCMIOD_EXPORT IODCIELabUtil
  {
  public:
  
    /// D65 standard lightpoint X component for conversion from CIEXYZ to CIELab
    static const double D65_WHITEPOINT_X;
    /// D65 standard lightpoint Y component for conversion from CIEXYZ to CIELab
    static const double D65_WHITEPOINT_Y;
    /// D65 standard lightpoint Z component for conversion from CIEXYZ to CIELab
    static const double D65_WHITEPOINT_Z;
  
    /** Convert CIELab color representation as found in DICOM to sRGB value
     *  representation. See DICOM part 3 for details.
     *  @param  R Output sRGB "R" component (red) with 0 <= R <= 1
     *  @param  G Output sRGB "G" component (green) with 0 <= G <= 1
     *  @param  B Output sRGB "R" component (blue) with 0 <= B <= 1
     *  @param  LDicom Input DICOM CIELab luminance component with 0 <= L <= 65535
     *  @param  aDicom Input DICOM CIELab "a" component (red<->green) with 0 <= a <= 65535
     *  @param  bDicom Input DIOCM CIELab "b" component (blue<->yellow) with 0 <= a <= 65535
     */
    static void dicomLab2RGB(double& R, double& G, double& B, double LDicom, double aDicom, double bDicom);
  
    /** Convert sRGB color representation to CIELab color representation as found
     *  in DICOM. See DICOM part 3 for details.
     *  @param  LDicom Output CIELab luminance component with 0 <= L <= 65535 as found
     *          in DICOM
     *  @param  aDicom Output CIELab "a" component (red<->green) with 0 <= a <= 65535
     *          as found in DICOM
     *  @param  bDicom Output CIELab "b" component (blue<->yellow) with 0 <= b <= 65535
     *          as found in DICOM
     *  @param  R Input sRGB "R" component (red) with 0 <= R <= 1
     *  @param  G Input sRGB "G" component (green) with 0 <= G <= 1
     *  @param  B Input sRGB "R" component (blue) with 0 <= B <= 1
     *
     */
    static void rgb2DicomLab(double& LDicom, double& aDicom, double& bDicom, double R, double G, double B);
  
    /** Convert CIELab color representation as found in DICOM to CIELab
     *  representation. See DICOM part 3 for details.
     *  @param  L Output CIELab luminance component with 0 <= L <= 100
     *  @param  a Output CIELab "a" component (red<->green) with -127 <= a <= 128
     *  @param  b Output CIELab "b" component (blue<->yellow) with -127 <= b <= 128
     *  @param  LDicom Input CIELab luminance component with 0 <= L <= 65535 as found
     *          in DICOM
     *  @param  aDicom Input CIELab "a" component (red<->green) with 0 <= a <= 65535
     *          as found in DICOM
     *  @param  bDicom Input CIELab "b" component (blue<->yellow) with 0 <= b <= 65535
     *          as found in DICOM
     */
    static void dicomlab2Lab(double& L, double& a, double& b, double LDicom, double aDicom, double bDicom);
  
    /** Convert CIELab color representation to CIELab color representation found
     *  in DICOM. See DICOM part 3 for details.
     *  @param  LDicom Output CIELab luminance component with 0 <= L <= 65535 as found
     *          in DICOM
     *  @param  aDicom Output CIELab "a" component (red<->green) with 0 <= a <= 65535
     *          as found in DICOM
     *  @param  bDicom Output CIELab "b" component (blue<->yellow) with 0 <= b <= 65535
     *          as found in DICOM
     *  @param  L Input CIELab luminance component with 0 <= L <= 100
     *  @param  a Input CIELab "a" component (red<->green) with -127 <= a <= 128
     *  @param  b Input CIELab "b" component (blue<->yellow) with -127 <= b <= 128
     *
     */
    static void lab2DicomLab(double& LDicom, double& aDicom, double& bDicom, double L, double a, double b);
  
    /** Convert sRGB color representation to CIELab representation
     *  @param  L Output CIELab luminance component with 0 <= L <= 100
     *  @param  a Output CIELab "a" component (red<->green) with -127 <= a <= 128
     *  @param  b Output CIELab "b" component (blue<->yellow) with -127 <= b <= 128
     *  @param  R Input sRGB "R" component (red) with 0 <= R <= 1
     *  @param  G Input sRGB "G" component (green) with 0 <= G <= 1
     *  @param  B Input sRGB "R" component (blue) with 0 <= B <= 1
     */
    static void rgb2Lab(double& L, double& a, double& b, double R, double G, double B);
  
    /** Convert sRGB color representation to CIE XYZ representation
     *  @param  X Output CIELab XYZ "X" component with 0 <= X <= 1
     *  @param  Y Output CIELab XYZ "Y" component with 0 <= Y <= 1
     *  @param  Z Output CIELab XYZ "Z" component with 0 <= Z <= 1
     *  @param  R Input sRGB "R" component (red) with 0 <= R <= 1
     *  @param  G Input sRGB "G" component (green) with 0 <= G <= 1
     *  @param  B Input sRGB "R" component (blue) with 0 <= B <= 1
     */
    static void rgb2Xyz(double& X, double& Y, double& Z, double R, double G, double B);
  
  
    /** Convert CIELAB XYZ color representation to CIELab representation
     *  @param  L Output CIELab luminance component with 0 <= L <= 100
     *  @param  a Output CIELab "a" component (red<->green) with -127 <= a <= 128
     *  @param  b Output CIELab "b" component (blue<->yellow) with -127 <= b <= 128
     *  @param  X Input CIELab XYZ "X" component with 0 <= X <= 1
     *  @param  Y Input CIELab XYZ "Y" component with 0 <= Y <= 1
     *  @param  Z Input CIELab XYZ "Z" component with 0 <= Z <= 1
     */
    static void xyz2Lab(double& L, double& a, double& b, double X, double Y, double Z);
  
    /** Convert CIELab color representation to sRGB representation
     *  @param  R Output sRGB "R" component (red) with 0 <= R <= 1
     *  @param  G Output sRGB "G" component (green) with 0 <= G <= 1
     *  @param  B Output sRGB "R" component (blue) with 0 <= B <= 1
     *  @param  L Input CIELab luminance component with 0 <= L <= 100
     *  @param  a Input CIELab "a" component (red<->green) with -127 <= a <= 128
     *  @param  b Input CIELab "b" component (blue<->yellow) with -127 <= b <= 128
     */
    static void lab2Rgb(double& R, double& G, double& B, double L, double a, double b);
  
    /** Convert CIELab color representation to CIE XYZ representation
     *  @param  X Output CIELab XYZ "X" component with 0 <= X <= 1
     *  @param  Y Output CIELab XYZ "Y" component with 0 <= Y <= 1
     *  @param  Z Output CIELab XYZ "Z" component with 0 <= Z <= 1
     *  @param  L Input CIELab luminance component with 0 <= L <= 100
     *  @param  a Input CIELab "a" component (red<->green) with -127 <= a <= 128
     *  @param  b Input CIELab "b" component (blue<->yellow) with -127 <= b <= 128
     */
    static void lab2Xyz(double& X, double& Y, double& Z, double L, double a, double b);
  
    /** Convert CIE XYZ color representation to sRGB representation
     *  @param  R Output sRGB "R" component (red) with 0 <= R <= 1
     *  @param  G Output sRGB "G" component (green) with 0 <= G <= 1
     *  @param  B Output sRGB "R" component (blue) with 0 <= B <= 1
     *  @param  X Output CIELab XYZ "X" component with 0 <= X <= 1
     *  @param  Y Output CIELab XYZ "Y" component with 0 <= Y <= 1
     *  @param  Z Output CIELab XYZ "Z" component with 0 <= Z <= 1
     */
    static void xyz2Rgb(double& R, double& G, double& B, double X, double Y, double Z);
  
  protected:
  
    /** Perform sRGB gamma correction, transforms R to R'
     *  @param  n The value to correct
     *  @return The gamma-corrected value
     */
    static double gammaCorrection(double n);
  
    /** Perform inverse sRGB gamma correction, transforms R' to R
     *  @param  n The value to invert
     *  @return The gamma-inverted value
     */
    static double invGammaCorrection(double n);
  
    /** CIE L*a*b* f function (used to convert XYZ to L*a*b*)
     *  @param  n value to convert
     *  @return The converted value
     */
    static double labf(double n);
  
    /** CIE L*a*b* inverse f function
     *  @param n The value to compute the inverse for
     *  @return The resulting inverse
     */
    static double labfInv(double n);
  
    /** Get the minimum of two numbers
     *  @param  a First number
     *  @param  b Second number
     *  @return The minimum of a, b. a if a and b are equal.
     */
    static double min(double a, double b);
  
    /** Get the minimum of three numbers
     *  @param  a First number
     *  @param  b Second number
     *  @param  c Third number
     *  @return The minimum of a, b and c. If a value occurs more than once,
     *          then preference order then a is preferred if possible, b
     *          otherwise
     */
    static double min3(double a, double b, double c);
  
  };
  
  #endif // CIELABUTIL_H
  