Поменять яркость, оттенок, контрастность изображения C# Unity3D, Delphi.

// C# ////////////////////////////////////////////////////////////////////////////////////////////////////////////
private Texture2D texture2;
    public Texture2D ChangeBSC(Texture2D texture,
        float Percent_Bright, float Max_Percent_Bright,
        float Percent_Shade, float Max_Percent_Shade,
        float Percent_Contrast, float Max_Percent_Contrast)
    { // Поменять яркость, оттенок, контрастность всего изображения 
        // Пример использования: MyNewTexture = ChangeBSC (MyTexture,-50,100,80,100,50,100);
        // texture = изначальное изображение
        // Percent_Bright = на сколько изменить яркость в процентах от "-Max_Percent_Bright" до "Max_Percent_Bright", где 0 оставляет яркость неизменной
        // Percent_Shade = на сколько изменить оттенок в процентах от "-Max_Percent_Shade" до "Max_Percent_Shade", где 0 оставляет оттенок неизменным
        // Percent_Contrast = на сколько изменить контрастность в процентах от "-Max_Percent_Contrast" до "Max_Percent_Contrast", где 0 оставляет контрастность неизменной
        // 255 - максимальное значение для = Max_Percent_Bright и Max_Percent_Contrast
        // 1530 - максимальное значение для = Max_Percent_Shade
        int Lc, Lc2, w, h, numofcolorXY; 
        float R, G, B, RGBmax, RGBmin, RGBmid, Bright, Shade, Contrast, MaxContrast,
        LcR, LcG, LcB, CountInRow, MaxCountInRow, Sline, Zero1, Kside, NextRGBmid, DiffRGBmid, 
        BGW, NextMidCount = 0;
        float Q,CellsCount,SideLR,E,Qmax,Qp,Qmid,Qmin;
        // Корректировка, если свойства вводятся вручную //////////////////////////////
        float Lp0,Lp1,D,Rm,Gm,Bm,Qrm,Qgm,Qbm;
        float OldShade,CellsInRow,OnePercentStep,StepNumber,CellsInRowTriangle,Qb,Ql,Qn,Qlout; // (-1529..1529)
        // -1 = уменьшить яркость, 0 = увеличить яркость
        Lc = Mathf.FloorToInt(Percent_Bright/(Mathf.Abs(Percent_Bright)+1)); // -1= если "Percent_Bright<0", иначе 0
        // 0 = уменьшить контрастность, 1 = увеличить контрастность
        Lc2 = Mathf.FloorToInt(Percent_Contrast/(Mathf.Abs(Percent_Contrast)+1))+1; // 1= если "Percent_Contrast<0", иначе 0
        // Перевести изображение "texture" в массив "Color" (с массивом "Color" напрямую работать быстрее чем с самой текстурой)
        w = texture.width;
        h = texture.height;
        Color[] PictByColor = new Color[w * h];
        PictByColor = texture.GetPixels(0, 0, w, h);
        Color[] DrawByColor = new Color[w * h]; // Холст на котором будет вестись отрисовка
        for (int Yy = 0; Yy < h; Yy++)
        {
            for (int Xx = 0; Xx < w; Xx++)
            {
                numofcolorXY = (h - 1 - Yy) * w + Xx; // Номер ячейки в массиве "PictByColor"
                // Если не прозрачный пиксель
                if (PictByColor [numofcolorXY].a > 0) {
                    Color color = PictByColor [numofcolorXY]; // цвет кисти
                    // Цвет "color" в формате от 0 до 1,  (R,G,B)/255f
                    R = color.r;
                    G = color.g;
                    B = color.b;
                    // Поменять оттенок ////////////////////////////////////////////////////            
                    R = Mathf.RoundToInt(R * 255f);
                    G = Mathf.RoundToInt(G * 255f);
                    B = Mathf.RoundToInt(B * 255f);
                    // Определить значение оттенка
                    RGBmax = (((((R + G) / 2f) + (Mathf.Abs (R - G) / 2f)) + B) / 2f) + (Mathf.Abs ((((R + G) / 2f) + (Mathf.Abs (R - G) / 2f)) - B) / 2f);
                    RGBmin = (((((R + G) / 2f) - (Mathf.Abs (R - G) / 2f)) + B) / 2f) - (Mathf.Abs ((((R + G) / 2f) - (Mathf.Abs (R - G) / 2f)) - B) / 2f);
                    Bright = (RGBmax + RGBmin) / 2f; // Яркость от 0 до 255
                    Contrast = (RGBmax - RGBmin) / 2f; // Контрастность от 0 до 127.5
                    Rm = Mathf.FloorToInt ((R - Bright) / 256f); // -1= если R<bright, 0="если" r="">=Bright
                    Gm = Mathf.FloorToInt ((G - Bright) / 256f); // -1= если G<bright, 0="если" g="">=Bright
                    Bm = Mathf.FloorToInt ((B - Bright) / 256f); // -1= если B<bright, 0="если" b="">=Bright
                    Qrm = (Rm + 1) * -Bm; //1= если 1 или 2 треугольник, иначе 0
                    Qgm = (Gm + 1) * -Rm; //1= если 3 или 4 треугольник, инач,,е 0
                    Qbm = (Bm + 1) * -Gm; //1= если 5 или 6 треугольник, иначе 0
                    Q = Qrm * (Gm + 2) + Qgm * (3 + (Bm + 1)) + Qbm * (5 + (Rm + 1)); // Номер треугольника "1..6"
                    Shade = (Q * 257 - 129 + Qrm * (G - (B * -Gm) - (R * (1 + Gm))) + Qgm * (B - (R * -Bm) - (G * (1 + Bm))) + Qbm * (R - (G * -Rm) - (B * (1 + Rm)))) * (Qrm + Qgm + Qbm); // Оттенок от 0 до 1540                
                    // Поменять значение оттенка
                    //4. (-1529..1529) Свойства оттенка (для 5 пункта) --------------------------
                    OldShade = Shade; // Оттенок в треугольнике (Уже просчитанный под контрастность "NumContrast")
                    //Q = Mathf.FloorToInt (OldShade / 257f) + 1; // Номер треугольника "1..6"
                    CellsCount = OldShade - (Q * 257f - 129); // Количество ячеек от середины треугольника к краям, + вправо, - влево
                    E = 1 - (Q / 2f - Mathf.FloorToInt (Q / 2f)) * 2f; // Если четный треугольник то E=1, иначе E=0
                    //-----
                    //5. (-1529..1529) Проверить, находится ли оттенок в пределах одного из треугольников ------
                    D = 1 - 2f * (Bright - Mathf.FloorToInt (Bright)); //1=если яркость с целым числом, иначе 0
                    CellsInRow = (Mathf.CeilToInt (Contrast) * 2f - 1) * 6f + D * 6f; // Количество ячеек во всех 6 треугольниках, в ряду "Mathf.CeilToInt(Contrast)"
                    OnePercentStep = Max_Percent_Shade / CellsInRow; // Сколько ячеек из 1530, являются одним шагом для "CellsInRow" ячеек. (Пример: на контрастности=1, 6 ячеек в ряду и для прохода каждой нужно 6 шагов, по 255 ячеек за шаг)
                    StepNumber = Mathf.FloorToInt (Percent_Shade / OnePercentStep); // Номер ячейки в ряду "Mathf.CeilToInt(Contrast)"
                    Shade = StepNumber;
                    CellsInRowTriangle = Mathf.Abs (Mathf.CeilToInt (Contrast) * 2f - 1); // Количество ячеек в треугольнике в ряду "Mathf.CeilToInt(Contrast)", без учета четности треугольника
                    Ql = Mathf.FloorToInt ((Shade + CellsCount) / (CellsInRowTriangle + D)); // Приблизительное количество треугольников в указанном промежутке "Shade"
                    Qn = (Shade + CellsCount) - Ql * (CellsInRowTriangle + D); // Количество ячеек от центра следующего треугольника
                    Qlout = -Mathf.FloorToInt (((Mathf.CeilToInt (Contrast) - 1 + D * (1 - ((Ql + 1) / 2f - Mathf.FloorToInt ((Ql + 1) / 2f)) * 2f)) - Mathf.Abs (Qn)) / 1531f); //1=если "Qn" за пределами треугольника "Ql", иначе 0
                    Qb = Ql + Qlout; // Количество треугольников в указанном промежутке "Shade"
                    // Установить новый оттенок в указанном промежутке "Shade", от предыдущего оттенка "OldShade"
                    Shade = Qb * 257f + OldShade + (Shade - CellsInRowTriangle * Qb - D * (1 - E) * Qb);
                    //-----
                    // Если "Shade<0" или "Shade>1541", то установить "Shade" в пределах "0..1541"
                    Lp0 = Mathf.Abs (Mathf.FloorToInt (Shade / (Mathf.Abs (Shade) + 1))); //1= если "Shade<0", иначе 0
                    Lp1 = Mathf.FloorToInt ((Mathf.Abs (Shade) - Lp0) / 1542f); // Во сколько раз "Mathf.Abs(Shade)>1542"
                    Shade = Mathf.Abs (Shade * (Lp0 * -2 + 1) - 1542f * (Lp1 + Lp0)); // "Shade" в пределах "0..1541"
                                                                
                    // Перевести яркость, оттенок, контрастность в RGB
                    Q = Mathf.FloorToInt (Shade / 257f) + 1; // Номер треугольника "1..6"
                    CellsCount = Shade - (Q * 257f - 129); // Количество ячеек от середины треугольника к краям, + вправо, - влево
                    SideLR = -Mathf.FloorToInt (CellsCount / 130f); //1= если "CellsCount < 0",  0= если "CellsCount >= 0"
                    E = 1 - (Q / 2f - Mathf.FloorToInt (Q / 2f)) * 2f; // Если четный треугольник то E=1, иначе E=0
                    Qmax = Mathf.CeilToInt (Q / 2f) - 1 + E * (1 - SideLR) - 3f * Mathf.FloorToInt (Q / 6f) * (1 - SideLR); // (0-R, 1-G, 2-B) = RGBmax
                    Qp = Q - Mathf.FloorToInt (Q / 4f) * 3f; // Приравнивание 6 треугольников, к 1,2,3 (1-1,2-2,3-3) (4-1,5-2,6-3)
                    Qmid = 2 - (Qp - SideLR - Mathf.FloorToInt (Qp / 3f) * (1 - SideLR) * 3f); // (0-R, 1-G, 2-B) = RGBmid
                    Qmin = 3 - (Qmax + Qmid); // (0-R, 1-G, 2-B) = RGBmin
                    RGBmax = Bright + Contrast; // Максимальное значение из R,G,B
                    RGBmin = Bright - Mathf.Abs (Contrast); // Минимальное значение из R,G,B
                    RGBmid = Mathf.Abs (RGBmin + (Mathf.Abs (CellsCount) - (Bright * 2f) * E) * Mathf.CeilToInt (Contrast / 129f)); // Среднее значение из R,G,B
                    R = Mathf.RoundToInt((Mathf.Abs (Qmax - 2 + 0.5f) - 0.5f) * RGBmax + (Mathf.Abs (Qmid - 2 + 0.5f) - 0.5f) * RGBmid + (Mathf.Abs (Qmin - 2 + 0.5f) - 0.5f) * RGBmin); // Если Qmax или Qmid или Qmin=0, то R = RGBmax или RGBmid или RGBmin соответственно
                    G = Mathf.RoundToInt((1 - Mathf.Abs (Qmax - 1)) * RGBmax + (1 - Mathf.Abs (Qmid - 1)) * RGBmid + (1 - Mathf.Abs (Qmin - 1)) * RGBmin); // Если Qmax или Qmid или Qmin=1, то G = RGBmax или RGBmid или RGBmin соответственно
                    B = Mathf.RoundToInt((Mathf.Abs (Qmax - 0.5f) - 0.5f) * RGBmax + (Mathf.Abs (Qmid - 0.5f) - 0.5f) * RGBmid + (Mathf.Abs (Qmin - 0.5f) - 0.5f) * RGBmin); // Если Qmax или Qmid или Qmin=2, то B = RGBmax или RGBmid или RGBmin соответственно
                    // Поменять контрастность ////////////////////////////////////////////////////
                    // Максимальное, минимальное значение из R,G,B
                    RGBmax = (((((R + G) /2f) + (Mathf.Abs(R - G) /2f)) + B) /2f) + (Mathf.Abs((((R + G) /2f) + (Mathf.Abs(R - G) /2f)) - B) /2f);
                    RGBmin = (((((R + G) /2f) - (Mathf.Abs(R - G) /2f)) + B) /2f) - (Mathf.Abs((((R + G) /2f) - (Mathf.Abs(R - G) /2f)) - B) /2f);
                    Bright = (RGBmax + RGBmin) /2f; // Яркость от 0 до 255
                    Contrast = (RGBmax - RGBmin) /2f; // Контрастность от 0 до 127.5
                    LcR = (Mathf.CeilToInt((R - Bright) /256f) * -2f) + 1; //1=Если "R" меньше "Bright", -1=если больше
                    LcG = (Mathf.CeilToInt((G - Bright) /256f) * -2f) + 1; //1=Если "G" меньше "Bright", -1=если больше
                    LcB = (Mathf.CeilToInt((B - Bright) /256f) * -2f) + 1; //1=Если "B" меньше "Bright", -1=если больше
                    //0 = уменьшить контрастность, 1 = увеличить контрастность
                    Lc2 = Mathf.FloorToInt(Percent_Contrast/(Mathf.Abs(Percent_Contrast)+1f))+1; //1= если "Percent_Bright<0", иначе 0
                    MaxContrast = 127.5f-Mathf.Abs(Bright-127.5f); // Определить максимальную контрастность на яркости "Bright"
                    RGBmid = (R + G + B)-(RGBmax+RGBmin); // Среднее значение из R,G,B
                    E = Mathf.CeilToInt((RGBmid+0.002f-Bright)/256f); //0=если нечетный треугольник, 1=если четный треугольник
                    D = 1-2f*(Bright-Mathf.FloorToInt(Bright)); //1=если яркость с целым числом, иначе 0
                    CountInRow = (Mathf.CeilToInt(Contrast)+E*D-1f)*2f; // Количество ячеек в основном ряду треугольника
                    MaxCountInRow = (Mathf.CeilToInt(MaxContrast)+E*D-1f)*2f; // Количество ячеек в целевом ряду треугольника
                    CellsCount = CountInRow/2f-(Mathf.Abs(RGBmax*E-(RGBmid-RGBmin*(1f-E)))); // Количество ячеек от середины треугольника
                    Sline = Mathf.CeilToInt((CellsCount+1f)/(CountInRow+1f))-1f; //1=если "CellsCount>CountInRow", иначе 0
                    Zero1 = 1f-Mathf.CeilToInt(CountInRow/254f); //1=если "CountInRow=0", иначе 0
                    Kside = (1f/(CountInRow+Zero1))*(CellsCount-Sline); // Коеффициент положения ячейки
                    NextMidCount = MaxCountInRow/2f-Mathf.Abs(Mathf.RoundToInt(Mathf.Abs(Kside)*MaxCountInRow))+Sline; // Количество ячеек от середины треугольника, в целевом ряду
                    NextRGBmid = Mathf.FloorToInt(Mathf.CeilToInt(Mathf.Abs(Bright+MaxContrast*(E*2f-1f)))-NextMidCount*(E*2f-1f)); // "RGBmid" в целевом ряду
                    DiffRGBmid = Mathf.Abs(NextRGBmid-RGBmid); // Сколько нужно приплюсовать к "RGBmid", чтобы получить "DiffRGBmid"
                    Rm = 1f+Mathf.FloorToInt(((RGBmax-RGBmin)-(Mathf.Abs((RGBmax-R)-(R-RGBmin))+1f))/256f); //1=если R=RGBmid, иначе 0
                    Gm = 1f+Mathf.FloorToInt(((RGBmax-RGBmin)-(Mathf.Abs((RGBmax-G)-(G-RGBmin))+1f))/256f); //1=если G=RGBmid, иначе 0
                    Bm = 1f+Mathf.FloorToInt(((RGBmax-RGBmin)-(Mathf.Abs((RGBmax-B)-(B-RGBmin))+1f))/256f); //1=если B=RGBmid, иначе 0
                    BGW = Mathf.CeilToInt((Mathf.Abs(R-G)+Mathf.Abs(R-B))/511f); //0=если R=G=B, иначе 1
                    R = Mathf.RoundToInt(Mathf.Abs(((((MaxContrast*Lc2-(Bright * LcR - R * LcR))*(1f-Rm*Lc2)+
                        DiffRGBmid*Rm*Lc2)*BGW * -Mathf.Abs(Percent_Contrast)) / Max_Percent_Contrast) + R * LcR));
                    G = Mathf.RoundToInt(Mathf.Abs(((((MaxContrast*Lc2-(Bright * LcG - G * LcG))*(1f-Gm*Lc2)+
                        DiffRGBmid*Gm*Lc2)*BGW * -Mathf.Abs(Percent_Contrast)) / Max_Percent_Contrast) + G * LcG));
                    B = Mathf.RoundToInt(Mathf.Abs(((((MaxContrast*Lc2-(Bright * LcB - B * LcB))*(1f-Bm*Lc2)+
                        DiffRGBmid*Bm*Lc2)*BGW * -Mathf.Abs(Percent_Contrast)) / Max_Percent_Contrast) + B * LcB));
                    R = R / 255f;
                    G = G / 255f;
                    B = B / 255f;
                    // Поменять яркость ////////////////////////////////////////////////////
                    R = Mathf.Abs (((((1 + Lc) + R * -(Lc * 2 + 1)) * Mathf.Abs (Percent_Bright)) / Max_Percent_Bright) - R * -(Lc * 2 + 1));
                    G = Mathf.Abs (((((1 + Lc) + G * -(Lc * 2 + 1)) * Mathf.Abs (Percent_Bright)) / Max_Percent_Bright) - G * -(Lc * 2 + 1));
                    B = Mathf.Abs (((((1 + Lc) + B * -(Lc * 2 + 1)) * Mathf.Abs (Percent_Bright)) / Max_Percent_Bright) - B * -(Lc * 2 + 1));                
                    color.r = R;
                    color.g = G;
                    color.b = B;
                    DrawByColor [numofcolorXY] = color; // Нарисовать новый цвет                                
                }
            }
        }            
        if (texture2==null)
        {
            texture2 = new Texture2D(w, h);
            texture2.filterMode = FilterMode.Point; // Для четкой отрисовки     
        }
        else texture2.Resize(w, h);
        texture2.SetPixels(DrawByColor);
        texture2.Apply();
        return texture2;
    }


// Delphi //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Перевести RGB в яркость, оттенок, контрастность.
  
uses  Math;
 
function RGB_to_BSC (R,G,B:extended; out NumOfBright,NumOfShade,NumOfContrast:extended):boolean;
// Перевести RGB в яркость, оттенок, контрастность
var
RGBmax,RGBmin,Rm,Gm,Bm,Qrm,Qgm,Qbm,Q: extended;
begin
 RGBmax := (((((R + G) / 2) + (Abs(R - G) / 2)) + B) / 2) + (Abs((((R + G) / 2) + (Abs(R - G) / 2)) - B) / 2);
 RGBmin := (((((R + G) / 2) - (Abs(R - G) / 2)) + B) / 2) - (Abs((((R + G) / 2) - (Abs(R - G) / 2)) - B) / 2);
 
 NumOfBright := (RGBmax + RGBmin) / 2; // Яркость от 0 до 255
 NumOfContrast := (RGBmax - RGBmin) / 2; // Контрастность от 0 до 127.5
 
 Rm := Floor((R-NumOfBright)/256); // -1= если R<Bright, 0= если R>=Bright
 Gm := Floor((G-NumOfBright)/256); // -1= если G<Bright, 0= если G>=Bright
 Bm := Floor((B-NumOfBright)/256); // -1= если B<Bright, 0= если B>=Bright
 Qrm := (Rm+1)*-Bm; // 1= если 1 или 2 треугольник, иначе 0
 Qgm := (Gm+1)*-Rm; // 1= если 3 или 4 треугольник, иначе 0
 Qbm := (Bm+1)*-Gm; // 1= если 5 или 6 треугольник, иначе 0
 
 Q := Qrm*(Gm+2)+Qgm*(3+(Bm+1))+Qbm*(5+(Rm+1)); // Номер треугольника "1..6"
 NumOfShade := (Q*257-129+Qrm*(G-(B*-Gm)-(R*(1+Gm)))+Qgm*(B-(R*-Bm)-(G*(1+Bm)))+Qbm*(R-(G*-Rm)-(B*(1+Rm))))*(Qrm+Qgm+Qbm); // Оттенок от 0 до 1540
end;
 
 
procedure TForm1.Button1Click(Sender: TObject); // По нажатию кнопки
var
R,G,B, Main_NumOfBright, Main_NumOfShade, Main_NumOfContrast : extended;
begin
 R := 255; G := 0; B := 0; // от 0 до 255
 
 // Перевести RGB в яркость, оттенок, контрастность
 RGB_to_BSC(R,G,B,  Main_NumOfBright, Main_NumOfShade, Main_NumOfContrast);
 
 Main_NumOfBright := Main_NumOfBright*2; // Поменять диапазон яркости от 0 до 510
 Main_NumOfContrast := Floor(Main_NumOfContrast+0.5); // Поменять диапазон контрастности от 0 до 128
 
 Form1.Caption := 'R: '+floattostr(R)+'  G: '+floattostr(G)+'  B: '+floattostr(B)
  +'  -  Яркость: '+floattostr(Main_NumOfBright)+'  Оттенок: '+floattostr(Main_NumOfShade)
  +'  Контрастность: '+floattostr(Main_NumOfContrast);
end;


// Delphi //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Перевести яркость, оттенок, контрастность в RGB (Цвет указывается вручную).
uses  Math;
function BSC_to_RGB_2 (NumOfBright,NumOfShade,NumOfContrast:extended; Move1:boolean;
    out ChangedBright,ChangedShade,ChangedContrast:extended; out R,G,B:extended):boolean; // Перевести яркость, оттенок, контрастность в RGB (Цвет указывается вручную)
var
Q,CellsCount,SideLR,E,Qmax,Qp,Qmid,Qmin,RGBmax,RGBmin,RGBmid: extended;
// Корректировка //////////////////////////////////////////////////////////////
Lp0,Lp1,MaxContrast,D,HalfSideCount,OutOfTriangle: extended;
begin
 // 0.Корректировка ///////////////////////////////////////////////////////////
 // 1.Проверка яркости --------------------------------------------------------
 NumOfBright := NumOfBright/2; // Перевести яркость "0...510" в формат с дробью "0.0 ... 255.0"
 //-----
 // Если "NumOfBright<0" или "NumOfBright>255", то поменять "NumOfBright" соответственно на 0 или 255
 Lp0 := 1-abs(Floor(NumOfBright/(abs(NumOfBright)+1))); // 1= если "NumOfBright>=0", иначе 0
 Lp1 := abs(Floor((255-abs(NumOfBright))/(abs(NumOfBright)+256)))*Lp0; // 1= если "abs(NumOfBright)>255", иначе 0
 NumOfBright := Lp0*(NumOfBright*(1-Lp1)+255*Lp1); // "NumOfBright" в пределах "0..255"
 // 2.Проверка контрастности --------------------------------------------------
 // Если "NumOfContrast<0" или "NumOfContrast>128", то поменять "NumOfContrast" соответственно на 0 или 128
 Lp0 := 1-abs(Floor(NumOfContrast/(abs(NumOfContrast)+1))); // 1= если "NumOfContrast>=0", иначе 0
 Lp1 := abs(Floor((128-abs(NumOfContrast))/(abs(NumOfContrast)+129)))*Lp0; // 1= если "abs(NumOfContrast)>128", иначе 0
 NumOfContrast := Lp0*(NumOfContrast*(1-Lp1)+128*Lp1); // "NumOfContrast" в пределах "0 ... 128"
 //----- (Проверить, выходит ли контрастность за пределы максимальной контрастности "MaxContrast" на заданной яркости "NumOfBright")
 NumOfContrast := Floor(NumOfContrast)-(NumOfBright-Floor(NumOfBright)); // Если яркость с дробью то добавить 0.5 к контрастности.
 MaxContrast := 127.5-abs(NumOfBright-127.5); // Определить максимальную контрастность на яркости "NumOfBright"
 Lp1 := abs(Floor((MaxContrast-abs(NumOfContrast))/(abs(NumOfContrast)+(MaxContrast+1)))); // 1= если "abs(NumOfContrast)>MaxContrast", иначе 0
 NumOfContrast := NumOfContrast*(1-Lp1)+MaxContrast*Lp1; // "NumOfContrast" в пределах "0..MaxContrast"
 // 3. (0..1541) Проверка оттенка ---------------------------------------------
 // Если "NumOfShade<0" или "NumOfShade>1541", то установить "NumOfShade" в пределах "0..1541"
 Lp0 := abs(Floor(NumOfShade/(abs(NumOfShade)+1))); // 1= если "NumOfShade<0", иначе 0
 Lp1 := Floor((abs(NumOfShade)-Lp0)/1542); // Во сколько раз "abs(NumOfShade)>1542"
 NumOfShade := abs(NumOfShade*(Lp0*-2+1)-1542*(Lp1+Lp0)); // "NumOfShade" в пределах "0..1541"
 //----------------------------------------------------------------------------
 // 4. (0..1541) Свойства оттенка (для 5 пункта) ------------------------------
 Q := Floor(NumOfShade/257)+1; // Номер треугольника "1..6"
 CellsCount := NumOfShade-(Q*257-129); // Количество ячеек от середины треугольника к краям, + вправо, - влево
 SideLR := -Floor(CellsCount/130); // 1= если "CellsCount < 0",  0= если "CellsCount >= 0"
 E := 1-(Q/2-Floor(Q/2))*2; // Если четный треугольник то E=1, иначе E=0
 //-----
 // 5. (0..1541) Проверить, находится ли оттенок в пределах одного из треугольников ------
 D := 1-2*(NumOfBright-Floor(NumOfBright)); // 1=если яркость с целым числом, иначе 0
 HalfSideCount := Ceil(NumOfContrast)+E*D-1; // Количество ячеек сбоку от треугольника, не учитывая центр
 OutOfTriangle := -Floor((HalfSideCount-abs(CellsCount))/130); // 1= если "NumOfShade" за пределами треугольника, иначе 0
 if (Move1 = true) then // Перейти к правому треугольнику если оттенок выходит за пределы с правой стороны от треугольника "Q" или к левому треугольнику если выходит за пределы слева от "Q", иначе оставить оттенок "NumOfShade" как есть
  NumOfShade := (OutOfTriangle*((Q*257-129)+(129+(128-(Ceil(NumOfContrast)-1))-(1-E)*D)*(SideLR*-2+1))
               +(1-OutOfTriangle)*NumOfShade)*Ceil(NumOfContrast/129)
 else // Оставить оттенок в "Q" треугольнике справа если оттенок выходит за пределы с правой стороны или в "Q" треугольнике слева если выходит за пределы слева от "Q", иначе оставить оттенок "NumOfShade" как есть
 NumOfShade := (OutOfTriangle*((Q*257-129)+HalfSideCount*(SideLR*-2+1))+(1-OutOfTriangle)*NumOfShade)*Ceil(NumOfContrast/129);
 //-----
 // Если "NumOfShade<0" или "NumOfShade>1541", то установить "NumOfShade" в пределах "0..1541"
 Lp0 := abs(Floor(NumOfShade/(abs(NumOfShade)+1))); // 1= если "NumOfShade<0", иначе 0
 Lp1 := Floor((abs(NumOfShade)-Lp0)/1542); // Во сколько раз "abs(NumOfShade)>1542"
 NumOfShade := abs(NumOfShade*(Lp0*-2+1)-1542*(Lp1+Lp0)); // "NumOfShade" в пределах "0..1541"
 
// 6. (0..1541)  Вывести за пределы функции измененные значения яркости, оттенка, контрастности ----
 ChangedBright := Floor(NumOfBright*2); // Новая яркость
 ChangedShade := Floor(NumOfShade); // Новый оттенок
 ChangedContrast := Floor(NumOfContrast+0.5); // Новая контрастность
 //////////////////////////////////////////////////////////////////////////////
 // Перевести яркость, оттенок, контрастность в RGB ///////////////////////////
 Q := Floor(NumOfShade/257)+1; // Номер треугольника "1..6"
 CellsCount := NumOfShade-(Q*257-129); // Количество ячеек от середины треугольника к краям, + вправо, - влево
 SideLR := -Floor(CellsCount/130); // 1= если "CellsCount < 0",  0= если "CellsCount >= 0"
 E := 1-(Q/2-Floor(Q/2))*2; // Если четный треугольник то E=1, иначе E=0
 Qmax := Ceil(Q/2)-1+E*(1-SideLR)-3*Floor(Q/6)*(1-SideLR); // (0-R, 1-G, 2-B) = RGBmax
 Qp := Q-Floor(Q/4)*3; // Приравнивание 6 треугольников, к 1,2,3 (1-1,2-2,3-3) (4-1,5-2,6-3)
 Qmid := 2-(Qp-SideLR-Floor(Qp/3)*(1-SideLR)*3); // (0-R, 1-G, 2-B) = RGBmid
 Qmin := 3-(Qmax+Qmid); // (0-R, 1-G, 2-B) = RGBmin
 RGBmax := NumOfBright+NumOfContrast; // Максимальное значение из R,G,B
 RGBmin := NumOfBright-abs(NumOfContrast); // Минимальное значение из R,G,B
 RGBmid := abs(RGBmin+(abs(CellsCount)-(NumOfBright*2)*E)*Ceil(NumOfContrast/129)); // Среднее значение из R,G,B
 R := Round((abs(Qmax-2+0.5)-0.5)*RGBmax+(abs(Qmid-2+0.5)-0.5)*RGBmid+(abs(Qmin-2+0.5)-0.5)*RGBmin); // Если Qmax или Qmid или Qmin=0, то R = RGBmax или RGBmid или RGBmin соответственно
 G := Round((1-abs(Qmax-1))*RGBmax+(1-abs(Qmid-1))*RGBmid+(1-abs(Qmin-1))*RGBmin); // Если Qmax или Qmid или Qmin=1, то G = RGBmax или RGBmid или RGBmin соответственно
 B := Round((abs(Qmax-0.5)-0.5)*RGBmax+(abs(Qmid-0.5)-0.5)*RGBmid+(abs(Qmin-0.5)-0.5)*RGBmin); // Если Qmax или Qmid или Qmin=2, то B = RGBmax или RGBmid или RGBmin соответственно
 //////////////////////////////////////////////////////////////////////////////
end;
procedure TForm1.Button4Click(Sender: TObject); // По нажатию кнопки
var
R,G,B, Main_NumOfBright, Main_NumOfShade, Main_NumOfContrast,
ChangedBright, ChangedShade, ChangedContrast : extended;
begin
 Main_NumOfBright := 255; // Яркость, от 0 до 510
 Main_NumOfShade := 1027; // Оттенок, от 0 до 1541 (0 и 1541 переходные значения между 1 и 6 треугольником)
 Main_NumOfContrast := 200; // Контрастность, от 0 до 128 (0=черно-белые оттенки)
 // Перевести яркость, оттенок, контрастность в RGB (Цвет указывается вручную) (true-переходить к следующим треугольникам если оттенок за пределами, false-оставаться в пределах указанного треугольника)
 BSC_to_RGB_2(Main_NumOfBright, Main_NumOfShade, Main_NumOfContrast, true,
            ChangedBright,ChangedShade,ChangedContrast, R,G,B);
 Form1.Caption := 'B: '+floattostr(Main_NumOfBright) +' S: '+floattostr(Main_NumOfShade)
  +' C: '+floattostr(Main_NumOfContrast) +'  |nB: '+floattostr(ChangedBright)
  +' nS: '+floattostr(ChangedShade)+' nC: '+floattostr(ChangedContrast)
  +'| R: '+floattostr(R)+' G: '+floattostr(G)+' B: '+floattostr(B);
end;


// Delphi //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Перевести яркость, оттенок, контрастность в RGB.
uses  Math;
function BSC_to_RGB (NumOfBright,NumOfShade,NumOfContrast:extended;  out R,G,B:extended):boolean; // Перевести яркость, оттенок, контрастность в RGB
var
Q,CellsCount,SideLR,E,Qmax,Qp,Qmid,Qmin,RGBmax,RGBmin,RGBmid: extended;
begin
 Q := Floor(NumOfShade/257)+1; // Номер треугольника "1..6"
 CellsCount := NumOfShade-(Q*257-129); // Количество ячеек от середины треугольника к краям, + вправо, - влево
 SideLR := -Floor(CellsCount/130); // 1= если "CellsCount < 0",  0= если "CellsCount >= 0"
 E := 1-(Q/2-Floor(Q/2))*2; // Если четный треугольник то E=1, иначе E=0
 Qmax := Ceil(Q/2)-1+E*(1-SideLR)-3*Floor(Q/6)*(1-SideLR); // (0-R, 1-G, 2-B) = RGBmax
 Qp := Q-Floor(Q/4)*3; // Приравнивание 6 треугольников, к 1,2,3 (1-1,2-2,3-3) (4-1,5-2,6-3)
 Qmid := 2-(Qp-SideLR-Floor(Qp/3)*(1-SideLR)*3); // (0-R, 1-G, 2-B) = RGBmid
 Qmin := 3-(Qmax+Qmid); // (0-R, 1-G, 2-B) = RGBmin
 RGBmax := NumOfBright+NumOfContrast; // Максимальное значение из R,G,B
 RGBmin := NumOfBright-abs(NumOfContrast); // Минимальное значение из R,G,B
 RGBmid := abs(RGBmin+(abs(CellsCount)-(NumOfBright*2)*E)*Ceil(NumOfContrast/129)); // Среднее значение из R,G,B
 R := Round((abs(Qmax-2+0.5)-0.5)*RGBmax+(abs(Qmid-2+0.5)-0.5)*RGBmid+(abs(Qmin-2+0.5)-0.5)*RGBmin); // Если Qmax или Qmid или Qmin=0, то R = RGBmax или RGBmid или RGBmin соответственно
 G := Round((1-abs(Qmax-1))*RGBmax+(1-abs(Qmid-1))*RGBmid+(1-abs(Qmin-1))*RGBmin); // Если Qmax или Qmid или Qmin=1, то G = RGBmax или RGBmid или RGBmin соответственно
 B := Round((abs(Qmax-0.5)-0.5)*RGBmax+(abs(Qmid-0.5)-0.5)*RGBmid+(abs(Qmin-0.5)-0.5)*RGBmin); // Если Qmax или Qmid или Qmin=2, то B = RGBmax или RGBmid или RGBmin соответственно
end;
procedure TForm1.Button2Click(Sender: TObject); // По нажатию кнопки
var
R,G,B, Main_NumOfBright, Main_NumOfShade, Main_NumOfContrast : extended;
begin
 Main_NumOfBright := 127.5; // Яркость, от 0 до 255
 Main_NumOfShade := 128; // Оттенок, от 1 до 1540
 Main_NumOfContrast := 127.5; // Контрастность, от 0 до 127.5 (0=черно-белые оттенки)
 BSC_to_RGB(Main_NumOfBright, Main_NumOfShade, Main_NumOfContrast,   R,G,B); // Перевести яркость, оттенок, контрастность в RGB
 Main_NumOfBright := Main_NumOfBright*2; // Поменять диапазон яркости от 0 до 510
 Main_NumOfContrast := Floor(Main_NumOfContrast+0.5); // Поменять диапазон контрастности от 0 до 128
 Form1.Caption := 'Яркость: '+floattostr(Main_NumOfBright)+'  Оттенок: '+floattostr(Main_NumOfShade)
  +'  Контрастность: '+floattostr(Main_NumOfContrast)
  +'  -  R: '+floattostr(R)+'  G: '+floattostr(G)+'  B: '+floattostr(B);
end;


// Delphi //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Поменять контрастность RGB.
uses  Math;
function RGB_Contrast (R,G,B, Max_Percent_Contrast,Percent_Contrast:extended;
              out R2,G2,B2:extended):boolean; // Поменять контрастность RGB
var
RGBmax,RGBmin,NumOfBright,NumOfContrast,LcR,LcG,LcB,Lc2,MaxNumOfContrast,
RGBmid,E,D,CountInRow,MaxCountInRow,CellsCount,Sline,Zero1,Kside,NextMidCount,
NextRGBmid,DiffRGBmid,Rm,Gm,Bm,BGW:extended;
begin
 // Максимальное, минимальное значение из R,G,B
 RGBmax := (((((R + G) / 2) + (Abs (R - G) / 2)) + B) / 2) + (Abs ((((R + G) / 2) + (Abs (R - G) / 2)) - B) / 2);
 RGBmin := (((((R + G) / 2) - (Abs (R - G) / 2)) + B) / 2) - (Abs ((((R + G) / 2) - (Abs (R - G) / 2)) - B) / 2);
 NumOfBright := (RGBmax + RGBmin) / 2; // Яркость от 0 до 255
 NumOfContrast := (RGBmax - RGBmin) / 2; // Контрастность от 0 до 127.5
 LcR := (Ceil ((R - NumOfBright) / 256) * -2) + 1; // 1=Если "R" меньше "NumOfBright", -1=если больше
 LcG := (Ceil ((G - NumOfBright) / 256) * -2) + 1; // 1=Если "G" меньше "NumOfBright", -1=если больше
 LcB := (Ceil ((B - NumOfBright) / 256) * -2) + 1; // 1=Если "B" меньше "NumOfBright", -1=если больше
 // 0 = уменьшить контрастность, 1 = увеличить контрастность
 Lc2 := Floor(Percent_Contrast/(Abs(Percent_Contrast)+1))+1; // 1= если "Percent_NumOfBright<0", иначе 0
 MaxNumOfContrast := 127.5-abs(NumOfBright-127.5); // Определить максимальную контрастность на яркости "NumOfBright"
 RGBmid := (R + G + B)-(RGBmax+RGBmin); // Среднее значение из R,G,B
 E := Ceil((RGBmid+0.002-NumOfBright)/256); // 0=если нечетный треугольник, 1=если четный треугольник
 D := 1-2*(NumOfBright-Floor(NumOfBright)); // 1=если яркость с целым числом, иначе 0
 CountInRow := (Ceil(NumOfContrast)+E*D-1)*2; // Количество ячеек в основном ряду треугольника
 MaxCountInRow := (Ceil(MaxNumOfContrast)+E*D-1)*2; // Количество ячеек в целевом ряду треугольника
 CellsCount := CountInRow/2-(abs(RGBmax*E-(RGBmid-RGBmin*(1-E)))); // Количество ячеек от середины треугольника
 Sline := Ceil((CellsCount+1)/(CountInRow+1))-1; // 1=если "CellsCount>CountInRow", иначе 0
 Zero1 := 1-Ceil(CountInRow/254); // 1=если "CountInRow=0", иначе 0
 Kside := (1/(CountInRow+Zero1))*(CellsCount-Sline); // Коеффициент положения ячейки
 NextMidCount := MaxCountInRow/2-abs(Round(abs(Kside)*MaxCountInRow))+Sline; // Количество ячеек от середины треугольника, в целевом ряду
 NextRGBmid := Floor(Ceil(abs(NumOfBright+MaxNumOfContrast*(E*2-1)))-NextMidCount*(E*2-1)); // "RGBmid" в целевом ряду
 DiffRGBmid := abs(NextRGBmid-RGBmid); // Сколько нужно приплюсовать к "RGBmid", чтобы получить "DiffRGBmid"
 Rm := 1+Floor(((RGBmax-RGBmin)-(abs((RGBmax-R)-(R-RGBmin))+1))/256); // 1=если R=RGBmid, иначе 0
 Gm := 1+Floor(((RGBmax-RGBmin)-(abs((RGBmax-G)-(G-RGBmin))+1))/256); // 1=если G=RGBmid, иначе 0
 Bm := 1+Floor(((RGBmax-RGBmin)-(abs((RGBmax-B)-(B-RGBmin))+1))/256); // 1=если B=RGBmid, иначе 0
 BGW := Ceil((abs(R-G)+abs(R-B))/511); // 0=если R=G=B, иначе 1
 R2 := Round(Abs(((((MaxNumOfContrast*Lc2-(NumOfBright * LcR - R * LcR))*(1-Rm*Lc2)+
  DiffRGBmid*Rm*Lc2)*BGW * -abs(Percent_Contrast)) / Max_Percent_Contrast) + R * LcR));
 G2 := Round(Abs(((((MaxNumOfContrast*Lc2-(NumOfBright * LcG - G * LcG))*(1-Gm*Lc2)+
  DiffRGBmid*Gm*Lc2)*BGW * -abs(Percent_Contrast)) / Max_Percent_Contrast) + G * LcG));
 B2 := Round(Abs(((((MaxNumOfContrast*Lc2-(NumOfBright * LcB - B * LcB))*(1-Bm*Lc2)+
  DiffRGBmid*Bm*Lc2)*BGW * -abs(Percent_Contrast)) / Max_Percent_Contrast) + B * LcB));
end;
procedure TForm1.Button3Click(Sender: TObject);
var
R,G,B,R2,G2,B2,Max_Percent_Contrast,Percent_Contrast: extended;
begin
 R := 199; G := 56; B := 56; // от 0 до 255
 Max_Percent_Contrast := 128; // Максимально допустимое значение контрастности (255= Учитывать треугольники на яркости с дробью и без, 128= Учитывать треугольники только одного типа яркости)
 Percent_Contrast := -64; // На сколько процентов поменять контрастность от –Max_Percent_Contrast до Max_Percent_Contrast
 // Поменять контрастность RGB
 RGB_Contrast (R,G,B, Max_Percent_Contrast,Percent_Contrast, R2,G2,B2);
 Form1.Caption := 'R: '+floattostr(R)+'  G: '+floattostr(G)+'  B: '+floattostr(B)
              +'  |Поменять контрастность на '+floattostr(Percent_Contrast)
              +'% из '+floattostr(Max_Percent_Contrast)
              +'|   R2: '+floattostr(R2)+'  G2: '+floattostr(G2)+'  B2: '+floattostr(B2);
end;


// Delphi //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Поменять оттенок RGB.
uses  Math;
function RGB_Shade (NumOfBright,NumOfShade,NumOfContrast,PlusShade:extended; RightColor:boolean;
    out ChangedBright,ChangedShade,ChangedContrast,ChangedShadeMin,ChangedShadeMax:extended;
    out R,G,B:extended):boolean; // Поменять оттенок RGB
var
Q,CellsCount,SideLR,E,Qmax,Qp,Qmid,Qmin,RGBmax,RGBmin,RGBmid: extended;
// Корректировка //////////////////////////////////////////////////////////////
Lp0,Lp1,MaxContrast,D,HalfSideCount,OutOfTriangle: extended;
CellsInRow,OnePercentStep,StepNumber,CellsInRowTriangle,Qb,Ql,Qn,Qlout: extended;
begin
 // 0.Корректировка ///////////////////////////////////////////////////////////
 if (RightColor = false) then // Цвет указывается вручную
 begin
  // 1.Проверка яркости --------------------------------------------------------
  NumOfBright := NumOfBright/2; // Перевести яркость "0...510" в формат с дробью "0.0 ... 255.0"
  //-----
  // Если "NumOfBright<0" или "NumOfBright>255", то поменять "NumOfBright" соответственно на 0 или 255
  Lp0 := 1-abs(Floor(NumOfBright/(abs(NumOfBright)+1))); // 1= если "NumOfBright>=0", иначе 0
  Lp1 := abs(Floor((255-abs(NumOfBright))/(abs(NumOfBright)+256)))*Lp0; // 1= если "abs(NumOfBright)>255", иначе 0
  NumOfBright := Lp0*(NumOfBright*(1-Lp1)+255*Lp1); // "NumOfBright" в пределах "0..255"
  // 2.Проверка контрастности --------------------------------------------------
  // Если "NumOfContrast<0" или "NumOfContrast>128", то поменять "NumOfContrast" соответственно на 0 или 128
  Lp0 := 1-abs(Floor(NumOfContrast/(abs(NumOfContrast)+1))); // 1= если "NumOfContrast>=0", иначе 0
  Lp1 := abs(Floor((128-abs(NumOfContrast))/(abs(NumOfContrast)+129)))*Lp0; // 1= если "abs(NumOfContrast)>128", иначе 0
  NumOfContrast := Lp0*(NumOfContrast*(1-Lp1)+128*Lp1); // "NumOfContrast" в пределах "0 ... 128"
  //----- (Проверить, выходит ли контрастность за пределы максимальной контрастности "MaxContrast" на заданной яркости "NumOfBright")
  NumOfContrast := Floor(NumOfContrast)-(NumOfBright-Floor(NumOfBright)); // Если яркость с дробью то добавить 0.5 к контрастности.
  MaxContrast := 127.5-abs(NumOfBright-127.5); // Определить максимальную контрастность на яркости "NumOfBright"
  Lp1 := abs(Floor((MaxContrast-abs(NumOfContrast))/(abs(NumOfContrast)+(MaxContrast+1)))); // 1= если "abs(NumOfContrast)>MaxContrast", иначе 0
  NumOfContrast := NumOfContrast*(1-Lp1)+MaxContrast*Lp1; // "NumOfContrast" в пределах "0..MaxContrast"
  // 3. (-1529..1529) Проверка оттенка -----------------------------------------
  // Если "PlusShade<-1529" или "PlusShade>1529", то поменять "PlusShade" соответственно на -1529 или 1529
  Lp0 := Floor(PlusShade/(abs(PlusShade)+1))*2+1; // 1= если "PlusShade>=0", иначе -1
  Lp1 := abs(Floor((1529-abs(PlusShade))/(abs(PlusShade)+1530))); // 1= если "abs(PlusShade)>1529", иначе 0
  PlusShade := Lp0*abs(PlusShade*(1-Lp1)+1529*Lp1); // "PlusShade" в пределах "-1529..1529"
  //----------------------------------------------------------------------------
  // 4. (0..1541) Свойства оттенка (для 5 пункта) ------------------------------
  Q := Floor(NumOfShade/257)+1; // Номер треугольника "1..6"
  CellsCount := NumOfShade-(Q*257-129); // Количество ячеек от середины треугольника к краям, + вправо, - влево
  SideLR := -Floor(CellsCount/130); // 1= если "CellsCount < 0",  0= если "CellsCount >= 0"
  E := 1-(Q/2-Floor(Q/2))*2; // Если четный треугольник то E=1, иначе E=0
  //-----
  // 5. (0..1541) Проверить, находится ли оттенок в пределах одного из треугольников ------
  D := 1-2*(NumOfBright-Floor(NumOfBright)); // 1=если яркость с целым числом, иначе 0
  HalfSideCount := Ceil(NumOfContrast)+E*D-1; // Количество ячеек сбоку от треугольника, не учитывая центр
  OutOfTriangle := -Floor((HalfSideCount-abs(CellsCount))/130); // 1= если "NumOfShade" за пределами треугольника, иначе 0
  // Оставить оттенок в "Q" треугольнике справа если оттенок выходит за пределы с правой стороны или в "Q" треугольнике слева если выходит за пределы слева от "Q", иначе оставить оттенок "NumOfShade" как есть
  NumOfShade := (OutOfTriangle*((Q*257-129)+HalfSideCount*(SideLR*-2+1))+(1-OutOfTriangle)*NumOfShade)*Ceil(NumOfContrast/129);
 end
 else // Цвет точно находится в треугольнике
 begin
  NumOfBright := NumOfBright/2; // Перевести яркость "0...510" в формат с дробью "0.0 ... 255.0"
  NumOfContrast := Floor(NumOfContrast)-(NumOfBright-Floor(NumOfBright)); // Если яркость с дробью то добавить 0.5 к контрастности.
 end;
 // 4. (-1529..1529) Свойства оттенка (для 5 пункта) --------------------------
 //NumOfShade := 128; // Оттенок в треугольнике (Уже просчитанный под контрастность "NumContrast")
 Q := Floor(NumOfShade/257)+1; // Номер треугольника "1..6"
 CellsCount := NumOfShade-(Q*257-129); // Количество ячеек от середины треугольника к краям, + вправо, - влево
 E := 1-(Q/2-Floor(Q/2))*2; // Если четный треугольник то E=1, иначе E=0
 //-----
 // 5. (-1529..1529) Проверить, находится ли оттенок в пределах одного из треугольников ------
 D := 1-2*(NumOfBright-Floor(NumOfBright)); // 1=если яркость с целым числом, иначе 0
 CellsInRow := (Ceil(NumOfContrast)*2-1)*6+D*6; // Количество ячеек во всех 6 треугольниках, в ряду "Ceil(NumOfContrast)"
 //OnePercentStep := 1530/CellsInRow; // Сколько ячеек из 1530, являются одним шагом для "CellsInRow" ячеек. (Пример: на контрастности=1, 6 ячеек в ряду и для прохода каждой нужно 6 шагов, по 255 ячеек за шаг)
 //StepNumber := Floor(PlusShade/OnePercentStep); // Номер ячейки в ряду "Ceil(NumOfContrast)"
 //PlusShade := StepNumber;
 CellsInRowTriangle := abs(Ceil(NumOfContrast)*2-1); // Количество ячеек в треугольнике в ряду "Ceil(NumOfContrast)", без учета четности треугольника
 Ql := Floor((PlusShade+CellsCount)/(CellsInRowTriangle+D)); // Приблизительное количество треугольников в указанном промежутке "PlusShade"
 Qn := (PlusShade+CellsCount)-Ql*(CellsInRowTriangle+D); // Количество ячеек от центра следующего треугольника
 Qlout := -Floor(((Ceil(NumOfContrast)-1+D*(1-((Ql+1)/2-Floor((Ql+1)/2))*2))-abs(Qn))/1531); // 1=если "Qn" за пределами треугольника "Ql", иначе 0
 Qb := Ql+Qlout; // Количество треугольников в указанном промежутке "PlusShade"
 // Установить новый оттенок в указанном промежутке "PlusShade", от предыдущего оттенка "NumOfShade"
 NumOfShade := Qb*257+NumOfShade+(PlusShade-CellsInRowTriangle*Qb-D*(1-E)*Qb);
 //-----
 // Если "NumOfShade<0" или "NumOfShade>1541", то установить "NumOfShade" в пределах "0..1541"
 Lp0 := abs(Floor(NumOfShade/(abs(NumOfShade)+1))); // 1= если "NumOfShade<0", иначе 0
 Lp1 := Floor((abs(NumOfShade)-Lp0)/1542); // Во сколько раз "abs(NumOfShade)>1542"
 NumOfShade := abs(NumOfShade*(Lp0*-2+1)-1542*(Lp1+Lp0)); // "NumOfShade" в пределах "0..1541"
 // 6. (-1529..1529) Вывести за пределы функции измененные значения яркости, оттенка, контрастности ----
 ChangedBright := Floor(NumOfBright*2); // Новая яркость
 ChangedShade := Floor(NumOfShade); // Новый оттенок
 ChangedShadeMax := Floor(CellsInRow); // Границы оттенка
 ChangedShadeMin := -Floor(CellsInRow);
 ChangedContrast := Floor(NumOfContrast+0.5); // Новая контрастность
 //////////////////////////////////////////////////////////////////////////////
 // Перевести яркость, оттенок, контрастность в RGB ///////////////////////////
 Q := Floor(NumOfShade/257)+1; // Номер треугольника "1..6"
 CellsCount := NumOfShade-(Q*257-129); // Количество ячеек от середины треугольника к краям, + вправо, - влево
 SideLR := -Floor(CellsCount/130); // 1= если "CellsCount < 0",  0= если "CellsCount >= 0"
 E := 1-(Q/2-Floor(Q/2))*2; // Если четный треугольник то E=1, иначе E=0
 Qmax := Ceil(Q/2)-1+E*(1-SideLR)-3*Floor(Q/6)*(1-SideLR); // (0-R, 1-G, 2-B) = RGBmax
 Qp := Q-Floor(Q/4)*3; // Приравнивание 6 треугольников, к 1,2,3 (1-1,2-2,3-3) (4-1,5-2,6-3)
 Qmid := 2-(Qp-SideLR-Floor(Qp/3)*(1-SideLR)*3); // (0-R, 1-G, 2-B) = RGBmid
 Qmin := 3-(Qmax+Qmid); // (0-R, 1-G, 2-B) = RGBmin
 RGBmax := NumOfBright+NumOfContrast; // Максимальное значение из R,G,B
 RGBmin := NumOfBright-abs(NumOfContrast); // Минимальное значение из R,G,B
 RGBmid := abs(RGBmin+(abs(CellsCount)-(NumOfBright*2)*E)*Ceil(NumOfContrast/129)); // Среднее значение из R,G,B
 R := Round((abs(Qmax-2+0.5)-0.5)*RGBmax+(abs(Qmid-2+0.5)-0.5)*RGBmid+(abs(Qmin-2+0.5)-0.5)*RGBmin); // Если Qmax или Qmid или Qmin=0, то R = RGBmax или RGBmid или RGBmin соответственно
 G := Round((1-abs(Qmax-1))*RGBmax+(1-abs(Qmid-1))*RGBmid+(1-abs(Qmin-1))*RGBmin); // Если Qmax или Qmid или Qmin=1, то G = RGBmax или RGBmid или RGBmin соответственно
 B := Round((abs(Qmax-0.5)-0.5)*RGBmax+(abs(Qmid-0.5)-0.5)*RGBmid+(abs(Qmin-0.5)-0.5)*RGBmin); // Если Qmax или Qmid или Qmin=2, то B = RGBmax или RGBmid или RGBmin соответственно
 //////////////////////////////////////////////////////////////////////////////
end;
procedure TForm1.TrackBar1Change(Sender: TObject); // Если передвинут ползунок "TrackBar1"
var
R,G,B, Main_NumOfBright, Main_NumOfShade, Main_NumOfContrast, PlusShade,
ChangedBright, ChangedShade, ChangedContrast, ChangedShadeMin, ChangedShadeMax : extended;
begin
 //R := 170; G := 0; B := 0; // от 0 до 255
 //RGB_to_BSC(R,G,B,  Main_NumOfBright, Main_NumOfShade, Main_NumOfContrast); // Перевести RGB в яркость, оттенок, контрастность
 //Main_NumOfBright := Main_NumOfBright*2; // Поменять диапазон яркости от 0 до 510
 //Main_NumOfContrast := Floor(Main_NumOfContrast+0.5); // Поменять диапазон контрастности от 0 до 128
 Main_NumOfBright := 170; // Яркость, от 0 до 510
 Main_NumOfShade := 128; // Оттенок, от 1 до 1540
 Main_NumOfContrast := 85; // Контрастность, от 0 до 128 (0=черно-белые оттенки)
 PlusShade := TrackBar1.Position; // Прибавить к оттенку от -1529 до 1529
 // Поменять оттенок RGB (true- цвет точно находится в треугольнике, false- цвет указывается вручную)
 RGB_Shade(Main_NumOfBright, Main_NumOfShade, Main_NumOfContrast, PlusShade, false,
            ChangedBright,ChangedShade,ChangedContrast,ChangedShadeMin,ChangedShadeMax,
            R,G,B);
 if ((TrackBar1.Min<>ChangedShadeMin) or (TrackBar1.Max<>ChangedShadeMax)) then
 begin
  TrackBar1.Min := Floor(ChangedShadeMin);
  TrackBar1.Max := Floor(ChangedShadeMax);
 end;
 Form1.Caption := 'B: '+floattostr(Main_NumOfBright) +' S: '+floattostr(Main_NumOfShade)
  +' C: '+floattostr(Main_NumOfContrast) +' plus: '+floattostr(PlusShade) +'  |nB: '+floattostr(ChangedBright)
  +' nS: '+floattostr(ChangedShade)+' nC: '+floattostr(ChangedContrast)
  +' min: '+floattostr(ChangedShadeMin)+' max: '+floattostr(ChangedShadeMax)
  +'| R: '+floattostr(R)+' G: '+floattostr(G)+' B: '+floattostr(B);
end;


// Delphi //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Поменять яркость RGB.
uses  Math;
function RGB_Bright (R,G,B, Max_Percent_Bright,Percent_Bright: extended;
    out R2,G2,B2:extended):boolean; // Поменять яркость RGB
var
Lc: extended;
begin
 Lc := Floor(Percent_Bright/(Abs(Percent_Bright)+1)); // -1 = уменьшить яркость, 0 = увеличить яркость
 // RGB в формат 0...1
 R := R/255;
 G := G/255;
 B := B/255;
 // Поменять яркость
 R := Abs (((((1 + Lc) + R * -(Lc * 2 + 1)) * Abs (Percent_Bright)) / Max_Percent_Bright) - R * -(Lc * 2 + 1));
 G := Abs (((((1 + Lc) + G * -(Lc * 2 + 1)) * Abs (Percent_Bright)) / Max_Percent_Bright) - G * -(Lc * 2 + 1));
 B := Abs (((((1 + Lc) + B * -(Lc * 2 + 1)) * Abs (Percent_Bright)) / Max_Percent_Bright) - B * -(Lc * 2 + 1));
 // RGB в формат 0...255
 R2 := Round(R * 255);
 G2 := Round(G * 255);
 B2 := Round(B * 255);
end;
procedure TForm1.Button5Click(Sender: TObject);
var
R,G,B,R2,G2,B2,Max_Percent_Bright,Percent_Bright: extended;
begin
 R := 255;  G := 0;   B := 0;
 Max_Percent_Bright := 255; // Максимально допустимое значение яркости (Максимальная яркость = 255)
 Percent_Bright := -127; // На сколько процентов поменять яркость
 // Поменять яркость RGB
 RGB_Bright (R,G,B, Max_Percent_Bright,Percent_Bright, R2,G2,B2);
 Form1.Caption := 'R: '+floattostr(R)+'  G: '+floattostr(G)+'  B: '+floattostr(B)
              +'  |Поменять яркость на '+floattostr(Percent_Bright)
              +'% из '+floattostr(Max_Percent_Bright)
              +'|   R2: '+floattostr(R2)+'  G2: '+floattostr(G2)+'  B2: '+floattostr(B2);
end;


// Delphi //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Порядковый номер RGB.
uses  Math;
function RGB_Number (R,G,B:extended; out MainNumberInRow:extended):boolean; // Найти порядковый номер R,G,B ( черно-белые оттенки = 0-255; цветные оттенки = 256-16777215 )
var
RGBmax,RGBmin,Bright,Contrast, Rm,Gm,Bm,Qrm,Qgm,Qbm,Q,Shade,RGBmid,
E,D,CountInRow,CellsInRow,CellsCount, NumberBeforeRow,NumberInRow,NumberInBright,
MaxContrast,CountBright1,CountBright2,CountBright3, CountMultiply1,CountMultiply2,CountCells127_5,
Bright127_5,MainCountCells,BGW: extended;
begin
 // Максимальное, минимальное значение из R,G,B
 RGBmax := (((((R + G) / 2) + (Abs(R - G) / 2)) + B) / 2) + (Abs((((R + G) / 2) + (Abs(R - G) / 2)) - B) / 2);
 RGBmin := (((((R + G) / 2) - (Abs(R - G) / 2)) + B) / 2) - (Abs((((R + G) / 2) - (Abs(R - G) / 2)) - B) / 2);
 Bright := (RGBmax + RGBmin) / 2; // Яркость от 0 до 255
 Contrast := (RGBmax - RGBmin) / 2; // Контрастность от 0 до 127.5
 Rm := Floor((R-Bright)/256); // -1= если R<Bright, 0= если R>=Bright
 Gm := Floor((G-Bright)/256); // -1= если G<Bright, 0= если G>=Bright
 Bm := Floor((B-Bright)/256); // -1= если B<Bright, 0= если B>=Bright
 Qrm := (Rm+1)*-Bm; // 1= если 1 или 2 треугольник, иначе 0
 Qgm := (Gm+1)*-Rm; // 1= если 3 или 4 треугольник, иначе 0
 Qbm := (Bm+1)*-Gm; // 1= если 5 или 6 треугольник, иначе 0
 Q := Qrm*(Gm+2)+Qgm*(3+(Bm+1))+Qbm*(5+(Rm+1)); // Номер треугольника "1..6"
 Shade := (Q*257-129+Qrm*(G-(B*-Gm)-(R*(1+Gm)))+Qgm*(B-(R*-Bm)-(G*(1+Bm)))+Qbm*(R-(G*-Rm)-(B*(1+Rm))))*(Qrm+Qgm+Qbm); // Оттенок от 0 до 1540
 RGBmid := (R + G + B)-(RGBmax+RGBmin); // Среднее значение из R,G,B
 E := Ceil((RGBmid+0.002-Bright)/256); // 0=если нечетный треугольник, 1=если четный треугольник
 D := 1-2*(Bright-Floor(Bright)); // 1=если яркость с целым числом, иначе 0
 CountInRow := (Ceil(Contrast)+E*D-1)*2; // Количество ячеек в основном ряду треугольника -1
 CellsInRow := (Ceil(Contrast)*2-1)*6+D*6; // Количество ячеек во всех 6 треугольниках, в ряду "Ceil(Contrast)"
 CellsCount := Shade-(Q*257-129); // Количество ячеек от середины треугольника к краям, + вправо, - влево
 NumberBeforeRow := (Power(Ceil(Contrast)-1, 2)+(Ceil(Contrast)-1)*D)*6; // № первой ячейки в ряду
 NumberInRow := Q*(CountInRow+1-(E*2-1)*D)-(1-E)*D-CountInRow/2+CellsCount-1; // Порядковый номер ячейки в ряду "Ceil(Contrast)"
 NumberInBright := NumberBeforeRow+NumberInRow; // Порядковый номер ячейки на яркости "Bright"
 MaxContrast := Ceil(127.5-abs(Bright-127.5)); // Определить максимальную контрастность на яркости "Bright" и перевести в целый формат
 CountBright1 := Power(MaxContrast, 2)*6; // Кол-во ячеек во всех треугольниках на яркости с дробным числом
 CountBright2 := (Power(MaxContrast, 2)+MaxContrast)*6; // Кол-во ячеек во всех треугольниках на яркости с целым числом
 CountBright3 := Power(128, 2)*6; // Кол-во ячеек во всех треугольниках на "127,5" яркости
 CountMultiply1 := ((Power(MaxContrast, 3)-MaxContrast)/6)*2+((MaxContrast+1)*MaxContrast)/2; // На сколько нужно умножить 6, чтобы определить кол-во ячеек в предыдущих и текущей яркости
 CountMultiply2 := (Power((MaxContrast+D), 3)-(MaxContrast+D))/6; // На сколько нужно умножить 12, чтобы определить кол-во ячеек в предыдущих и текущей яркости
 CountCells127_5 := (((Power(128, 3)-128)/6)*2+(129*128)/2)*6+((Power(128, 3)-128)/6)*12; // Количество ячеек на "127,5" и нижних яркостях
 Bright127_5 := -Floor((127.5-Bright)/256); // 1=если "Bright>127,5", иначе 0
 MainCountCells := abs(CountCells127_5*Bright127_5+
                (CountCells127_5*Bright127_5-(CountMultiply1*6+CountMultiply2*12)-
                (CountBright3-CountBright2*D-CountBright1*(1-D))*Bright127_5)); // Количество ячеек на яркости "Bright" и нижних яркостях
 BGW := Ceil((abs(R-G)+abs(R-B))/511); // 0=если R=G=B, иначе 1
 MainNumberInRow := R*(1-BGW)+(256+MainCountCells-CountBright2*D-CountBright1*(1-D)+NumberInBright)*BGW; // Порядковый номер R,G,B
end;
procedure TForm1.Button6Click(Sender: TObject); // Если нажата кнопка
var
R,G,B,MainNumberInRow: extended;
begin
 R := 255;  G := 0;   B := 0;
 // Найти порядковый номер R,G,B ( черно-белые оттенки = 0-255; цветные оттенки = 256-16777215 )
 RGB_Number (R,G,B, MainNumberInRow);
 Form1.Caption := 'R: '+floattostr(R)+'  G: '+floattostr(G)+'  B: '+floattostr(B)
              +'  |  Порядковый номер RGB: '+floattostr(MainNumberInRow);
end;




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

// C# ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    private Texture2D texture2;
    public Texture2D ChangeBC(Texture2D texture,
        float Percent_Bright, float Max_Percent_Bright,
        float Percent_Contrast, float Max_Percent_Contrast)
    { // Поменять яркость, контрастность всего изображения
      // Пример использования: MyNewTexture = ChangeBC (MyTexture,-50,100,50,100);
      // texture = изначальное изображение
      // Percent_Bright = на сколько изменить яркость в процентах от "-Max_Percent_Bright" до "Max_Percent_Bright", где 0 оставляет яркость неизменной
      // Percent_Contrast = на сколько изменить контрастность в процентах от "-Max_Percent_Contrast" до "Max_Percent_Contrast", где 0 оставляет контрастность неизменной
      // 255 - максимальное значение для = Max_Percent_Bright и Max_Percent_Contrast
        int Lc, LcR, LcG, LcB, w, h, numofcolorXY; ;
        float R, G, B, RGBmax, RGBmin, Bright = 0;
        if (Percent_Bright < 0)
            Lc = -1; // -1 = уменьшить яркость
        else
            Lc = 0; // 0 = увеличить яркость
        // Перевести изображение "texture" в массив "Color" (с массивом "Color" напрямую работать быстрее чем с самой текстурой)
        w = texture.width;
        h = texture.height;
        Color[] PictByColor = new Color[w * h];
        PictByColor = texture.GetPixels(0, 0, w, h);
        Color[] DrawByColor = new Color[w * h]; // Холст на котором будет вестись отрисовка
        for (int Yy = 0; Yy < h; Yy++)
        {
            for (int Xx = 0; Xx < w; Xx++)
            {
                numofcolorXY = (h - 1 - Yy) * w + Xx; // Номер ячейки в массиве "PictByColor"
                                                      // Если не прозрачный пиксель
                if (PictByColor[numofcolorXY].a > 0)
                {
                    Color color = PictByColor[numofcolorXY]; // цвет кисти
                    // Цвет "color" в формате от 0 до 1,  (R,G,B)/255f
                    R = color.r;
                    G = color.g;
                    B = color.b;
                    // Поменять яркость ////////////////////////////////////////////////////
                    R = Mathf.Abs(((((1 + Lc) + R * -(Lc * 2 + 1)) * Mathf.Abs(Percent_Bright)) / Max_Percent_Bright) - R * -(Lc * 2 + 1));
                    G = Mathf.Abs(((((1 + Lc) + G * -(Lc * 2 + 1)) * Mathf.Abs(Percent_Bright)) / Max_Percent_Bright) - G * -(Lc * 2 + 1));
                    B = Mathf.Abs(((((1 + Lc) + B * -(Lc * 2 + 1)) * Mathf.Abs(Percent_Bright)) / Max_Percent_Bright) - B * -(Lc * 2 + 1));
                    // Поменять контрастность ////////////////////////////////////////////////////
                    RGBmax = (((((R + G) / 2f) + (Mathf.Abs(R - G) / 2f)) + B) / 2f) + (Mathf.Abs((((R + G) / 2f) + (Mathf.Abs(R - G) / 2f)) - B) / 2f);
                    RGBmin = (((((R + G) / 2f) - (Mathf.Abs(R - G) / 2f)) + B) / 2f) - (Mathf.Abs((((R + G) / 2f) - (Mathf.Abs(R - G) / 2f)) - B) / 2f);
                    Bright = (RGBmax + RGBmin) / 2f; // Яркость от 0 до 255 (или от 0 до 1)
                    //Contrast = (RGBmax-RGBmin)/2f; // Контрастность от 0 до 127.5 (или от 0 до 0.5)
                    LcR = (Mathf.CeilToInt((R - Bright) / 2f) * -2) + 1; // 1=Если "R" меньше "Bright", -1=если больше
                    LcG = (Mathf.CeilToInt((G - Bright) / 2f) * -2) + 1; // 1=Если "G" меньше "Bright", -1=если больше
                    LcB = (Mathf.CeilToInt((B - Bright) / 2f) * -2) + 1; // 1=Если "B" меньше "Bright", -1=если больше
                    R = Mathf.Abs((((Bright * LcR - R * LcR) * Percent_Contrast) / Max_Percent_Contrast) + R * LcR);
                    G = Mathf.Abs((((Bright * LcG - G * LcG) * Percent_Contrast) / Max_Percent_Contrast) + G * LcG);
                    B = Mathf.Abs((((Bright * LcB - B * LcB) * Percent_Contrast) / Max_Percent_Contrast) + B * LcB);
                    if (R>1) R = 1;
                    if (G>1) G = 1;
                    if (B>1) B = 1;
                    color.r = R;
                    color.g = G;
                    color.b = B;
                    DrawByColor[numofcolorXY] = color; // Нарисовать новый цвет
                }
            }
        }
        if (texture2==null)
        {
            texture2 = new Texture2D(w, h);
            texture2.filterMode = FilterMode.Point; // Для четкой отрисовки     
        }
        else texture2.Resize(w, h);
        texture2.SetPixels(DrawByColor);
        texture2.Apply();
        return texture2;
    }


// Delphi //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
uses Math;
function ChangeBC(RGB1: TColor;
 Percent_Bright,Max_Percent_Bright,
 Percent_Contrast,Max_Percent_Contrast: extended):TColor; // Поменять яркость, контрастность
var
Lc, LcR, LcG, LcB, w, h, numofcolorXY: integer ;
R, G, B, RGBmax, RGBmin, Bright, Contrast: extended;
//Shade, Rm, Gm, Bm, Qrm, Qgm, Qbm: extended;
begin
 showmessage('Прибавить к яркости: '+floattostr(Percent_Bright)
 +#13#10+'Прибавить к контрастности: '+floattostr(Percent_Contrast));
  R := GetRValue(RGB1);
  G := GetGValue(RGB1);
  B := GetBValue(RGB1);
// Percent_Bright = на сколько изменить яркость в процентах от "-Max_Percent_Bright" до "Max_Percent_Bright", где 0 оставляет яркость неизменной
// Percent_Contrast = на сколько изменить контрастность в процентах от "-Max_Percent_Contrast" до "Max_Percent_Contrast", где 0 оставляет контрастность неизменной
// 255 - максимальное значение для = Max_Percent_Bright и Max_Percent_Contrast
// Цвет "color" в формате от 0 до 1,  (R,G,B)/255
R := R /255;
G := G /255;
B := B /255;
if (Percent_Bright < 0) then
 Lc := -1 // -1 = уменьшить яркость
else Lc := 0; // 0 = увеличить яркость
// Поменять яркость ////////////////////////////////////////////////////
R := Abs(((((1 + Lc) + R * -(Lc * 2 + 1)) * Abs(Percent_Bright)) / Max_Percent_Bright) - R * -(Lc * 2 + 1));
G := Abs(((((1 + Lc) + G * -(Lc * 2 + 1)) * Abs(Percent_Bright)) / Max_Percent_Bright) - G * -(Lc * 2 + 1));
B := Abs(((((1 + Lc) + B * -(Lc * 2 + 1)) * Abs(Percent_Bright)) / Max_Percent_Bright) - B * -(Lc * 2 + 1));
// Поменять контрастность ////////////////////////////////////////////////////
// Максимальное и минимальное значение из трех чисел
RGBmax := (((((R + G) / 2) + (Abs(R - G) / 2)) + B) / 2) + (Abs((((R + G) / 2) + (Abs(R - G) / 2)) - B) / 2);
RGBmin := (((((R + G) / 2) - (Abs(R - G) / 2)) + B) / 2) - (Abs((((R + G) / 2) - (Abs(R - G) / 2)) - B) / 2);
Bright := (RGBmax + RGBmin) / 2; // Яркость от 0 до 255 (или от 0 до 1)
//Contrast := (RGBmax-RGBmin)/2; // Контрастность от 0 до 127.5 (или от 0 до 0.5)
// Условие, уменьшать или увеличивать переменную
LcR := (Ceil((R - Bright) / 2) * -2) + 1; // 1=Если "R" меньше "Bright", -1=если больше
LcG := (Ceil((G - Bright) / 2) * -2) + 1; // 1=Если "G" меньше "Bright", -1=если больше
LcB := (Ceil((B - Bright) / 2) * -2) + 1; // 1=Если "B" меньше "Bright", -1=если больше
R := Abs((((Bright * LcR - R * LcR) * Percent_Contrast) / Max_Percent_Contrast) + R * LcR);
G := Abs((((Bright * LcG - G * LcG) * Percent_Contrast) / Max_Percent_Contrast) + G * LcG);
B := Abs((((Bright * LcB - B * LcB) * Percent_Contrast) / Max_Percent_Contrast) + B * LcB);
if (R>1) then R := 1;
if (G>1) then G := 1;
if (B>1) then B := 1;
ChangeBC := RGB(Round(R*255),Round(G*255),Round(B*255));
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Color1: TColor;
begin
 Color1 := RGB(255,8,14);
 Form1.Color := Color1;
 Form1.Color := ChangeBC(Color1, 50, 100, 60, 100);
end;


StatusReleased
CategoryTool
PlatformsHTML5
AuthorUchenik_333
Made withUnity

Download

Download
ChangeBrightContrast_Script.zip 3 kB
Download
ChangeBrightShadeContrast_Script.zip 7 kB

Leave a comment

Log in with itch.io to leave a comment.