unit colors; {$MODE OBJFPC} {$M+} interface uses type_fixes; // TODO: use "object", no interfaces, for such small types. type // TODO make this more dynamic? TColorspace = (csCustom, csRGB, csCMYK, csHSV, csGray, csIndexed); // TODO use a normal "TColor" pascal-object instead? or include the system representation herein? // if so, provide a registry for colorspaces (enum). IColor = interface ['{09915160-CAD7-11DD-8103-476C55D89593}'] end; IGrayColor = interface(IColor) ['{D0BA74E8-CAD6-11DD-B71B-866A55D89593}'] function GetGray : TUINT16; property Gray : TUINT16 read GetGray; end; IBitColor = interface(IGrayColor) ['{DBFC4E62-CAD6-11DD-B57A-096B55D89593}'] // no. function GetGray : TByte; // property Gray : TByte { 0..1 }{bit} read GetGray; end; IRGBColor = interface(IColor) ['{E306D452-CAD6-11DD-A005-466B55D89593}'] function GetRed : TUINT16; function GetGreen : TUINT16; function GetBlue : TUINT16; property Red : TUINT16 read GetRed; property Green : TUINT16 read GetGreen; property Blue : TUINT16 read GetBlue; end; IRGBAColor = interface(IRGBColor) ['{E66F48C2-CAD6-11DD-9995-656B55D89593}'] function GetAlpha : TUINT16; property Alpha : TUINT16 read GetAlpha; { 0: translucent } end; { I8Red8Green8BlueColor = interface(IRGBColor) property Red : Byte; property Green : Byte; property Blue : Byte; end; I8Red8Green8Blue8AlphaColor = interface(I8Red8Green8BlueColor) property Alpha : Byte; end; and 5 and 6 and 2 and .... } TIColorArray = array of IColor; TRGBAColor = class(TInterfacedObject, IRGBAColor, IRGBColor, IColor, IInterface) private fRed : TUINT16; fGreen : TUINT16; fBlue : TUINT16; fAlpha : TUINT16; published constructor Create(aRed, aGreen, aBlue, aAlpha : TUINT16); protected function GetRed : TUINT16; function GetGreen : TUINT16; function GetBlue : TUINT16; function GetAlpha : TUINT16; published property Red : TUINT16 read GetRed; property Green : TUINT16 read GetGreen; property Blue : TUINT16 read GetBlue; property Alpha : TUINT16 read GetAlpha; end; TRGBColor = class(TRGBAColor, IRGBColor, IColor, IInterface) published constructor Create(aRed, aGreen, aBlue : TUINT16); end; { YUV: U \approx 0.872021 \cdot Pb V \approx 1.229951 \cdot Pr Y := 0.299 \cdot R + 0.587 \cdot G + 0.114 \cdot B U := ( B - Y ) \cdot 0.493 V := ( R - Y ) \cdot 0.877 B = Y + U/0.493\, R = Y + V/0.877\, G = 1.7 \cdot Y - 0.509 \cdot R - 0.194 \cdot B (ca) bzw: G = Y - 0.39466 \cdot U - 0.5806 \cdot V (ca) } { JPEG: Die YCbCr-Transformation bei JPEG und MPEG verwendet ebenfalls dieses Farbmodell. Da JPEG keine Synchronisationswerte in den Bilddatenstrom abbilden muss, kann für die Werte von YCbCr der volle Wertebereich von 8 Bit verwendet werden, also sind Y', Cb', Cr' und auch R, G und B im Wertebereich 0..255 möglich. \begin bmatrix Y' \\ Cb \\ Cr \end bmatrix \approx \begin bmatrix 0 \\ 128 \\ 128 \end bmatrix + \begin bmatrix 0.299 & 0.587 & 0.114 \\ -0.168736 & -0.331264 & 0.5 \\ 0.5 & -0.418688 & -0.081312 \end bmatrix \cdot \begin bmatrix R'_d \\ G'_d \\ B'_d \end bmatrix . # YCbCr 4:4:4 Chrominanz-Auflösung identisch zur Luminanz-Auflösung 4:2:0: sowohl horizontal als auch vertikal halbierte Chrominanz. } procedure YCbCrFromRGB8(aRed, aGreen, aBlue : TByte; out aY, aCb, aCr : TByte); procedure RGB8FromYCbCr(aY, aCb, aCr : TByte; out aRed, aGreen, aBlue : TByte); implementation constructor TRGBAColor.Create(aRed, aGreen, aBlue, aAlpha : TUINT16); begin fRed := aRed; fGreen := aGreen; fBlue := aBlue; fAlpha := aAlpha; end; function TRGBAColor.GetRed : TUINT16; begin Result := fRed; end; function TRGBAColor.GetGreen : TUINT16; begin Result := fGreen; end; function TRGBAColor.GetBlue : TUINT16; begin Result := fBlue; end; function TRGBAColor.GetAlpha : TUINT16; begin Result := fAlpha; end; { TRGBColor } constructor TRGBColor.Create(aRed, aGreen, aBlue : TUINT16); begin inherited Create(aRed, aGreen, aBlue, $FFFF); end; procedure YCbCrFromRGB8(aRed, aGreen, aBlue : TByte; out aY, aCb, aCr : TByte); inline; begin aY := Trunc(0.299 * aRed + 0.587 * aGreen + 0.114 * aBlue); aCb := Trunc(-0.1687 * aRed - 0.3313 * aGreen + 0.5 * aBlue + 128); aCr := Trunc(0.5 * aRed - 0.4187 * aGreen - 0.0813 * aBlue + 128); end; procedure RGB8FromYCbCr(aY, aCb, aCr : TByte; out aRed, aGreen, aBlue : TByte); inline; begin aRed := Trunc(aY + 1.402 * (aCr - 128)); aGreen := Trunc(aY - 0.34414 * (aCb - 128) - 0.71414 * (aCr - 128)); aBlue := Trunc(aY + 1.772 * (aCb - 128)); end; end.