4150 lines
165 KiB
ObjectPascal
4150 lines
165 KiB
ObjectPascal
{$IFDEF FPC}
|
|
{$DEFINE NOT_USE_KOL_ERR}
|
|
{$MODE Delphi}
|
|
{$ASMMODE intel}
|
|
{$GOTO ON}
|
|
{$ENDIF}
|
|
|
|
unit KOLGraphicColor;
|
|
|
|
// This file is part of the image library GraphicEx (www.lischke-online.de/Graphics.html).
|
|
//
|
|
// GraphicColor contains the implementation of the color conversion manager.
|
|
// This class is responsible for converting between these color schemes/formats:
|
|
// - RGB(A)
|
|
// - BGR(A)
|
|
// - CMY(K)
|
|
// - CIE L*a*b*
|
|
// - PhotoYCC, standard YCbCr
|
|
// - indexed
|
|
// - grayscale (with alpha, which is ignored currently)
|
|
//
|
|
// Additional tasks are:
|
|
// - coversions between bit depths (1,2,4,8,16 bits)
|
|
// - palette creation
|
|
// - gamma tables creation and application
|
|
// - masked pixel transfer for interlaced images
|
|
// - big endian swap
|
|
// - plane (planar) -> interleaved (interlaced) conversion
|
|
//
|
|
// Notes:
|
|
// - Throughout the entire unit I used the terms BPS and SPP for "bits per sample" and
|
|
// "samples per pixel", respectively. A sample is one component per pixel. For indexed color schemes
|
|
// there's only 1 sample per pixel, for RGB there are 3 (red, green and blue) and so on.
|
|
// - The bit depth of multi sample formats like RGB must be equal for each color component.
|
|
// - Because of the large amount of possible combinations (color schemes, sample depth, gamma, byte swap)
|
|
// I limited the accepted combinations to pratical ones. This leaves currently out:
|
|
// + gamma correction for 16 bit values
|
|
// + conversion to 16 bit (target) grayscale with alpha
|
|
// + samples sizes less than 8 bits for multi-sample schemes (RGB etc.)
|
|
// + indexed schemes with planes (e.g. 16 colors indexed as 4 planes each with one bit per sample)
|
|
// - For now there is no conversion between indexed and non-indexed formats. Also between grayscale
|
|
// and any other scheme is no conversion possible.
|
|
//
|
|
// (c) Copyright 1999, 2000 Dipl. Ing. Mike Lischke (public@lischke-online.de). All rights reserved.
|
|
//
|
|
// This package is freeware for non-commercial use only.
|
|
// Contact author for licenses (shareware@lischke-online.de) and see License.txt which comes with the package.
|
|
|
|
//////////////////////////////////////////////////
|
|
// Converted to KOL by Dimaxx (dimaxx@atnet.ru) //
|
|
//////////////////////////////////////////////////
|
|
|
|
interface
|
|
|
|
{$ALIGN OFF}
|
|
{$I KOLDEF.INC}
|
|
|
|
uses Windows, KOL, Errors, {$IFDEF NOT_USE_KOL_ERR}sysutils {$ELSE}Err {$ENDIF};
|
|
|
|
const
|
|
// this is the value for average CRT monitors, adjust it if your monitor differs
|
|
DefaultDisplayGamma = 2.2;
|
|
|
|
type
|
|
TColorScheme = (
|
|
csUnknown, // not (yet) defined color scheme
|
|
csIndexed, // any palette format
|
|
csG, // gray scale
|
|
csGA, // gray scale with alpha channel
|
|
csRGB, // red, green, blue
|
|
csRGBA, // RGB with alpha channel
|
|
csBGR, // RGB in reversed order (used under Windows)
|
|
csBGRA, // BGR with alpha channel (alpha is always the last component)
|
|
csCMY, // cyan, magenta, yellow (used mainly for printing processes)
|
|
csCMYK, // CMY with black
|
|
csCIELab, // CIE color format using luminance and chromaticities
|
|
csYCbCr, // another format using luminance and chromaticities
|
|
csPhotoYCC // a modified YCbCr version used for photo CDs
|
|
);
|
|
|
|
TConvertOptions = set of (
|
|
coAlpha, // alpha channel is to be considered (this value is
|
|
// usually automatically set depending on the color scheme)
|
|
coApplyGamma, // target only, gamma correction must take place
|
|
coNeedByteSwap, // endian switch needed
|
|
coLabByteRange, // CIE L*a*b* only, luminance range is from 0..255 instead 0..100
|
|
coLabChromaOffset); // CIE L*a*b* only, chrominance values a and b are given in 0..255 instead -128..127
|
|
|
|
// format of the raw data to create a color palette from
|
|
TRawPaletteFormat = (
|
|
pfInterlaced8Triple, // rgb triple with 8 bits per component
|
|
pfInterlaced8Quad, // rgb quad with 8 bits per component (fourth entry is reserved as in Windows' logical palette)
|
|
pfPlane8Triple, // 3 separate planes of data with 8 bits per component
|
|
pfPlane8Quad,
|
|
pfInterlaced16Triple, // rgb triple with 16 bits per component
|
|
pfInterlaced16Quad,
|
|
pfPlane16Triple, // 3 separate planes of data with 16 bits per component
|
|
pfPlane16Quad);
|
|
|
|
// TConversionMethod describes the general parameter list to which each implemented conversion method conforms.
|
|
// Note: Source is defined as open array parameter to allow plane and interlaced source data.
|
|
TConversionMethod = procedure(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte) of object;
|
|
|
|
PColorManager = ^TColorManager;
|
|
TColorManager = object(TObj)
|
|
private
|
|
FChanged: boolean; // set if any of the parameters changed
|
|
FSourceBPS, // bits per sample of source data (allowed values are 1, 2, 4, 8, 16)
|
|
FTargetBPS, // bits per sample of target data (allowed values are 1, 2, 4, 8, 16)
|
|
FSourceSPP, // samples per source pixel (allowed values are 1, 3, 4)
|
|
FTargetSPP: byte; // samples per target pixel (allowed values are 1, 3, 4)
|
|
FMainGamma, // primary gamma value which is usually read from a file (default is 1)
|
|
FDisplayGamma: single; // (constant) gamma value of the current monitor (default is 2.2)
|
|
FGammaTable: array[Byte] of byte; // contains precalculated gamma values for each possible component value
|
|
// (range is 0..255)
|
|
FYCbCrCoefficients: array[0..2] of single;
|
|
FHSubsampling,
|
|
FVSubSampling: byte; // additional parameters used for YCbCr conversion
|
|
FCrToRedTable, // lookup tables used for YCbCr conversion
|
|
FCbToBlueTable,
|
|
FCrToGreenTable,
|
|
FCbToGreenTable: array of integer;
|
|
FSourceScheme,FTargetScheme: TColorScheme;
|
|
FRowConversion: TConversionMethod; // procedure variable for the actual conversion method used
|
|
FSourceOptions,
|
|
FTargetOptions: TConvertOptions; // options to control conversion
|
|
protected
|
|
// Low level conversion helper used to convert one pixel component.
|
|
function ComponentGammaConvert(Value: byte): byte;
|
|
function ComponentNoConvert16(Value: word): word;
|
|
function ComponentNoConvert8(Value: byte): byte;
|
|
function ComponentScaleConvert(Value: word): byte;
|
|
function ComponentScaleGammaConvert(Value: word): byte;
|
|
function ComponentSwapScaleGammaConvert(Value: Word): byte;
|
|
function ComponentSwapScaleConvert(Value: word): byte;
|
|
function ComponentSwapConvert(Value: word): word;
|
|
// row conversion routines
|
|
procedure RowConvertBGR2BGR(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
procedure RowConvertBGR2RGB(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
procedure RowConvertCIELAB2BGR(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
procedure RowConvertCIELAB2RGB(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
procedure RowConvertCMYK2BGR(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
procedure RowConvertCMYK2RGB(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
procedure RowConvertGray(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
procedure RowConvertIndexed8(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
procedure RowConvertIndexedBoth16(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
procedure RowConvertIndexedSource16(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
procedure RowConvertIndexedTarget16(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
procedure RowConvertRGB2BGR(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
procedure RowConvertRGB2RGB(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
procedure RowConvertPhotoYCC2BGR(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
procedure RowConvertPhotoYCC2RGB(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
procedure RowConvertYCbCr2BGR(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
procedure RowConvertYCbCr2RGB(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
|
|
// other general routines
|
|
procedure CreateYCbCrLookup;
|
|
function GetPixelFormat(Index: integer): TPixelFormat;
|
|
procedure PrepareConversion;
|
|
procedure SetSourceBitsPerSample(const Value: byte);
|
|
procedure SetSourceColorScheme(const Value: TColorScheme);
|
|
procedure SetSourceSamplesPerPixel(const Value: byte);
|
|
procedure SetTargetBitsPerSample(const Value: byte);
|
|
procedure SetTargetColorScheme(const Value: TColorScheme);
|
|
procedure SetTargetSamplesPerPixel(const Value: byte);
|
|
public
|
|
// constructor Create;
|
|
procedure ConvertRow(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
procedure CreateColorPalette(BMP: PBitmap; Data: array of pointer; DataFormat: TRawPaletteFormat; ColorCount: cardinal; RGB: boolean);
|
|
procedure CreateGrayscalePalette(BMP: PBitmap; MinimumIsWhite: boolean);
|
|
procedure Error(Code: integer);
|
|
procedure SetGamma(MainGamma: single; DisplayGamma: single = DefaultDisplayGamma);
|
|
procedure SetYCbCrParameters(Values: array of single; HSubSampling,VSubSampling: byte);
|
|
|
|
property SourceBitsPerSample: byte read FSourceBPS write SetSourceBitsPerSample;
|
|
property SourceColorScheme: TColorScheme read FSourceScheme write SetSourceColorScheme;
|
|
property SourceOptions: TConvertOptions read FSourceOptions write FSourceOptions;
|
|
property SourcePixelFormat: TPixelFormat index 0 read GetPixelFormat;
|
|
property SourceSamplesPerPixel: byte read FSourceSPP write SetSourceSamplesPerPixel;
|
|
property TargetBitsPerSample: byte read FTargetBPS write SetTargetBitsPerSample;
|
|
property TargetColorScheme: TColorScheme read FTargetScheme write SetTargetColorScheme;
|
|
property TargetOptions: TConvertOptions read FTargetOptions write FTargetOptions;
|
|
property TargetPixelFormat: TPixelFormat index 1 read GetPixelFormat;
|
|
property TargetSamplesPerPixel: byte read FTargetSPP write SetTargetSamplesPerPixel;
|
|
end;
|
|
|
|
function NewColorManager: PColorManager;
|
|
function ClampByte(Value: integer): byte;
|
|
function MulDiv16(Number,Numerator,Denominator: word): word;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
implementation
|
|
|
|
uses {$IFDEF NOT_USE_KOL_ERR}math{$ELSE}KolMath{$ENDIF};
|
|
|
|
type
|
|
PCMYK = ^TCMYK;
|
|
TCMYK = packed record
|
|
C,M,Y,K: byte;
|
|
end;
|
|
PCMYK16 = ^TCMYK16;
|
|
TCMYK16 = packed record
|
|
C,M,Y,K: word;
|
|
end;
|
|
PCMY = ^TCMY;
|
|
TCMY = packed record
|
|
C,M,Y: byte;
|
|
end;
|
|
PCMY16 = ^TCMY16;
|
|
TCMY16 = packed record
|
|
C,M,Y: word;
|
|
end;
|
|
PRGB = ^TRGB;
|
|
TRGB = packed record
|
|
R,G,B: byte;
|
|
end;
|
|
PRGB16 = ^TRGB16;
|
|
TRGB16 = packed record
|
|
R,G,B: word;
|
|
end;
|
|
PRGBA = ^TRGBA;
|
|
TRGBA = packed record
|
|
R,G,B,A: byte;
|
|
end;
|
|
PRGBA16 = ^TRGBA16;
|
|
TRGBA16 = packed record
|
|
R,G,B,A: word;
|
|
end;
|
|
PBGR = ^TBGR;
|
|
TBGR = packed record
|
|
B,G,R: byte;
|
|
end;
|
|
PBGR16 = ^TBGR16;
|
|
TBGR16 = packed record
|
|
B,G,R: word;
|
|
end;
|
|
PBGRA = ^TBGRA;
|
|
TBGRA = packed record
|
|
B,G,R,A: byte;
|
|
end;
|
|
PBGRA16 = ^TBGRA16;
|
|
TBGRA16 = packed record
|
|
B,G,R,A: word;
|
|
end;
|
|
|
|
//----------------- helper functions -----------------------------------------------------------------------------------
|
|
|
|
function ClampByte(Value: integer): byte;
|
|
// ensures Value is in the range 0..255, values<0 are clamped to 0 and values > 255 are clamped to 255
|
|
asm
|
|
OR EAX,EAX
|
|
JNS @@positive
|
|
XOR EAX,EAX
|
|
RET
|
|
@@positive:
|
|
CMP EAX,255
|
|
JBE @@OK
|
|
MOV EAX,255
|
|
@@OK:
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
function MulDiv16(Number,Numerator,Denominator: word): word;
|
|
// faster equivalent to Windows' MulDiv function
|
|
// Number is passed via AX
|
|
// Numerator is passed via DX
|
|
// Denominator is passed via CX
|
|
// Result is passed via AX
|
|
// Note: No error checking takes place. Denominator must be > 0!
|
|
asm
|
|
MUL DX
|
|
DIV CX
|
|
end;
|
|
|
|
//----------------- TColorManager --------------------------------------------------------------------------------------
|
|
|
|
function NewColorManager: PColorManager;
|
|
// set some default values
|
|
begin
|
|
New(Result,Create);
|
|
Result.FSourceBPS:=8;
|
|
Result.FTargetBPS:=8;
|
|
Result.FSourceSPP:=3; // 24 bit format
|
|
Result.FTargetSPP:=3; // 24 bit format
|
|
Result.SetGamma(1,DefaultDisplayGamma);
|
|
Result.FSourceScheme:=csRGB;
|
|
Result.FTargetScheme:=csBGR;
|
|
// defaults are from CCIR Recommendation 601-1
|
|
Result.FYCbCrCoefficients[0]:=0.299;
|
|
Result.FYCbCrCoefficients[1]:=0.587;
|
|
Result.FYCbCrCoefficients[2]:=0.114;
|
|
Result.FHSubSampling:=1;
|
|
Result.FVSubSampling:=1;
|
|
Result.FChanged:=True;
|
|
end;
|
|
|
|
//----------------- low level conversion routines ----------------------------------------------------------------------
|
|
|
|
// These routines are used for conversions from 16 to 8 bit values, either with gamma correction or byte swap (or both).
|
|
|
|
function TColorManager.ComponentNoConvert8(Value: byte): byte;
|
|
begin
|
|
Result:=Value;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
function TColorManager.ComponentNoConvert16(Value: word): word;
|
|
begin
|
|
Result:=Value;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
function TColorManager.ComponentGammaConvert(Value: byte): byte;
|
|
begin
|
|
Result:=FGammaTable[Value];
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
function TColorManager.ComponentScaleConvert(Value: word): byte;
|
|
begin
|
|
Result:=MulDiv16(Value,255,65535);
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
function TColorManager.ComponentScaleGammaConvert(Value: word): byte;
|
|
begin
|
|
Result:=FGammaTable[MulDiv16(Value,255,65535)];
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
function TColorManager.ComponentSwapScaleGammaConvert(Value: word): byte;
|
|
begin
|
|
Result:=FGammaTable[MulDiv16(System.Swap(Value),255,65535)];
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
function TColorManager.ComponentSwapScaleConvert(Value: word): byte;
|
|
begin
|
|
Result:=MulDiv16(System.Swap(Value),255,65535);
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
function TColorManager.ComponentSwapConvert(Value: word): word;
|
|
begin
|
|
Result:=System.Swap(Value);
|
|
end;
|
|
|
|
//----------------- row conversion routines ----------------------------------------------------------------------------
|
|
|
|
// Notes: Each method takes parameters for source and target data as well as the count of pixels to work on. This count
|
|
// determines the number of pixels in the target buffer. The actual source count may differ for special color
|
|
// schemes (like YCbCr) or interlaced lines.
|
|
// Mask is a parameter which determines (in a repeative manner) which source pixel should actually be transferred
|
|
// to the target buffer. A 1 in the corresponding bit (MSB is leftmost pixel) causes the transfer to happen.
|
|
// Usually, this parameter is $FF to transfer all pixels, but for interlaced images (e.g. as in PNG format)
|
|
// this will differ to limit pixel transfers. The bit mask only describes which target pixel is to skip. Source
|
|
// pixel must be packed.
|
|
// Windows DIBs are always byte aligned, so we don't need checks for byte alignments (in target).
|
|
|
|
procedure TColorManager.RowConvertBGR2BGR(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
// same as ConvertBGR2RGB but for BGR target schemes
|
|
var
|
|
SourceR16,SourceG16,SourceB16,SourceA16: PWord;
|
|
SourceR8,SourceG8,SourceB8,SourceA8: PByte;
|
|
TargetRun16: PBGR16;
|
|
TargetRunA16: PBGRA16;
|
|
TargetRun8: PBGR;
|
|
TargetRunA8: PBGRA;
|
|
BitRun: byte;
|
|
Convert8_8: function(Value: byte): byte of object;
|
|
Convert16_8: function(Value: word): byte of object;
|
|
Convert16_8Alpha: function(Value: word): byte of object;
|
|
Convert16_16: function(Value: word): word of object;
|
|
SourceIncrement,TargetIncrement: cardinal;
|
|
CopyAlpha: boolean;
|
|
begin
|
|
BitRun:=$80;
|
|
// determine alpha handling once
|
|
CopyAlpha:=False;
|
|
if coAlpha in FSourceOptions then
|
|
begin
|
|
SourceIncrement:=sizeof(TRGBA);
|
|
TargetIncrement:=sizeof(TRGB);
|
|
if coAlpha in FTargetOptions then CopyAlpha:=True;
|
|
end
|
|
else
|
|
begin
|
|
SourceIncrement:=sizeof(TRGB);
|
|
if coAlpha in FTargetOptions then TargetIncrement:=sizeof(TRGBA) else TargetIncrement:=sizeof(TRGB);
|
|
end;
|
|
// in planar mode source increment is always 1
|
|
if Length(Source)>1 then SourceIncrement:=1;
|
|
case FSourceBPS of
|
|
8: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
// interleaved mode
|
|
SourceB8:=Source[0];
|
|
SourceG8:=SourceB8;
|
|
Inc(SourceG8);
|
|
SourceR8:=SourceG8;
|
|
Inc(SourceR8);
|
|
SourceA8:=SourceR8;
|
|
Inc(SourceA8);
|
|
end
|
|
else
|
|
begin
|
|
SourceB8:=Source[0];
|
|
SourceG8:=Source[1];
|
|
SourceR8:=Source[2];
|
|
if coAlpha in FSourceOptions then SourceA8:=Source[3] else SourceA8:=nil;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 888 to 888
|
|
if coApplyGamma in FTargetOptions then Convert8_8:=ComponentGammaConvert else Convert8_8:=ComponentNoConvert8;
|
|
if CopyAlpha then
|
|
begin
|
|
TargetRunA8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRunA8.R:=Convert8_8(SourceR8^);
|
|
TargetRunA8.G:=Convert8_8(SourceG8^);
|
|
TargetRunA8.B:=Convert8_8(SourceB8^);
|
|
// alpha values are never gamma corrected
|
|
TargetRunA8.A:=SourceA8^;
|
|
Inc(SourceB8,SourceIncrement);
|
|
Inc(SourceG8,SourceIncrement);
|
|
Inc(SourceR8,SourceIncrement);
|
|
Inc(SourceA8,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(TargetRunA8);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TargetRun8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRun8.R:=Convert8_8(SourceR8^);
|
|
TargetRun8.G:=Convert8_8(SourceG8^);
|
|
TargetRun8.B:=Convert8_8(SourceB8^);
|
|
Inc(SourceB8,SourceIncrement);
|
|
Inc(SourceG8,SourceIncrement);
|
|
Inc(SourceR8,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(PByte(TargetRun8),TargetIncrement);
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin // 888 to 161616
|
|
if coApplyGamma in FTargetOptions then Convert8_8:=ComponentGammaConvert else Convert8_8:=ComponentNoConvert8;
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_16:=ComponentSwapConvert else Convert16_16:=ComponentNoConvert16;
|
|
if Length(Source)=1 then
|
|
begin
|
|
SourceB8:=Source[0];
|
|
SourceG8:=SourceB8;
|
|
Inc(SourceG8);
|
|
SourceR8:=SourceG8;
|
|
Inc(SourceR8);
|
|
SourceA8:=SourceR8;
|
|
Inc(SourceA8);
|
|
end
|
|
else
|
|
begin
|
|
SourceB8:=Source[0];
|
|
SourceG8:=Source[1];
|
|
SourceR8:=Source[2];
|
|
if coAlpha in FSourceOptions then SourceA8:=Source[3] else SourceA8:=nil;
|
|
end;
|
|
if CopyAlpha then
|
|
begin
|
|
TargetRunA16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRunA16.R:=Convert16_16(MulDiv16(Convert8_8(SourceR8^),65535,255));
|
|
TargetRunA16.G:=Convert16_16(MulDiv16(Convert8_8(SourceG8^),65535,255));
|
|
TargetRunA16.B:=Convert16_16(MulDiv16(Convert8_8(SourceB8^),65535,255));
|
|
TargetRunA16.A:=Convert16_16(MulDiv16(SourceA8^,65535,255));
|
|
Inc(SourceB8,SourceIncrement);
|
|
Inc(SourceG8,SourceIncrement);
|
|
Inc(SourceR8,SourceIncrement);
|
|
Inc(SourceA8,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(TargetRunA16);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TargetRun16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRun16.R:=Convert16_16(MulDiv16(Convert8_8(SourceR8^),65535,255));
|
|
TargetRun16.G:=Convert16_16(MulDiv16(Convert8_8(SourceG8^),65535,255));
|
|
TargetRun16.B:=Convert16_16(MulDiv16(Convert8_8(SourceB8^),65535,255));
|
|
Inc(SourceB8,SourceIncrement);
|
|
Inc(SourceG8,SourceIncrement);
|
|
Inc(SourceR8,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(Pword(TargetRun16),TargetIncrement);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
SourceB16:=Source[0];
|
|
SourceG16:=SourceB16;
|
|
Inc(SourceG16);
|
|
SourceR16:=SourceG16;
|
|
Inc(SourceR16);
|
|
SourceA16:=SourceR16;
|
|
Inc(SourceA16);
|
|
end
|
|
else
|
|
begin
|
|
SourceB16:=Source[0];
|
|
SourceG16:=Source[1];
|
|
SourceR16:=Source[2];
|
|
if coAlpha in FSourceOptions then SourceA16:=Source[3] else SourceA16:=nil;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 161616 to 888
|
|
if coApplyGamma in FTargetOptions then
|
|
begin
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_8:=ComponentSwapScaleGammaConvert else Convert16_8:=ComponentScaleGammaConvert;
|
|
end
|
|
else
|
|
begin
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_8:=ComponentSwapScaleConvert else Convert16_8:=ComponentScaleConvert;
|
|
end;
|
|
// since alpha channels are never gamma corrected we need a separate conversion routine
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_8Alpha:=ComponentSwapScaleConvert else Convert16_8Alpha:=ComponentScaleConvert;
|
|
if CopyAlpha then
|
|
begin
|
|
TargetRunA8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRunA8.R:=Convert16_8(SourceR16^);
|
|
TargetRunA8.G:=Convert16_8(SourceG16^);
|
|
TargetRunA8.B:=Convert16_8(SourceB16^);
|
|
TargetRunA8.A:=Convert16_8Alpha(SourceA16^);
|
|
Inc(SourceB16,SourceIncrement);
|
|
Inc(SourceG16,SourceIncrement);
|
|
Inc(SourceR16,SourceIncrement);
|
|
Inc(SourceA16,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(TargetRunA8);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TargetRun8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRun8.R:=Convert16_8(SourceR16^);
|
|
TargetRun8.G:=Convert16_8(SourceG16^);
|
|
TargetRun8.B:=Convert16_8(SourceB16^);
|
|
Inc(SourceB16,SourceIncrement);
|
|
Inc(SourceG16,SourceIncrement);
|
|
Inc(SourceR16,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(Pbyte(TargetRun8),TargetIncrement);
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin // 161616 to 161616
|
|
// no gamma correction for 16 bit samples yet
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_16:=ComponentSwapConvert else Convert16_16:=ComponentNoConvert16;
|
|
if Length(Source)=1 then
|
|
begin
|
|
SourceB16:=Source[0];
|
|
SourceG16:=SourceB16;
|
|
Inc(SourceG16);
|
|
SourceR16:=SourceG16;
|
|
Inc(SourceR16);
|
|
SourceA16:=SourceR16;
|
|
Inc(SourceA16);
|
|
end
|
|
else
|
|
begin
|
|
SourceB16:=Source[0];
|
|
SourceG16:=Source[1];
|
|
SourceR16:=Source[2];
|
|
if coAlpha in FSourceOptions then SourceA16:=Source[3] else SourceA16:=nil;
|
|
end;
|
|
if CopyAlpha then
|
|
begin
|
|
TargetRunA16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRunA16.R:=Convert16_16(SourceR16^);
|
|
TargetRunA16.G:=Convert16_16(SourceG16^);
|
|
TargetRunA16.B:=Convert16_16(SourceB16^);
|
|
TargetRunA16.A:=Convert16_16(SourceA16^);
|
|
Inc(SourceB16,SourceIncrement);
|
|
Inc(SourceG16,SourceIncrement);
|
|
Inc(SourceR16,SourceIncrement);
|
|
Inc(SourceA16,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(TargetRunA16);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TargetRun16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRun16.R:=Convert16_16(SourceR16^);
|
|
TargetRun16.G:=Convert16_16(SourceG16^);
|
|
TargetRun16.B:=Convert16_16(SourceB16^);
|
|
Inc(SourceB16,SourceIncrement);
|
|
Inc(SourceG16,SourceIncrement);
|
|
Inc(SourceR16,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(PWord(TargetRun16),TargetIncrement);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.RowConvertBGR2RGB(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
// Converts BGR source schemes to RGB target schemes and takes care for byte swapping, alpha copy/skip and
|
|
// gamma correction.
|
|
var SourceR16,SourceG16,SourceB16,SourceA16: PWord;
|
|
SourceR8,SourceG8,SourceB8,SourceA8: PByte;
|
|
TargetRun16: PRGB16;
|
|
TargetRunA16: PRGBA16;
|
|
TargetRun8: PRGB;
|
|
TargetRunA8: PRGBA;
|
|
BitRun: byte;
|
|
Convert8_8: function(Value: byte): byte of object;
|
|
Convert16_8: function(Value: word): byte of object;
|
|
Convert16_8Alpha: function(Value: word): byte of object;
|
|
Convert16_16: function(Value: word): word of object;
|
|
SourceIncrement,TargetIncrement: cardinal;
|
|
CopyAlpha: boolean;
|
|
begin
|
|
BitRun:=$80;
|
|
// determine alpha handling once
|
|
CopyAlpha:=False;
|
|
if coAlpha in FSourceOptions then
|
|
begin
|
|
SourceIncrement:=SizeOf(TRGBA);
|
|
TargetIncrement:=SizeOf(TRGB);
|
|
if coAlpha in FTargetOptions then CopyAlpha:=True;
|
|
end
|
|
else
|
|
begin
|
|
SourceIncrement:=SizeOf(TRGB);
|
|
if coAlpha in FTargetOptions then TargetIncrement:=sizeof(TRGBA) else TargetIncrement:=sizeof(TRGB);
|
|
end;
|
|
// in planar mode source increment is always 1
|
|
if Length(Source)>1 then SourceIncrement:=1;
|
|
case FSourceBPS of
|
|
8: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
// interleaved mode
|
|
SourceB8:=Source[0];
|
|
SourceG8:=SourceB8;
|
|
Inc(SourceG8);
|
|
SourceR8:=SourceG8;
|
|
Inc(SourceR8);
|
|
SourceA8:=SourceR8;
|
|
Inc(SourceA8);
|
|
end
|
|
else
|
|
begin
|
|
SourceB8:=Source[0];
|
|
SourceG8:=Source[1];
|
|
SourceR8:=Source[2];
|
|
if coAlpha in FSourceOptions then SourceA8:=Source[3] else SourceA8:=nil;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 888 to 888
|
|
if coApplyGamma in FTargetOptions then Convert8_8:=ComponentGammaConvert else Convert8_8:=ComponentNoConvert8;
|
|
if CopyAlpha then
|
|
begin
|
|
TargetRunA8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRunA8.R:=Convert8_8(SourceR8^);
|
|
TargetRunA8.G:=Convert8_8(SourceG8^);
|
|
TargetRunA8.B:=Convert8_8(SourceB8^);
|
|
// alpha values are never gamma corrected
|
|
TargetRunA8.A:=SourceA8^;
|
|
Inc(SourceB8,SourceIncrement);
|
|
Inc(SourceG8,SourceIncrement);
|
|
Inc(SourceR8,SourceIncrement);
|
|
Inc(SourceA8,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(TargetRunA8);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TargetRun8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRun8.R:=Convert8_8(SourceR8^);
|
|
TargetRun8.G:=Convert8_8(SourceG8^);
|
|
TargetRun8.B:=Convert8_8(SourceB8^);
|
|
Inc(SourceB8,SourceIncrement);
|
|
Inc(SourceG8,SourceIncrement);
|
|
Inc(SourceR8,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(PByte(TargetRun8),TargetIncrement);
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin // 888 to 161616
|
|
if coApplyGamma in FTargetOptions then Convert8_8:=ComponentGammaConvert else Convert8_8:=ComponentNoConvert8;
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_16:=ComponentSwapConvert else Convert16_16:=ComponentNoConvert16;
|
|
if Length(Source)=1 then
|
|
begin
|
|
SourceB8:=Source[0];
|
|
SourceG8:=SourceB8;
|
|
Inc(SourceG8);
|
|
SourceR8:=SourceG8;
|
|
Inc(SourceR8);
|
|
SourceA8:=SourceR8;
|
|
Inc(SourceA8);
|
|
end
|
|
else
|
|
begin
|
|
SourceB8:=Source[0];
|
|
SourceG8:=Source[1];
|
|
SourceR8:=Source[2];
|
|
if coAlpha in FSourceOptions then SourceA8:=Source[3] else SourceA8:=nil;
|
|
end;
|
|
if CopyAlpha then
|
|
begin
|
|
TargetRunA16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRunA16.R:=Convert16_16(MulDiv16(Convert8_8(SourceR8^),65535,255));
|
|
TargetRunA16.G:=Convert16_16(MulDiv16(Convert8_8(SourceG8^),65535,255));
|
|
TargetRunA16.B:=Convert16_16(MulDiv16(Convert8_8(SourceB8^),65535,255));
|
|
TargetRunA16.A:=Convert16_16(MulDiv16(SourceA8^,65535,255));
|
|
Inc(SourceB8,SourceIncrement);
|
|
Inc(SourceG8,SourceIncrement);
|
|
Inc(SourceR8,SourceIncrement);
|
|
Inc(SourceA8,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(TargetRunA16);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TargetRun16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRun16.R:=Convert16_16(MulDiv16(Convert8_8(SourceR8^), 65535, 255));
|
|
TargetRun16.G:=Convert16_16(MulDiv16(Convert8_8(SourceG8^), 65535, 255));
|
|
TargetRun16.B:=Convert16_16(MulDiv16(Convert8_8(SourceB8^), 65535, 255));
|
|
Inc(SourceB8,SourceIncrement);
|
|
Inc(SourceG8,SourceIncrement);
|
|
Inc(SourceR8,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(PWord(TargetRun16),TargetIncrement);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
SourceB16:=Source[0];
|
|
SourceG16:=SourceB16;
|
|
Inc(SourceG16);
|
|
SourceR16:=SourceG16;
|
|
Inc(SourceR16);
|
|
SourceA16:=SourceR16;
|
|
Inc(SourceA16);
|
|
end
|
|
else
|
|
begin
|
|
SourceB16:=Source[0];
|
|
SourceG16:=Source[1];
|
|
SourceR16:=Source[2];
|
|
if coAlpha in FSourceOptions then SourceA16:=Source[3] else SourceA16:=nil;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 161616 to 888
|
|
if coApplyGamma in FTargetOptions then
|
|
begin
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_8:=ComponentSwapScaleGammaConvert else Convert16_8:=ComponentScaleGammaConvert;
|
|
end
|
|
else
|
|
begin
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_8:=ComponentSwapScaleConvert else Convert16_8:=ComponentScaleConvert;
|
|
end;
|
|
// since alpha channels are never gamma corrected we need a separate conversion routine
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_8Alpha:=ComponentSwapScaleConvert else Convert16_8Alpha:=ComponentScaleConvert;
|
|
if CopyAlpha then
|
|
begin
|
|
TargetRunA8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRunA8.R:=Convert16_8(SourceR16^);
|
|
TargetRunA8.G:=Convert16_8(SourceG16^);
|
|
TargetRunA8.B:=Convert16_8(SourceB16^);
|
|
TargetRunA8.A:=Convert16_8Alpha(SourceA16^);
|
|
Inc(SourceB16,SourceIncrement);
|
|
Inc(SourceG16,SourceIncrement);
|
|
Inc(SourceR16,SourceIncrement);
|
|
Inc(SourceA16,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(TargetRunA8);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TargetRun8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRun8.R:=Convert16_8(SourceR16^);
|
|
TargetRun8.G:=Convert16_8(SourceG16^);
|
|
TargetRun8.B:=Convert16_8(SourceB16^);
|
|
Inc(SourceB16,SourceIncrement);
|
|
Inc(SourceG16,SourceIncrement);
|
|
Inc(SourceR16,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(PByte(TargetRun8),TargetIncrement);
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin // 161616 to 161616
|
|
// no gamma correction for 16 bit samples yet
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_16:=ComponentSwapConvert else Convert16_16:=ComponentNoConvert16;
|
|
if Length(Source)=1 then
|
|
begin
|
|
SourceB16:=Source[0];
|
|
SourceG16:=SourceB16;
|
|
Inc(SourceG16);
|
|
SourceR16:=SourceG16;
|
|
Inc(SourceR16);
|
|
SourceA16:=SourceR16;
|
|
Inc(SourceA16);
|
|
end
|
|
else
|
|
begin
|
|
SourceB16:=Source[0];
|
|
SourceG16:=Source[1];
|
|
SourceR16:=Source[2];
|
|
if coAlpha in FSourceOptions then SourceA16:=Source[3] else SourceA16:=nil;
|
|
end;
|
|
if CopyAlpha then
|
|
begin
|
|
TargetRunA16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRunA16.R:=Convert16_16(SourceR16^);
|
|
TargetRunA16.G:=Convert16_16(SourceG16^);
|
|
TargetRunA16.B:=Convert16_16(SourceB16^);
|
|
TargetRunA16.A:=Convert16_16(SourceA16^);
|
|
Inc(SourceB16,SourceIncrement);
|
|
Inc(SourceG16,SourceIncrement);
|
|
Inc(SourceR16,SourceIncrement);
|
|
Inc(SourceA16,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(TargetRunA16);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TargetRun16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRun16.R:=Convert16_16(SourceR16^);
|
|
TargetRun16.G:=Convert16_16(SourceG16^);
|
|
TargetRun16.B:=Convert16_16(SourceB16^);
|
|
Inc(SourceB16,SourceIncrement);
|
|
Inc(SourceG16,SourceIncrement);
|
|
Inc(SourceR16,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(PWord(TargetRun16),TargetIncrement);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.RowConvertCIELAB2BGR(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
// conversion of the CIE L*a*b color space to BGR using a two way approach assuming a D65 white point,
|
|
// first a conversion to CIE XYZ is performed and then from there to RGB
|
|
var LRun8,aRun8,bRun8: PByte;
|
|
LRun16,aRun16,bRun16: PWord;
|
|
L,A,B,X,Y,Z, // color values in float format
|
|
T,
|
|
YYn3: extended; // intermediate results
|
|
Target8: PByte;
|
|
Target16: PWord;
|
|
Increment,AlphaSkip: integer;
|
|
BitRun: byte;
|
|
begin
|
|
BitRun:=$80;
|
|
AlphaSkip:=Ord(coAlpha in FTargetOptions); // 0 if no alpha must be skipped, otherwise 1
|
|
case FSourceBPS of
|
|
8: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
LRun8:=Source[0];
|
|
aRun8:=LRun8;
|
|
Inc(aRun8);
|
|
bRun8:=aRun8;
|
|
Inc(bRun8);
|
|
Increment:=3;
|
|
end
|
|
else
|
|
begin
|
|
LRun8:=Source[0];
|
|
aRun8:=Source[1];
|
|
bRun8:=Source[2];
|
|
Increment:=1;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin /// 888 to 888
|
|
Target8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
if coLabbyteRange in FSourceOptions then L:=LRun8^/2.55 else L:=LRun8^;
|
|
Inc(LRun8, Increment);
|
|
if coLabChromaOffset in FSourceOptions then
|
|
begin
|
|
A:=aRun8^-128;
|
|
Inc(aRun8,Increment);
|
|
B:=bRun8^-128;
|
|
Inc(bRun8,Increment);
|
|
end
|
|
else
|
|
begin
|
|
A:=ShortInt(aRun8^);
|
|
Inc(aRun8,Increment);
|
|
B:=ShortInt(bRun8^);
|
|
Inc(bRun8,Increment);
|
|
end;
|
|
YYn3:=(L+16)/116; // this corresponds to (Y/Yn)^1/3
|
|
if L<7.9996 then
|
|
begin
|
|
Y:=L/903.3;
|
|
X:=A/3893.5+Y;
|
|
Z:=Y-B/1557.4;
|
|
end
|
|
else
|
|
begin
|
|
T:=YYn3+A/500;
|
|
X:=T*T*T;
|
|
Y:=YYn3*YYn3*YYn3;
|
|
T:=YYn3-B/200;
|
|
Z:=T*T*T;
|
|
end;
|
|
// once we have CIE XYZ it is easy (yet quite expensive)
|
|
// to calculate RGB values from this
|
|
// blue
|
|
Target8^:=ClampByte(Round(255*(0.099*X-0.198*Y+1.099*Z)));
|
|
Inc(Target8);
|
|
// green
|
|
Target8^:=ClampByte(Round(255*(-0.952*X+1.893*Y+0.059*Z)));
|
|
Inc(Target8);
|
|
// red
|
|
Target8^:=ClampByte(Round(255*(2.998*X-1.458*Y-0.541*Z)));
|
|
Inc(Target8,1+AlphaSkip);
|
|
end
|
|
else Inc(Target8,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
16: begin // 888 to 161616
|
|
Target16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
if coLabbyteRange in FSourceOptions then L:=LRun8^/2.55 else L:=LRun8^;
|
|
Inc(LRun8,Increment);
|
|
if coLabChromaOffset in FSourceOptions then
|
|
begin
|
|
A:=aRun8^-128;
|
|
Inc(aRun8,Increment);
|
|
B:=bRun8^-128;
|
|
Inc(bRun8,Increment);
|
|
end
|
|
else
|
|
begin
|
|
A:=ShortInt(aRun8^);
|
|
Inc(aRun8,Increment);
|
|
B:=ShortInt(bRun8^);
|
|
Inc(bRun8,Increment);
|
|
end;
|
|
YYn3:=(L+16)/116; // this corresponds to (Y/Yn)^1/3
|
|
if L<7.9996 then
|
|
begin
|
|
Y:=L/903.3;
|
|
X:=A/3893.5+Y;
|
|
Z:=Y-B/1557.4;
|
|
end
|
|
else
|
|
begin
|
|
T:=YYn3+A/500;
|
|
X:=T*T*T;
|
|
Y:=YYn3*YYn3*YYn3;
|
|
T:=YYn3-B/200;
|
|
Z:=T*T*T;
|
|
end;
|
|
// blue
|
|
Target16^:=MulDiv16(ClampByte(Round(255*(0.099*X-0.198*Y+1.099*Z))),65535,255);
|
|
Inc(Target16);
|
|
// green
|
|
Target16^:=MulDiv16(ClampByte(Round(255*(-0.952*X+1.893*Y+0.059*Z))),65535,255);
|
|
Inc(Target16);
|
|
// red
|
|
Target16^:=MulDiv16(ClampByte(Round(255*(2.998*X-1.458*Y-0.541*Z))),65535,255);
|
|
Inc(Target16,1+AlphaSkip);
|
|
end
|
|
else Inc(Target16,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
LRun16:=Source[0];
|
|
aRun16:=LRun16;
|
|
Inc(aRun16);
|
|
bRun16:=aRun16;
|
|
Inc(bRun16);
|
|
Increment:=3;
|
|
end
|
|
else
|
|
begin
|
|
LRun16:=Source[0];
|
|
aRun16:=Source[1];
|
|
bRun16:=Source[2];
|
|
Increment:=1;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 161616 to 888
|
|
Target8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
if coLabbyteRange in FSourceOptions then L:=LRun16^/2.55 else L:=LRun16^;
|
|
Inc(LRun16,Increment);
|
|
if coLabChromaOffset in FSourceOptions then
|
|
begin
|
|
A:=aRun16^-128;
|
|
Inc(aRun16,Increment);
|
|
B:=bRun16^-128;
|
|
Inc(bRun16,Increment);
|
|
end
|
|
else
|
|
begin
|
|
A:=ShortInt(aRun16^);
|
|
Inc(aRun16, Increment);
|
|
B:=ShortInt(bRun16^);
|
|
Inc(bRun16, Increment);
|
|
end;
|
|
YYn3:=(L+16)/116; // this corresponds to (Y/Yn)^1/3
|
|
if L<7.9996 then
|
|
begin
|
|
Y:=L/903.3;
|
|
X:=A/3893.5+Y;
|
|
Z:=Y-B/1557.4;
|
|
end
|
|
else
|
|
begin
|
|
T:=YYn3+A/500;
|
|
X:=T*T*T;
|
|
Y:=YYn3*YYn3*YYn3;
|
|
T:=YYn3-B/200;
|
|
Z:=T*T*T;
|
|
end;
|
|
// blue
|
|
Target8^:=ClampByte(Round(255*(0.099*X-0.198*Y+1.099*Z)));
|
|
Inc(Target8);
|
|
// green
|
|
Target8^:=ClampByte(Round(255*(-0.952*X+1.893*Y+0.059*Z)));
|
|
Inc(Target8);
|
|
// red
|
|
Target8^:=ClampByte(Round(255*(2.998*X-1.458*Y-0.541*Z)));
|
|
Inc(Target8,1+AlphaSkip);
|
|
end
|
|
else Inc(Target8,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
16: begin // 161616 to 161616
|
|
Target16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
if coLabbyteRange in FSourceOptions then L:=LRun16^/2.55 else L:=LRun16^;
|
|
Inc(LRun16,Increment);
|
|
if coLabChromaOffset in FSourceOptions then
|
|
begin
|
|
A:=aRun16^-128;
|
|
Inc(aRun16,Increment);
|
|
B:=bRun16^-128;
|
|
Inc(bRun16,Increment);
|
|
end
|
|
else
|
|
begin
|
|
A:=ShortInt(aRun16^);
|
|
Inc(aRun16,Increment);
|
|
B:=ShortInt(bRun16^);
|
|
Inc(bRun16,Increment);
|
|
end;
|
|
YYn3:=(L+16)/116; // this corresponds to (Y/Yn)^1/3
|
|
if L<7.9996 then
|
|
begin
|
|
Y:=L/903.3;
|
|
X:=A/3893.5+Y;
|
|
Z:=Y-B/1557.4;
|
|
end
|
|
else
|
|
begin
|
|
T:=YYn3+A/500;
|
|
X:=T*T*T;
|
|
Y:=YYn3*YYn3*YYn3;
|
|
T:=YYn3-B/200;
|
|
Z:=T*T*T;
|
|
end;
|
|
// blue
|
|
Target16^:=ClampByte(Round(255*(0.099*X-0.198*Y+1.099*Z)));
|
|
Inc(Target16);
|
|
// green
|
|
Target16^:=ClampByte(Round(255*(-0.952*X+1.893*Y+0.059*Z)));
|
|
Inc(Target16);
|
|
// red
|
|
Target16^:=ClampByte(Round(255*(2.998*X-1.458*Y-0.541*Z)));
|
|
Inc(Target16,1+AlphaSkip);
|
|
end
|
|
else Inc(Target16,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.RowConvertCIELAB2RGB(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
// just like RowConvertCIELAB2BGR but for RGB target schemes
|
|
var LRun8,aRun8,bRun8: PByte;
|
|
LRun16,aRun16,bRun16: PWord;
|
|
L,A,B,X,Y,Z, // color values in float format
|
|
T,YYn3: extended; // intermediate results
|
|
Target8: PByte;
|
|
Target16: PWord;
|
|
Increment,AlphaSkip: integer;
|
|
BitRun: byte;
|
|
begin
|
|
BitRun:=$80;
|
|
AlphaSkip:=Ord(coAlpha in FTargetOptions); // 0 if no alpha must be skipped, otherwise 1
|
|
case FSourceBPS of
|
|
8: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
LRun8:=Source[0];
|
|
aRun8:=LRun8;
|
|
Inc(aRun8);
|
|
bRun8:=aRun8;
|
|
Inc(bRun8);
|
|
Increment:=3;
|
|
end
|
|
else
|
|
begin
|
|
LRun8:=Source[0];
|
|
aRun8:=Source[1];
|
|
bRun8:=Source[2];
|
|
Increment:=1;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 888 to 888
|
|
Target8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
if coLabbyteRange in FSourceOptions then L:=LRun8^/2.55 else L:=LRun8^;
|
|
Inc(LRun8,Increment);
|
|
if coLabChromaOffset in FSourceOptions then
|
|
begin
|
|
A:=aRun8^-128;
|
|
Inc(aRun8,Increment);
|
|
B:=bRun8^-128;
|
|
Inc(bRun8,Increment);
|
|
end
|
|
else
|
|
begin
|
|
A:=ShortInt(aRun8^);
|
|
Inc(aRun8,Increment);
|
|
B:=ShortInt(bRun8^);
|
|
Inc(bRun8,Increment);
|
|
end;
|
|
YYn3:=(L+16)/116; // this corresponds to (Y/Yn)^1/3
|
|
if L<7.9996 then
|
|
begin
|
|
Y:=L/903.3;
|
|
X:=A/3893.5+Y;
|
|
Z:=Y-B/1557.4;
|
|
end
|
|
else
|
|
begin
|
|
T:=YYn3+A/500;
|
|
X:=T*T*T;
|
|
Y:=YYn3*YYn3*YYn3;
|
|
T:=YYn3-B/200;
|
|
Z:=T*T*T;
|
|
end;
|
|
// once we have CIE XYZ it is easy (yet quite expensive) to calculate RGB values from this
|
|
// red
|
|
Target8^:=ClampByte(Round(255*(2.998*X-1.458*Y-0.541*Z)));
|
|
Inc(Target8);
|
|
// green
|
|
Target8^:=ClampByte(Round(255*(-0.952*X+1.893*Y+0.059*Z)));
|
|
Inc(Target8);
|
|
// blue
|
|
Target8^:=ClampByte(Round(255*(0.099*X-0.198*Y+1.099*Z)));
|
|
Inc(Target8,1+AlphaSkip);
|
|
end
|
|
else Inc(Target8,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
16: begin // 888 to 161616
|
|
Target16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
if coLabbyteRange in FSourceOptions then L:=LRun8^/2.55 else L:=LRun8^;
|
|
Inc(LRun8,Increment);
|
|
if coLabChromaOffset in FSourceOptions then
|
|
begin
|
|
A:=aRun8^-128;
|
|
Inc(aRun8,Increment);
|
|
B:=bRun8^-128;
|
|
Inc(bRun8,Increment);
|
|
end
|
|
else
|
|
begin
|
|
A:=ShortInt(aRun8^);
|
|
Inc(aRun8,Increment);
|
|
B:=ShortInt(bRun8^);
|
|
Inc(bRun8,Increment);
|
|
end;
|
|
YYn3:=(L+16)/116; // this corresponds to (Y/Yn)^1/3
|
|
if L<7.9996 then
|
|
begin
|
|
Y:=L/903.3;
|
|
X:=A/3893.5+Y;
|
|
Z:=Y-B/1557.4;
|
|
end
|
|
else
|
|
begin
|
|
T:=YYn3+A/500;
|
|
X:=T*T*T;
|
|
Y:=YYn3*YYn3*YYn3;
|
|
T:=YYn3-B/200;
|
|
Z:=T*T*T;
|
|
end;
|
|
// red
|
|
Target16^:=MulDiv16(Clampbyte(Round(255*(2.998*X-1.458*Y-0.541*Z))),65535,255);
|
|
Inc(Target16);
|
|
// green
|
|
Target16^:=MulDiv16(Clampbyte(Round(255*(-0.952*X+1.893*Y+0.059*Z))),65535,255);
|
|
Inc(Target16);
|
|
// blue
|
|
Target16^:=MulDiv16(Clampbyte(Round(255*(0.099*X-0.198*Y+1.099*Z))),65535,255);
|
|
Inc(Target16,1+AlphaSkip);
|
|
end
|
|
else Inc(Target16,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
LRun16:=Source[0];
|
|
aRun16:=LRun16;
|
|
Inc(aRun16);
|
|
bRun16:=aRun16;
|
|
Inc(bRun16);
|
|
Increment:=3;
|
|
end
|
|
else
|
|
begin
|
|
LRun16:=Source[0];
|
|
aRun16:=Source[1];
|
|
bRun16:=Source[2];
|
|
Increment:=1;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 161616 to 888
|
|
Target8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
if coLabbyteRange in FSourceOptions then L:=LRun16^/2.55 else L:=LRun16^;
|
|
Inc(LRun16,Increment);
|
|
if coLabChromaOffset in FSourceOptions then
|
|
begin
|
|
A:=aRun16^-128;
|
|
Inc(aRun16,Increment);
|
|
B:=bRun16^-128;
|
|
Inc(bRun16,Increment);
|
|
end
|
|
else
|
|
begin
|
|
A:=ShortInt(aRun16^);
|
|
Inc(aRun16,Increment);
|
|
B:=ShortInt(bRun16^);
|
|
Inc(bRun16,Increment);
|
|
end;
|
|
YYn3:=(L+16)/116; // this corresponds to (Y/Yn)^1/3
|
|
if L<7.9996 then
|
|
begin
|
|
Y:=L/903.3;
|
|
X:=A/3893.5+Y;
|
|
Z:=Y-B/1557.4;
|
|
end
|
|
else
|
|
begin
|
|
T:=YYn3+A/500;
|
|
X:=T*T*T;
|
|
Y:=YYn3*YYn3*YYn3;
|
|
T:=YYn3-B/200;
|
|
Z:=T*T*T;
|
|
end;
|
|
// red
|
|
Target8^:=ClampByte(Round(255*(2.998*X-1.458*Y-0.541*Z)));
|
|
Inc(Target8);
|
|
// green
|
|
Target8^:=ClampByte(Round(255*(-0.952*X+1.893*Y+0.059*Z)));
|
|
Inc(Target8);
|
|
// blue
|
|
Target8^:=ClampByte(Round(255*(0.099*X-0.198*Y+1.099*Z)));
|
|
Inc(Target8,1+AlphaSkip);
|
|
end
|
|
else Inc(Target8,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
16: begin // 161616 to 161616
|
|
Target16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
if coLabbyteRange in FSourceOptions then L:=LRun16^/2.55 else L:=LRun16^;
|
|
Inc(LRun16,Increment);
|
|
if coLabChromaOffset in FSourceOptions then
|
|
begin
|
|
a:=aRun16^-128;
|
|
Inc(aRun16,Increment);
|
|
b:=bRun16^-128;
|
|
Inc(bRun16,Increment);
|
|
end
|
|
else
|
|
begin
|
|
a:=ShortInt(aRun16^);
|
|
Inc(aRun16,Increment);
|
|
b:=ShortInt(bRun16^);
|
|
Inc(bRun16,Increment);
|
|
end;
|
|
YYn3:=(L+16)/116; // this corresponds to (Y/Yn)^1/3
|
|
if L<7.9996 then
|
|
begin
|
|
Y:=L/903.3;
|
|
X:=A/3893.5+Y;
|
|
Z:=Y-B/1557.4;
|
|
end
|
|
else
|
|
begin
|
|
T:=YYn3+A/500;
|
|
X:=T*T*T;
|
|
Y:=YYn3*YYn3*YYn3;
|
|
T:=YYn3-B/200;
|
|
Z:=T*T*T;
|
|
end;
|
|
// red
|
|
Target16^:=ClampByte(Round(255*(2.998*X-1.458*Y-0.541*Z)));
|
|
Inc(Target16);
|
|
// green
|
|
Target16^:=ClampByte(Round(255*(-0.952*X+1.893*Y+0.059*Z)));
|
|
Inc(Target16);
|
|
// blue
|
|
Target16^:=ClampByte(Round(255*(0.099*X-0.198*Y+1.099*Z)));
|
|
Inc(Target16,1+AlphaSkip);
|
|
end
|
|
else Inc(Target16,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.RowConvertCMYK2BGR(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
// converts a stream of Count CMYK values to BGR
|
|
var C8,M8,Y8,K8: PByte;
|
|
C16,M16,Y16,K16: PWord;
|
|
Target8: PByte;
|
|
Target16: PWord;
|
|
Increment,AlphaSkip: integer;
|
|
BitRun: byte;
|
|
begin
|
|
BitRun:=$80;
|
|
AlphaSkip:=Ord(coAlpha in FTargetOptions); // 0 if no alpha must be skipped, otherwise 1
|
|
case FSourceBPS of
|
|
8: begin
|
|
if Length(Source)=4 then
|
|
begin
|
|
// plane mode
|
|
C8:=Source[0];
|
|
M8:=Source[1];
|
|
Y8:=Source[2];
|
|
K8:=Source[3];
|
|
Increment:=1;
|
|
end
|
|
else
|
|
begin
|
|
// interleaved mode
|
|
C8:=Source[0];
|
|
M8:=C8;
|
|
Inc(M8);
|
|
Y8:=M8;
|
|
Inc(Y8);
|
|
K8:=Y8;
|
|
Inc(K8);
|
|
Increment:=4;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 888 to 888
|
|
Target8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
// blue
|
|
Target8^:=ClampByte(255-(Y8^-MulDiv16(Y8^,K8^,255)+K8^));
|
|
Inc(Target8);
|
|
// green
|
|
Target8^:=ClampByte(255-(M8^-MulDiv16(M8^,K8^,255)+K8^));
|
|
Inc(Target8);
|
|
// blue
|
|
Target8^:=ClampByte(255-(C8^-MulDiv16(C8^,K8^,255)+K8^));
|
|
Inc(Target8,1+AlphaSkip);
|
|
Inc(C8,Increment);
|
|
Inc(M8,Increment);
|
|
Inc(Y8,Increment);
|
|
Inc(K8,Increment);
|
|
end
|
|
else Inc(Target8,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
16: begin // 888 to 161616
|
|
Target16:=Target;
|
|
while Count > 0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
// blue
|
|
Target16^:=MulDiv16(Clampbyte(255-(Y8^-MulDiv16(Y8^,K8^,255)+K8^)),65535,255);
|
|
Inc(Target16);
|
|
// green
|
|
Target16^:=MulDiv16(Clampbyte(255-(M8^-MulDiv16(M8^,K8^,255)+K8^)),65535,255);
|
|
Inc(Target16);
|
|
// blue
|
|
Target16^:=MulDiv16(Clampbyte(255-(C8^-MulDiv16(C8^,K8^,255)+K8^)),65535,255);
|
|
Inc(Target16,1+AlphaSkip);
|
|
Inc(C8,Increment);
|
|
Inc(M8,Increment);
|
|
Inc(Y8,Increment);
|
|
Inc(K8,Increment);
|
|
end
|
|
else Inc(Target16,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin
|
|
if Length(Source)=4 then
|
|
begin
|
|
// plane mode
|
|
C16:=Source[0];
|
|
M16:=Source[1];
|
|
Y16:=Source[2];
|
|
K16:=Source[3];
|
|
Increment:=1;
|
|
end
|
|
else
|
|
begin
|
|
// interleaved mode
|
|
C16:=Source[0];
|
|
M16:=C16;
|
|
Inc(M16);
|
|
Y16:=M16;
|
|
Inc(Y16);
|
|
K16:=Y16;
|
|
Inc(K16);
|
|
Increment:=4;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 161616 to 888
|
|
Target8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
// blue
|
|
Target8^:=ClampByte(255-MulDiv16((Y16^-MulDiv16(Y16^,K16^,65535)+K16^),255,65535));
|
|
Inc(Target8);
|
|
// green
|
|
Target8^:=ClampByte(255-MulDiv16((M16^-MulDiv16(M16^,K16^,65535)+K16^),255,65535));
|
|
Inc(Target8);
|
|
// blue
|
|
Target8^:=ClampByte(255-MulDiv16((C16^-MulDiv16(C16^,K16^,65535)+K16^),255,65535));
|
|
Inc(Target8,1+AlphaSkip);
|
|
Inc(C16,Increment);
|
|
Inc(M16,Increment);
|
|
Inc(Y16,Increment);
|
|
Inc(K16,Increment);
|
|
end
|
|
else Inc(Target8,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
16: begin // 161616 to 161616
|
|
Target16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
// blue
|
|
Target16^:=65535-(Y16^-MulDiv16(Y16^,K16^,65535)+K16^);
|
|
Inc(Target16);
|
|
// green
|
|
Target16^:=65535-(M16^-MulDiv16(M16^,K16^,65535)+K16^);
|
|
Inc(Target16);
|
|
// blue
|
|
Target16^:=65535-(C16^-MulDiv16(C16^,K16^,65535)+K16^);
|
|
Inc(Target16,1+AlphaSkip);
|
|
Inc(C16,Increment);
|
|
Inc(M16,Increment);
|
|
Inc(Y16,Increment);
|
|
Inc(K16,Increment);
|
|
end
|
|
else Inc(Target16,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.RowConvertCMYK2RGB(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
// converts a stream of Count CMYK values to RGB,
|
|
var C8,M8,Y8,K8: PByte;
|
|
C16,M16,Y16,K16: PWord;
|
|
Target8: PByte;
|
|
Target16: PWord;
|
|
Increment,AlphaSkip: integer;
|
|
BitRun: byte;
|
|
begin
|
|
BitRun:=$80;
|
|
AlphaSkip:=Ord(coAlpha in FTargetOptions); // 0 if no alpha must be skipped, otherwise 1
|
|
case FSourceBPS of
|
|
8: begin
|
|
if Length(Source)=4 then
|
|
begin
|
|
// plane mode
|
|
C8:=Source[0];
|
|
M8:=Source[1];
|
|
Y8:=Source[2];
|
|
K8:=Source[3];
|
|
Increment:=1;
|
|
end
|
|
else
|
|
begin
|
|
// interleaved mode
|
|
C8:=Source[0];
|
|
M8:=C8;
|
|
Inc(M8);
|
|
Y8:=M8;
|
|
Inc(Y8);
|
|
K8:=Y8;
|
|
Inc(K8);
|
|
Increment:=4;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 888 to 888
|
|
Target8:=Target;
|
|
while Count > 0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
// red
|
|
Target8^:=ClampByte(255-(C8^-MulDiv16(C8^,K8^,255)+K8^));
|
|
Inc(Target8);
|
|
// green
|
|
Target8^:=ClampByte(255-(M8^-MulDiv16(M8^,K8^,255)+K8^));
|
|
Inc(Target8);
|
|
// blue
|
|
Target8^:=ClampByte(255-(Y8^-MulDiv16(Y8^,K8^,255)+K8^));
|
|
Inc(Target8,1+AlphaSkip);
|
|
Inc(C8,Increment);
|
|
Inc(M8,Increment);
|
|
Inc(Y8,Increment);
|
|
Inc(K8,Increment);
|
|
end
|
|
else Inc(Target8,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
16: begin // 888 to 161616
|
|
Target16:=Target;
|
|
while Count > 0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
// red
|
|
Target16^:=MulDiv16(ClampByte(255-(C8^-MulDiv16(C8^,K8^,255)+K8^)),65535,255);
|
|
Inc(Target16);
|
|
// green
|
|
Target16^:=MulDiv16(ClampByte(255-(M8^-MulDiv16(M8^,K8^,255)+K8^)),65535,255);
|
|
Inc(Target16);
|
|
// blue
|
|
Target16^:=MulDiv16(ClampByte(255-(Y8^-MulDiv16(Y8^,K8^,255)+K8^)),65535,255);
|
|
Inc(Target16,1+AlphaSkip);
|
|
Inc(C8,Increment);
|
|
Inc(M8,Increment);
|
|
Inc(Y8,Increment);
|
|
Inc(K8,Increment);
|
|
end
|
|
else Inc(Target16,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin
|
|
if Length(Source)=4 then
|
|
begin
|
|
// plane mode
|
|
C16:=Source[0];
|
|
M16:=Source[1];
|
|
Y16:=Source[2];
|
|
K16:=Source[3];
|
|
Increment:=1;
|
|
end
|
|
else
|
|
begin
|
|
// interleaved mode
|
|
C16:=Source[0];
|
|
M16:=C16;
|
|
Inc(M16);
|
|
Y16:=M16;
|
|
Inc(Y16);
|
|
K16:=Y16;
|
|
Inc(K16);
|
|
Increment:=4;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 161616 to 888
|
|
Target8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
// red
|
|
Target8^:=ClampByte(255-MulDiv16((C16^-MulDiv16(C16^,K16^,65535)+K16^),255,65535));
|
|
Inc(Target8);
|
|
// green
|
|
Target8^:=ClampByte(255-MulDiv16((M16^-MulDiv16(M16^,K16^,65535)+K16^),255,65535));
|
|
Inc(Target8);
|
|
// blue
|
|
Target8^:=ClampByte(255-MulDiv16((Y16^-MulDiv16(Y16^,K16^,65535)+K16^),255,65535));
|
|
Inc(Target8,1+AlphaSkip);
|
|
Inc(C16,Increment);
|
|
Inc(M16,Increment);
|
|
Inc(Y16,Increment);
|
|
Inc(K16,Increment);
|
|
end
|
|
else Inc(Target8,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
16: begin // 161616 to 161616
|
|
Target16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
// red
|
|
Target16^:=65535-(C16^-MulDiv16(C16^,K16^,65535)+K16^);
|
|
Inc(Target16);
|
|
// green
|
|
Target16^:=65535-(M16^-MulDiv16(M16^,K16^,65535)+K16^);
|
|
Inc(Target16);
|
|
// blue
|
|
Target16^:=65535-(Y16^-MulDiv16(Y16^,K16^,65535)+K16^);
|
|
Inc(Target16,1+AlphaSkip);
|
|
Inc(C16,Increment);
|
|
Inc(M16,Increment);
|
|
Inc(Y16,Increment);
|
|
Inc(K16,Increment);
|
|
end
|
|
else Inc(Target16,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.RowConvertGray(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
// conversion from source grayscale (possibly with alpha) to target grayscale
|
|
// Note: Since grayscale is basically handled like indexed mode (palette), there is no need to
|
|
// handle gamma correction here as this happend already during palette creation.
|
|
var Target8: PByte;
|
|
Target16: PWord;
|
|
Source8: PByte;
|
|
Source16: PWord;
|
|
BitRun: byte;
|
|
AlphaSkip: integer;
|
|
Convert16: function(Value: word): byte of object;
|
|
begin
|
|
BitRun:=$80;
|
|
AlphaSkip:=Ord(coAlpha in FSourceOptions); // 0 if no alpha must be skipped, otherwise 1
|
|
case FSourceBPS of
|
|
8: case FTargetBPS of
|
|
8: begin // 888 to 888
|
|
Source8:=Source[0];
|
|
Target8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Target8^:=Source8^;
|
|
Inc(Source8,1+AlphaSkip);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(Target8);
|
|
end;
|
|
end;
|
|
16: begin // 888 to 161616
|
|
Source8:=Source[0];
|
|
Target16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Target16^:=MulDiv16(Source8^,65535,255);
|
|
Inc(Source8,1+AlphaSkip);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(Target16);
|
|
end;
|
|
end;
|
|
end;
|
|
16: case FTargetBPS of
|
|
8: begin // 161616 to 888
|
|
Source16:=Source[0];
|
|
Target8:=Target;
|
|
if coNeedbyteSwap in FSourceOptions then Convert16:=ComponentSwapScaleConvert else Convert16:=ComponentScaleConvert;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Target8^:=Convert16(Source16^);
|
|
Inc(Source16,1+AlphaSkip);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(Target8);
|
|
end;
|
|
end;
|
|
16: begin // 161616 to 161616
|
|
Source16:=Source[0];
|
|
Target16:=Target;
|
|
if coNeedbyteSwap in FSourceOptions then
|
|
begin
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Target16^:=System.Swap(Source16^);
|
|
Inc(Source16,1+AlphaSkip);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(Target16);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Target16^:=Source16^;
|
|
Inc(Source16,1+AlphaSkip);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(Target16);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.RowConvertIndexed8(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
// This is the core conversion routine for indexed pixel formats.
|
|
// This routine takes care about sample scaling and interlacing.
|
|
// Note: 16 bit indexed mode is a bit different (words instead bytes and byte swap) and handled separately.
|
|
var SourceRun,TargetRun: PByte;
|
|
Value,BitRun,TargetMask,SourceMask,SourceShift,TargetShift,MaxInSample,
|
|
MaxOutSample,SourceBPS, // local copies to ease assembler access
|
|
TargetBPS: byte;
|
|
Done: cardinal;
|
|
begin
|
|
SourceRun:=Source[0];
|
|
TargetRun:=Target;
|
|
if (FSourceBPS=FTargetBPS) and (Mask=$FF) then Move(SourceRun^,TargetRun^,(Count*FSourceBPS+7) div 8) else
|
|
begin
|
|
BitRun:=$80;
|
|
// make a copy of these both values from private variables to local variables
|
|
// to ease access during assembler parts in the code
|
|
SourceBPS:=FSourceBPS;
|
|
TargetBPS:=FTargetBPS;
|
|
SourceMask:=byte(not ((1 shl (8-SourceBPS))-1));
|
|
MaxInSample:=(1 shl SourceBPS)-1;
|
|
TargetMask:=(1 shl (8-TargetBPS))-1;
|
|
MaxOutSample:=(1 shl TargetBPS)-1;
|
|
SourceShift:=8;
|
|
TargetShift:=8-TargetBPS;
|
|
Done:=0;
|
|
while Done<Count do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
// adjust shift value by source bit depth
|
|
Dec(SourceShift,SourceBPS);
|
|
Value:=(SourceRun^ and SourceMask) shr SourceShift;
|
|
Value:=MulDiv16(Value,MaxOutSample,MaxInSample);
|
|
TargetRun^:=(TargetRun^ and TargetMask) or (Value shl TargetShift);
|
|
if SourceShift=0 then
|
|
begin
|
|
SourceShift:=8;
|
|
Inc(SourceRun);
|
|
end;
|
|
asm
|
|
MOV CL,[SourceBPS]
|
|
ROR byte PTR [SourceMask],CL // roll source bit mask with source bit count
|
|
end;
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1 // adjust test bit mask
|
|
MOV CL,[TargetBPS]
|
|
ROR byte PTR [TargetMask],CL // roll target mask with target bit count
|
|
end;
|
|
if TargetShift=0 then TargetShift:=8-TargetBPS else Dec(TargetShift,TargetBPS);
|
|
Inc(Done);
|
|
// advance target pointer every (8 div target bit count)
|
|
if (Done mod (8 div TargetBPS))=0 then Inc(TargetRun);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.RowConvertIndexedBoth16(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
// This is the core conversion routine for indexed pixel formats with 16 bits per sample values involved
|
|
// (special version for source and target resolution being both 16 BPS).
|
|
var TargetRun,SourceRun: PWord;
|
|
BitRun: byte;
|
|
begin
|
|
SourceRun:=Source[0];
|
|
TargetRun:=Target;
|
|
BitRun:=$80;
|
|
if coNeedbyteSwap in FSourceOptions then
|
|
begin
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRun^:=System.Swap(SourceRun^);
|
|
Inc(SourceRun);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(TargetRun);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if Mask=$FF then Move(SourceRun^,TargetRun^,2*Count) else
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRun^:=SourceRun^;
|
|
Inc(SourceRun);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(TargetRun);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.RowConvertIndexedSource16(Source: array of Pointer; Target: Pointer; Count: Cardinal; Mask: byte);
|
|
// This is the core conversion routine for indexed pixel formats with 16 bits per source sample values involved.
|
|
var TargetRun8: PByte;
|
|
SourceRun16: PWord;
|
|
Value,BitRun,TargetMask,TargetShift,MaxOutSample,
|
|
TargetBPS: byte; // local copies to ease assembler access
|
|
begin
|
|
SourceRun16:=Source[0];
|
|
TargetRun8:=Target;
|
|
BitRun:=$80;
|
|
// make a copy of these both values from private variables to local variables
|
|
// to ease access during assembler parts in the code
|
|
TargetBPS:=FTargetBPS;
|
|
TargetMask:=(1 shl (8-TargetBPS))-1;
|
|
MaxOutSample:=(1 shl TargetBPS)-1;
|
|
TargetShift:=8-TargetBPS;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
if coNeedbyteSwap in FSourceOptions then Value:=MulDiv16(System.Swap(SourceRun16^),MaxOutSample,65535) else Value:=MulDiv16(SourceRun16^,MaxOutSample,65535);
|
|
TargetRun8^:=(TargetRun8^ and TargetMask) or (Value shl TargetShift);
|
|
Inc(SourceRun16);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1 // adjust test bit mask
|
|
MOV CL,[TargetBPS]
|
|
ROR byte PTR [TargetMask],CL // roll target mask with target bit count
|
|
end;
|
|
if TargetShift=0 then TargetShift:=8-TargetBPS else Dec(TargetShift,TargetBPS);
|
|
Dec(Count);
|
|
// advance target pointer every (8 div target bit count)
|
|
if (Count mod (8 div TargetBPS))=0 then Inc(TargetRun8);
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.RowConvertIndexedTarget16(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
// This is the core conversion routine for indexed pixel formats with 16 bits per target sample values involved.
|
|
var SourceRun8: PByte;
|
|
TargetRun16: PWord;
|
|
Value: word;
|
|
BitRun,SourceMask,SourceShift,MaxInSample,SourceBPS: byte;
|
|
begin
|
|
SourceRun8:=Source[0];
|
|
TargetRun16:=Target;
|
|
BitRun:=$80;
|
|
SourceBPS:=FSourceBPS;
|
|
SourceMask:=byte(not ((1 shl (8-SourceBPS))-1));
|
|
MaxInSample:=(1 shl SourceBPS)-1;
|
|
SourceShift:=8;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
// adjust shift value by source bit depth
|
|
Dec(SourceShift,SourceBPS);
|
|
Value:=(SourceRun8^ and SourceMask) shr SourceShift;
|
|
Value:=MulDiv16(Value,65535,MaxInSample);
|
|
if coNeedbyteSwap in FSourceOptions then TargetRun16^:=System.Swap(Value) else TargetRun16^:=Value;
|
|
if SourceShift=0 then
|
|
begin
|
|
SourceShift:=8;
|
|
Inc(SourceRun8);
|
|
end;
|
|
asm
|
|
MOV CL,[SourceBPS]
|
|
ROR byte PTR [SourceMask],CL // roll source bit mask with source bit count
|
|
end;
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1 // adjust test bit mask
|
|
end;
|
|
Dec(Count);
|
|
// advance target pointer every (8 div target bit count)
|
|
Inc(TargetRun16);
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.RowConvertRGB2BGR(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
// Converts RGB source schemes to BGR target schemes and takes care for byte swapping, alpha copy/skip and
|
|
// gamma correction.
|
|
var SourceR16,SourceG16,SourceB16,SourceA16: PWord;
|
|
SourceR8,SourceG8,SourceB8,SourceA8: PByte;
|
|
TargetRun16: PBGR16;
|
|
TargetRunA16: PBGRA16;
|
|
TargetRun8: PBGR;
|
|
TargetRunA8: PBGRA;
|
|
BitRun: byte;
|
|
Convert8_8: function(Value: byte): byte of object;
|
|
Convert16_8: function(Value: word): byte of object;
|
|
Convert16_8Alpha: function(Value: word): byte of object;
|
|
Convert16_16: function(Value: word): word of object;
|
|
SourceIncrement,TargetIncrement: cardinal;
|
|
CopyAlpha: boolean;
|
|
begin
|
|
BitRun:=$80;
|
|
// determine alpha handling once
|
|
CopyAlpha:=False;
|
|
if coAlpha in FSourceOptions then
|
|
begin
|
|
// byte size of components doesn't matter as the increments are applied to
|
|
// pointers whose data types determine the final increment
|
|
SourceIncrement:=sizeof(TRGBA);
|
|
TargetIncrement:=sizeof(TRGB);
|
|
if coAlpha in FTargetOptions then CopyAlpha:=True;
|
|
end
|
|
else
|
|
begin
|
|
SourceIncrement:=sizeof(TRGB);
|
|
if coAlpha in FTargetOptions then TargetIncrement:=sizeof(TRGBA) else TargetIncrement:=sizeof(TRGB);
|
|
end;
|
|
// in planar mode source increment is always 1
|
|
if Length(Source)>1 then SourceIncrement:=1;
|
|
case FSourceBPS of
|
|
8: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
// interleaved mode
|
|
SourceR8:=Source[0];
|
|
SourceG8:=SourceR8;
|
|
Inc(SourceG8);
|
|
SourceB8:=SourceG8;
|
|
Inc(SourceB8);
|
|
SourceA8:=SourceB8;
|
|
Inc(SourceA8);
|
|
end
|
|
else
|
|
begin
|
|
SourceR8:=Source[0];
|
|
SourceG8:=Source[1];
|
|
SourceB8:=Source[2];
|
|
if coAlpha in FSourceOptions then SourceA8:=Source[3] else SourceA8:=nil;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 888 to 888
|
|
if coApplyGamma in FTargetOptions then Convert8_8:=ComponentGammaConvert else Convert8_8:=ComponentNoConvert8;
|
|
if CopyAlpha then
|
|
begin
|
|
TargetRunA8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRunA8.R:=Convert8_8(SourceR8^);
|
|
TargetRunA8.G:=Convert8_8(SourceG8^);
|
|
TargetRunA8.B:=Convert8_8(SourceB8^);
|
|
// alpha values are never gamma corrected
|
|
TargetRunA8.A:=SourceA8^;
|
|
Inc(SourceB8, SourceIncrement);
|
|
Inc(SourceG8, SourceIncrement);
|
|
Inc(SourceR8, SourceIncrement);
|
|
Inc(SourceA8, SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(TargetRunA8);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TargetRun8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRun8.R:=Convert8_8(SourceR8^);
|
|
TargetRun8.G:=Convert8_8(SourceG8^);
|
|
TargetRun8.B:=Convert8_8(SourceB8^);
|
|
Inc(SourceB8,SourceIncrement);
|
|
Inc(SourceG8,SourceIncrement);
|
|
Inc(SourceR8,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(PByte(TargetRun8),TargetIncrement);
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin // 888 to 161616
|
|
if coApplyGamma in FTargetOptions then Convert8_8:=ComponentGammaConvert else Convert8_8:=ComponentNoConvert8;
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_16:=ComponentSwapConvert else Convert16_16:=ComponentNoConvert16;
|
|
if Length(Source)=1 then
|
|
begin
|
|
SourceB8:=Source[0];
|
|
SourceG8:=SourceB8;
|
|
Inc(SourceG8);
|
|
SourceR8:=SourceG8;
|
|
Inc(SourceR8);
|
|
SourceA8:=SourceR8;
|
|
Inc(SourceA8);
|
|
end
|
|
else
|
|
begin
|
|
SourceB8:=Source[0];
|
|
SourceG8:=Source[1];
|
|
SourceR8:=Source[2];
|
|
if coAlpha in FSourceOptions then SourceA8:=Source[3] else SourceA8:=nil;
|
|
end;
|
|
if CopyAlpha then
|
|
begin
|
|
TargetRunA16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRunA16.R:=Convert16_16(MulDiv16(Convert8_8(SourceR8^),65535,255));
|
|
TargetRunA16.G:=Convert16_16(MulDiv16(Convert8_8(SourceG8^),65535,255));
|
|
TargetRunA16.B:=Convert16_16(MulDiv16(Convert8_8(SourceB8^),65535,255));
|
|
TargetRunA16.A:=Convert16_16(MulDiv16(SourceA8^,65535,255));
|
|
Inc(SourceB8,SourceIncrement);
|
|
Inc(SourceG8,SourceIncrement);
|
|
Inc(SourceR8,SourceIncrement);
|
|
Inc(SourceA8,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(TargetRunA16);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TargetRun16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRun16.R:=Convert16_16(MulDiv16(Convert8_8(SourceR8^),65535,255));
|
|
TargetRun16.G:=Convert16_16(MulDiv16(Convert8_8(SourceG8^),65535,255));
|
|
TargetRun16.B:=Convert16_16(MulDiv16(Convert8_8(SourceB8^),65535,255));
|
|
Inc(SourceB8,SourceIncrement);
|
|
Inc(SourceG8,SourceIncrement);
|
|
Inc(SourceR8,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(PWord(TargetRun16),TargetIncrement);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
SourceR16:=Source[0];
|
|
SourceG16:=SourceR16;
|
|
Inc(SourceG16);
|
|
SourceB16:=SourceG16;
|
|
Inc(SourceB16);
|
|
SourceA16:=SourceB16;
|
|
Inc(SourceA16);
|
|
end
|
|
else
|
|
begin
|
|
SourceR16:=Source[0];
|
|
SourceG16:=Source[1];
|
|
SourceB16:=Source[2];
|
|
if coAlpha in FSourceOptions then SourceA16:=Source[3] else SourceA16:=nil;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 161616 to 888
|
|
if coApplyGamma in FTargetOptions then
|
|
begin
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_8:=ComponentSwapScaleGammaConvert else Convert16_8:=ComponentScaleGammaConvert;
|
|
end
|
|
else
|
|
begin
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_8:=ComponentSwapScaleConvert else Convert16_8:=ComponentScaleConvert;
|
|
end;
|
|
// since alpha channels are never gamma corrected we need a separate conversion routine
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_8Alpha:=ComponentSwapScaleConvert else Convert16_8Alpha:=ComponentScaleConvert;
|
|
if CopyAlpha then
|
|
begin
|
|
TargetRunA8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRunA8.R:=Convert16_8(SourceR16^);
|
|
TargetRunA8.G:=Convert16_8(SourceG16^);
|
|
TargetRunA8.B:=Convert16_8(SourceB16^);
|
|
TargetRunA8.A:=Convert16_8Alpha(SourceA16^);
|
|
Inc(SourceB16,SourceIncrement);
|
|
Inc(SourceG16,SourceIncrement);
|
|
Inc(SourceR16,SourceIncrement);
|
|
Inc(SourceA16,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(TargetRunA8);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TargetRun8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRun8.R:=Convert16_8(SourceR16^);
|
|
TargetRun8.G:=Convert16_8(SourceG16^);
|
|
TargetRun8.B:=Convert16_8(SourceB16^);
|
|
Inc(SourceB16,SourceIncrement);
|
|
Inc(SourceG16,SourceIncrement);
|
|
Inc(SourceR16,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(Pbyte(TargetRun8),TargetIncrement);
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin // 161616 to 161616
|
|
// no gamma correction for 16 bit samples yet
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_16:=ComponentSwapConvert else Convert16_16:=ComponentNoConvert16;
|
|
if Length(Source)=1 then
|
|
begin
|
|
SourceB16:=Source[0];
|
|
SourceG16:=SourceB16;
|
|
Inc(SourceG16);
|
|
SourceR16:=SourceG16;
|
|
Inc(SourceR16);
|
|
SourceA16:=SourceR16;
|
|
Inc(SourceA16);
|
|
end
|
|
else
|
|
begin
|
|
SourceB16:=Source[0];
|
|
SourceG16:=Source[1];
|
|
SourceR16:=Source[2];
|
|
if coAlpha in FSourceOptions then SourceA16:=Source[3] else SourceA16:=nil;
|
|
end;
|
|
if CopyAlpha then
|
|
begin
|
|
TargetRunA16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRunA16.R:=Convert16_16(SourceR16^);
|
|
TargetRunA16.G:=Convert16_16(SourceG16^);
|
|
TargetRunA16.B:=Convert16_16(SourceB16^);
|
|
TargetRunA16.A:=Convert16_16(SourceA16^);
|
|
Inc(SourceB16,SourceIncrement);
|
|
Inc(SourceG16,SourceIncrement);
|
|
Inc(SourceR16,SourceIncrement);
|
|
Inc(SourceA16,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(TargetRunA16);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TargetRun16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRun16.R:=Convert16_16(SourceR16^);
|
|
TargetRun16.G:=Convert16_16(SourceG16^);
|
|
TargetRun16.B:=Convert16_16(SourceB16^);
|
|
Inc(SourceB16,SourceIncrement);
|
|
Inc(SourceG16,SourceIncrement);
|
|
Inc(SourceR16,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(PWord(TargetRun16),TargetIncrement);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.RowConvertRGB2RGB(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
// same as ConvertRGB2BGR but for RGB target schemes
|
|
var SourceR16,SourceG16,SourceB16,SourceA16: PWord;
|
|
SourceR8,SourceG8,SourceB8,SourceA8: PByte;
|
|
TargetRun16: PRGB16;
|
|
TargetRunA16: PRGBA16;
|
|
TargetRun8: PRGB;
|
|
TargetRunA8: PRGBA;
|
|
BitRun: byte;
|
|
Convert8_8: function(Value: byte): byte of object;
|
|
Convert16_8: function(Value: word): byte of object;
|
|
Convert16_8Alpha: function(Value: word): byte of object;
|
|
Convert16_16: function(Value: word): word of object;
|
|
SourceIncrement,TargetIncrement: cardinal;
|
|
CopyAlpha: boolean;
|
|
begin
|
|
BitRun:=$80;
|
|
// determine alpha handling once
|
|
CopyAlpha:=False;
|
|
if coAlpha in FSourceOptions then
|
|
begin
|
|
SourceIncrement:=sizeof(TRGBA);
|
|
TargetIncrement:=sizeof(TRGB);
|
|
if coAlpha in FTargetOptions then CopyAlpha:=True;
|
|
end
|
|
else
|
|
begin
|
|
SourceIncrement:=sizeof(TRGB);
|
|
if coAlpha in FTargetOptions then TargetIncrement:=sizeof(TRGBA) else TargetIncrement:=sizeof(TRGB);
|
|
end;
|
|
// in planar mode source increment is always 1
|
|
if Length(Source)>1 then SourceIncrement:=1;
|
|
case FSourceBPS of
|
|
8: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
// interleaved mode
|
|
SourceR8:=Source[0];
|
|
SourceG8:=SourceR8;
|
|
Inc(SourceG8);
|
|
SourceB8:=SourceG8;
|
|
Inc(SourceB8);
|
|
SourceA8:=SourceB8;
|
|
Inc(SourceA8);
|
|
end
|
|
else
|
|
begin
|
|
SourceR8:=Source[0];
|
|
SourceG8:=Source[1];
|
|
SourceB8:=Source[2];
|
|
if coAlpha in FSourceOptions then SourceA8:=Source[3] else SourceA8:=nil;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 888 to 888
|
|
if coApplyGamma in FTargetOptions then Convert8_8:=ComponentGammaConvert else Convert8_8:=ComponentNoConvert8;
|
|
if CopyAlpha then
|
|
begin
|
|
TargetRunA8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRunA8.R:=Convert8_8(SourceR8^);
|
|
TargetRunA8.G:=Convert8_8(SourceG8^);
|
|
TargetRunA8.B:=Convert8_8(SourceB8^);
|
|
// alpha values are never gamma corrected
|
|
TargetRunA8.A:=SourceA8^;
|
|
Inc(SourceB8,SourceIncrement);
|
|
Inc(SourceG8,SourceIncrement);
|
|
Inc(SourceR8,SourceIncrement);
|
|
Inc(SourceA8,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(TargetRunA8);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TargetRun8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRun8.R:=Convert8_8(SourceR8^);
|
|
TargetRun8.G:=Convert8_8(SourceG8^);
|
|
TargetRun8.B:=Convert8_8(SourceB8^);
|
|
Inc(SourceB8,SourceIncrement);
|
|
Inc(SourceG8,SourceIncrement);
|
|
Inc(SourceR8,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(PByte(TargetRun8),TargetIncrement);
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin // 888 to 161616
|
|
if coApplyGamma in FTargetOptions then Convert8_8:=ComponentGammaConvert else Convert8_8:=ComponentNoConvert8;
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_16:=ComponentSwapConvert else Convert16_16:=ComponentNoConvert16;
|
|
if Length(Source)=1 then
|
|
begin
|
|
SourceB8:=Source[0];
|
|
SourceG8:=SourceB8;
|
|
Inc(SourceG8);
|
|
SourceR8:=SourceG8;
|
|
Inc(SourceR8);
|
|
SourceA8:=SourceR8;
|
|
Inc(SourceA8);
|
|
end
|
|
else
|
|
begin
|
|
SourceB8:=Source[0];
|
|
SourceG8:=Source[1];
|
|
SourceR8:=Source[2];
|
|
if coAlpha in FSourceOptions then SourceA8:=Source[3] else SourceA8:=nil;
|
|
end;
|
|
if CopyAlpha then
|
|
begin
|
|
TargetRunA16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRunA16.R:=Convert16_16(MulDiv16(Convert8_8(SourceR8^),65535,255));
|
|
TargetRunA16.G:=Convert16_16(MulDiv16(Convert8_8(SourceG8^),65535,255));
|
|
TargetRunA16.B:=Convert16_16(MulDiv16(Convert8_8(SourceB8^),65535,255));
|
|
TargetRunA16.A:=Convert16_16(MulDiv16(SourceA8^,65535,255));
|
|
Inc(SourceB8,SourceIncrement);
|
|
Inc(SourceG8,SourceIncrement);
|
|
Inc(SourceR8,SourceIncrement);
|
|
Inc(SourceA8,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(TargetRunA16);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TargetRun16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRun16.R:=Convert16_16(MulDiv16(Convert8_8(SourceR8^), 65535, 255));
|
|
TargetRun16.G:=Convert16_16(MulDiv16(Convert8_8(SourceG8^), 65535, 255));
|
|
TargetRun16.B:=Convert16_16(MulDiv16(Convert8_8(SourceB8^), 65535, 255));
|
|
Inc(SourceB8,SourceIncrement);
|
|
Inc(SourceG8,SourceIncrement);
|
|
Inc(SourceR8,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(PWord(TargetRun16),TargetIncrement);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
SourceR16:=Source[0];
|
|
SourceG16:=SourceR16;
|
|
Inc(SourceG16);
|
|
SourceB16:=SourceG16;
|
|
Inc(SourceB16);
|
|
SourceA16:=SourceB16;
|
|
Inc(SourceA16);
|
|
end
|
|
else
|
|
begin
|
|
SourceR16:=Source[0];
|
|
SourceG16:=Source[1];
|
|
SourceB16:=Source[2];
|
|
if coAlpha in FSourceOptions then SourceA16:=Source[3] else SourceA16:=nil;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 161616 to 888
|
|
if coApplyGamma in FTargetOptions then
|
|
begin
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_8:=ComponentSwapScaleGammaConvert else Convert16_8:=ComponentScaleGammaConvert;
|
|
end
|
|
else
|
|
begin
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_8:=ComponentSwapScaleConvert else Convert16_8:=ComponentScaleConvert;
|
|
end;
|
|
// since alpha channels are never gamma corrected we need a separate conversion routine
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_8Alpha:=ComponentSwapScaleConvert else Convert16_8Alpha:=ComponentScaleConvert;
|
|
if CopyAlpha then
|
|
begin
|
|
TargetRunA8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRunA8.R:=Convert16_8(SourceR16^);
|
|
TargetRunA8.G:=Convert16_8(SourceG16^);
|
|
TargetRunA8.B:=Convert16_8(SourceB16^);
|
|
TargetRunA8.A:=Convert16_8Alpha(SourceA16^);
|
|
Inc(SourceB16,SourceIncrement);
|
|
Inc(SourceG16,SourceIncrement);
|
|
Inc(SourceR16,SourceIncrement);
|
|
Inc(SourceA16,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(TargetRunA8);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TargetRun8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRun8.R:=Convert16_8(SourceR16^);
|
|
TargetRun8.G:=Convert16_8(SourceG16^);
|
|
TargetRun8.B:=Convert16_8(SourceB16^);
|
|
Inc(SourceB16,SourceIncrement);
|
|
Inc(SourceG16,SourceIncrement);
|
|
Inc(SourceR16,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(PByte(TargetRun8),TargetIncrement);
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin // 161616 to 161616
|
|
// no gamma correction for 16 bit samples yet
|
|
if coNeedbyteSwap in FSourceOptions then Convert16_16:=ComponentSwapConvert else Convert16_16:=ComponentNoConvert16;
|
|
if Length(Source)=1 then
|
|
begin
|
|
SourceB16:=Source[0];
|
|
SourceG16:=SourceB16;
|
|
Inc(SourceG16);
|
|
SourceR16:=SourceG16;
|
|
Inc(SourceR16);
|
|
SourceA16:=SourceR16;
|
|
Inc(SourceA16);
|
|
end
|
|
else
|
|
begin
|
|
SourceB16:=Source[0];
|
|
SourceG16:=Source[1];
|
|
SourceR16:=Source[2];
|
|
if coAlpha in FSourceOptions then SourceA16:=Source[3] else SourceA16:=nil;
|
|
end;
|
|
if CopyAlpha then
|
|
begin
|
|
TargetRunA16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRunA16.R:=Convert16_16(SourceR16^);
|
|
TargetRunA16.G:=Convert16_16(SourceG16^);
|
|
TargetRunA16.B:=Convert16_16(SourceB16^);
|
|
TargetRunA16.A:=Convert16_16(SourceA16^);
|
|
Inc(SourceB16,SourceIncrement);
|
|
Inc(SourceG16,SourceIncrement);
|
|
Inc(SourceR16,SourceIncrement);
|
|
Inc(SourceA16,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(TargetRunA16);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TargetRun16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
TargetRun16.R:=Convert16_16(SourceR16^);
|
|
TargetRun16.G:=Convert16_16(SourceG16^);
|
|
TargetRun16.B:=Convert16_16(SourceB16^);
|
|
Inc(SourceB16,SourceIncrement);
|
|
Inc(SourceG16,SourceIncrement);
|
|
Inc(SourceR16,SourceIncrement);
|
|
end;
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
Inc(PWord(TargetRun16),TargetIncrement);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.RowConvertPhotoYCC2BGR(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
// converts from PhotoYCC format to BGR(A)
|
|
var Y,Cb,Cr: integer;
|
|
Yf,Cbf,Crf: single;
|
|
Y8Run,Cb8Run,Cr8Run: PByte;
|
|
Y16Run,Cb16Run,Cr16Run: PWord;
|
|
Target8: PByte;
|
|
Target16: PWord;
|
|
AlphaSkip: integer;
|
|
BitRun: byte;
|
|
Increment: integer;
|
|
begin
|
|
BitRun:=$80;
|
|
AlphaSkip:=Ord(coAlpha in FTargetOptions); // 0 if no alpha must be skipped, otherwise 1
|
|
case FSourceBPS of
|
|
8: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
Y8Run:=Source[0];
|
|
Cb8Run:=Y8Run;
|
|
Inc(Cb8Run);
|
|
Cr8Run:=Cb8Run;
|
|
Inc(Cr8Run);
|
|
Increment:=3;
|
|
end
|
|
else
|
|
begin
|
|
Y8Run:=Source[0];
|
|
Cb8Run:=Source[1];
|
|
Cr8Run:=Source[2];
|
|
Increment:=1;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 888 to 888
|
|
Target8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Y:=Y8Run^;
|
|
Inc(Y8Run,Increment);
|
|
Cb:=Cb8Run^;
|
|
Inc(Cb8Run,Increment);
|
|
Cr:=Cr8Run^;
|
|
Inc(Cr8Run,Increment);
|
|
// blue
|
|
Target8^:=ClampByte(Y+FCbToBlueTable[Cb]);
|
|
Inc(Target8);
|
|
// green
|
|
Target8^:=ClampByte(Y+FCbToGreenTable[Cb]+FCrToGreentable[Cr]);
|
|
Inc(Target8);
|
|
// red
|
|
Target8^:=ClampByte(Y+FCrToRedTable[Cr]);
|
|
Inc(Target8,1+AlphaSkip);
|
|
end
|
|
else Inc(Target8,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
16: begin // 888 to 161616
|
|
Target16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Y:=Y8Run^;
|
|
Inc(Y8Run,Increment);
|
|
Cb:=Cb8Run^;
|
|
Inc(Cb8Run,Increment);
|
|
Cr:=Cr8Run^;
|
|
Inc(Cr8Run,Increment);
|
|
// blue
|
|
Target16^:=MulDiv16(Clampbyte(Y+FCbToBlueTable[Cb]),65535,255);
|
|
Inc(Target16);
|
|
// green
|
|
Target16^:=MulDiv16(Clampbyte(Y+FCbToGreenTable[Cb]+FCrToGreentable[Cr]), 65535, 255);
|
|
Inc(Target16);
|
|
// red
|
|
Target16^:=MulDiv16(Clampbyte(Y+FCrToRedTable[Cr]),65535,255);
|
|
Inc(Target16,1+AlphaSkip);
|
|
end
|
|
else Inc(Target16,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
Y16Run:=Source[0];
|
|
Cb16Run:=Y16Run;
|
|
Inc(Cb16Run);
|
|
Cr16Run:=Cb16Run;
|
|
Inc(Cr16Run);
|
|
Increment:=3;
|
|
end
|
|
else
|
|
begin
|
|
Y16Run:=Source[0];
|
|
Cb16Run:=Source[1];
|
|
Cr16Run:=Source[2];
|
|
Increment:=1;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 161616 to 888
|
|
Target8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Y:=MulDiv16(Y16Run^,255,65535);
|
|
Inc(Y16Run,Increment);
|
|
Cb:=MulDiv16(Cb16Run^,255,65535);
|
|
Inc(Cb16Run,Increment);
|
|
Cr:=MulDiv16(Cr16Run^,255,65535);
|
|
Inc(Cr16Run,Increment);
|
|
// blue
|
|
Target8^:=ClampByte(Y+FCbToBlueTable[Cb]);
|
|
Inc(Target8);
|
|
// green
|
|
Target8^:=ClampByte(Y+FCbToGreenTable[Cb]+FCrToGreentable[Cr]);
|
|
Inc(Target8);
|
|
// red
|
|
Target8^:=ClampByte(Y+FCrToRedTable[Cr]);
|
|
Inc(Target8,1+AlphaSkip);
|
|
end
|
|
else Inc(Target8,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
16: begin // 161616 to 161616
|
|
Target16:=Target;
|
|
// conversion from 16 to 16 is done with full precision, so there is no
|
|
// loss of information, but the code is slower because the lookup tables
|
|
// cannot be used
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Yf:=1.3584*Y16Run^;
|
|
Inc(Y16Run,Increment);
|
|
Cbf:=Cb16Run^-40092; // (156*65535) div 255
|
|
Inc(Cb16Run,Increment);
|
|
Crf:=Cr16Run^-35209; // (137*65535) div 255
|
|
Inc(Cr16Run,Increment);
|
|
// blue
|
|
Target16^:=Round(Yf+2.2179*Cbf);
|
|
Inc(Target16);
|
|
// green
|
|
Target16^:=Round(Yf-0.9271435*Crf-0.4302726*Cbf);
|
|
Inc(Target16);
|
|
// red
|
|
Target16^:=Round(Yf+1.8215*Crf);
|
|
Inc(Target16,1+AlphaSkip);
|
|
end
|
|
else Inc(Target16,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.RowConvertPhotoYCC2RGB(Source: array of Pointer; Target: Pointer; Count: Cardinal; Mask: byte);
|
|
// converts from PhotoYCC format to RGB(A)
|
|
var Y,Cb,Cr,AlphaSkip,Increment: integer;
|
|
Yf,Cbf,Crf: single;
|
|
Y8Run, Cb8Run, Cr8Run: PByte;
|
|
Y16Run, Cb16Run, Cr16Run: PWord;
|
|
Target8: PByte;
|
|
Target16: PWord;
|
|
BitRun: byte;
|
|
begin
|
|
BitRun:=$80;
|
|
AlphaSkip:=Ord(coAlpha in FTargetOptions); // 0 if no alpha must be skipped, otherwise 1
|
|
case FSourceBPS of
|
|
8: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
Y8Run:=Source[0];
|
|
Cb8Run:=Y8Run;
|
|
Inc(Cb8Run);
|
|
Cr8Run:=Cb8Run;
|
|
Inc(Cr8Run);
|
|
Increment:=3;
|
|
end
|
|
else
|
|
begin
|
|
Y8Run:=Source[0];
|
|
Cb8Run:=Source[1];
|
|
Cr8Run:=Source[2];
|
|
Increment:=1;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 888 to 888
|
|
Target8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Y:=Y8Run^;
|
|
Inc(Y8Run,Increment);
|
|
Cb:=Cb8Run^;
|
|
Inc(Cb8Run,Increment);
|
|
Cr:=Cr8Run^;
|
|
Inc(Cr8Run,Increment);
|
|
// red
|
|
Target8^:=ClampByte(Y+FCrToRedTable[Cr]);
|
|
Inc(Target8,1+AlphaSkip);
|
|
// green
|
|
Target8^:=ClampByte(Y+FCbToGreenTable[Cb]+FCrToGreentable[Cr]);
|
|
Inc(Target8);
|
|
// blue
|
|
Target8^:=ClampByte(Y+FCbToBlueTable[Cb]);
|
|
Inc(Target8);
|
|
end
|
|
else Inc(Target8,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
16: begin // 888 to 161616
|
|
Target16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Y:=Y8Run^;
|
|
Inc(Y8Run,Increment);
|
|
Cb:=Cb8Run^;
|
|
Inc(Cb8Run,Increment);
|
|
Cr:=Cr8Run^;
|
|
Inc(Cr8Run,Increment);
|
|
// red
|
|
Target16^:=MulDiv16(ClampByte(Y+FCrToRedTable[Cr]),65535,255);
|
|
Inc(Target16,1+AlphaSkip);
|
|
// green
|
|
Target16^:=MulDiv16(ClampByte(Y+FCbToGreenTable[Cb]+FCrToGreentable[Cr]),65535,255);
|
|
Inc(Target16);
|
|
// blue
|
|
Target16^:=MulDiv16(ClampByte(Y+FCbToBlueTable[Cb]),65535,255);
|
|
Inc(Target16);
|
|
end
|
|
else Inc(Target16,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
Y16Run:=Source[0];
|
|
Cb16Run:=Y16Run;
|
|
Inc(Cb16Run);
|
|
Cr16Run:=Cb16Run;
|
|
Inc(Cr16Run);
|
|
Increment:=3;
|
|
end
|
|
else
|
|
begin
|
|
Y16Run:=Source[0];
|
|
Cb16Run:=Source[1];
|
|
Cr16Run:=Source[2];
|
|
Increment:=1;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 161616 to 888
|
|
Target8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Y:=MulDiv16(Y16Run^,255,65535);
|
|
Inc(Y16Run,Increment);
|
|
Cb:=MulDiv16(Cb16Run^,255,65535);
|
|
Inc(Cb16Run,Increment);
|
|
Cr:=MulDiv16(Cr16Run^,255,65535);
|
|
Inc(Cr16Run,Increment);
|
|
// red
|
|
Target8^:=ClampByte(Y+FCrToRedTable[Cr]);
|
|
Inc(Target8,1+AlphaSkip);
|
|
// green
|
|
Target8^:=ClampByte(Y+FCbToGreenTable[Cb]+FCrToGreenTable[Cr]);
|
|
Inc(Target8);
|
|
// blue
|
|
Target8^:=ClampByte(Y+FCbToBlueTable[Cb]);
|
|
Inc(Target8);
|
|
end
|
|
else Inc(Target8,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
16: begin // 161616 to 161616
|
|
Target16:=Target;
|
|
// conversion from 16 to 16 is done with full precision, so there is no
|
|
// loss of information, but the code is slower because the lookup tables
|
|
// cannot be used
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Yf:=1.3584*Y16Run^;
|
|
Inc(Y16Run,Increment);
|
|
Cbf:=Cb16Run^-40092; // (156*65535) div 255
|
|
Inc(Cb16Run,Increment);
|
|
Crf:=Cr16Run^-35209; // (137*65535) div 255
|
|
Inc(Cr16Run,Increment);
|
|
// red
|
|
Target16^:=Round(Yf+1.8215*Crf);
|
|
Inc(Target16,1+AlphaSkip);
|
|
// green
|
|
Target16^:=Round(Yf-0.9271435*Crf-0.4302726*Cbf);
|
|
Inc(Target16);
|
|
// blue
|
|
Target16^:=Round(Yf+2.2179*Cbf);
|
|
Inc(Target16);
|
|
end
|
|
else Inc(Target16,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.RowConvertYCbCr2BGR(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
// converts from standard YCbCr to BGR(A)
|
|
var Y,Cb,Cr,AlphaSkip,Increment: integer;
|
|
Yf,Cbf,Crf: single;
|
|
Y8Run,Cb8Run,Cr8Run: PByte;
|
|
Y16Run,Cb16Run,Cr16Run: PWord;
|
|
Target8: PByte;
|
|
Target16: PWord;
|
|
BitRun: byte;
|
|
begin
|
|
BitRun:=$80;
|
|
AlphaSkip:=Ord(coAlpha in FTargetOptions); // 0 if no alpha must be skipped, otherwise 1
|
|
case FSourceBPS of
|
|
8: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
Y8Run:=Source[0];
|
|
Cb8Run:=Y8Run;
|
|
Inc(Cb8Run);
|
|
Cr8Run:=Cb8Run;
|
|
Inc(Cr8Run);
|
|
Increment:=3;
|
|
end
|
|
else
|
|
begin
|
|
Y8Run:=Source[0];
|
|
Cb8Run:=Source[1];
|
|
Cr8Run:=Source[2];
|
|
Increment:=1;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 888 to 888
|
|
Target8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Y:=Y8Run^;
|
|
Inc(Y8Run,Increment);
|
|
Cb:=Cb8Run^;
|
|
Inc(Cb8Run,Increment);
|
|
Cr:=Cr8Run^;
|
|
Inc(Cr8Run,Increment);
|
|
// blue
|
|
Target8^:=ClampByte(Y+FCbToBlueTable[Cb]);
|
|
Inc(Target8);
|
|
// green
|
|
Target8^:=ClampByte(Y+FCbToGreenTable[Cb]+FCrToGreentable[Cr]);
|
|
Inc(Target8);
|
|
// red
|
|
Target8^:=ClampByte(Y+FCrToRedTable[Cr]);
|
|
Inc(Target8,1+AlphaSkip);
|
|
end
|
|
else Inc(Target8,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
16: begin // 888 to 161616
|
|
Target16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Y:=Y8Run^;
|
|
Inc(Y8Run,Increment);
|
|
Cb:=Cb8Run^;
|
|
Inc(Cb8Run,Increment);
|
|
Cr:=Cr8Run^;
|
|
Inc(Cr8Run,Increment);
|
|
// blue
|
|
Target16^:=MulDiv16(Clampbyte(Y+FCbToBlueTable[Cb]),65535,255);
|
|
Inc(Target16);
|
|
// green
|
|
Target16^:=MulDiv16(Clampbyte(Y+FCbToGreenTable[Cb]+FCrToGreentable[Cr]),65535,255);
|
|
Inc(Target16);
|
|
// red
|
|
Target16^:=MulDiv16(Clampbyte(Y+FCrToRedTable[Cr]),65535,255);
|
|
Inc(Target16,1+AlphaSkip);
|
|
end
|
|
else Inc(Target16,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
Y16Run:=Source[0];
|
|
Cb16Run:=Y16Run;
|
|
Inc(Cb16Run);
|
|
Cr16Run:=Cb16Run;
|
|
Inc(Cr16Run);
|
|
Increment:=3;
|
|
end
|
|
else
|
|
begin
|
|
Y16Run:=Source[0];
|
|
Cb16Run:=Source[1];
|
|
Cr16Run:=Source[2];
|
|
Increment:=1;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 161616 to 888
|
|
Target8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Y:=MulDiv16(Y16Run^,255,65535);
|
|
Inc(Y16Run,Increment);
|
|
Cb:=MulDiv16(Cb16Run^,255,65535);
|
|
Inc(Cb16Run,Increment);
|
|
Cr:=MulDiv16(Cr16Run^,255,65535);
|
|
Inc(Cr16Run,Increment);
|
|
// blue
|
|
Target8^:=ClampByte(Y+FCbToBlueTable[Cb]);
|
|
Inc(Target8);
|
|
// green
|
|
Target8^:=ClampByte(Y+FCbToGreenTable[Cb]+FCrToGreentable[Cr]);
|
|
Inc(Target8);
|
|
// red
|
|
Target8^:=ClampByte(Y+FCrToRedTable[Cr]);
|
|
Inc(Target8,1+AlphaSkip);
|
|
end
|
|
else Inc(Target8,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
16: begin // 161616 to 161616
|
|
Target16:=Target;
|
|
// conversion from 16 to 16 is done with full precision, so there is no
|
|
// loss of information, but the code is slower because the lookup tables
|
|
// cannot be used
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Yf:=1.3584*Y16Run^;
|
|
Inc(Y16Run,Increment);
|
|
Cbf:=Cb16Run^-40092; // (156*65535) div 255
|
|
Inc(Cb16Run,Increment);
|
|
Crf:=Cr16Run^-35209; // (137*65535) div 255
|
|
Inc(Cr16Run,Increment);
|
|
// blue
|
|
Target16^:=Round(Yf+2.2179*Cbf);
|
|
Inc(Target16);
|
|
// green
|
|
Target16^:=Round(Yf-0.9271435*Crf-0.4302726*Cbf);
|
|
Inc(Target16);
|
|
// red
|
|
Target16^:=Round(Yf+1.8215*Crf);
|
|
Inc(Target16,1+AlphaSkip);
|
|
end
|
|
else Inc(Target16,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.RowConvertYCbCr2RGB(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
// converts from standard YCbCr to RGB(A)
|
|
var Y,Cb,Cr,AlphaSkip,Increment: integer;
|
|
Yf,Cbf,Crf: single;
|
|
Y8Run,Cb8Run,Cr8Run: PByte;
|
|
Y16Run,Cb16Run,Cr16Run: PWord;
|
|
Target8: PByte;
|
|
Target16: PWord;
|
|
BitRun: byte;
|
|
begin
|
|
BitRun:=$80;
|
|
AlphaSkip:=Ord(coAlpha in FTargetOptions); // 0 if no alpha must be skipped, otherwise 1
|
|
case FSourceBPS of
|
|
8: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
Y8Run:=Source[0];
|
|
Cb8Run:=Y8Run;
|
|
Inc(Cb8Run);
|
|
Cr8Run:=Cb8Run;
|
|
Inc(Cr8Run);
|
|
Increment:=3;
|
|
end
|
|
else
|
|
begin
|
|
Y8Run:=Source[0];
|
|
Cb8Run:=Source[1];
|
|
Cr8Run:=Source[2];
|
|
Increment:=1;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 888 to 888
|
|
Target8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Y:=Y8Run^;
|
|
Inc(Y8Run,Increment);
|
|
Cb:=Cb8Run^;
|
|
Inc(Cb8Run,Increment);
|
|
Cr:=Cr8Run^;
|
|
Inc(Cr8Run,Increment);
|
|
// red
|
|
Target8^:=ClampByte(Y+FCrToRedTable[Cr]);
|
|
Inc(Target8,1+AlphaSkip);
|
|
// green
|
|
Target8^:=ClampByte(Y+FCbToGreenTable[Cb]+FCrToGreenTable[Cr]);
|
|
Inc(Target8);
|
|
// blue
|
|
Target8^:=ClampByte(Y+FCbToBlueTable[Cb]);
|
|
Inc(Target8);
|
|
end
|
|
else Inc(Target8,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
16: begin // 888 to 161616
|
|
Target16:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Y:=Y8Run^;
|
|
Inc(Y8Run,Increment);
|
|
Cb:=Cb8Run^;
|
|
Inc(Cb8Run,Increment);
|
|
Cr:=Cr8Run^;
|
|
Inc(Cr8Run,Increment);
|
|
// red
|
|
Target16^:=MulDiv16(Clampbyte(Y+FCrToRedTable[Cr]),65535,255);
|
|
Inc(Target16, 1+AlphaSkip);
|
|
// green
|
|
Target16^:=MulDiv16(Clampbyte(Y+FCbToGreenTable[Cb]+FCrToGreentable[Cr]), 65535, 255);
|
|
Inc(Target16);
|
|
// blue
|
|
Target16^:=MulDiv16(Clampbyte(Y+FCbToBlueTable[Cb]),65535,255);
|
|
Inc(Target16);
|
|
end
|
|
else Inc(Target16,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
16: begin
|
|
if Length(Source)=1 then
|
|
begin
|
|
Y16Run:=Source[0];
|
|
Cb16Run:=Y16Run; Inc(Cb16Run);
|
|
Cr16Run:=Cb16Run; Inc(Cr16Run);
|
|
Increment:=3;
|
|
end
|
|
else
|
|
begin
|
|
Y16Run:=Source[0];
|
|
Cb16Run:=Source[1];
|
|
Cr16Run:=Source[2];
|
|
Increment:=1;
|
|
end;
|
|
case FTargetBPS of
|
|
8: begin // 161616 to 888
|
|
Target8:=Target;
|
|
while Count>0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Y:=MulDiv16(Y16Run^, 255, 65535);
|
|
Inc(Y16Run, Increment);
|
|
Cb:=MulDiv16(Cb16Run^, 255, 65535);
|
|
Inc(Cb16Run, Increment);
|
|
Cr:=MulDiv16(Cr16Run^, 255, 65535);
|
|
Inc(Cr16Run, Increment);
|
|
// red
|
|
Target8^:=Clampbyte(Y+FCrToRedTable[Cr]);
|
|
Inc(Target8, 1+AlphaSkip);
|
|
// green
|
|
Target8^:=Clampbyte(Y+FCbToGreenTable[Cb]+FCrToGreentable[Cr]);
|
|
Inc(Target8);
|
|
// blue
|
|
Target8^:=Clampbyte(Y+FCbToBlueTable[Cb]);
|
|
Inc(Target8);
|
|
end
|
|
else Inc(Target8, 3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
16: begin // 161616 to 161616
|
|
Target16:=Target;
|
|
// conversion from 16 to 16 is done with full precision, so there is no
|
|
// loss of information, but the code is slower because the lookup tables
|
|
// cannot be used
|
|
while Count > 0 do
|
|
begin
|
|
if Boolean(Mask and BitRun) then
|
|
begin
|
|
Yf:=1.3584*Y16Run^;
|
|
Inc(Y16Run,Increment);
|
|
Cbf:=Cb16Run^-40092; // (156*65535) div 255
|
|
Inc(Cb16Run,Increment);
|
|
Crf:=Cr16Run^-35209; // (137*65535) div 255
|
|
Inc(Cr16Run,Increment);
|
|
// red
|
|
Target16^:=Round(Yf+1.8215*Crf);
|
|
Inc(Target16,1+AlphaSkip);
|
|
// green
|
|
Target16^:=Round(Yf-0.9271435*Crf-0.4302726*Cbf);
|
|
Inc(Target16);
|
|
// blue
|
|
Target16^:=Round(Yf+2.2179*Cbf);
|
|
Inc(Target16);
|
|
end
|
|
else Inc(Target16,3+AlphaSkip);
|
|
asm
|
|
ROR byte PTR [BitRun],1
|
|
end;
|
|
Dec(Count);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.CreateYCbCrLookup;
|
|
// In order to speedup YCbCr conversion lookup tables are used, this methods creates them.
|
|
// R:=Y+Cr*(2-2*LumaRed);
|
|
// B:=Y+Cb*(2-2*LumaBlue);
|
|
// G:=Y-LumaBlue*Cb*(2-2*LumaBlue) / LumaGreen
|
|
// -LumaRed*Cr*(2-2*LumaRed) / LumaGreen;
|
|
//
|
|
// To avoid floating point arithmetic the fractional constants that come out of the equations are represented
|
|
// as fixed point values in the range 0...2^16. We also eliminate multiplications by // pre-calculating possible
|
|
// values indexed by Cb and Cr (this code assumes conversion is being done for 8-bit samples).
|
|
//
|
|
// Note: the color manager uses dynamic arrays so the memory used here is automatically freed.
|
|
//
|
|
// Needed settings:
|
|
//-YCbCr parameters must be set or default values are used
|
|
var F1,F2,F3,F4: single;
|
|
LumaRed,LumaGreen,LumaBlue: single;
|
|
I,Offset1,Offset2: integer;
|
|
begin
|
|
LumaRed:=FYCbCrCoefficients[0];
|
|
LumaGreen:=FYCbCrCoefficients[1];
|
|
LumaBlue:=FYCbCrCoefficients[2];
|
|
F1:=2-2*LumaRed;
|
|
F2:=LumaRed*F1/LumaGreen;
|
|
F3:=2-2*LumaBlue;
|
|
F4:=LumaBlue*F3/LumaGreen;
|
|
SetLength(FCrToRedTable,256);
|
|
SetLength(FCbToBlueTable,256);
|
|
SetLength(FCrToGreenTable,256);
|
|
SetLength(FCbToGreenTable,256);
|
|
if FSourceScheme=csYCbCr then
|
|
begin
|
|
// I is the actual input pixel value in the range 0..255, Cb and Cr values are in the range -128..127.
|
|
// (for TIFF files they are in a range defined by the ReferenceBlackWhite tag).
|
|
Offset1:=-128;
|
|
for I:=0 to 255 do
|
|
begin
|
|
FCrToRedTable[I]:=Round(F1*Offset1);
|
|
FCbToBlueTable[I]:=Round(F3*Offset1);
|
|
FCrToGreenTable[I]:=-Round(F2*Offset1);
|
|
FCbToGreenTable[I]:=-Round(F4*Offset1);
|
|
Inc(Offset1);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
// PhotoYCC
|
|
// I is the actual input pixel value in the range 0..255, Cb values are in the range -156..99,
|
|
// Cr values are in the range -137..118.
|
|
// (for TIFF files they are in a range defined by the ReferenceBlackWhite tag).
|
|
Offset1:=-156;
|
|
Offset2:=-137;
|
|
for I:=0 to 255 do
|
|
begin
|
|
FCrToRedTable[I]:=Round(F1*Offset2);
|
|
FCbToBlueTable[I]:=Round(F3*Offset1);
|
|
FCrToGreenTable[I]:=-Round(F2*Offset2);
|
|
FCbToGreenTable[I]:=-Round(F4*Offset1);
|
|
Inc(Offset1);
|
|
Inc(Offset2);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
function TColorManager.GetPixelFormat(Index: integer): TPixelFormat;
|
|
// determines the pixel format from the current sample and pixel sizes
|
|
// Note: setting pfCustom as pixel format will raise an exception so check the result from this method first
|
|
// before you actually assign it to a bitmap.
|
|
//
|
|
// Needed settings:
|
|
//-source samples per pixel and bits per sample for Index = 0
|
|
//-target samples per pixel and bits per sample for Index = 1
|
|
var SamplesPerPixel,BitsPerSample: byte;
|
|
begin
|
|
case Index of
|
|
0: begin
|
|
SamplesPerPixel:=FSourceSPP;
|
|
BitsPerSample:=FSourceBPS;
|
|
end;
|
|
else
|
|
SamplesPerPixel:=FTargetSPP;
|
|
BitsPerSample:=FTargetBPS;
|
|
end;
|
|
case SamplesPerPixel of
|
|
1: // one sample per pixel, this is usually a palette format
|
|
case BitsPerSample of
|
|
1: Result:=pf1Bit;
|
|
2..4: Result:=pf4bit; // values<4 should be upscaled
|
|
8..16: Result:=pf8bit; // values > 8 bits must be downscaled to 8 bits
|
|
else
|
|
Result:=pfCustom;
|
|
end;
|
|
3: // Typical case is RGB or CIE L*a*b* (565 and 555 16 bit color formats would also be possible, but aren't handled
|
|
// by the manager).
|
|
case BitsPerSample of
|
|
1..5: Result:=pf15Bit; // values<5 should be upscaled
|
|
else
|
|
// values > 8 bits should be downscaled
|
|
Result:=pf24bit;
|
|
end;
|
|
4: // Typical cases: RGBA and CMYK (with 8 bps, other formats like PCX's
|
|
// 4 planes with 1 bit must be handled elsewhere)
|
|
if BitsPerSample>=8 then Result:=pf32Bit else Result:=pfCustom;
|
|
else
|
|
Result:=pfCustom;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.PrepareConversion;
|
|
// depending on the source and target pixel and color formats a conversion function must be
|
|
// determined which actually carries out the conversion
|
|
//
|
|
// Needed settings:
|
|
//-source and target samples per pixel and bits per sample
|
|
//-source and target color scheme
|
|
begin
|
|
FRowConversion:=nil;
|
|
// Conversion between indexed and non-indexed formats is not supported as well as
|
|
// between source BPS<8 and target BPS > 8.
|
|
// csGA and csG (grayscale w and w/o alpha) are considered being indexed modes
|
|
if (FSourceScheme in [csIndexed,csG,csGA]) xor
|
|
(FTargetScheme in [csIndexed,csG]) then
|
|
Error(14{gesIndexedNotSupported});
|
|
// set up special conversion options
|
|
if FSourceScheme in [csGA,csRGBA,csBGRA] then
|
|
Include(FSourceOptions,coAlpha)
|
|
else
|
|
Exclude(FSourceOptions,coAlpha);
|
|
if FTargetScheme in [csGA,csRGBA,csBGRA] then
|
|
Include(FTargetOptions,coAlpha)
|
|
else
|
|
Exclude(FTargetOptions,coAlpha);
|
|
case FSourceScheme of
|
|
csG: if (FSourceBPS=16) or (FTargetBPS=16) then
|
|
begin
|
|
if (FSourceBPS>=8) and (FTargetBPS>=8) then FRowConversion:=RowConvertGray;
|
|
end
|
|
else FRowConversion:=RowConvertIndexed8;
|
|
csGA: if (FSourceBPS in [8,16]) and (FTargetBPS in [8,16]) then FRowConversion:=RowConvertGray;
|
|
csIndexed:
|
|
begin
|
|
// Grayscale is handled like indexed mode.
|
|
// Generally use indexed conversions (with various possible bit operations),
|
|
// assign special methods for source only, target only or source and target being 16 bits per sample
|
|
if (FSourceBPS=16) and (FTargetBPS=16) then FRowConversion:=RowConvertIndexedBoth16 else
|
|
if FSourceBPS=16 then FRowConversion:=RowConvertIndexedSource16 else
|
|
if FTargetBPS=16 then FRowConversion:=RowConvertIndexedTarget16 else
|
|
FRowConversion:=RowConvertIndexed8;
|
|
end;
|
|
csRGB,
|
|
csRGBA:
|
|
case FTargetScheme of
|
|
csRGB: FRowConversion:=RowConvertRGB2RGB;
|
|
csRGBA: FRowConversion:=RowConvertRGB2RGB;
|
|
csBGR: FRowConversion:=RowConvertRGB2BGR;
|
|
csBGRA: FRowConversion:=RowConvertRGB2BGR;
|
|
csCMY,csCMYK,csCIELab,csYCbCr: ;
|
|
end;
|
|
csBGRA,
|
|
csBGR:
|
|
case FTargetScheme of
|
|
csRGBA: FRowConversion:=RowConvertBGR2RGB;
|
|
csBGRA: FRowConversion:=RowConvertBGR2BGR;
|
|
csRGB,csBGR,csCMY,csCMYK,csCIELab,csYCbCr: ;
|
|
end;
|
|
csCMY:
|
|
case FTargetScheme of
|
|
csRGB,csRGBA,csBGR,csBGRA,csCMY,csCMYK,csCIELab,csYCbCr: ;
|
|
end;
|
|
csCMYK:
|
|
case FTargetScheme of
|
|
csRGBA: FRowConversion:=RowConvertCMYK2RGB;
|
|
csBGRA, csBGR: FRowConversion:=RowConvertCMYK2BGR;
|
|
csRGB,{csBGR,}csCMY,csCMYK,csCIELab,csYCbCr: ;
|
|
end;
|
|
csCIELab:
|
|
case FTargetScheme of
|
|
csRGBA: FRowConversion:=RowConvertCIELab2RGB;
|
|
csBGRA,csBGR: FRowConversion:=RowConvertCIELab2BGR;
|
|
csRGB,csCMY,csCMYK,csCIELab,csYCbCr: ;
|
|
end;
|
|
csYCbCr:
|
|
begin
|
|
// create lookup tables to speed up conversion
|
|
CreateYCbCrLookup;
|
|
case FTargetScheme of
|
|
csRGBA: FRowConversion:=RowConvertYCbCr2RGB;
|
|
csBGRA: FRowConversion:=RowConvertYCbCr2BGR;
|
|
csRGB,csBGR,csCMY,csCMYK,csCIELab,csYCbCr: ;
|
|
end;
|
|
end;
|
|
csPhotoYCC:
|
|
begin
|
|
// create lookup tables to speed up conversion
|
|
CreateYCbCrLookup;
|
|
case FTargetScheme of
|
|
csRGBA: FRowConversion:=RowConvertPhotoYCC2RGB;
|
|
csBGRA: FRowConversion:=RowConvertPhotoYCC2BGR;
|
|
csRGB,csBGR,csCMY,csCMYK,csCIELab,csYCbCr: ;
|
|
end;
|
|
end;
|
|
end;
|
|
FChanged:=False;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.SetSourceBitsPerSample(const Value: byte);
|
|
begin
|
|
if not (Value in [1..16]) then Error(16{gesInvalidSampleDepth});
|
|
if FSourceBPS<>Value then
|
|
begin
|
|
FSourceBPS:=Value;
|
|
FChanged:=True;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.SetSourceColorScheme(const Value: TColorScheme);
|
|
begin
|
|
if FSourceScheme<>Value then
|
|
begin
|
|
FSourceScheme:=Value;
|
|
FChanged:=True;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.SetSourceSamplesPerPixel(const Value: byte);
|
|
begin
|
|
if not (Value in [1..4]) then Error(17{gesInvalidPixelDepth});
|
|
if FSourceSPP<>Value then
|
|
begin
|
|
FSourceSPP:=Value;
|
|
FChanged:=True;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.SetTargetBitsPerSample(const Value: byte);
|
|
begin
|
|
if not (Value in [1..16]) then Error(16{gesInvalidSampleDepth});
|
|
if FTargetBPS<>Value then
|
|
begin
|
|
FTargetBPS:=Value;
|
|
FChanged:=True;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.SetTargetColorScheme(const Value: TColorScheme);
|
|
begin
|
|
if FTargetScheme<>Value then
|
|
begin
|
|
FTargetScheme:=Value;
|
|
FChanged:=True;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.SetTargetSamplesPerPixel(const Value: byte);
|
|
begin
|
|
if not (Value in [1..4]) then Error(17{gesInvalidPixelDepth});
|
|
if FTargetSPP<>Value then
|
|
begin
|
|
FTargetSPP:=Value;
|
|
FChanged:=True;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.ConvertRow(Source: array of pointer; Target: pointer; Count: cardinal; Mask: byte);
|
|
// initializes the color conversion method if necessary and calls it to do the actual conversion
|
|
//
|
|
// Needed settings:
|
|
//-source and target BPS and SPP
|
|
//-main and display gamma, if gamma correction is wanted
|
|
//-conversion options
|
|
//-YCbCr parameters if any of the color schemes is csYCbCr
|
|
begin
|
|
// if there are pending changes then apply them
|
|
if FChanged then PrepareConversion;
|
|
// check if there's now a conversion method
|
|
if not Assigned( FRowConversion ) then
|
|
Error(15{gesConversionUnsupported})
|
|
else
|
|
FRowConversion(Source,Target,Count,Mask);
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.CreateColorPalette(BMP: PBitmap;
|
|
Data: array of pointer; DataFormat: TRawPaletteFormat;
|
|
ColorCount: cardinal; RGB: boolean);
|
|
// Creates a color palette from the provided data which can be in various raw formats:
|
|
//-either interlaced or plane
|
|
//-8 bits or 16 bits per component
|
|
//-in RGB or BGR order
|
|
//-with 3 or 4 components per entry (fourth is ignored)
|
|
// ColorCount determines the number of color entries to create. If this number does not equal the
|
|
// number of palette entries which would result from the given target bits per sample resolution
|
|
// then the palette is adjusted accordingly to allow conversion between resolutions.
|
|
//
|
|
// Notes: For interlaced formats only one pointer needs to be passed in Data (only the first one is used)
|
|
// while for plane data 3 pointers are necessary (for each plane one pointer).
|
|
// The data order is assumed rgb or bgr in interlaced order (depending on RGB). In plane mode the three needed
|
|
// pointers must also be given such that the pointer to red components is in Data[0], the green pointer in
|
|
// Data[1] and the blue one in Data[2]. In this case BGR is not needed.
|
|
//
|
|
// Needed settings:
|
|
//-main and display gamma, if gamma correction is wanted
|
|
//-Options set as needed (gamma, byte swap)
|
|
//-source and target bits per sample resolution
|
|
var I,MaxIn,MaxOut: integer;
|
|
RunR8,RunG8,RunB8: PByte;
|
|
RunR16,RunG16,RunB16: PWord;
|
|
Convert8: function(Value: byte): byte of object;
|
|
Convert16: function(Value: word): byte of object;
|
|
R,G,B: byte;
|
|
begin
|
|
case DataFormat of
|
|
pfInterlaced8Triple,
|
|
pfInterlaced8Quad:
|
|
begin
|
|
RunR8:=Data[0];
|
|
if coApplyGamma in FTargetOptions then Convert8:=ComponentGammaConvert else Convert8:=ComponentNoConvert8;
|
|
if RGB then
|
|
begin
|
|
for I:=0 to pred(ColorCount) do
|
|
begin
|
|
B:=Convert8(RunR8^);
|
|
Inc(RunR8);
|
|
G:=Convert8(RunR8^);
|
|
Inc(RunR8);
|
|
R:=Convert8(RunR8^);
|
|
Inc(RunR8);
|
|
BMP.DIBPalEntries[I]:=Windows.RGB(R,G,B);
|
|
if DataFormat=pfInterlaced8Quad then Inc(RunR8);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
for I:=0 to pred(ColorCount) do
|
|
begin
|
|
R:=Convert8(RunR8^);
|
|
Inc(RunR8);
|
|
G:=Convert8(RunR8^);
|
|
Inc(RunR8);
|
|
B:=Convert8(RunR8^);
|
|
Inc(RunR8);
|
|
BMP.DIBPalEntries[I]:=Windows.RGB(R,G,B);
|
|
if DataFormat=pfInterlaced8Quad then Inc(RunR8);
|
|
end;
|
|
end;
|
|
end;
|
|
pfPlane8Triple,
|
|
pfPlane8Quad:
|
|
begin
|
|
RunR8:=Data[0];
|
|
RunG8:=Data[1];
|
|
RunB8:=Data[2];
|
|
if coApplyGamma in FTargetOptions then Convert8:=ComponentGammaConvert else Convert8:=ComponentNoConvert8;
|
|
for I:=0 to pred(ColorCount) do
|
|
begin
|
|
R:=Convert8(RunR8^);
|
|
Inc(RunR8);
|
|
G:=Convert8(RunG8^);
|
|
Inc(RunG8);
|
|
B:=Convert8(RunB8^);
|
|
Inc(RunB8);
|
|
BMP.DIBPalEntries[I]:=Windows.RGB(R,G,B);
|
|
end;
|
|
end;
|
|
pfInterlaced16Triple,
|
|
pfInterlaced16Quad:
|
|
begin
|
|
RunR16:=Data[0];
|
|
if coApplyGamma in FTargetOptions then
|
|
begin
|
|
if coNeedbyteSwap in FSourceOptions then Convert16:=ComponentSwapScaleGammaConvert else Convert16:=ComponentScaleGammaConvert;
|
|
end
|
|
else
|
|
begin
|
|
if coNeedbyteSwap in FSourceOptions then Convert16:=ComponentSwapScaleConvert else Convert16:=ComponentScaleConvert;
|
|
end;
|
|
if RGB then
|
|
begin
|
|
for I:=0 to pred(ColorCount) do
|
|
begin
|
|
R:=Convert16(RunR16^);
|
|
Inc(RunR16);
|
|
G:=Convert16(RunR16^);
|
|
Inc(RunR16);
|
|
B:=Convert16(RunR16^);
|
|
Inc(RunR16);
|
|
BMP.DIBPalEntries[I]:=Windows.RGB(R,G,B);
|
|
if DataFormat=pfInterlaced16Quad then Inc(RunR16);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
for I:=0 to pred(ColorCount) do
|
|
begin
|
|
B:=Convert16(RunR16^);
|
|
Inc(RunR16);
|
|
G:=Convert16(RunR16^);
|
|
Inc(RunR16);
|
|
R:=Convert16(RunR16^);
|
|
Inc(RunR16);
|
|
BMP.DIBPalEntries[I]:=Windows.RGB(R,G,B);
|
|
if DataFormat=pfInterlaced16Quad then Inc(RunR16);
|
|
end;
|
|
end;
|
|
end;
|
|
pfPlane16Triple,
|
|
pfPlane16Quad:
|
|
begin
|
|
RunR16:=Data[0];
|
|
RunG16:=Data[1];
|
|
RunB16:=Data[2];
|
|
if coApplyGamma in FTargetOptions then
|
|
begin
|
|
if coNeedbyteSwap in FSourceOptions then
|
|
Convert16:=ComponentSwapScaleGammaConvert
|
|
else
|
|
Convert16:=ComponentScaleGammaConvert;
|
|
end
|
|
else
|
|
begin
|
|
if coNeedbyteSwap in FSourceOptions then
|
|
Convert16:=ComponentSwapScaleConvert
|
|
else
|
|
Convert16:=ComponentScaleConvert;
|
|
end;
|
|
for I:=0 to pred(ColorCount) do
|
|
begin
|
|
R:=Convert16(RunR16^);
|
|
Inc(RunR16);
|
|
G:=Convert16(RunG16^);
|
|
Inc(RunG16);
|
|
B:=Convert16(RunB16^);
|
|
Inc(RunB16);
|
|
BMP.DIBPalEntries[I]:=Windows.RGB(B,G,R);
|
|
end;
|
|
end;
|
|
end;
|
|
MaxIn:=(1 shl FSourceBPS)-1;
|
|
MaxOut:=(1 shl FTargetBPS)-1;
|
|
if (FTargetBPS<=8) and (MaxIn<>MaxOut) then
|
|
begin
|
|
// If target resolution and given color depth differ then the palette needs to be adjusted.
|
|
// Consider the case for 2 bit to 4 bit conversion. Only 4 colors will be given to create
|
|
// the palette but after scaling all values will be up to 15 for which no color is in the palette.
|
|
// This and the reverse case need to be accounted for.
|
|
MaxIn:=(1 shl FSourceBPS)-1;
|
|
MaxOut:=(1 shl FTargetBPS)-1;
|
|
if MaxIn<MaxOut then
|
|
begin
|
|
// palette is too small, enhance it
|
|
for I:=MaxOut downto 0 do
|
|
begin
|
|
R:=GetRValue(BMP.DIBPalEntries[MulDiv16(I,MaxIn,MaxOut)]);
|
|
G:=GetGValue(BMP.DIBPalEntries[MulDiv16(I,MaxIn,MaxOut)]);
|
|
B:=GetBValue(BMP.DIBPalEntries[MulDiv16(I,MaxIn,MaxOut)]);
|
|
BMP.DIBPalEntries[I]:=Windows.RGB(R,G,B);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
// palette contains too many entries, shorten it
|
|
for I:=0 to MaxOut do
|
|
begin
|
|
R:=GetRValue(BMP.DIBPalEntries[MulDiv16(I,MaxIn,MaxOut)]);
|
|
G:=GetGValue(BMP.DIBPalEntries[MulDiv16(I,MaxIn,MaxOut)]);
|
|
B:=GetBValue(BMP.DIBPalEntries[MulDiv16(I,MaxIn,MaxOut)]);
|
|
BMP.DIBPalEntries[I]:=Windows.RGB(R,G,B);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.CreateGrayscalePalette(BMP: PBitmap; MinimumIsWhite: boolean);
|
|
// Creates a grayscale palette depending on the target bit depth and returns the handle of it,
|
|
// optionally applies gamma to each entry. MinimumIsWhite is True if the palette starts
|
|
// with white in index 0 decreasing to black while the index grows otherwise (and this is the usual case)
|
|
// a lower palette index has a lower brightness.
|
|
//
|
|
// Needed settings:
|
|
//-target BPS, 16 bits are handled as 8 bits
|
|
//-target SPP should be set to 1 (indicating an indexed image), but is not evaluated here
|
|
//-main and display gamma, if gamma correction is wanted
|
|
// Note: Target bps must not be changed between setting gamma and creating the palette.
|
|
var I: Integer;
|
|
BPS,Upper,Factor: byte;
|
|
begin
|
|
// the product of BPS and SPP considers planar organizatons correctly
|
|
// (e.g. PCX has a format 4 planes with 1 bit resulting to 16 color image)
|
|
BPS:=FTargetBPS*FTargetSPP;
|
|
if BPS>8 then BPS:=8;
|
|
Upper:=(1 shl BPS)-1;
|
|
Factor:=255 div Upper;
|
|
if MinimumIsWhite then
|
|
begin
|
|
if not (coApplyGamma in FTargetOptions) then
|
|
begin
|
|
for I:=0 to Upper do BMP.DIBPalEntries[Upper-I]:=RGB(I*Factor,I*Factor,I*Factor);
|
|
end
|
|
else
|
|
begin
|
|
for I:=0 to Upper do BMP.DIBPalEntries[Upper-I]:=RGB(FGammaTable[I*Factor],FGammaTable[I*Factor],FGammaTable[I*Factor]);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if not (coApplyGamma in FTargetOptions) then
|
|
begin
|
|
for I:=0 to Upper do BMP.DIBPalEntries[I]:=RGB(I*Factor,I*Factor,I*Factor);
|
|
end
|
|
else
|
|
begin
|
|
for I:=0 to Upper do BMP.DIBPalEntries[I]:=RGB(FGammaTable[I*Factor],FGammaTable[I*Factor],FGammaTable[I*Factor]);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
{$IFDEF NOT_USE_KOL_ERR}
|
|
procedure TColorManager.Error(Code: integer);
|
|
var E: Exception;
|
|
begin
|
|
E:=Exception.Create(int2str(Code));
|
|
//E.ErrorCode:=Code;
|
|
raise E;
|
|
end;
|
|
{$ELSE}
|
|
procedure TColorManager.Error(Code: integer);
|
|
var E: Exception;
|
|
begin
|
|
E:=Exception.Create(e_Custom,ErrorMsg[Code]);
|
|
E.ErrorCode:=Code;
|
|
raise E;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.SetGamma(MainGamma,DisplayGamma: single);
|
|
// sets the current gamma values and creates the gamma lookup table
|
|
//
|
|
// Needed settings:
|
|
//-source bits per samples must be set
|
|
//-target bits per samples must be set
|
|
var I,SourceHighBound,TargetHighBound: integer;
|
|
Gamma: single;
|
|
begin
|
|
if MainGamma<=0 then FMainGamma:=1 else FMainGamma:=MainGamma;
|
|
if DisplayGamma<=0 then FDisplayGamma:=2.2 {default value for a usual CRT} else FDisplayGamma:=DisplayGamma;
|
|
Gamma:=1/(FMainGamma*FDisplayGamma);
|
|
// source high bound is the maximum possible source value which can appear (0..255)
|
|
if FSourceBPS>=8 then SourceHighBound:=255 else SourceHighBound:=(1 shl FTargetBPS)-1;
|
|
// target high bound is the target value which corresponds to a target sample value of 1 (0..255)
|
|
if FTargetBPS>=8 then TargetHighBound:=255 else TargetHighBound:=(1 shl FTargetBPS)-1;
|
|
for I:=0 to SourceHighBound do
|
|
FGammaTable[I]:=Round(Power((I/SourceHighBound),Gamma)*TargetHighBound);
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
procedure TColorManager.SetYCbCrParameters(Values: array of single; HSubSampling,VSubSampling: byte);
|
|
// sets coefficients needed to convert from YCbCr color scheme
|
|
begin
|
|
// there must always be at least one value in an open array
|
|
FYCbCrCoefficients[0]:=Values[0];
|
|
if High(Values)>0 then
|
|
begin
|
|
FYCbCrCoefficients[1]:=Values[1];
|
|
if High(Values)>1 then FYCbCrCoefficients[2]:=Values[2];
|
|
end;
|
|
// subsampling can be 1, 2 or 4 and vertical subsampling must always be<=horizontal subsampling
|
|
if not (HSubSampling in [1,2,4]) then Error(18{gesInvalidSubSampling});
|
|
if not (VSubSampling in [1,2,4]) then Error(18{gesInvalidSubSampling});
|
|
if VSubSampling>HSubSampling then Error(19{gesVerticalSubSamplingError});
|
|
FHSubSampling:=HSubSampling;
|
|
FVSubSampling:=VSubSampling;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
end.
|
|
|