mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-06 01:38:01 +02:00
1677 lines
51 KiB
ObjectPascal
1677 lines
51 KiB
ObjectPascal
{ $Id$ }
|
|
{
|
|
/***************************************************************************
|
|
graphtype.pp
|
|
------------
|
|
Graphic related platform independent types
|
|
and utility functions.
|
|
Initial Revision : Sat Feb 02 0:02:58 2002
|
|
|
|
***************************************************************************/
|
|
|
|
*****************************************************************************
|
|
* *
|
|
* This file is part of the Lazarus Component Library (LCL) *
|
|
* *
|
|
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
|
|
* for details about the copyright. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
* *
|
|
*****************************************************************************
|
|
}
|
|
unit GraphType;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
FPCAdds, Classes, SysUtils, LCLType, LCLProc;
|
|
|
|
{$ifdef Trace}
|
|
{$ASSERTIONS ON}
|
|
{$endif}
|
|
|
|
type
|
|
TGraphicsColor = -$7FFFFFFF-1..$7FFFFFFF;
|
|
TGraphicsFillStyle =
|
|
(
|
|
fsSurface, // fill till the color (it fills all execpt this color)
|
|
fsBorder // fill this color (it fills only conneted pixels of this color)
|
|
);
|
|
TGraphicsBevelCut =
|
|
(
|
|
bvNone,
|
|
bvLowered,
|
|
bvRaised,
|
|
bvSpace
|
|
);
|
|
TGraphicsDrawEffect =
|
|
(
|
|
gdeNormal, // no effect
|
|
gdeDisabled, // grayed image
|
|
gdeHighlighted, // a bit highlighted image
|
|
gdeShadowed, // a bit shadowed image
|
|
gde1Bit // 1 Bit image (for non-XP windows buttons)
|
|
);
|
|
|
|
//------------------------------------------------------------------------------
|
|
// raw image data
|
|
type
|
|
{ Colorformat: Higher values means higher intensity.
|
|
For example: Red=0 means no red, Alpha=0 means transparent }
|
|
TRawImageColorFormat = (
|
|
ricfNone, // Uninitialized
|
|
ricfRGBA, // one pixel contains red, green, blue and alpha
|
|
// If AlphaPrec=0 then there is no alpha.
|
|
// Same for RedPrec, GreenPrec and BluePrec.
|
|
ricfGray // R=G=B. The Red stores the Gray. AlphaPrec can be >0.
|
|
);
|
|
|
|
TRawImageByteOrder = (
|
|
riboLSBFirst, // least significant byte first
|
|
riboMSBFirst // most significant byte first
|
|
);
|
|
|
|
TRawImageBitOrder = (
|
|
riboBitsInOrder, // Bit 0 is pixel 0
|
|
riboReversedBits // Bit 0 is pixel 7 (Bit 1 is pixel 6, ...)
|
|
);
|
|
|
|
TRawImageLineEnd = (
|
|
rileTight, // no gap at end of lines
|
|
rileByteBoundary, // each line starts at byte boundary. For example:
|
|
// If BitsPerPixel=3 and Width=1, each line has a gap
|
|
// of 5 unused bits at the end.
|
|
rileWordBoundary, // each line starts at word (16bit) boundary
|
|
rileDWordBoundary, // each line starts at double word (32bit) boundary
|
|
rileQWordBoundary, // each line starts at quad word (64bit) boundary
|
|
rileDQWordBoundary // each line starts at double quad word (128bit) boundary
|
|
);
|
|
|
|
TRawImageLineOrder = (
|
|
riloTopToBottom, // The line 0 is the top line
|
|
riloBottomToTop // The line 0 is the bottom line
|
|
);
|
|
|
|
TRawImageQueryFlag = (
|
|
riqfMono, // Include a description for a mono image
|
|
riqfGrey, // Include a description for a grey image
|
|
riqfRGB, // Include a description for a RGB image
|
|
riqfAlpha, // Include a description for an Alpha channel
|
|
riqfMask, // Include a description for a Mask
|
|
riqfPalette, // Include a description for a Palette
|
|
riqfUpdate // Update given description (instead of clearing it)
|
|
);
|
|
TRawImageQueryFlags = set of TRawImageQueryFlag;
|
|
|
|
{ TRawImageDescription }
|
|
|
|
TRawImageDescription = object
|
|
Format: TRawImageColorFormat;
|
|
Width: cardinal;
|
|
Height: cardinal;
|
|
Depth: Byte; // used bits per pixel
|
|
BitOrder: TRawImageBitOrder;
|
|
ByteOrder: TRawImageByteOrder;
|
|
LineOrder: TRawImageLineOrder;
|
|
LineEnd: TRawImageLineEnd;
|
|
BitsPerPixel: Byte; // bits per pixel. can be greater than Depth.
|
|
RedPrec: Byte; // red or gray precision. bits for red
|
|
RedShift: Byte; // bitshift. Direction: from least to most significant
|
|
GreenPrec: Byte;
|
|
GreenShift: Byte;
|
|
BluePrec: Byte;
|
|
BlueShift: Byte;
|
|
AlphaPrec: Byte;
|
|
AlphaShift: Byte;
|
|
|
|
// The next values are only valid, if there is a mask (MaskBitsPerPixel > 0)
|
|
// Masks are always separate with a depth of 1 bpp. One pixel can occupy
|
|
// one byte at most
|
|
// a value of 1 means that pixel is masked
|
|
// a value of 0 means the pixel value is shown
|
|
MaskBitsPerPixel: Byte; // bits per mask pixel, usually 1, 0 when no mask
|
|
MaskShift: Byte; // the shift (=position) of the mask bit
|
|
MaskLineEnd: TRawImageLineEnd;
|
|
MaskBitOrder: TRawImageBitOrder;
|
|
|
|
// The next values are only valid, if there is a palette (PaletteColorCount > 0)
|
|
PaletteColorCount: Word; // entries in color palette. 0 when no palette.
|
|
PaletteBitsPerIndex: Byte; // bits per palette index, this can be larger than the colors used
|
|
PaletteShift: Byte; // bitshift. Direction: from least to most significant
|
|
PaletteLineEnd: TRawImageLineEnd;
|
|
PaletteBitOrder: TRawImageBitOrder;
|
|
PaletteByteOrder: TRawImageByteOrder;
|
|
|
|
// don't use a contructor here, it will break compatebility with a record
|
|
procedure Init;
|
|
|
|
procedure Init_BPP24_B8G8R8_BIO_TTB(AWidth, AHeight: integer);
|
|
procedure Init_BPP24_B8G8R8_M1_BIO_TTB(AWidth, AHeight: integer);
|
|
procedure Init_BPP32_B8G8R8_BIO_TTB(AWidth, AHeight: integer);
|
|
procedure Init_BPP32_B8G8R8_M1_BIO_TTB(AWidth, AHeight: integer);
|
|
procedure Init_BPP32_B8G8R8A8_BIO_TTB(AWidth, AHeight: integer);
|
|
procedure Init_BPP32_B8G8R8A8_M1_BIO_TTB(AWidth, AHeight: integer);
|
|
|
|
function GetDescriptionFromMask: TRawImageDescription;
|
|
function GetDescriptionFromAlpha: TRawImageDescription;
|
|
|
|
|
|
function BytesPerLine: PtrUInt;
|
|
function BitsPerLine: PtrUInt;
|
|
function MaskBytesPerLine: PtrUInt;
|
|
function MaskBitsPerLine: PtrUInt;
|
|
|
|
function AsString: string;
|
|
function IsEqual(ADesc: TRawImageDescription): Boolean;
|
|
end;
|
|
PRawImageDescription = ^TRawImageDescription;
|
|
|
|
// Note: not all devices/images have all parts at any time. But if a part can
|
|
// be applied to the device/image, the 'Description' describes its structure.
|
|
|
|
|
|
TRawImagePosition = record
|
|
Byte: PtrUInt;
|
|
Bit: cardinal;
|
|
end;
|
|
PRawImagePosition = ^TRawImagePosition;
|
|
|
|
{ TRawImage }
|
|
|
|
TRawImage = object
|
|
Description: TRawImageDescription;
|
|
Data: PByte;
|
|
DataSize: PtrUInt;
|
|
Mask: PByte;
|
|
MaskSize: PtrUInt;
|
|
Palette: PByte;
|
|
PaletteSize: PtrUInt;
|
|
|
|
// don't use a contructor here, it will break compatebility with a record
|
|
procedure Init;
|
|
procedure CreateData(AZeroMem: Boolean);
|
|
|
|
procedure FreeData;
|
|
procedure ReleaseData;
|
|
procedure ExtractRect(const ARect: TRect; out ADst: TRawImage);
|
|
|
|
procedure PerformEffect(const ADrawEffect: TGraphicsDrawEffect; CreateNewData: Boolean = True);
|
|
function ReadBits(const APosition: TRawImagePosition; APrec, AShift: Byte): Word;
|
|
procedure ReadChannels(const APosition: TRawImagePosition; out ARed, AGreen, ABlue, AAlpha: Word);
|
|
procedure ReadMask(const APosition: TRawImagePosition; out AMask: Boolean);
|
|
procedure WriteBits(const APosition: TRawImagePosition; APrec, AShift: Byte; ABits: Word);
|
|
procedure WriteChannels(const APosition: TRawImagePosition; ARed, AGreen, ABlue, AAlpha: Word);
|
|
procedure WriteMask(const APosition: TRawImagePosition; AMask: Boolean);
|
|
|
|
function IsMasked(ATestPixels: Boolean): Boolean;
|
|
function IsTransparent(ATestPixels: Boolean): Boolean;
|
|
function IsEqual(AImage: TRawImage): Boolean;
|
|
end;
|
|
PRawImage = ^TRawImage;
|
|
|
|
{ TRawImageLineStarts }
|
|
|
|
TRawImageLineStarts = object
|
|
private
|
|
FWidth: Cardinal;
|
|
FHeight: Cardinal;
|
|
FBitsPerPixel: Byte;
|
|
FLineEnd: TRawImageLineEnd;
|
|
FLineOrder: TRawImageLineOrder;
|
|
public
|
|
Positions: array of TRawImagePosition;
|
|
|
|
// don't use a contructor here, it will break compatibility with a record
|
|
procedure Init(AWidth, AHeight: cardinal; ABitsPerPixel: Byte; ALineEnd: TRawImageLineEnd; ALineOrder: TRawImageLineOrder);
|
|
function GetPosition(x, y: cardinal): TRawImagePosition;
|
|
end;
|
|
PRawImageLineStarts = ^TRawImageLineStarts;
|
|
|
|
const
|
|
RawImageColorFormatNames: array[TRawImageColorFormat] of string = (
|
|
'ricfNone',
|
|
'ricfRGBA',
|
|
'ricfGray'
|
|
);
|
|
|
|
RawImageByteOrderNames: array[TRawImageByteOrder] of string = (
|
|
'riboLSBFirst',
|
|
'riboMSBFirst'
|
|
);
|
|
|
|
RawImageBitOrderNames: array[TRawImageBitOrder] of string = (
|
|
'riboBitsInOrder',
|
|
'riboReversedBits'
|
|
);
|
|
|
|
RawImageLineEndNames: array[TRawImageLineEnd] of string = (
|
|
'rileTight',
|
|
'rileByteBoundary',
|
|
'rileWordBoundary',
|
|
'rileDWordBoundary',
|
|
'rileQWordBoundary',
|
|
'rileDQWordBoundary'
|
|
);
|
|
|
|
RawImageLineOrderNames: array[TRawImageLineOrder] of string = (
|
|
'riloTopToBottom',
|
|
'riloBottomToTop'
|
|
);
|
|
|
|
DefaultByteOrder = {$IFDEF Endian_Little}riboLSBFirst{$ELSE}riboMSBFirst{$ENDIF};
|
|
|
|
|
|
function GetBytesPerLine(AWidth: Cardinal; ABitsPerPixel: Byte; ALineEnd: TRawImageLineEnd): PtrUInt;
|
|
function GetBitsPerLine(AWidth: Cardinal; ABitsPerPixel: Byte; ALineEnd: TRawImageLineEnd): PtrUInt;
|
|
|
|
function CopyImageData(AWidth, AHeight, ARowStride: Integer; ABPP: Word;
|
|
ASource: Pointer; const ARect: TRect; ASourceOrder: TRawImageLineOrder;
|
|
ADestinationOrder: TRawImageLineOrder; ADestinationEnd: TRawImageLineEnd;
|
|
out ADestination: Pointer; out ASize: PtrUInt): Boolean;
|
|
|
|
var
|
|
MissingBits: array[0..15] of array[0..7] of word;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Math;
|
|
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: CopyImageData
|
|
------------------------------------------------------------------------------}
|
|
|
|
function CopyImageData(AWidth, AHeight, ARowStride: Integer; ABPP: Word; ASource: Pointer; const ARect: TRect; ASourceOrder: TRawImageLineOrder;
|
|
ADestinationOrder: TRawImageLineOrder; ADestinationEnd: TRawImageLineEnd; out ADestination: Pointer; out ASize: PtrUInt): Boolean;
|
|
const
|
|
SIZEMAP: array[TRawImageLineEnd] of Byte = (
|
|
0, 0, 1, 3, 7, 15
|
|
);
|
|
var
|
|
W, H, RS, x, LineBytes, LineCount, CopySize, ZeroSize, DstRowInc: Integer;
|
|
P, DstRowPtr: PByte;
|
|
ShiftL, ShiftR: Byte;
|
|
SrcPtr: PByte absolute ASource;
|
|
DstPtr: PByte absolute ADestination;
|
|
begin
|
|
// check if we are within bounds
|
|
Result := False;
|
|
if ARect.Left < 0 then Exit;
|
|
if ARect.Top < 0 then Exit;
|
|
|
|
W := ARect.Right - ARect.Left;
|
|
H := ARect.Bottom - ARect.Top;
|
|
if W < 0 then Exit;
|
|
if H < 0 then Exit;
|
|
|
|
// calc destination rowstride
|
|
RS := (W * ABPP + 7) shr 3;
|
|
x := RS and SIZEMAP[ADestinationEnd];
|
|
if x <> 0
|
|
then Inc(RS, 1 + SIZEMAP[ADestinationEnd] - x);
|
|
|
|
// check if we can copy all
|
|
if (ARect.Left = 0) and (ARect.Top = 0)
|
|
and (ARect.Right = AWidth) and (ARect.Bottom = AHeight)
|
|
and (ASourceOrder = ADestinationOrder)
|
|
and (ARowStride = RS)
|
|
then begin
|
|
// full copy
|
|
ASize := AHeight * ARowStride;
|
|
GetMem(ADestination, ASize);
|
|
Move(ASource^, ADestination^, ASize);
|
|
Exit(True);
|
|
end;
|
|
|
|
// partial copy
|
|
|
|
// calc numer of lines to copy
|
|
if AHeight - ARect.Top < H
|
|
then LineCount := AHeight - ARect.Top
|
|
else LineCount := H;
|
|
|
|
ASize := H * RS;
|
|
GetMem(ADestination, ASize);
|
|
|
|
if (W = AWidth)
|
|
and (ASourceOrder = ADestinationOrder)
|
|
and (RS = ARowStride)
|
|
then begin
|
|
// easy case, only LineCount lines to copy
|
|
CopySize := LineCount * ARowStride;
|
|
ZeroSize := ASize - CopySize;
|
|
|
|
if ASourceOrder = riloTopToBottom
|
|
then begin
|
|
// top to bottom, adjust start
|
|
Inc(SrcPtr, ARect.Top * ARowStride);
|
|
Move(SrcPtr[0], DstPtr[0], CopySize);
|
|
// wipe remaining
|
|
if ZeroSize > 0
|
|
then FillChar(DstPtr[CopySize], ZeroSize, 0);
|
|
end
|
|
else begin
|
|
// bottom to top
|
|
// wipe remaining
|
|
if ZeroSize > 0
|
|
then FillChar(DstPtr[0], ZeroSize, 0);
|
|
|
|
x := AHeight - ARect.Bottom;
|
|
if x > 0
|
|
then Inc(SrcPtr, x * ARowStride);
|
|
Move(SrcPtr[0], DstPtr[ZeroSize], CopySize);
|
|
end;
|
|
Exit(True);
|
|
end;
|
|
|
|
// calc number of bytes to copy
|
|
// and wipe destination when source width is smaller than destination
|
|
// I'm to lazy to zero line by line, so we might do to much here
|
|
if AWidth < W
|
|
then begin
|
|
LineBytes := ((AWidth - ARect.Left) * ABPP + 7) shr 3;
|
|
FillByte(DstPtr[0], ASize, 0);
|
|
end
|
|
else begin
|
|
LineBytes := Min(RS, ARowStride);
|
|
if H <> LineCount
|
|
then FillByte(DstPtr[0], ASize, 0);
|
|
end;
|
|
|
|
// move to start line
|
|
DstRowPtr := ADestination;
|
|
if ASourceOrder = riloTopToBottom
|
|
then begin
|
|
Inc(SrcPtr, ARect.Top * ARowStride);
|
|
end
|
|
else begin
|
|
x := AHeight - ARect.Bottom;
|
|
if x >= 0
|
|
then Inc(SrcPtr, x * ARowStride)
|
|
else Inc(DstRowPtr, -x * RS);
|
|
end;
|
|
|
|
// check source and destionation order
|
|
if ASourceOrder = ADestinationOrder
|
|
then begin
|
|
DstRowInc := RS;
|
|
end
|
|
else begin
|
|
// reversed, so fill destination backwards
|
|
DstRowInc := -RS;
|
|
Inc(DstRowPtr, (LineCount - 1) * RS);
|
|
end;
|
|
|
|
// move to left pixel
|
|
Inc(SrcPtr, (ARect.Left * ABPP) shr 3);
|
|
|
|
// check if we can do byte copies
|
|
ShiftL := (ARect.Left * ABPP) and 7;
|
|
if ShiftL = 0
|
|
then begin
|
|
// Partial width, byte aligned
|
|
while LineCount > 0 do
|
|
begin
|
|
Move(SrcPtr^, DstRowPtr^, LineBytes);
|
|
Inc(SrcPtr, ARowStride);
|
|
Inc(DstRowPtr, DstRowInc);
|
|
Dec(LineCount);
|
|
end;
|
|
Exit(True);
|
|
end;
|
|
|
|
// Partial width, not aligned
|
|
ShiftR := 8 - ShiftL;
|
|
while LineCount > 0 do
|
|
begin
|
|
P := DstRowPtr;
|
|
for x := 0 to RS - 1 do
|
|
begin
|
|
P^ := Byte(SrcPtr[x] shl ShiftL) or Byte(SrcPtr[x+1] shr ShiftR);
|
|
Inc(P);
|
|
end;
|
|
Inc(SrcPtr, ARowStride);
|
|
Inc(DstRowPtr, DstRowInc);
|
|
Dec(LineCount);
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: GetBytesPerLine
|
|
------------------------------------------------------------------------------}
|
|
|
|
function GetBytesPerLine(AWidth: Cardinal; ABitsPerPixel: Byte; ALineEnd: TRawImageLineEnd): PtrUInt;
|
|
begin
|
|
Result := (GetBitsPerLine(AWidth, ABitsPerPixel, ALineEnd) + 7) shr 3;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: GetBitsPerLine
|
|
------------------------------------------------------------------------------}
|
|
|
|
function GetBitsPerLine(AWidth: Cardinal; ABitsPerPixel: Byte; ALineEnd: TRawImageLineEnd): PtrUInt;
|
|
begin
|
|
Result := AWidth * ABitsPerPixel;
|
|
case ALineEnd of
|
|
rileTight: ;
|
|
rileByteBoundary: Result := (Result + 7) and not PtrUInt(7);
|
|
rileWordBoundary: Result := (Result + 15) and not PtrUInt(15);
|
|
rileDWordBoundary: Result := (Result + 31) and not PtrUInt(31);
|
|
rileQWordBoundary: Result := (Result + 63) and not PtrUInt(63);
|
|
rileDQWordBoundary: Result := (Result +127) and not PtrUInt(127);
|
|
end;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: RawImage_ReadBits
|
|
------------------------------------------------------------------------------}
|
|
|
|
procedure RawImage_ReadBits(AData: PByte; const APosition: TRawImagePosition;
|
|
ABitsPerPixel, APrec, AShift: Byte;
|
|
ABitOrder: TRawImageBitOrder; out ABits: Word);
|
|
var
|
|
PB: PByte;
|
|
PW: PWord absolute PB;
|
|
PC: PCardinal absolute PB;
|
|
PrecMask: Word;
|
|
begin
|
|
PrecMask := (Word(1) shl APrec) - 1;
|
|
PB := @AData[APosition.Byte];
|
|
case ABitsPerPixel of
|
|
1,2,4:
|
|
begin
|
|
if ABitOrder = riboBitsInOrder then
|
|
ABits := (PB^ shr (AShift + APosition.Bit)) and PrecMask
|
|
else
|
|
ABits := (PB^ shr (AShift + 7 - APosition.Bit)) and PrecMask;
|
|
end;
|
|
8: begin
|
|
ABits := (PB^ shr AShift) and PrecMask;
|
|
end;
|
|
16: begin
|
|
{$IFDEF VerboseLCLTodos}{$note check endian and/or source byte order}{$ENDIF}
|
|
ABits := (PW^ shr AShift) and PrecMask;
|
|
end;
|
|
32: begin
|
|
{$IFDEF VerboseLCLTodos}{$note check endian and/or source byte order}{$ENDIF}
|
|
ABits := (PC^ shr AShift) and PrecMask;
|
|
end;
|
|
else
|
|
ABits:=0;
|
|
end;
|
|
|
|
if APrec<16
|
|
then begin
|
|
// add missing bits
|
|
ABits := ABits shl (16 - APrec);
|
|
ABits := ABits or MissingBits[APrec, ABits shr 13];
|
|
end;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: RawImage_WriteBits
|
|
------------------------------------------------------------------------------}
|
|
|
|
procedure RawImage_WriteBits(AData: PByte; const APosition: TRawImagePosition;
|
|
ABitsPerPixel, APrec, AShift: Byte;
|
|
ABitOrder: TRawImageBitOrder; ABits: Word);
|
|
var
|
|
PB: PByte;
|
|
PW: PWord absolute PB;
|
|
PC: PCardinal absolute PB;
|
|
PrecMask: Cardinal;
|
|
BitShift: Integer;
|
|
begin
|
|
PB := @AData[APosition.Byte];
|
|
PrecMask := (Cardinal(1) shl APrec) - 1;
|
|
ABits := ABits shr (16 - APrec);
|
|
|
|
case ABitsPerPixel of
|
|
1,2,4:
|
|
begin
|
|
if ABitOrder = riboBitsInOrder
|
|
then BitShift := AShift + APosition.Bit
|
|
else BitShift := AShift + 7 - APosition.Bit;
|
|
|
|
PrecMask := not(PrecMask shl BitShift);
|
|
PB^ := (PB^ and PrecMask) or (ABits shl BitShift);
|
|
end;
|
|
8: begin
|
|
PrecMask := not(PrecMask shl aShift);
|
|
PB^ := (PB^ and PrecMask) or (ABits shl AShift);
|
|
end;
|
|
16: begin
|
|
{$IFDEF VerboseLCLTodos}{$note check endian and/or source byte order}{$ENDIF}
|
|
PrecMask := not(PrecMask shl AShift);
|
|
PW^ := (PW^ and PrecMask) or (ABits shl AShift);
|
|
end;
|
|
32: begin
|
|
{$IFDEF VerboseLCLTodos}{$note check endian and/or source byte order}{$ENDIF}
|
|
PrecMask := not(PrecMask shl AShift);
|
|
PC^ := (PC^ and PrecMask) or (ABits shl AShift);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: IntersectRect
|
|
Params: var DestRect: TRect; const SrcRect1, SrcRect2: TRect
|
|
Returns: Boolean
|
|
|
|
Intersects SrcRect1 and SrcRect2 into DestRect.
|
|
Intersecting means that DestRect will be the overlapping area of SrcRect1 and
|
|
SrcRect2. If SrcRect1 and SrcRect2 do not overlapp the Result is false, else
|
|
true.
|
|
------------------------------------------------------------------------------}
|
|
function IntersectRect(var DestRect: TRect;
|
|
const SrcRect1, SrcRect2: TRect): Boolean;
|
|
begin
|
|
Result := False;
|
|
|
|
// test if rectangles intersects
|
|
Result:=(SrcRect2.Left < SrcRect1.Right)
|
|
and (SrcRect2.Right > SrcRect1.Left)
|
|
and (SrcRect2.Top < SrcRect1.Bottom)
|
|
and (SrcRect2.Bottom > SrcRect1.Top);
|
|
|
|
if Result then begin
|
|
DestRect.Left:=Max(SrcRect1.Left,SrcRect2.Left);
|
|
DestRect.Top:=Max(SrcRect1.Top,SrcRect2.Top);
|
|
DestRect.Right:=Min(SrcRect1.Right,SrcRect2.Right);
|
|
DestRect.Bottom:=Min(SrcRect1.Bottom,SrcRect2.Bottom);
|
|
end else begin
|
|
FillChar(DestRect,SizeOf(DestRect),0);
|
|
end;
|
|
end;
|
|
|
|
{ TRawImageDescription }
|
|
|
|
procedure TRawImageDescription.Init;
|
|
begin
|
|
FillChar(Self, SizeOf(Self), 0);
|
|
end;
|
|
|
|
procedure TRawImageDescription.Init_BPP24_B8G8R8_BIO_TTB(AWidth, AHeight: integer);
|
|
{ pf24bit:
|
|
|
|
Format=ricfRGBA HasPalette=false Depth=24 PaletteColorCount=0
|
|
BitOrder=riboBitsInOrder ByteOrder=DefaultByteOrder
|
|
LineOrder=riloTopToBottom
|
|
BitsPerPixel=24 LineEnd=rileDWordBoundary
|
|
RedPrec=8 RedShift=16 GreenPrec=8 GreenShift=8 BluePrec=8 BlueShift=0
|
|
}
|
|
begin
|
|
// setup an artificial ScanLineImage with format RGB 24 bit, 24bit depth format
|
|
FillChar(Self, SizeOf(Self), 0);
|
|
|
|
Format := ricfRGBA;
|
|
Depth := 24; // used bits per pixel
|
|
Width := AWidth;
|
|
Height := AHeight;
|
|
BitOrder := riboBitsInOrder;
|
|
ByteOrder := riboLSBFirst;
|
|
LineOrder := riloTopToBottom;
|
|
BitsPerPixel := 24; // bits per pixel. can be greater than Depth.
|
|
LineEnd := rileDWordBoundary;
|
|
RedPrec := 8; // red precision. bits for red
|
|
RedShift := 16;
|
|
GreenPrec := 8;
|
|
GreenShift := 8; // bitshift. Direction: from least to most significant
|
|
BluePrec := 8;
|
|
// BlueShift:=0;
|
|
// AlphaPrec:=0;
|
|
// MaskBitsPerPixel:=0;
|
|
end;
|
|
|
|
procedure TRawImageDescription.Init_BPP24_B8G8R8_M1_BIO_TTB(AWidth, AHeight: integer);
|
|
{ pf24bit:
|
|
|
|
Format=ricfRGBA HasPalette=false Depth=24 PaletteColorCount=0
|
|
BitOrder=riboBitsInOrder ByteOrder=DefaultByteOrder
|
|
LineOrder=riloTopToBottom
|
|
BitsPerPixel=24 LineEnd=rileDWordBoundary
|
|
RedPrec=8 RedShift=16 GreenPrec=8 GreenShift=8 BluePrec=8 BlueShift=0
|
|
Masked
|
|
}
|
|
begin
|
|
// setup an artificial ScanLineImage with format RGB 24 bit, 24bit depth format
|
|
FillChar(Self, SizeOf(Self), 0);
|
|
|
|
Format := ricfRGBA;
|
|
Depth := 24; // used bits per pixel
|
|
Width := AWidth;
|
|
Height := AHeight;
|
|
BitOrder := riboBitsInOrder;
|
|
ByteOrder := riboLSBFirst;
|
|
LineOrder := riloTopToBottom;
|
|
BitsPerPixel := 24; // bits per pixel. can be greater than Depth.
|
|
LineEnd := rileDWordBoundary;
|
|
RedPrec := 8; // red precision. bits for red
|
|
RedShift := 16;
|
|
GreenPrec := 8;
|
|
GreenShift := 8; // bitshift. Direction: from least to most significant
|
|
BluePrec := 8;
|
|
// BlueShift := 0;
|
|
// AlphaPrec := 0;
|
|
MaskBitsPerPixel := 1;
|
|
MaskBitOrder := riboBitsInOrder;
|
|
// MaskShift := 0; // the shift (=position) of the mask bit
|
|
MaskLineEnd := rileWordBoundary;
|
|
end;
|
|
|
|
procedure TRawImageDescription.Init_BPP32_B8G8R8_BIO_TTB(AWidth, AHeight: integer);
|
|
{ pf32bit:
|
|
|
|
Format=ricfRGBA HasPalette=false Depth=24 PaletteColorCount=0
|
|
BitOrder=riboBitsInOrder ByteOrder=DefaultByteOrder
|
|
LineOrder=riloTopToBottom
|
|
BitsPerPixel=32 LineEnd=rileDWordBoundary
|
|
RedPrec=8 RedShift=16 GreenPrec=8 GreenShift=8 BluePrec=8 BlueShift=0
|
|
No alpha
|
|
No mask
|
|
}
|
|
begin
|
|
// setup an artificial ScanLineImage with format RGB 24 bit, 32bit depth format
|
|
FillChar(Self, SizeOf(Self), 0);
|
|
|
|
Format := ricfRGBA;
|
|
Depth := 24; // used bits per pixel
|
|
Width := AWidth;
|
|
Height := AHeight;
|
|
BitOrder := riboBitsInOrder;
|
|
ByteOrder := riboLSBFirst;
|
|
LineOrder := riloTopToBottom;
|
|
BitsPerPixel := 32; // bits per pixel. can be greater than Depth.
|
|
LineEnd := rileDWordBoundary;
|
|
RedPrec := 8; // red precision. bits for red
|
|
RedShift := 16;
|
|
GreenPrec := 8;
|
|
GreenShift := 8; // bitshift. Direction: from least to most signifikant
|
|
BluePrec := 8;
|
|
// BlueShift := 0;
|
|
// AlphaPrec := 0;
|
|
// MaskBitsPerPixel:=0;
|
|
end;
|
|
|
|
procedure TRawImageDescription.Init_BPP32_B8G8R8_M1_BIO_TTB(AWidth, AHeight: integer);
|
|
{ pf32bit:
|
|
|
|
Format=ricfRGBA HasPalette=false Depth=24 PaletteColorCount=0
|
|
BitOrder=riboBitsInOrder ByteOrder=DefaultByteOrder
|
|
LineOrder=riloTopToBottom
|
|
BitsPerPixel=32 LineEnd=rileDWordBoundary
|
|
RedPrec=8 RedShift=16 GreenPrec=8 GreenShift=8 BluePrec=8 BlueShift=0
|
|
no alpha
|
|
with mask
|
|
}
|
|
begin
|
|
// setup an artificial ScanLineImage with format RGB 24 bit, 32bit depth format
|
|
FillChar(Self, SizeOf(Self), 0);
|
|
|
|
Format := ricfRGBA;
|
|
Depth := 24; // used bits per pixel
|
|
Width := AWidth;
|
|
Height := AHeight;
|
|
BitOrder := riboBitsInOrder;
|
|
ByteOrder := riboLSBFirst;
|
|
LineOrder := riloTopToBottom;
|
|
BitsPerPixel := 32; // bits per pixel. can be greater than Depth.
|
|
LineEnd := rileDWordBoundary;
|
|
RedPrec := 8; // red precision. bits for red
|
|
RedShift := 16;
|
|
GreenPrec := 8;
|
|
GreenShift := 8; // bitshift. Direction: from least to most signifikant
|
|
BluePrec := 8;
|
|
// BlueShift := 0;
|
|
// AlphaPrec := 0;
|
|
MaskBitsPerPixel := 1;
|
|
MaskBitOrder := riboBitsInOrder;
|
|
// MaskShift := 0; // the shift (=position) of the mask bit
|
|
MaskLineEnd := rileWordBoundary;
|
|
end;
|
|
|
|
function TRawImageDescription.MaskBitsPerLine: PtrUInt;
|
|
begin
|
|
Result := GetBitsPerLine(Width, MaskBitsPerPixel, MaskLineEnd);
|
|
end;
|
|
|
|
function TRawImageDescription.MaskBytesPerLine: PtrUInt;
|
|
begin
|
|
Result := (GetBitsPerLine(Width, MaskBitsPerPixel, MaskLineEnd) + 7) shr 3;
|
|
end;
|
|
|
|
procedure TRawImageDescription.Init_BPP32_B8G8R8A8_BIO_TTB(AWidth, AHeight: integer);
|
|
{ pf32bit:
|
|
|
|
Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
BitOrder=riboBitsInOrder ByteOrder=DefaultByteOrder
|
|
LineOrder=riloTopToBottom
|
|
BitsPerPixel=32 LineEnd=rileDWordBoundary
|
|
RedPrec=8 RedShift=16 GreenPrec=8 GreenShift=8 BluePrec=8 BlueShift=0
|
|
alpha
|
|
no mask
|
|
}
|
|
begin
|
|
// setup an artificial ScanLineImage with format RGB 32 bit, 32bit depth format
|
|
FillChar(Self, SizeOf(Self), 0);
|
|
|
|
Format := ricfRGBA;
|
|
Depth := 32; // used bits per pixel
|
|
Width := AWidth;
|
|
Height := AHeight;
|
|
BitOrder := riboBitsInOrder;
|
|
ByteOrder := riboLSBFirst;
|
|
LineOrder := riloTopToBottom;
|
|
BitsPerPixel := 32; // bits per pixel. can be greater than Depth.
|
|
LineEnd := rileDWordBoundary;
|
|
RedPrec := 8; // red precision. bits for red
|
|
RedShift := 16;
|
|
GreenPrec := 8;
|
|
GreenShift := 8; // bitshift. Direction: from least to most signifikant
|
|
BluePrec := 8;
|
|
BlueShift := 0;
|
|
AlphaPrec := 8;
|
|
AlphaShift := 24;
|
|
// MaskBitsPerPixel := 0;
|
|
end;
|
|
|
|
procedure TRawImageDescription.Init_BPP32_B8G8R8A8_M1_BIO_TTB(AWidth, AHeight: integer);
|
|
begin
|
|
Init_BPP32_B8G8R8A8_BIO_TTB(AWidth, AHeight);
|
|
|
|
MaskBitsPerPixel := 1;
|
|
MaskBitOrder := riboBitsInOrder;
|
|
MaskLineEnd := rileWordBoundary;
|
|
end;
|
|
|
|
|
|
function TRawImageDescription.GetDescriptionFromMask: TRawImageDescription;
|
|
begin
|
|
Result.Init;
|
|
|
|
Result.Format := ricfGray;
|
|
Result.Width := Width;
|
|
Result.Height := Height;
|
|
Result.Depth := 1; // per def
|
|
Result.BitOrder := MaskBitOrder;
|
|
Result.ByteOrder := DefaultByteOrder;
|
|
Result.LineOrder := LineOrder;
|
|
Result.LineEnd := MaskLineEnd;
|
|
Result.BitsPerPixel := MaskBitsPerPixel;
|
|
Result.RedPrec := 1;
|
|
Result.RedShift := MaskShift;
|
|
end;
|
|
|
|
function TRawImageDescription.BitsPerLine: PtrUInt;
|
|
begin
|
|
Result := GetBitsPerLine(Width, BitsPerPixel, LineEnd);
|
|
end;
|
|
|
|
function TRawImageDescription.BytesPerLine: PtrUInt;
|
|
begin
|
|
Result := (GetBitsPerLine(Width, BitsPerPixel, LineEnd) + 7) shr 3;
|
|
end;
|
|
|
|
function TRawImageDescription.GetDescriptionFromAlpha: TRawImageDescription;
|
|
begin
|
|
Result.Init;
|
|
|
|
Result.Format := ricfGray;
|
|
Result.Width := Width;
|
|
Result.Height := Height;
|
|
Result.Depth := AlphaPrec;
|
|
Result.BitOrder := BitOrder;
|
|
Result.ByteOrder := ByteOrder;
|
|
Result.LineOrder := LineOrder;
|
|
Result.LineEnd := LineEnd;
|
|
Result.BitsPerPixel := BitsPerPixel;
|
|
Result.RedPrec := AlphaPrec;
|
|
Result.RedShift := AlphaShift;
|
|
end;
|
|
|
|
function TRawImageDescription.AsString: string;
|
|
begin
|
|
Result:=
|
|
' Format='+RawImageColorFormatNames[Format]
|
|
+' HasPalette->'+dbgs(PaletteColorCount <> 0)
|
|
+' HasMask->'+dbgs(PaletteColorCount <> 0)
|
|
+' Depth='+IntToStr(Depth)
|
|
+' Width='+IntToStr(Width)
|
|
+' Height='+IntToStr(Height)
|
|
+' BitOrder='+RawImageBitOrderNames[BitOrder]
|
|
+' ByteOrder='+RawImageByteOrderNames[ByteOrder]
|
|
+' LineOrder='+RawImageLineOrderNames[LineOrder]
|
|
+' LineEnd='+RawImageLineEndNames[LineEnd]
|
|
+' BitsPerPixel='+IntToStr(BitsPerPixel)
|
|
+' BytesPerLine->'+IntToStr(GetBytesPerLine(Width,BitsPerPixel,LineEnd))
|
|
+' RedPrec='+IntToStr(RedPrec)
|
|
+' RedShift='+IntToStr(RedShift)
|
|
+' GreenPrec='+IntToStr(GreenPrec)
|
|
+' GreenShift='+IntToStr(GreenShift)
|
|
+' BluePrec='+IntToStr(BluePrec)
|
|
+' BlueShift='+IntToStr(BlueShift)
|
|
+' AlphaPrec='+IntToStr(AlphaPrec)
|
|
+' AlphaShift='+IntToStr(AlphaShift)
|
|
+' ~~~mask~~~'
|
|
+' MaskBitsPerPixel='+IntToStr(MaskBitsPerPixel)
|
|
+' MaskShift='+IntToStr(MaskShift)
|
|
+' MaskLineEnd='+RawImageLineEndNames[MaskLineEnd]
|
|
+' MaskBitOrder='+RawImageBitOrderNames[MaskBitOrder]
|
|
+' MaskBytesPerLine->'+IntToStr(GetBytesPerLine(Width,MaskBitsPerPixel,MaskLineEnd))
|
|
+' ~~~palette~~~'
|
|
+' PaletteColorCount='+IntToStr(PaletteColorCount)
|
|
+' PaletteBitsPerIndex='+IntToStr(PaletteBitsPerIndex)
|
|
+' PaletteShift='+IntToStr(PaletteShift)
|
|
+' PaletteLineEnd='+RawImageLineEndNames[PaletteLineEnd]
|
|
+' PaletteBitOrder='+RawImageBitOrderNames[PaletteBitOrder]
|
|
+' PaletteByteOrder='+RawImageByteOrderNames[PaletteByteOrder]
|
|
+' PaletteBytesPerLine->'+IntToStr(GetBytesPerLine(Width,PaletteBitsPerIndex,PaletteLineEnd))
|
|
+'';
|
|
end;
|
|
|
|
function TRawImageDescription.IsEqual(ADesc: TRawImageDescription): Boolean;
|
|
begin
|
|
// We cannot use CompareMem since some fields are depending on other fields
|
|
// Result := CompareMem(@Self, @ADescription, SizeOf(Self));
|
|
Result := False;
|
|
|
|
if Format <> ADesc.Format then Exit;
|
|
if Width <> ADesc.Width then Exit;
|
|
if Height <> ADesc.Height then Exit;
|
|
if Depth <> ADesc.Depth then Exit;
|
|
if BitOrder <> ADesc.BitOrder then Exit;
|
|
if ByteOrder <> ADesc.ByteOrder then Exit;
|
|
if LineOrder <> ADesc.LineOrder then Exit;
|
|
if LineEnd <> ADesc.LineEnd then Exit;
|
|
if BitsPerPixel <> ADesc.BitsPerPixel then Exit;
|
|
if RedPrec <> ADesc.RedPrec then Exit;
|
|
if GreenPrec <> ADesc.GreenPrec then Exit;
|
|
if BluePrec <> ADesc.BluePrec then Exit;
|
|
if AlphaPrec <> ADesc.AlphaPrec then Exit;
|
|
|
|
// The next values are only valid, if there is a precision
|
|
if (RedPrec <> 0) and (RedShift <> ADesc.RedShift ) then Exit;
|
|
if Format = ricfRGBA
|
|
then begin
|
|
// for mono images only red is of importance
|
|
if (GreenPrec <> 0) and (GreenShift <> ADesc.GreenShift) then Exit;
|
|
if (BluePrec <> 0) and (BlueShift <> ADesc.BlueShift ) then Exit;
|
|
end;
|
|
if (AlphaPrec <> 0) and (AlphaShift <> ADesc.AlphaShift) then Exit;
|
|
|
|
// The next values are only valid, if there is a mask (MaskBitsPerPixel > 0)
|
|
if MaskBitsPerPixel <> ADesc.MaskBitsPerPixel then Exit;
|
|
if MaskBitsPerPixel <> 0
|
|
then begin
|
|
if MaskShift <> ADesc.MaskShift then Exit;
|
|
if MaskLineEnd <> ADesc.MaskLineEnd then Exit;
|
|
if MaskBitOrder <> ADesc.MaskBitOrder then Exit;
|
|
end;
|
|
|
|
// The next values are only valid, if there is a palette (PaletteColorCount > 0)
|
|
if PaletteColorCount <> ADesc.PaletteColorCount then Exit;
|
|
if PaletteColorCount <> 0
|
|
then begin
|
|
if PaletteBitsPerIndex <> ADesc.PaletteBitsPerIndex then Exit;
|
|
if PaletteShift <> ADesc.PaletteShift then Exit;
|
|
if PaletteLineEnd <> ADesc.PaletteLineEnd then Exit;
|
|
if PaletteBitOrder <> ADesc.PaletteBitOrder then Exit;
|
|
if PaletteByteOrder <> ADesc.PaletteByteOrder then Exit;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
|
|
{ TRawImage }
|
|
|
|
function TRawImage.IsMasked(ATestPixels: Boolean): Boolean;
|
|
|
|
function CheckMask: boolean;
|
|
var
|
|
Width: cardinal;
|
|
Height: cardinal;
|
|
UsedBitsPerLine: cardinal;
|
|
TotalBits: Cardinal;
|
|
TotalBitsPerLine: cardinal;
|
|
TotalBytesPerLine: cardinal;
|
|
UnusedBitsAtEnd: Byte;
|
|
UnusedBytesAtEnd: Byte;
|
|
P: PCardinal;
|
|
LinePtr: PByte;
|
|
x, y, xEnd: Integer;
|
|
EndMask: Cardinal; // No mask bits should be set. The Cardinal at line end
|
|
// can contain some unused bits. This mask AND cardinal
|
|
// at line end makes the unsused bits all 0.
|
|
|
|
procedure CreateEndMask;
|
|
begin
|
|
if Description.MaskBitOrder = riboBitsInOrder
|
|
then EndMask := ($FF shr UnusedBitsAtEnd)
|
|
else EndMask := ($FF shl UnusedBitsAtEnd) and $FF;
|
|
// add unused bytes
|
|
{$ifdef endian_big}
|
|
// read in memory -> [??][eM][uu][uu]
|
|
EndMask := ($FFFFFF00 or EndMask) shl (UnusedBytesAtEnd shl 3);
|
|
{$else}
|
|
// read in memory -> [uu][uu][eM][??]
|
|
EndMask := ((EndMask shl 24) or $00FFFFFF) shr (UnusedBytesAtEnd shl 3);
|
|
{$endif}
|
|
end;
|
|
|
|
// separate dump procs to avoid code flow cluttering
|
|
// added here in case somone want to debug
|
|
{$IFDEF VerboseRawImage}
|
|
procedure DumpFull;
|
|
begin
|
|
DebugLn('RawImageMaskIsEmpty FullByte y=',dbgs(y),' x=',dbgs(x),' Byte=',DbgS(p^));
|
|
end;
|
|
|
|
procedure DumpEdge;
|
|
begin
|
|
DebugLn('RawImageMaskIsEmpty EdgeByte y=',dbgs(y),' x=',dbgs(x),
|
|
' Byte=',HexStr(Cardinal(p^),2),
|
|
//' UnusedMask=',HexStr(Cardinal(UnusedMask),2),
|
|
//' OR='+dbgs(p^ or UnusedMask),
|
|
' UnusedBitsAtEnd='+dbgs(UnusedBitsAtEnd),
|
|
' UsedBitsPerLine='+dbgs(UsedBitsPerLine),
|
|
' Width='+dbgs(Width),
|
|
' ARawImage.Description.MaskBitsPerPixel='+dbgs(Description.MaskBitsPerPixel));
|
|
end;
|
|
{$endif}
|
|
|
|
begin
|
|
Result := True;
|
|
|
|
Width := Description.Width;
|
|
Height := Description.Height;
|
|
|
|
TotalBitsPerLine := GetBitsPerLine(Width, Description.MaskBitsPerPixel, Description.MaskLineEnd);
|
|
TotalBits := Height * TotalBitsPerLine;
|
|
if MaskSize < PtrUInt((TotalBits + 7) shr 3)
|
|
then raise Exception.Create('RawImage_IsMasked - Invalid MaskSize');
|
|
|
|
UsedBitsPerLine := Width * Description.MaskBitsPerPixel;
|
|
UnusedBitsAtEnd := TotalBitsPerLine - UsedBitsPerLine;
|
|
|
|
if UnusedBitsAtEnd = 0
|
|
then begin
|
|
// the next line follows the previous one, so we can compare the whole
|
|
// memblock in one go
|
|
|
|
P := PCardinal(Mask);
|
|
for x := 1 to TotalBits shr 5 do
|
|
begin
|
|
if p^ <> 0 then Exit;
|
|
Inc(p);
|
|
end;
|
|
|
|
// redefine UnusedBitsAtEnd as the bits at the end of the block
|
|
UnusedBitsAtEnd := TotalBits and $1F;
|
|
if UnusedBitsAtEnd <> 0
|
|
then begin
|
|
// check last piece
|
|
UnusedBytesAtEnd := UnusedBitsAtEnd shr 3;
|
|
// adjust to byte bounds
|
|
UnusedBitsAtEnd := UnusedBitsAtEnd and 7;
|
|
CreateEndMask;
|
|
|
|
if p^ and EndMask <> 0 then Exit;
|
|
end;
|
|
end
|
|
else begin
|
|
// scan each line
|
|
TotalBytesPerLine := TotalBitsPerLine shr 3;
|
|
UnusedBytesAtEnd := UnusedBitsAtEnd shr 3;
|
|
|
|
// Number of cardinals to check
|
|
xEnd := (TotalBytesPerLine - UnusedBytesAtEnd) shr 2;
|
|
|
|
// Adjust unused to only the last checked
|
|
UnusedBytesAtEnd := UnusedBytesAtEnd and 3;
|
|
UnusedBitsAtEnd := UnusedBitsAtEnd and 7;
|
|
|
|
// create mask for the last bits
|
|
CreateEndMask;
|
|
|
|
LinePtr := Mask;
|
|
for y := 0 to Height - 1 do
|
|
begin
|
|
p := PCardinal(LinePtr);
|
|
for x := 0 to xEnd - 1 do
|
|
begin
|
|
if p^ <> 0 then Exit;
|
|
Inc(p);
|
|
end;
|
|
// check last end
|
|
if (EndMask <> 0) and (p^ and EndMask <> 0) then Exit;
|
|
|
|
Inc(LinePtr, TotalBytesPerLine);
|
|
end;
|
|
end;
|
|
Result := False;
|
|
end;
|
|
|
|
begin
|
|
Result := False;
|
|
//DebugLn('RawImageMaskIsEmpty Quicktest: empty ',dbgs(RawImage^.Description.Width),'x',dbgs(RawImage^.Description.Height));
|
|
|
|
// quick test
|
|
if (Mask = nil)
|
|
or (MaskSize = 0)
|
|
or (Description.MaskBitsPerPixel = 0)
|
|
or (Description.Width = 0)
|
|
or (Description.Height = 0)
|
|
then begin
|
|
{$IFDEF VerboseRawImage}
|
|
DebugLn('RawImageMaskIsEmpty Quicktest: empty');
|
|
{$ENDIF}
|
|
exit;
|
|
end;
|
|
|
|
if ATestPixels
|
|
then begin
|
|
Result := CheckMask;
|
|
|
|
{$IFDEF VerboseRawImage}
|
|
DebugLn('RawImageMaskIsEmpty Empty=',dbgs(not Result));
|
|
{$ENDIF}
|
|
end
|
|
else begin
|
|
Result := True;
|
|
{$IFDEF VerboseRawImage}
|
|
DebugLn('RawImageMaskIsEmpty NoPixelTest: not empty');
|
|
{$ENDIF}
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
function TRawImage.IsTransparent(ATestPixels: Boolean): Boolean;
|
|
function CheckAlpha: Boolean;
|
|
begin
|
|
{$IFDEF VerboseLCLTodos}{$note TODO: implement CheckAlpha}{$ENDIF}
|
|
Result := True;
|
|
end;
|
|
begin
|
|
Result :=
|
|
(Data <> nil) and
|
|
(DataSize <> 0) and
|
|
(Description.AlphaPrec <> 0) and
|
|
(Description.Width = 0) and
|
|
(Description.Height = 0);
|
|
|
|
if Result and ATestPixels then
|
|
Result := CheckAlpha;
|
|
end;
|
|
|
|
function TRawImage.ReadBits(const APosition: TRawImagePosition; APrec, AShift: Byte): Word;
|
|
begin
|
|
RawImage_ReadBits(Data, APosition, Description.BitsPerPixel, APrec, AShift, Description.BitOrder, Result);
|
|
end;
|
|
|
|
procedure TRawImage.ReadChannels(const APosition: TRawImagePosition; out ARed, AGreen, ABlue, AAlpha: Word);
|
|
var
|
|
D: TRawImageDescription absolute Description;
|
|
begin
|
|
case Description.Format of
|
|
ricfRGBA: begin
|
|
RawImage_ReadBits(Data, APosition, D.BitsPerPixel, D.RedPrec, D.RedShift, D.BitOrder, ARed);
|
|
RawImage_ReadBits(Data, APosition, D.BitsPerPixel, D.GreenPrec, D.GreenShift, D.BitOrder, AGreen);
|
|
RawImage_ReadBits(Data, APosition, D.BitsPerPixel, D.BluePrec, D.BlueShift, D.BitOrder, ABlue);
|
|
end;
|
|
|
|
ricfGray: begin
|
|
RawImage_ReadBits(Data, APosition, D.BitsPerPixel, D.RedPrec, D.RedShift, D.BitOrder, ARed);
|
|
AGreen := ARed;
|
|
ABlue := ARed;
|
|
end;
|
|
|
|
else
|
|
ARed := 0;
|
|
AGreen := 0;
|
|
ABlue := 0;
|
|
AAlpha := 0;
|
|
Exit;
|
|
end;
|
|
|
|
if D.AlphaPrec > 0
|
|
then RawImage_ReadBits(Data, APosition, D.BitsPerPixel, D.AlphaPrec, D.AlphaShift, D.BitOrder, AAlpha)
|
|
else AAlpha := High(AAlpha);
|
|
end;
|
|
|
|
procedure TRawImage.ReadMask(const APosition: TRawImagePosition; out AMask: Boolean);
|
|
var
|
|
D: TRawImageDescription absolute Description;
|
|
M: Word;
|
|
begin
|
|
if (D.MaskBitsPerPixel > 0) and (Mask <> nil)
|
|
then begin
|
|
RawImage_ReadBits(Mask, APosition, D.MaskBitsPerPixel, 1, D.MaskShift, D.MaskBitOrder, M);
|
|
AMask := M <> 0;
|
|
end
|
|
else AMask := False;
|
|
end;
|
|
|
|
procedure TRawImage.FreeData;
|
|
begin
|
|
FreeMem(Data);
|
|
Data := nil;
|
|
DataSize:=0;
|
|
|
|
FreeMem(Mask);
|
|
Mask := nil;
|
|
MaskSize := 0;
|
|
|
|
FreeMem(Palette);
|
|
Palette := nil;
|
|
PaletteSize:=0;
|
|
end;
|
|
|
|
procedure TRawImage.Init;
|
|
begin
|
|
Description.Init;
|
|
Data := nil;
|
|
DataSize:=0;
|
|
Mask := nil;
|
|
MaskSize := 0;
|
|
Palette := nil;
|
|
PaletteSize:=0;
|
|
end;
|
|
|
|
function TRawImage.IsEqual(AImage: TRawImage): Boolean;
|
|
begin
|
|
//Result := CompareMem(@Self, @AImage, SizeOf(Self));
|
|
Result :=
|
|
Description.IsEqual(AImage.Description) and
|
|
(DataSize = AImage.DataSize) and
|
|
(MaskSize = AImage.MaskSize) and
|
|
(PaletteSize = AImage.PaletteSize);
|
|
|
|
if Result then
|
|
Result := CompareMem(Data, AImage.Data, DataSize);
|
|
if Result then
|
|
Result := CompareMem(Mask, AImage.Mask, MaskSize);
|
|
if Result then
|
|
Result := CompareMem(Palette, AImage.Palette, PaletteSize);
|
|
end;
|
|
|
|
procedure TRawImage.ReleaseData;
|
|
begin
|
|
Data := nil;
|
|
DataSize := 0;
|
|
Mask := nil;
|
|
MaskSize := 0;
|
|
Palette := nil;
|
|
PaletteSize := 0;
|
|
end;
|
|
|
|
procedure TRawImage.WriteBits(const APosition: TRawImagePosition; APrec, AShift: Byte; ABits: Word);
|
|
begin
|
|
RawImage_WriteBits(Data, APosition, Description.BitsPerPixel, APrec, AShift, Description.BitOrder, ABits);
|
|
end;
|
|
|
|
procedure TRawImage.WriteChannels(const APosition: TRawImagePosition; ARed, AGreen, ABlue, AAlpha: Word);
|
|
var
|
|
D: TRawImageDescription absolute Description;
|
|
begin
|
|
case D.Format of
|
|
ricfRGBA: begin
|
|
RawImage_WriteBits(Data, APosition, D.BitsPerPixel, D.RedPrec, D.RedShift, D.BitOrder, ARed);
|
|
RawImage_WriteBits(Data, APosition, D.BitsPerPixel, D.GreenPrec, D.GreenShift, D.BitOrder, AGreen);
|
|
RawImage_WriteBits(Data, APosition, D.BitsPerPixel, D.BluePrec, D.BlueShift, D.BitOrder, ABlue);
|
|
end;
|
|
|
|
ricfGray: begin
|
|
RawImage_WriteBits(Data, APosition, D.BitsPerPixel, D.RedPrec, D.RedShift, D.BitOrder, ARed);
|
|
end;
|
|
else
|
|
Exit;
|
|
end;
|
|
|
|
if D.AlphaPrec = 0 then Exit;
|
|
|
|
RawImage_WriteBits(Data, APosition, D.BitsPerPixel, D.AlphaPrec, D.AlphaShift, D.BitOrder, AAlpha);
|
|
end;
|
|
|
|
procedure TRawImage.WriteMask(const APosition: TRawImagePosition; AMask: Boolean);
|
|
const
|
|
M: array[Boolean] of Word = (0, $FFFF);
|
|
var
|
|
D: TRawImageDescription absolute Description;
|
|
begin
|
|
if Mask = nil then Exit;
|
|
if D.MaskBitsPerPixel = 0 then Exit;
|
|
RawImage_WriteBits(Mask, APosition, D.MaskBitsPerPixel, 1, D.MaskShift, D.MaskBitOrder, M[AMask]);
|
|
end;
|
|
|
|
procedure TRawImage.CreateData(AZeroMem: Boolean);
|
|
var
|
|
Size: QWord;
|
|
begin
|
|
// get current size
|
|
if Description.Width = 0 then Exit;
|
|
if Description.Height = 0 then Exit;
|
|
|
|
// calculate size
|
|
with Description do
|
|
Size := GetBitsPerLine(Width, BitsPerPixel, LineEnd);
|
|
Size := (Size * Description.Height) shr 3;
|
|
|
|
if Size < High(DataSize)
|
|
then DataSize := Size
|
|
else DataSize := High(DataSize);
|
|
|
|
ReAllocMem(Data, DataSize);
|
|
|
|
if AZeroMem
|
|
then FillChar(Data^, DataSize, 0);
|
|
|
|
// Setup mask if needed
|
|
if Description.MaskBitsPerPixel = 0 then Exit;
|
|
|
|
// calculate mask size
|
|
with Description do
|
|
Size := GetBitsPerLine(Width, MaskBitsPerPixel, MaskLineEnd);
|
|
Size := (Size * Description.Height) shr 3;
|
|
|
|
if Size < High(MaskSize)
|
|
then MaskSize := Size
|
|
else MaskSize := High(MaskSize);
|
|
|
|
ReAllocMem(Mask, MaskSize);
|
|
|
|
if AZeroMem
|
|
then FillChar(Mask^, MaskSize, 0);
|
|
end;
|
|
|
|
procedure TRawImage.ExtractRect(const ARect: TRect; out ADst: TRawImage);
|
|
procedure ExtractData(AData: PByte; ADataSize: PtrUInt; ABitsPerPixel: Byte;
|
|
ABitOrder: TRawImageBitOrder; ALineEnd: TRawImageLineEnd;
|
|
ADest: PByte; ADestSize: PtrUInt);
|
|
var
|
|
SrcWidth, SrcHeight, SrcRight: LongInt;
|
|
DstWidth, DstHeight: LongInt;
|
|
x, y: Integer;
|
|
LineOrder: TRawImageLineOrder;
|
|
SrcLineStarts, DstLineStarts: TRawImageLineStarts;
|
|
SrcStartPos, SrcEndPos, DstStartPos: TRawImagePosition;
|
|
Shift0, Shift1: Byte;
|
|
SrcPos: PByte;
|
|
DstPos: PByte;
|
|
ByteCount: PtrUInt;
|
|
begin
|
|
SrcWidth := Description.Width;
|
|
DstWidth := ADst.Description.Width;
|
|
LineOrder := Description.LineOrder;
|
|
|
|
//DebugLn'ExtractRawImageDataRect data=',DbgS(DestData),' Size=',DestDataSize);
|
|
if SrcWidth = DstWidth
|
|
then begin
|
|
if LineOrder = riloTopToBottom
|
|
then // copy whole source from beginning
|
|
System.Move(AData[0], ADest[0], ADestSize)
|
|
else // copy remainder
|
|
System.Move(AData[ADataSize - ADestSize], ADest[0], ADestSize);
|
|
Exit;
|
|
end;
|
|
|
|
SrcHeight := Description.Height;
|
|
DstHeight := ADst.Description.Height;
|
|
|
|
// calculate line starts
|
|
if LineOrder = riloTopToBottom
|
|
then // we only need the first part from start
|
|
SrcLineStarts.Init(SrcWidth, ARect.Top + DstHeight, ABitsPerPixel, ALineEnd, LineOrder)
|
|
else
|
|
SrcLineStarts.Init(SrcWidth, SrcHeight - ARect.Top, ABitsPerPixel, ALineEnd, LineOrder);
|
|
DstLineStarts.Init(DstWidth, DstHeight, ABitsPerPixel, ALineEnd, LineOrder);
|
|
|
|
// copy
|
|
SrcRight := ARect.Left + DstWidth;
|
|
for y := 0 to DstHeight - 1 do
|
|
begin
|
|
SrcStartPos := SrcLineStarts.GetPosition(ARect.Left, y + ARect.Top);
|
|
SrcEndPos := SrcLineStarts.GetPosition(SrcRight, y + ARect.Top);
|
|
DstStartPos := DstLineStarts.GetPosition(0, y);
|
|
|
|
//DebugLn'ExtractRawImageDataRect A y=',y,' SrcByte=',SrcLineStartPosition.Byte,' SrcBit=',SrcLineStartPosition.Bit,
|
|
//' DestByte=',DestLineStartPosition.Byte,' DestBit=',DestLineStartPosition.Bit);
|
|
|
|
if (SrcStartPos.Bit = 0) and (DstStartPos.Bit = 0)
|
|
then begin
|
|
// copy bytes
|
|
ByteCount := SrcEndPos.Byte - SrcStartPos.Byte;
|
|
if SrcEndPos.Bit > 0
|
|
then Inc(ByteCount);
|
|
|
|
//DebugLn'ExtractRawImageDataRect B ByteCount=',ByteCount);
|
|
System.Move(AData[SrcStartPos.Byte], ADest[DstStartPos.Byte], ByteCount);
|
|
end
|
|
else if DstStartPos.Bit = 0
|
|
then begin
|
|
// copy and move bits
|
|
ByteCount := (DstWidth * ABitsPerPixel + 7) shr 3;
|
|
SrcPos := @AData[SrcStartPos.Byte];
|
|
DstPos := @ADest[DstStartPos.Byte];
|
|
Shift0 := SrcStartPos.Bit;
|
|
Shift1 := 8 - Shift0;
|
|
|
|
if ABitOrder = riboBitsInOrder
|
|
then begin
|
|
// src[byte|bit]: 07 06 05 04 03 02 01 00 :: 17 16 15 14 13 12 11 10 :
|
|
// imagine startbit = 3 ->
|
|
// dst[byte|bit]: 12 11 10 07 06 05 04 03 :
|
|
for x := 0 to ByteCount - 1 do
|
|
begin
|
|
DstPos^ := (SrcPos[0] shr Shift0) or (SrcPos[1] shl Shift1);
|
|
inc(SrcPos);
|
|
inc(DstPos);
|
|
end;
|
|
end
|
|
else begin
|
|
// src[byte|bit]: 07 06 05 04 03 02 01 00 :: 17 16 15 14 13 12 11 10 :
|
|
// imagine startbit = 3 ->
|
|
// dst[byte|bit]: 04 03 02 01 00 17 16 15 :
|
|
for x := 0 to ByteCount - 1 do
|
|
begin
|
|
DstPos^ := (SrcPos[0] shl Shift0) or (SrcPos[1] shr Shift1);
|
|
inc(SrcPos);
|
|
inc(DstPos);
|
|
end;
|
|
end;
|
|
end
|
|
else begin
|
|
DebugLn('ToDo: ExtractRawImageRect DestLineStartPosition.Bit>0');
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
R: TRect;
|
|
begin
|
|
//DebugLn'ExtractRawImageRect SrcRawImage=',RawImageDescriptionAsString(@SrcRawImage^.Description),
|
|
// ' SrcRect=',SrcRect.Left,',',SrcRect.Top,',',SrcRect.Right,',',SrcRect.Bottom);
|
|
|
|
// copy description
|
|
ADst.Description := Description;
|
|
ADst.ReleaseData;
|
|
|
|
// get intersection
|
|
IntersectRect(R, Rect(0, 0, Description.Width, Description.Height), ARect);
|
|
ADst.Description.Width := R.Right - R.Left;
|
|
ADst.Description.Height := R.Bottom - R.Top;
|
|
if (ADst.Description.Width <= 0)
|
|
or (ADst.Description.Height <= 0)
|
|
then begin
|
|
ADst.Description.Width := 0;
|
|
ADst.Description.Height := 0;
|
|
Exit;
|
|
end;
|
|
|
|
if Data = nil then Exit;
|
|
if DataSize = 0 then Exit;
|
|
|
|
// allocate some space
|
|
ADst.CreateData(False);
|
|
|
|
// extract rectangle from Data
|
|
ExtractData(Data, DataSize, Description.BitsPerPixel, Description.BitOrder,
|
|
Description.LineEnd, ADst.Data, ADst.DataSize);
|
|
|
|
// extract rectangle from MAsk
|
|
|
|
if Description.MaskBitsPerPixel = 0 then Exit;
|
|
if Mask = nil then Exit;
|
|
if MaskSize = 0 then Exit;
|
|
|
|
|
|
//DebugLn'ExtractRawImageRect Mask SrcRawImage=',RawImageDescriptionAsString(@SrcMaskDesc));
|
|
ExtractData(Mask, MaskSize, Description.MaskBitsPerPixel, Description.MaskBitOrder,
|
|
Description.MaskLineEnd, ADst.Mask, ADst.MaskSize);
|
|
end;
|
|
|
|
procedure TRawImage.PerformEffect(const ADrawEffect: TGraphicsDrawEffect;
|
|
CreateNewData: Boolean);
|
|
|
|
function CheckDescription: Boolean;
|
|
begin
|
|
Result :=
|
|
(Description.Format = ricfRGBA) and
|
|
(Description.PaletteColorCount = 0) and
|
|
(Description.MaskBitsPerPixel = 0) and
|
|
(Description.Depth = 32) and
|
|
(Description.BitOrder = riboBitsInOrder) and
|
|
(Description.ByteOrder = riboMSBFirst) and
|
|
(Description.LineOrder = riloTopToBottom) and
|
|
(Description.BitsPerPixel = 32) and
|
|
(Description.RedPrec = 8) and
|
|
(Description.RedShift = 8) and
|
|
(Description.GreenPrec = 8) and
|
|
(Description.GreenShift = 16) and
|
|
(Description.BluePrec = 8) and
|
|
(Description.BlueShift = 24) and
|
|
(Description.AlphaPrec = 8) and
|
|
(Description.AlphaShift = 0);
|
|
end;
|
|
|
|
const
|
|
Glow = 68;
|
|
Shadow = 48;
|
|
GlowColorMultiplier = (256 - Glow) / 256;
|
|
ShadowColorMultiplier = (256 - Shadow) / 256;
|
|
// 1 Bit color weights. Total weight = 1000
|
|
R_Weight: Word = $00DE;
|
|
G_Weight: Word = $02C3;
|
|
B_Weight: Word = $0047;
|
|
H_Threshold = $D5; // threshold of highlight ($D5 is value from experiments. $80 is standard)
|
|
|
|
var
|
|
AData: PRGBAQuad;
|
|
P: Pointer;
|
|
i, j: integer;
|
|
begin
|
|
if CreateNewData then
|
|
begin
|
|
GetMem(AData, DataSize);
|
|
Move(Data^, AData^, DataSize);
|
|
P := AData;
|
|
end
|
|
else
|
|
begin
|
|
P := Data;
|
|
AData := P;
|
|
end;
|
|
|
|
// check here for Description. Only RGBA data can be processed here.
|
|
if not CheckDescription then
|
|
Exit;
|
|
|
|
|
|
case ADrawEffect of
|
|
gdeNormal: ;
|
|
gdeDisabled:
|
|
begin
|
|
for i := 0 to Description.Height - 1 do
|
|
for j := 0 to Description.Width - 1 do
|
|
begin
|
|
with AData^ do
|
|
begin
|
|
Red := (Red + Green + Blue) div 3;
|
|
Green := Red;
|
|
Blue := Red;
|
|
end;
|
|
inc(AData);
|
|
end;
|
|
end;
|
|
gdeHighlighted:
|
|
begin
|
|
for i := 0 to Description.Height - 1 do
|
|
for j := 0 to Description.Width - 1 do
|
|
begin
|
|
with AData^ do
|
|
begin
|
|
Red := Round(Glow + Red * GlowColorMultiplier);
|
|
Green := Round(Glow + Green * GlowColorMultiplier);
|
|
Blue := Round(Glow + Blue * GlowColorMultiplier);
|
|
end;
|
|
inc(AData);
|
|
end;
|
|
end;
|
|
gdeShadowed:
|
|
begin
|
|
for i := 0 to Description.Height - 1 do
|
|
for j := 0 to Description.Width - 1 do
|
|
begin
|
|
with AData^ do
|
|
begin
|
|
Red := Round(Red * ShadowColorMultiplier);
|
|
Green := Round(Green * ShadowColorMultiplier);
|
|
Blue := Round(Blue * ShadowColorMultiplier);
|
|
end;
|
|
inc(AData);
|
|
end;
|
|
end;
|
|
gde1Bit:
|
|
begin
|
|
for i := 0 to Description.Height - 1 do
|
|
for j := 0 to Description.Width - 1 do
|
|
begin
|
|
with AData^ do
|
|
begin
|
|
// color should be either black or none
|
|
Alpha := ord
|
|
(
|
|
((R_Weight * Red + G_Weight * Green + B_Weight * Blue) < H_Threshold * 1000) and
|
|
(Alpha >= $80)
|
|
) * $FF;
|
|
if Alpha = $FF then
|
|
begin
|
|
Red := 00;
|
|
Green := 00;
|
|
Blue := 00;
|
|
end;
|
|
end;
|
|
inc(AData);
|
|
end;
|
|
end;
|
|
end;
|
|
Data := P;
|
|
end;
|
|
|
|
{ TRawImageLineStarts }
|
|
|
|
function TRawImageLineStarts.GetPosition(x, y: cardinal): TRawImagePosition;
|
|
var
|
|
BitOffset: Cardinal;
|
|
begin
|
|
if FLineOrder = riloBottomToTop then
|
|
y := FHeight - y - 1;
|
|
Result := Positions[y];
|
|
BitOffset := x * FBitsPerPixel + Result.Bit;
|
|
Result.Bit := BitOffset and 7;
|
|
Inc(Result.Byte, BitOffset shr 3);
|
|
end;
|
|
|
|
procedure TRawImageLineStarts.Init(AWidth, AHeight: cardinal; ABitsPerPixel: Byte; ALineEnd: TRawImageLineEnd; ALineOrder: TRawImageLineOrder);
|
|
var
|
|
PixelCount: cardinal;
|
|
BitsPerLine: cardinal;
|
|
CurLine: cardinal;
|
|
BytesPerLine: cardinal;
|
|
ExtraBitsPerLine: Byte;
|
|
CurBitOffset: Byte;
|
|
LoopBit: Byte;
|
|
LoopByte: PtrUInt;
|
|
begin
|
|
FWidth := AWidth;
|
|
FHeight := AHeight;
|
|
FBitsPerPixel := ABitsPerPixel;
|
|
FLineEnd := ALineEnd;
|
|
FLineOrder := ALineOrder;
|
|
|
|
// get current size
|
|
PixelCount := AWidth * AHeight;
|
|
if PixelCount = 0 then exit;
|
|
|
|
// calculate BitsPerLine, BytesPerLine and ExtraBitsPerLine
|
|
BitsPerLine := GetBitsPerLine(AWidth, ABitsPerPixel, ALineEnd);
|
|
BytesPerLine := BitsPerLine shr 3;
|
|
ExtraBitsPerLine := BitsPerLine and 7;
|
|
|
|
// create line start array
|
|
SetLength(Positions, AHeight);
|
|
|
|
Positions[0].Byte := 0;
|
|
Positions[0].Bit := 0;
|
|
LoopBit := 0;
|
|
LoopByte := 0;
|
|
for CurLine := 1 to AHeight-1 do
|
|
begin
|
|
CurBitOffset := LoopBit + ExtraBitsPerLine;
|
|
LoopByte := LoopByte + BytesPerLine + (CurBitOffset shr 3);
|
|
LoopBit := CurBitOffset and 7;
|
|
Positions[CurLine].Byte := LoopByte;
|
|
Positions[CurLine].Bit := LoopBit;
|
|
end;
|
|
end;
|
|
|
|
//------------------------------------------------------------------------------
|
|
procedure InternalInit;
|
|
var
|
|
Prec: Integer;
|
|
HighValue: word;
|
|
Bits: word;
|
|
CurShift, DShift: Integer;
|
|
begin
|
|
for Prec := 0 to 15 do
|
|
begin
|
|
for HighValue := 0 to 7 do
|
|
begin
|
|
// HighValue represents the three highest bits
|
|
// For example:
|
|
// Prec=5 and the read value is %10110
|
|
// => HighValue=%101
|
|
// copy the HighValue till all missing bits are set
|
|
// For example:
|
|
// Prec=5, HighValue=%110
|
|
// => MissingBits[5,6]:=%0000011011011011
|
|
// because 00000 110 110 110 11
|
|
MissingBits[Prec, HighValue] := 0;
|
|
if Prec = 0 then Continue;
|
|
|
|
if Prec>=3 then begin
|
|
DShift := 3;
|
|
Bits := HighValue;
|
|
end else begin
|
|
DShift := Prec;
|
|
Bits := HighValue shr (3-Prec);
|
|
end;
|
|
|
|
CurShift := 16 - Prec;
|
|
while CurShift > 0 do
|
|
begin
|
|
//DebugLn(['InternalInit CurShift=',CurShift,' DShift=',DShift]);
|
|
if CurShift >= DShift then
|
|
MissingBits[Prec, HighValue] :=
|
|
word(MissingBits[Prec, HighValue] or (Bits shl (CurShift - DShift)))
|
|
else
|
|
MissingBits[Prec, HighValue] :=
|
|
word(MissingBits[Prec, HighValue] or (Bits shr (DShift - CurShift)));
|
|
Dec(CurShift, DShift);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
initialization
|
|
InternalInit;
|
|
|
|
end.
|