lazarus/lcl/graphtype.pp
mattias 6eb4930179 fixed references to COPYING.LCL
git-svn-id: trunk@9243 -
2006-05-05 05:52:08 +00:00

797 lines
28 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, 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
Classes, SysUtils, LCLType, LCLProc;
{$ifdef Trace}
{$ASSERTIONS ON}
{$endif}
type
TGraphicsColor = -$7FFFFFFF-1..$7FFFFFFF;
TGraphicsFillStyle = (fsSurface, fsBorder);
TGraphicsBevelCut = (bvNone, bvLowered, bvRaised, bvSpace);
//------------------------------------------------------------------------------
// raw image data
type
{ Colorformat: Higher values means higher intensity.
For example: Red=0 means no red, Alpha=0 means transparent }
TRawImageColorFormat = (
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
);
TRawImageLineOrder = (
riloTopToBottom, // The line 0 is the top line
riloBottomToTop // The line 0 is the bottom line
);
TRawImageDescription = record
Format: TRawImageColorFormat;
HasPalette: boolean; // if true, each pixel is an index in the palette
Depth: cardinal; // used bits per pixel
Width: cardinal;
Height: cardinal;
PaletteColorCount: integer;
BitOrder: TRawImageBitOrder;
ByteOrder: TRawImageByteOrder;
LineOrder: TRawImageLineOrder;
ColorCount: cardinal; // entries in color palette. Ignore when no palette.
BitsPerPixel: cardinal; // bits per pixel. can be greater than Depth.
LineEnd: TRawImageLineEnd;
RedPrec: cardinal; // red precision. bits for red
RedShift: cardinal;
GreenPrec: cardinal;
GreenShift: cardinal; // bitshift. Direction: from least to most signifikant
BluePrec: cardinal;
BlueShift: cardinal;
AlphaPrec: cardinal;
AlphaShift: cardinal;
AlphaSeparate: boolean; // the alpha is stored as separate Mask
// The next values are only valid, if there is a separate alpha mask
AlphaBitsPerPixel: cardinal; // bits per alpha mask pixel.
AlphaLineEnd: TRawImageLineEnd;
AlphaBitOrder: TRawImageBitOrder;
AlphaByteOrder: TRawImageByteOrder;
// ToDo: add attributes for palette
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.
TRawImage = record
Description: TRawImageDescription;
Data: PByte;
DataSize: cardinal;
Mask: PByte;
MaskSize: cardinal;
Palette: PByte;
PaletteSize: cardinal;
end;
PRawImage = ^TRawImage;
TRawImagePosition = record
Byte: cardinal;
Bit: cardinal;
end;
PRawImagePosition = ^TRawImagePosition;
const
RawImageColorFormatNames: array[TRawImageColorFormat] of string = (
'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'
);
RawImageLineOrderNames: array[TRawImageLineOrder] of string = (
'riloTopToBottom',
'riloBottomToTop'
);
DefaultByteOrder = {$IFDEF Endian_Little}riboLSBFirst{$ELSE}riboMSBFirst{$ENDIF};
function RawImageMaskIsEmpty(RawImage: PRawImage; TestPixels: boolean): boolean;
function RawImageDescriptionAsString(Desc: PRawImageDescription): string;
procedure FreeRawImageData(RawImage: PRawImage);
procedure ReleaseRawImageData(RawImage: PRawImage);
procedure CreateRawImageData(Width, Height, BitsPerPixel: cardinal;
LineEnd: TRawImageLineEnd;
var Data: Pointer; var DataSize: cardinal);
procedure CreateRawImageLineStarts(Width, Height, BitsPerPixel: cardinal;
LineEnd: TRawImageLineEnd;
var LineStarts: PRawImagePosition);
procedure CreateRawImageDescFromMask(SrcRawImageDesc,
DestRawImageDesc: PRawImageDescription);
procedure GetRawImageXYPosition(RawImageDesc: PRawImageDescription;
LineStarts: PRawImagePosition; x, y: cardinal;
var Position: TRawImagePosition);
procedure ExtractRawImageRect(SrcRawImage: PRawImage; const SrcRect: TRect;
DestRawImage: PRawImage);
procedure ExtractRawImageDataRect(SrcRawImageDesc: PRawImageDescription;
const SrcRect: TRect; SrcData: Pointer;
DestRawImageDesc: PRawImageDescription;
var DestData: Pointer; var DestDataSize: cardinal);
function GetBytesPerLine(Width, BitsPerPixel: cardinal;
LineEnd: TRawImageLineEnd): cardinal;
function GetBitsPerLine(Width, BitsPerPixel: cardinal;
LineEnd: TRawImageLineEnd): cardinal;
procedure ReadRawImageBits(TheData: PByte; const Position: TRawImagePosition;
BitsPerPixel, Prec, Shift: cardinal;
BitOrder: TRawImageBitOrder; var Bits: word);
procedure WriteRawImageBits(TheData: PByte; const Position: TRawImagePosition;
BitsPerPixel, Prec, Shift: cardinal;
BitOrder: TRawImageBitOrder; Bits: word);
var
MissingBits: array[0..15] of array[0..7] of word;
implementation
uses Math;
{------------------------------------------------------------------------------
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;
function RawImageMaskIsEmpty(RawImage: PRawImage; TestPixels: boolean): boolean;
var
Width: cardinal;
Height: cardinal;
BitsPerLine: cardinal;
UsedBitsPerLine: cardinal;
UnusedBitsAtEnd: cardinal;
p: PByte;
y: cardinal;
x: cardinal;
UnusedByteMask: Byte; // Alpha Bits should be all set. The Byte at line end
// can contain some unused bits. This mask OR byte at
// line end makes the unsused bits all true.
UsedBytesPerLine: cardinal;
begin
Result:=true;
//DebugLn('RawImageMaskIsEmpty Quicktest: empty ',dbgs(RawImage^.Description.Width),'x',dbgs(RawImage^.Description.Height));
// quick test
if (RawImage^.Mask=nil) or (RawImage^.MaskSize=0)
or (RawImage^.Description.Width=0) or (RawImage^.Description.Height=0)
or (RawImage^.Description.AlphaPrec=0) then begin
{$IFDEF VerboseRawImage}
DebugLn('RawImageMaskIsEmpty Quicktest: empty');
{$ENDIF}
exit;
end;
Result:=false;
// slow test
if TestPixels then begin
Width:=RawImage^.Description.Width;
Height:=RawImage^.Description.Height;
if RawImage^.Description.AlphaSeparate then begin
BitsPerLine:=GetBitsPerLine(Width,RawImage^.Description.AlphaBitsPerPixel,
RawImage^.Description.AlphaLineEnd);
UsedBitsPerLine:=Width*RawImage^.Description.AlphaBitsPerPixel;
if RawImage^.MaskSize<((Height*BitsPerLine+7) shr 3) then
raise Exception.Create('RawImageMaskIsEmpty Invalid MaskSize');
if (BitsPerLine and 7)=0 then begin
// byte boundary
UsedBytesPerLine:=UsedBitsPerLine shr 3;
UnusedBitsAtEnd:=(8-(UsedBitsPerLine and 7)) and 7;
if RawImage^.Description.AlphaBitOrder=riboBitsInOrder then
UnusedByteMask:=(($ff00 shr UnusedBitsAtEnd) and $ff)
else
UnusedByteMask:=(1 shl UnusedBitsAtEnd) - 1;
p:=RawImage^.Mask;
for y:=0 to Height-1 do begin
// check fully used bytes in line
for x:=0 to UsedBytesPerLine-1 do begin
if p^<>$ff then begin
// not all bits set -> transparent pixels found -> Mask needed
{$IFDEF VerboseRawImage}
DebugLn('RawImageMaskIsEmpty FullByte y=',dbgs(y),' x=',dbgs(x),' Byte=',DbgS(p^));
{$ENDIF}
exit;
end;
inc(p);
end;
// check partly used bytes at end of line
if UnusedBitsAtEnd>0 then begin
if (p^ or UnusedByteMask)<>$ff then begin
// not all bits set -> transparent pixels found -> Mask needed
{$IFDEF VerboseRawImage}
DebugLn('RawImageMaskIsEmpty EdgeByte y=',dbgs(y),' x=',dbgs(x),
' Byte=',HexStr(Cardinal(p^),2),
' UnusedByteMask=',HexStr(Cardinal(UnusedByteMask),2),
' OR='+dbgs(p^ or UnusedByteMask),
' UnusedBitsAtEnd='+dbgs(UnusedBitsAtEnd),
' UsedBitsPerLine='+dbgs(UsedBitsPerLine),
' Width='+dbgs(Width),
' RawImage^.Description.AlphaBitsPerPixel='+dbgs(RawImage^.Description.AlphaBitsPerPixel));
{$ENDIF}
exit;
end;
inc(p);
end;
end;
end else begin
// ToDo: AlphaSeparate and rileTight
{$IFDEF VerboseRawImage}
DebugLn('RawImageMaskIsEmpty TODO AlphaSeparate and rileTight');
{$ENDIF}
exit;
end;
end else begin
{$IFDEF VerboseRawImage}
DebugLn('RawImageMaskIsEmpty TODO');
{$ENDIF}
exit;
end;
// no pixel is transparent
Result:=true;
end;
{$IFDEF VerboseRawImage}
DebugLn('RawImageMaskIsEmpty Empty=',dbgs(Result));
{$ENDIF}
end;
function RawImageDescriptionAsString(Desc: PRawImageDescription): string;
function BoolStr(b: boolean): string;
begin
if b then
Result:='true'
else
Result:='false';
end;
begin
Result:='';
with Desc^ do begin
Result:=
' Format='+RawImageColorFormatNames[Format]
+' HasPalette='+BoolStr(HasPalette)
+' Depth='+IntToStr(Depth)
+' Width='+IntToStr(Width)
+' Height='+IntToStr(Height)
+' PaletteColorCount='+IntToStr(PaletteColorCount)
+' BitOrder='+RawImageBitOrderNames[BitOrder]
+' ByteOrder='+RawImageByteOrderNames[ByteOrder]
+' LineOrder='+RawImageLineOrderNames[LineOrder]
+' ColorCount='+IntToStr(ColorCount)
+' BitsPerPixel='+IntToStr(BitsPerPixel)
+' BytesPerLine='+IntToStr(GetBytesPerLine(Width,BitsPerPixel,LineEnd))
+' LineEnd='+RawImageLineEndNames[LineEnd]
+' RedPrec='+IntToStr(RedPrec)
+' RedShift='+IntToStr(RedShift)
+' GreenPrec='+IntToStr(GreenPrec)
+' GreenShift='+IntToStr(GreenShift)
+' BluePrec='+IntToStr(BluePrec)
+' BlueShift='+IntToStr(BlueShift)
+' AlphaSeparate='+BoolStr(AlphaSeparate)
+' AlphaPrec='+IntToStr(AlphaPrec)
+' AlphaShift='+IntToStr(AlphaShift)
+' AlphaBitsPerPixel='+IntToStr(AlphaBitsPerPixel)
+' AlphaLineEnd='+RawImageLineEndNames[AlphaLineEnd]
+' AlphaBitOrder='+RawImageBitOrderNames[AlphaBitOrder]
+' AlphaByteOrder='+RawImageByteOrderNames[AlphaByteOrder]
+' AlphaBytesPerLine='+IntToStr(GetBytesPerLine(Width,AlphaBitsPerPixel,AlphaLineEnd))
+'';
end;
end;
procedure FreeRawImageData(RawImage: PRawImage);
begin
ReAllocMem(RawImage^.Data,0);
RawImage^.DataSize:=0;
ReAllocMem(RawImage^.Mask,0);
RawImage^.MaskSize:=0;
ReAllocMem(RawImage^.Palette,0);
RawImage^.PaletteSize:=0;
end;
procedure ReleaseRawImageData(RawImage: PRawImage);
begin
RawImage^.Data:=nil;
RawImage^.DataSize:=0;
RawImage^.Mask:=nil;
RawImage^.MaskSize:=0;
RawImage^.Palette:=nil;
RawImage^.PaletteSize:=0;
end;
{-------------------------------------------------------------------------------
Beware: Data is used in ReallocMem
-------------------------------------------------------------------------------}
procedure CreateRawImageData(Width, Height, BitsPerPixel: cardinal;
LineEnd: TRawImageLineEnd; var Data: Pointer; var DataSize: cardinal);
var
PixelCount: cardinal;
BitsPerLine: cardinal;
DataBits: Int64;
begin
// get current size
PixelCount:=Width*Height;
if PixelCount=0 then exit;
// calculate BitsPerLine
BitsPerLine:=GetBitsPerLine(Width,BitsPerPixel,LineEnd);
// create pixels
DataBits:=int64(BitsPerLine)*Height;
DataSize:=cardinal((DataBits+7) shr 3);
ReAllocMem(Data,DataSize);
FillChar(Data^,DataSize,0);
end;
procedure CreateRawImageDescFromMask(SrcRawImageDesc,
DestRawImageDesc: PRawImageDescription);
begin
if (not SrcRawImageDesc^.AlphaSeparate) then
RaiseGDBException('CreateRawImageFromMask Alpha not separate');
DestRawImageDesc^:=SrcRawImageDesc^;
// set values
with DestRawImageDesc^ do begin
Format:=ricfGray;
HasPalette:=false;
Depth:=AlphaBitsPerPixel; // used bits per pixel
PaletteColorCount:=0;
ColorCount:=0; // entries in color palette. Ignore when no palette.
BitsPerPixel:=AlphaBitsPerPixel; // bits per pixel. can be greater than Depth.
LineEnd:=AlphaLineEnd;
RedPrec:=AlphaPrec; // gray precision. bits for gray
RedShift:=AlphaShift;
AlphaPrec:=0;
AlphaShift:=0;
AlphaSeparate:=false; // the alpha is stored as separate Mask
// The next values are only valid, if there is a separate alpha mask
AlphaBitsPerPixel:=0; // bits per alpha mask pixel.
// ToDo: add attributes for palette
end;
end;
procedure GetRawImageXYPosition(RawImageDesc: PRawImageDescription;
LineStarts: PRawImagePosition; x, y: cardinal;
var Position: TRawImagePosition);
var
BitOffset: cardinal;
begin
if RawImageDesc^.LineOrder=riloBottomToTop then
y:=RawImageDesc^.Height-y;
Position:=LineStarts[y];
BitOffset:=RawImageDesc^.BitsPerPixel*cardinal(x)+Position.Bit;
Position.Bit:=(BitOffset and 7);
inc(Position.Byte,BitOffset shr 3);
end;
procedure ExtractRawImageRect(SrcRawImage: PRawImage; const SrcRect: TRect;
DestRawImage: PRawImage);
var
SrcMaskDesc, DestMaskDesc: TRawImageDescription;
begin
//DebugLn'ExtractRawImageRect SrcRawImage=',RawImageDescriptionAsString(@SrcRawImage^.Description),
// ' SrcRect=',SrcRect.Left,',',SrcRect.Top,',',SrcRect.Right,',',SrcRect.Bottom);
// copy description
DestRawImage^:=SrcRawImage^;
ReleaseRawImageData(DestRawImage);
// extract rectangle from Data
ExtractRawImageDataRect(@SrcRawImage^.Description,SrcRect,SrcRawImage^.Data,
@DestRawImage^.Description,DestRawImage^.Data,DestRawImage^.DataSize);
// extract rectangle from separate Alpha
//DebugLn'ExtractRawImageDataRect data=',DbgS(DestRawImage^.Data),' Size=',DestRawImage^.DataSize);
if SrcRawImage^.Description.AlphaSeparate
and (SrcRawImage^.Mask<>nil) then begin
CreateRawImageDescFromMask(@SrcRawImage^.Description,@SrcMaskDesc);
//DebugLn'ExtractRawImageRect Mask SrcRawImage=',RawImageDescriptionAsString(@SrcMaskDesc));
ExtractRawImageDataRect(@SrcMaskDesc,SrcRect,SrcRawImage^.Mask,
@DestMaskDesc,DestRawImage^.Mask,DestRawImage^.MaskSize);
end;
end;
{-------------------------------------------------------------------------------
Beware: DestData is used in ReallocMem
-------------------------------------------------------------------------------}
procedure ExtractRawImageDataRect(SrcRawImageDesc: PRawImageDescription;
const SrcRect: TRect; SrcData: Pointer;
DestRawImageDesc: PRawImageDescription;
var DestData: Pointer; var DestDataSize: cardinal);
var
SrcWidth: cardinal;
SrcHeight: cardinal;
MaxRect, SourceRect: TRect;
y: Integer;
TotalWidth: cardinal;
TotalHeight: cardinal;
BitsPerPixel: cardinal;
LineEnd: TRawImageLineEnd;
SrcLineStarts, DestLineStarts: PRawImagePosition;
SrcLineStartPosition, SrcLineEndPosition: TRawImagePosition;
DestLineStartPosition: TRawImagePosition;
w: Word;
Shift: LongWord;
SrcPos: PByte;
DestPos: PByte;
ByteCount: LongWord;
x: Integer;
begin
// init
DestRawImageDesc^:=SrcRawImageDesc^;
// intersect SrcRect
TotalWidth:=SrcRawImageDesc^.Width;
TotalHeight:=SrcRawImageDesc^.Height;
BitsPerPixel:=SrcRawImageDesc^.BitsPerPixel;
LineEnd:=SrcRawImageDesc^.LineEnd;
MaxRect:=Bounds(0,0,TotalWidth,TotalHeight);
IntersectRect(SourceRect,MaxRect,SrcRect);
if (SourceRect.Right<=SourceRect.Left)
or (SourceRect.Bottom<=SourceRect.Top) then exit;
SrcWidth:=SourceRect.Right-SourceRect.Left;
SrcHeight:=SourceRect.Bottom-SourceRect.Top;
// allocate Data
DestRawImageDesc^.Width:=SrcWidth;
DestRawImageDesc^.Height:=SrcHeight;
//DebugLn'ExtractRawImageDataRect Src=',SrcWidth,',',SrcHeight,' DestData=',DbgS(DestData));
CreateRawImageData(SrcWidth,SrcHeight,BitsPerPixel,LineEnd,
DestData,DestDataSize);
//DebugLn'ExtractRawImageDataRect data=',DbgS(DestData),' Size=',DestDataSize);
if (SrcWidth=TotalWidth) and (TotalHeight=SrcHeight) then begin
// copy whole source
System.Move(SrcData^,DestData^,DestDataSize);
exit;
end;
// calculate line starts for source
SrcLineStarts:=nil;
CreateRawImageLineStarts(TotalWidth,TotalHeight,BitsPerPixel,LineEnd,
SrcLineStarts);
// calculate line starts for destination
DestLineStarts:=nil;
CreateRawImageLineStarts(SrcWidth,SrcHeight,BitsPerPixel,LineEnd,
DestLineStarts);
// copy
for y:=0 to SrcHeight-1 do begin
GetRawImageXYPosition(SrcRawImageDesc,SrcLineStarts,
SourceRect.Left,y+SourceRect.Top,
SrcLineStartPosition);
GetRawImageXYPosition(SrcRawImageDesc,SrcLineStarts,
SourceRect.Right,y+SourceRect.Top,
SrcLineEndPosition);
GetRawImageXYPosition(DestRawImageDesc,DestLineStarts,0,y,
DestLineStartPosition);
//DebugLn'ExtractRawImageDataRect A y=',y,' SrcByte=',SrcLineStartPosition.Byte,' SrcBit=',SrcLineStartPosition.Bit,
//' DestByte=',DestLineStartPosition.Byte,' DestBit=',DestLineStartPosition.Bit);
if (SrcLineStartPosition.Bit=0)
and (DestLineStartPosition.Bit=0) then begin
// copy bytes
ByteCount:=SrcLineEndPosition.Byte-SrcLineStartPosition.Byte;
if SrcLineEndPosition.Bit>0 then
inc(ByteCount);
//DebugLn'ExtractRawImageDataRect B ByteCount=',ByteCount);
System.Move(
Pointer(PtrUInt(SrcData)+SrcLineStartPosition.Byte)^,
Pointer(PtrUInt(DestData)+DestLineStartPosition.Byte)^,
ByteCount);
end else if (DestLineStartPosition.Bit=0) then begin
// copy and move bits
ByteCount:=((SrcWidth*BitsPerPixel)+7) shr 3;
Shift:=8-SrcLineStartPosition.Bit;
SrcPos:=PByte(PtrUInt(SrcData)+SrcLineStartPosition.Byte);
DestPos:=PByte(PtrUInt(DestData)+DestLineStartPosition.Byte);
for x:=0 to ByteCount-1 do begin
w:=PWord(SrcPos)^;
w:=w shr Shift;
DestPos^:=byte(w);
inc(SrcPos);
inc(DestPos);
end;
end else begin
DebugLn('ToDo: ExtractRawImageRect DestLineStartPosition.Bit>0');
break;
end;
end;
// clean up
FreeMem(SrcLineStarts);
FreeMem(DestLineStarts);
end;
procedure CreateRawImageLineStarts(Width, Height, BitsPerPixel: cardinal;
LineEnd: TRawImageLineEnd; var LineStarts: PRawImagePosition);
// LineStarts is recreated, so make sure it is nil or a valid mem
var
PixelCount: cardinal;
BitsPerLine: cardinal;
CurLine: cardinal;
BytesPerLine: cardinal;
ExtraBitsPerLine: cardinal;
CurBitOffset: cardinal;
begin
// get current size
PixelCount:=Width*Height;
if PixelCount=0 then exit;
// calculate BitsPerLine, BytesPerLine and ExtraBitsPerLine
BitsPerLine:=GetBitsPerLine(Width,BitsPerPixel,LineEnd);
BytesPerLine:=BitsPerLine shr 3;
ExtraBitsPerLine:=BitsPerLine and 7;
// create line start array
ReAllocMem(LineStarts,Height*SizeOf(TRawImagePosition));
LineStarts[0].Byte:=0;
LineStarts[0].Bit:=0;
for CurLine:=1 to Height-1 do begin
CurBitOffset:=LineStarts[CurLine-1].Bit+ExtraBitsPerLine;
LineStarts[CurLine].Byte:=LineStarts[CurLine-1].Byte+BytesPerLine
+(CurBitOffset shr 3);
LineStarts[CurLine].Bit:=CurBitOffset and 7;
end;
end;
function GetBytesPerLine(Width, BitsPerPixel: cardinal;
LineEnd: TRawImageLineEnd): cardinal;
begin
Result:=(GetBitsPerLine(Width,BitsPerPixel,LineEnd)+7) shr 3;
end;
function GetBitsPerLine(Width, BitsPerPixel: cardinal;
LineEnd: TRawImageLineEnd): cardinal;
var
BitsPerLine: Cardinal;
begin
BitsPerLine:=Width*BitsPerPixel;
case LineEnd of
rileTight: ;
rileByteBoundary: BitsPerLine:=(BitsPerLine+7) and not cardinal(7);
rileWordBoundary: BitsPerLine:=(BitsPerLine+15) and not cardinal(15);
rileDWordBoundary: BitsPerLine:=(BitsPerLine+31) and not cardinal(31);
rileQWordBoundary: BitsPerLine:=(BitsPerLine+63) and not cardinal(63);
end;
Result:=BitsPerLine;
end;
procedure ReadRawImageBits(TheData: PByte;
const Position: TRawImagePosition;
BitsPerPixel, Prec, Shift: cardinal; BitOrder: TRawImageBitOrder;
var Bits: word);
var
P: PByte;
PrecMask: Cardinal;
OneByte: Byte;
TwoBytes: Word;
FourBytes: Cardinal;
begin
PrecMask:=(Cardinal(1) shl Prec)-1;
P:=@(TheData[Position.Byte]);
case BitsPerPixel of
1,2,4:
begin
OneByte:=P^;
if BitOrder=riboBitsInOrder then
Bits:=Word(cardinal(OneByte shr (Shift+Position.Bit)) and PrecMask)
else
Bits:=Word(cardinal(OneByte shr (Shift+7-Position.Bit)) and PrecMask);
end;
8: begin
OneByte:=P^;
Bits:=Word(cardinal(OneByte shr Shift) and PrecMask);
end;
16: begin
TwoBytes:=PWord(P)^;
Bits:=Word(cardinal(TwoBytes shr Shift) and PrecMask);
end;
32: begin
FourBytes:=PDWord(P)^;
Bits:=Word(cardinal(FourBytes shr Shift) and PrecMask);
end;
else
Bits:=0;
end;
if Prec<16 then begin
// add missing bits
Bits:=(Bits shl (16-Prec));
Bits:=Bits or MissingBits[Prec,Bits shr 13];
end;
end;
procedure WriteRawImageBits(TheData: PByte;
const Position: TRawImagePosition;
BitsPerPixel, Prec, Shift: cardinal; BitOrder: TRawImageBitOrder; Bits: word);
var
P: PByte;
PrecMask: Cardinal;
OneByte: Byte;
TwoBytes: Word;
FourBytes: Cardinal;
ShiftLeft: Integer;
begin
P:=@(TheData[Position.Byte]);
PrecMask:=(Cardinal(1) shl Prec)-1;
Bits:=Bits shr (16-Prec);
{DebugLn'WriteDataBits WRITE Position=',Position.Byte,'/',Position.Bit,
' Shift=',Shift,' Prec=',Prec,' BitsPerPixel=',BitsPerPixel,
' PrecMask=',DbgS(PrecMask),
' Bits=',DbgS(Bits),
'');}
case BitsPerPixel of
1,2,4:
begin
OneByte:=P^;
if BitOrder=riboBitsInOrder then
ShiftLeft:=Shift+Position.Bit
else
ShiftLeft:=Shift+7-Position.Bit;
PrecMask:=not (PrecMask shl ShiftLeft);
OneByte:=OneByte and PrecMask; // clear old
OneByte:=OneByte or (Bits shl ShiftLeft); // set new
P^:=OneByte;
//DebugLn'WriteDataBits 1,2,4 Result=',DbgS(OneByte));
end;
8: begin
OneByte:=P^;
PrecMask:=not (PrecMask shl Shift);
OneByte:=OneByte and PrecMask; // clear old
OneByte:=OneByte or (Bits shl Shift); // set new
P^:=OneByte;
//DebugLn'WriteDataBits 8 Result=',DbgS(OneByte));
end;
16: begin
TwoBytes:=PWord(P)^;
PrecMask:=not (PrecMask shl Shift);
TwoBytes:=TwoBytes and PrecMask; // clear old
TwoBytes:=TwoBytes or (Bits shl Shift); // set new
PWord(P)^:=TwoBytes;
//DebugLn'WriteDataBits 16 Result=',DbgS(TwoBytes));
end;
32: begin
FourBytes:=PDWord(P)^;
PrecMask:=not (PrecMask shl Shift);
FourBytes:=FourBytes and PrecMask; // clear old
FourBytes:=FourBytes or cardinal(Bits shl Shift); // set new
PDWord(P)^:=FourBytes;
//DebugLn'WriteDataBits 32 Result=',DbgS(FourBytes));
end;
end;
end;
//------------------------------------------------------------------------------
procedure InternalInit;
var
Prec: Integer;
HighValue: word;
Bits: word;
CurShift: Integer;
begin
for Prec:=0 to 15 do begin
For HighValue:=0 to 7 do begin
// Value represents the three highest bits
// For example:
// Prec=5 and the read value is %10110
// => Value=%101
if Prec=0 then begin
MissingBits[Prec,HighValue]:=0;
continue;
end;
// copy the value till all missing bits are set
// For example:
// Prec=5, HighValue=%110
// => MissingBits[5,6]:=%0000011011011011
Bits:=HighValue;
if Prec<3 then
// for Precision 1 and 2 the high bits are less
Bits:=Bits shr (3-Prec);
MissingBits[Prec,HighValue]:=0;
CurShift:=16-Prec;
while CurShift>0 do begin
MissingBits[Prec,HighValue]:=
MissingBits[Prec,HighValue] or (Bits shl CurShift);
dec(CurShift,Prec);
end;
end;
end;
end;
initialization
InternalInit;
end.