mirror of
				https://gitlab.com/freepascal.org/lazarus/lazarus.git
				synced 2025-11-04 05:39:34 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			798 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			798 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.LCL, 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.
 | 
						|
 |