mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-05 00:48:05 +02:00
6699 lines
189 KiB
ObjectPascal
6699 lines
189 KiB
ObjectPascal
{ $Id$ }
|
|
{
|
|
/***************************************************************************
|
|
intfgraphics.pp
|
|
---------------
|
|
|
|
***************************************************************************/
|
|
|
|
*****************************************************************************
|
|
This file is part of the Lazarus Component Library (LCL)
|
|
|
|
See the file COPYING.modifiedLGPL.txt, included in this distribution,
|
|
for details about the license.
|
|
*****************************************************************************
|
|
|
|
Author: Mattias Gaertner
|
|
|
|
Abstract:
|
|
Classes and functions for easy handling of raw images (interface images).
|
|
}
|
|
unit IntfGraphics;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
// RTL + FCL
|
|
Classes, SysUtils, Math, fpImage,
|
|
FPReadBMP, FPWriteBMP, BMPComn,
|
|
FPReadPNG, FPWritePNG,
|
|
{$IFNDEF DisableLCLTIFF}
|
|
FPReadTiff, FPWriteTiff, FPTiffCmn,
|
|
{$ENDIF}
|
|
AVL_Tree,
|
|
// LazUtils
|
|
GraphType, FPCAdds, LazLoggerBase, LazTracer,
|
|
// LCL
|
|
LCLType, LCLversion, IcnsTypes;
|
|
|
|
type
|
|
{ TLazIntfImage }
|
|
{ This descendent of TFPCustomImage stores its image data as raw images and
|
|
is therefore able to directly interchange images with the LCL interfaces.
|
|
|
|
Usage examples:
|
|
|
|
1. Loading a .xpm file into a TBitmap:
|
|
|
|
var
|
|
BmpHnd,MaskHnd: HBitmap;
|
|
Bitmap1: TBitmap;
|
|
IntfImg1: TLazIntfImage;
|
|
Reader: TLazReaderXPM;
|
|
begin
|
|
// create a bitmap (or use an existing one)
|
|
Bitmap1:=TBitmap.Create;
|
|
// create the raw image for the screenformat you want
|
|
IntfImg1:=TLazIntfImage.Create(0,0,[riqfRGB, riqfAlpha, riqfMask]);
|
|
// create the XPM reader
|
|
Reader:=TLazReaderXPM.Create;
|
|
// load the image
|
|
IntfImg1.LoadFromFile('filename.xpm',Reader);
|
|
// create the bitmap handles
|
|
IntfImg1.CreateBitmap(BmpHnd,MaskHnd);
|
|
// apply handles to the Bitmap1
|
|
Bitmap1.Handle:=BmpHnd;
|
|
Bitmap1.MaskHandle:=MaskHnd;
|
|
// clean up
|
|
Reader.Free;
|
|
IntfImg1.Free;
|
|
// do something with the Bitmap1
|
|
...
|
|
end;
|
|
|
|
|
|
2. Saving a TBitmap to a .xpm file:
|
|
|
|
var
|
|
BmpHnd,MaskHnd: HBitmap;
|
|
Bitmap1: TBitmap;
|
|
IntfImg1: TLazIntfImage;
|
|
Writer: TLazWriterXPM;
|
|
begin
|
|
...
|
|
// create the raw image
|
|
IntfImg1:=TLazIntfImage.Create(0,0,[]);
|
|
// load the raw image from the bitmap handles
|
|
IntfImg1.LoadFromBitmap(Bitmap1.Handle,Bitmap1.MaskHandle);
|
|
// create the XPM writer
|
|
Writer:=TLazWriterXPM.Create;
|
|
// save image to file
|
|
IntfImg1.SaveToFile('filename.xpm',Writer);
|
|
// clean up
|
|
Writer.Free;
|
|
IntfImg1.Free;
|
|
...
|
|
end;
|
|
}
|
|
|
|
TLazIntfImageGetPixelProc = procedure(x, y: integer; out Color: TFPColor) of object;
|
|
TLazIntfImageSetPixelProc = procedure(x, y: integer; const Color: TFPColor) of object;
|
|
|
|
TOnReadRawImageBits = procedure(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal; var Bits: word);
|
|
|
|
TOnWriteRawImageBits = procedure(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal; Bits: word);
|
|
|
|
|
|
{ TLazIntfImage }
|
|
|
|
TLazIntfImage = class(TFPCustomImage)
|
|
private
|
|
FRawImage: TRawImage;
|
|
FLineStarts: PRawImageLineStarts;
|
|
FMaskLineStarts: PRawImageLineStarts;
|
|
FMaskSet: Boolean; // Set when at least one maskpixel is set
|
|
FUpdateCount: integer;
|
|
fCreateAllDataNeeded: boolean;
|
|
FGetSetColorFunctionsUpdateNeeded: boolean;
|
|
FReadRawImageBits: TOnReadRawImageBits;
|
|
FWriteRawImageBits: TOnWriteRawImageBits;
|
|
FMaskReadRawImageBits: TOnReadRawImageBits;
|
|
FMaskWriteRawImageBits: TOnWriteRawImageBits;
|
|
FDataOwner: Boolean;
|
|
function GetMasked(x, y: integer): Boolean;
|
|
function GetTColors(x, y: integer): TGraphicsColor;
|
|
|
|
procedure InternalSetSize(AWidth, AHeight: integer);
|
|
|
|
procedure SetMasked(x, y: integer; const AValue: Boolean);
|
|
procedure SetTColors(x, y: integer; const AValue: TGraphicsColor);
|
|
protected
|
|
FGetInternalColorProc: TLazIntfImageGetPixelProc;
|
|
FSetInternalColorProc: TLazIntfImageSetPixelProc;
|
|
procedure SetUsePalette (Value: boolean); override;
|
|
procedure SetInternalColor(x, y: integer; const Value: TFPColor); override;
|
|
function GetInternalColor(x, y: integer): TFPColor; override;
|
|
procedure SetInternalPixel (x,y:integer; Value:integer); override;
|
|
function GetInternalPixel (x,y:integer) : integer; override;
|
|
procedure FreeData; virtual;
|
|
procedure SetDataDescription(const ADescription: TRawImageDescription); virtual;
|
|
procedure ChooseGetSetColorFunctions; virtual;
|
|
procedure ChooseRawBitsProc(BitsPerPixel: cardinal;
|
|
ByteOrder: TRawImageByteOrder;
|
|
BitOrder: TRawImageBitOrder;
|
|
out ProcReadRawImageBits: TOnReadRawImageBits;
|
|
out ProcWriteRawImageBits: TOnWriteRawImageBits);
|
|
// get color functions
|
|
procedure GetColor_Generic(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_RGBA_NoPalette(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_RGB_NoPalette(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_Gray_NoPalette(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_GrayAlpha_NoPalette(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_NULL(x, y: integer; out Value: TFPColor);
|
|
// 32 bpp alpha
|
|
procedure GetColor_BPP32_A8R8G8B8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_A8B8G8R8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_A8G8R8B8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_A8G8B8R8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_A8R8B8G8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_A8B8R8G8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_B8G8R8A8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_R8G8B8A8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_G8B8R8A8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_G8R8B8A8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_B8R8G8A8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_R8B8G8A8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// 32 bpp no alpha
|
|
procedure GetColor_BPP32_X8R8G8B8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_X8B8G8R8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_X8G8R8B8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_X8G8B8R8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_X8R8B8G8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_X8B8R8G8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_B8G8R8X8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_R8G8B8X8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_G8B8R8X8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_G8R8B8X8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_B8R8G8X8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP32_R8B8G8X8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// 24 bpp
|
|
procedure GetColor_BPP24_B8G8R8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP24_R8G8B8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP24_G8B8R8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP24_G8R8B8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP24_B8R8G8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
procedure GetColor_BPP24_R8B8G8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
|
|
procedure GetMask_Generic(x, y: integer; out AValue: Boolean);
|
|
|
|
// set color functions
|
|
procedure SetColor_Generic(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_RGBA_NoPalette(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_RGB_NoPalette(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_Gray_NoPalette(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_GrayAlpha_NoPalette(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_NULL(x, y: integer; const Value: TFPColor);
|
|
// 32 bpp alpha
|
|
procedure SetColor_BPP32_A8R8G8B8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_A8B8G8R8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_A8G8R8B8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_A8G8B8R8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_A8R8B8G8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_A8B8R8G8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_B8G8R8A8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_R8G8B8A8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_G8B8R8A8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_G8R8B8A8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_B8R8G8A8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_R8B8G8A8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// 32 bpp no alpha
|
|
procedure SetColor_BPP32_X8R8G8B8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_X8B8G8R8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_X8G8R8B8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_X8G8B8R8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_X8R8B8G8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_X8B8R8G8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_B8G8R8X8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_R8G8B8X8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_G8B8R8X8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_G8R8B8X8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_B8R8G8X8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP32_R8B8G8X8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// 24 bpp
|
|
procedure SetColor_BPP24_B8G8R8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP24_R8G8B8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP24_G8B8R8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP24_G8R8B8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP24_B8R8G8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
procedure SetColor_BPP24_R8B8G8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
|
|
procedure SetMask_Generic(x, y: integer; const AValue: Boolean);
|
|
public
|
|
constructor Create(AWidth, AHeight: integer); override;
|
|
constructor Create(AWidth, AHeight: integer; AFlags: TRawImageQueryFlags);
|
|
constructor Create(ARawImage: TRawImage; ADataOwner: Boolean);
|
|
constructor CreateCompatible(IntfImg: TLazIntfImage; AWidth, AHeight: integer);
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
procedure BeginUpdate;
|
|
procedure EndUpdate;
|
|
procedure SetSize(AWidth, AHeight: integer); override;
|
|
function CheckDescription(const ADescription: TRawImageDescription;
|
|
ExceptionOnError: boolean): boolean; virtual;
|
|
procedure LoadFromDevice(DC: HDC); virtual;
|
|
procedure LoadFromBitmap(ABitmap, AMaskBitmap: HBitmap; AWidth: integer = -1; AHeight: integer = -1); virtual;
|
|
procedure CreateBitmaps(out ABitmap, AMask: HBitmap; ASkipMask: boolean = False); virtual;
|
|
procedure SetRawImage(const ARawImage: TRawImage; ADataOwner: Boolean = True); virtual;
|
|
procedure GetRawImage(out ARawImage: TRawImage; ATransferOwnership: Boolean = False); virtual;
|
|
procedure FillPixels(const Color: TFPColor); virtual;
|
|
procedure CopyPixels(ASource: TFPCustomImage; XDst: Integer = 0; YDst: Integer = 0;
|
|
AlphaMask: Boolean = False; AlphaTreshold: Word = 0); virtual;
|
|
procedure AlphaBlend(ASource, ASourceAlpha: TLazIntfImage; const ADestX, ADestY: Integer);
|
|
procedure AlphaFromMask(AKeepAlpha: Boolean = True);
|
|
procedure Mask(const AColor: TFPColor; AKeepOldMask: Boolean = False);
|
|
procedure GetXYDataPosition(x, y: integer; out Position: TRawImagePosition);
|
|
procedure GetXYMaskPosition(x, y: integer; out Position: TRawImagePosition);
|
|
function GetDataLineStart(y: integer): Pointer;// similar to Delphi TBitmap.ScanLine. Only works with lines aligned to whole bytes.
|
|
procedure CreateData; virtual;
|
|
function HasTransparency: boolean; virtual;
|
|
function HasMask: boolean; virtual;
|
|
procedure SetDataDescriptionKeepData(const ADescription: TRawImageDescription);
|
|
public
|
|
property PixelData: PByte read FRawImage.Data;
|
|
property MaskData: PByte read FRawImage.Mask;
|
|
property DataDescription: TRawImageDescription read FRawImage.Description
|
|
write SetDataDescription;
|
|
property GetInternalColorProc: TLazIntfImageGetPixelProc read FGetInternalColorProc;
|
|
property SetInternalColorProc: TLazIntfImageSetPixelProc read FSetInternalColorProc;
|
|
property TColors[x,y: integer]: TGraphicsColor read GetTColors write SetTColors;
|
|
property Masked[x,y:integer]: Boolean read GetMasked write SetMasked;
|
|
end;
|
|
|
|
|
|
{ TLazIntfImageMask }
|
|
|
|
TLazIntfImageMask = class(TFPCustomImage)
|
|
private
|
|
FImage: TLazIntfImage;
|
|
protected
|
|
procedure SetInternalColor(x, y: integer; const Value: TFPColor); override;
|
|
function GetInternalColor(x, y: integer): TFPColor; override;
|
|
procedure SetInternalPixel (x,y:integer; Value:integer); override;
|
|
function GetInternalPixel (x,y:integer) : integer; override;
|
|
public
|
|
constructor CreateWithImage(TheImage: TLazIntfImage); virtual;
|
|
property Image: TLazIntfImage read FImage;
|
|
end;
|
|
|
|
|
|
{ TLazAVLPalette }
|
|
{ This descendent of TFPPalette uses an AVL tree for speed up. }
|
|
|
|
TLazAVLPalette = class(TFPPalette)
|
|
protected
|
|
FAVLPalette: TAvlTree; // tree of PLazAVLPaletteEntry 'color to index'
|
|
FAVLNodes: PAvlTreeNode;// 'index to node' array
|
|
procedure SetCount(NewCount: integer); override;
|
|
procedure SetColor(Index: integer; const NewColor: TFPColor); override;
|
|
function CompareEntries(Index1, Index2: integer): integer;
|
|
function CompareColorWithEntries(const AColor: TFPColor;
|
|
Index: integer): integer;
|
|
procedure EnlargeData; override;
|
|
public
|
|
destructor Destroy; override;
|
|
function IndexOf(const AColor: TFPColor): integer; override;
|
|
function Add(const NewColor: TFPColor): integer; override;
|
|
procedure CheckConsistency; virtual;
|
|
end;
|
|
|
|
|
|
{ TArrayNodesTree }
|
|
|
|
PArrayNode = ^TArrayNode;
|
|
TArrayNode = class
|
|
public
|
|
Parent: TArrayNode;
|
|
Value: integer;
|
|
Children: PArrayNode;
|
|
StartValue: integer;
|
|
Capacity: integer;
|
|
Data: Pointer;
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure DeleteChilds;
|
|
procedure UnbindFromParent;
|
|
procedure CreateChildNode(ChildValue: integer);
|
|
function GetChildNode(ChildValue: integer;
|
|
CreateIfNotExists: boolean): TArrayNode;
|
|
procedure Expand(ValueToInclude: integer);
|
|
function FindPrevSibling: TArrayNode;
|
|
function FindNextSibling: TArrayNode;
|
|
function FindNextUTF8: TArrayNode;
|
|
function FindPrev: TArrayNode;
|
|
function FindFirstChild: TArrayNode;
|
|
function FindLastChild: TArrayNode;
|
|
function FindLastSubChild: TArrayNode;
|
|
function FindFirstSibling: TArrayNode;
|
|
function FindLastSibling: TArrayNode;
|
|
procedure ConsistencyCheck;
|
|
end;
|
|
|
|
TArrayNodesTree = class
|
|
public
|
|
Root: TArrayNode;
|
|
function FindNode(Path: PInteger; Count: integer): TArrayNode;
|
|
function FindData(Path: PInteger; Count: integer): Pointer;
|
|
function SetNode(Path: PInteger; Count: integer;
|
|
Data: Pointer): TArrayNode;
|
|
procedure Delete(Node: TArrayNode);
|
|
procedure Clear;
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure ConsistencyCheck;
|
|
end;
|
|
|
|
|
|
{ ILazImageReader }
|
|
{ Extension to TFPCustomImageReader to initialize a TRawImgeDescription based
|
|
on the image to be read
|
|
}
|
|
|
|
ILazImageReader = interface
|
|
['{DD8B14DE-4E97-4816-8B40-DD6C4D8CCD1B}']
|
|
function GetUpdateDescription: Boolean;
|
|
procedure SetUpdateDescription(AValue: Boolean);
|
|
|
|
property UpdateDescription: Boolean read GetUpdateDescription write SetUpdateDescription;
|
|
end;
|
|
|
|
{ ILazImageWriter }
|
|
{ Extension to TFPCustomImageWriter to initialize the writer based
|
|
on the intfimage data. To be able to write different formats, the writer
|
|
should initialize itself
|
|
}
|
|
ILazImageWriter = interface
|
|
['{DFE8D2A0-E318-45CE-87DE-9C6F1F1928E5}']
|
|
procedure Initialize(AImage: TLazIntfImage);
|
|
procedure Finalize;
|
|
end;
|
|
|
|
|
|
{ TLazReaderXPM }
|
|
{ This is a FPImage reader for xpm images. }
|
|
|
|
TLazReaderXPM = class(TFPCustomImageReader, ILazImageReader)
|
|
private
|
|
FWidth: Integer;
|
|
FHeight: Integer;
|
|
FColorCount: Integer;
|
|
FCharsPerPixel: Integer;
|
|
FXHot: Integer;
|
|
FYHot: Integer;
|
|
FPixelToColorTree: TArrayNodesTree;
|
|
FContinue: Boolean;
|
|
FUpdateDescription: Boolean; // If set, update rawimagedescription
|
|
public
|
|
function GetUpdateDescription: Boolean;
|
|
procedure SetUpdateDescription(AValue: Boolean);
|
|
function QueryInterface(constref iid: TGuid; out obj): LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
function _AddRef: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
function _Release: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
protected
|
|
procedure ClearPixelToColorTree;
|
|
procedure InternalRead(Str: TStream; Img: TFPCustomImage); override;
|
|
function InternalCheck(Str: TStream): boolean; override;
|
|
public
|
|
constructor Create; override;
|
|
destructor Destroy; override;
|
|
property UpdateDescription: Boolean read GetUpdateDescription write SetUpdateDescription;
|
|
end;
|
|
|
|
|
|
{ TLazWriterXPM }
|
|
{ This is a FPImage writer for xpm images. }
|
|
|
|
TLazWriterXPM = class(TFPCustomImageWriter)
|
|
private
|
|
FNibblesPerSample: word;
|
|
FRightShiftSample: cardinal;
|
|
FContinue: Boolean;
|
|
procedure SetNibblesPerSample(const AValue: word);
|
|
protected
|
|
procedure InternalWrite(Str: TStream; Img: TFPCustomImage); override;
|
|
public
|
|
constructor Create; override;
|
|
property NibblesPerSample: word read FNibblesPerSample
|
|
write SetNibblesPerSample;
|
|
end;
|
|
|
|
|
|
{ TLazReaderDIB }
|
|
{ This is an imroved FPImage reader for dib images. }
|
|
|
|
TLazReaderMaskMode = (
|
|
lrmmNone, // no mask is generated
|
|
lrmmAuto, // a mask is generated based on the first pixel read (*)
|
|
lrmmColor // a mask is generated based on the given color (*)
|
|
);
|
|
// (*) Note: when reading images with an alpha channel and the alpha channel
|
|
// has no influence on the mask (unless the maskcolor is transparent)
|
|
|
|
TLazReaderDIBEncoding = (
|
|
lrdeRGB,
|
|
lrdeRLE,
|
|
lrdeBitfield,
|
|
lrdeJpeg, // for completion, don't know if they exist
|
|
lrdePng, // for completion, don't know if they exist
|
|
lrdeHuffman // for completion, don't know if they exist
|
|
);
|
|
|
|
TLazReaderDIBInfo = record
|
|
Width: Cardinal;
|
|
Height: Cardinal;
|
|
BitCount: Byte;
|
|
Encoding: TLazReaderDIBEncoding;
|
|
PaletteCount: Word;
|
|
UpsideDown: Boolean;
|
|
PixelMasks: packed record
|
|
R, G, B, A: LongWord;
|
|
end;
|
|
MaskShift: record
|
|
R, G, B, A: Byte;
|
|
end;
|
|
MaskSize: record
|
|
R, G, B, A: Byte;
|
|
end;
|
|
end;
|
|
|
|
{ TLazReaderDIB }
|
|
|
|
TLazReaderDIB = class (TFPCustomImageReader, ILazImageReader)
|
|
private
|
|
FImage: TLazIntfImage;
|
|
|
|
FMaskMode: TLazReaderMaskMode;
|
|
FMaskColor: TFPColor; // color which should be interpreted as masked
|
|
FMaskIndex: Integer; // for palette based images, index of the color which should be interpreted as masked
|
|
|
|
FReadSize: Integer; // Size (in bytes) of 1 scanline.
|
|
FDIBinfo: TLazReaderDIBInfo; // Info about the bitmap as read from the stream
|
|
FPalette: array of TFPColor; // Buffer with Palette entries.
|
|
FLineBuf: PByte; // Buffer for 1 scanline. Can be Byte, Word, TColorRGB or TColorRGBA
|
|
FUpdateDescription: Boolean; // If set, update rawimagedescription
|
|
FContinue: Boolean; // for progress support
|
|
FIgnoreAlpha: Boolean; // if alpha-channel is declared but does not exists (all values = 0)
|
|
|
|
function BitfieldsToFPColor(const AColor: Cardinal): TFPcolor;
|
|
function RGBToFPColor(const AColor: TColorRGBA): TFPcolor;
|
|
function RGBToFPColor(const AColor: TColorRGB): TFPcolor;
|
|
function RGBToFPColor(const AColor: Word): TFPcolor;
|
|
|
|
public
|
|
function GetUpdateDescription: Boolean;
|
|
procedure SetUpdateDescription(AValue: Boolean);
|
|
function QueryInterface(constref iid: TGuid; out obj): LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
function _AddRef: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
function _Release: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
protected
|
|
procedure InitLineBuf;
|
|
procedure FreeLineBuf;
|
|
|
|
procedure ReadScanLine(Row: Integer); virtual;
|
|
procedure WriteScanLine(Row: Cardinal); virtual;
|
|
// required by TFPCustomImageReader
|
|
procedure InternalRead(Stream: TStream; Img: TFPCustomImage); override;
|
|
procedure InternalReadHead; virtual;
|
|
procedure InternalReadBody; virtual;
|
|
function InternalCheck(Stream: TStream) : boolean; override;
|
|
|
|
property ReadSize: Integer read FReadSize;
|
|
property LineBuf: PByte read FLineBuf;
|
|
property Info: TLazReaderDIBInfo read FDIBInfo;
|
|
public
|
|
constructor Create; override;
|
|
destructor Destroy; override;
|
|
property MaskColor: TFPColor read FMaskColor write FMaskColor;
|
|
property MaskMode: TLazReaderMaskMode read FMaskMode write FMaskMode;
|
|
property UpdateDescription: Boolean read GetUpdateDescription write SetUpdateDescription;
|
|
end;
|
|
|
|
|
|
{ TLazReaderBMP }
|
|
|
|
TLazReaderBMP = class(TLazReaderDIB)
|
|
private
|
|
FDataOffset: Int64; // some bitmaps can specify the data offset
|
|
protected
|
|
function InternalCheck(Stream: TStream) : boolean; override;
|
|
procedure InternalReadHead; override;
|
|
{$IF FPC_FullVersion < 30301}
|
|
class function InternalSize(Stream: TStream): TPoint; override;
|
|
{$IFEND}
|
|
end;
|
|
|
|
{ TLazWriterBMP }
|
|
|
|
TLazWriterBMP = class(TFPWriterBMP, ILazImageWriter)
|
|
public
|
|
function QueryInterface(constref iid: TGuid; out obj): LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
function _AddRef: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
function _Release: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
public
|
|
procedure Initialize(AImage: TLazIntfImage);
|
|
procedure Finalize;
|
|
end;
|
|
|
|
|
|
{ TLazReaderIconDIB }
|
|
{ This is a FPImage reader for a single DIB from an icon file }
|
|
TLazReaderIconDIB = class (TLazReaderDIB)
|
|
protected
|
|
procedure InternalRead(Stream: TStream; Img: TFPCustomImage); override;
|
|
end;
|
|
|
|
|
|
|
|
{ TLazReaderPNG }
|
|
|
|
TLazReaderPNG = class(TFPReaderPNG, ILazImageReader)
|
|
private
|
|
FAlphaPalette: Boolean;
|
|
FUpdateDescription: Boolean;
|
|
public
|
|
function GetUpdateDescription: Boolean;
|
|
procedure SetUpdateDescription(AValue: Boolean);
|
|
function QueryInterface(constref iid: TGuid; out obj): LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
function _AddRef: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
function _Release: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
protected
|
|
procedure DoDecompress; override;
|
|
procedure HandleAlpha; override;
|
|
procedure InternalRead(Str:TStream; Img:TFPCustomImage); override;
|
|
public
|
|
property UpdateDescription: Boolean read GetUpdateDescription write SetUpdateDescription;
|
|
end;
|
|
|
|
{ TLazWriterPNG }
|
|
|
|
TLazWriterPNG = class(TFPWriterPNG, ILazImageWriter)
|
|
public
|
|
function QueryInterface(constref iid: TGuid; out obj): LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
function _AddRef: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
function _Release: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
public
|
|
procedure Initialize(AImage: TLazIntfImage);
|
|
procedure Finalize;
|
|
end;
|
|
|
|
{$IFNDEF DisableLCLTIFF}
|
|
|
|
{ TLazReaderTiff }
|
|
|
|
const
|
|
LazTiffExtraPrefix = 'LazTiff';
|
|
LazTiffHostComputer = LazTiffExtraPrefix + 'HostComputer';
|
|
LazTiffMake = LazTiffExtraPrefix + 'Make';
|
|
LazTiffModel = LazTiffExtraPrefix + 'Model';
|
|
LazTiffSoftware = LazTiffExtraPrefix + 'Software';
|
|
|
|
type
|
|
TLazReaderTiff = class(TFPReaderTiff, ILazImageReader)
|
|
private
|
|
FUpdateDescription: Boolean;
|
|
protected
|
|
procedure DoCreateImage(ImgFileDir: TTiffIFD); override;
|
|
public
|
|
function GetUpdateDescription: Boolean;
|
|
procedure SetUpdateDescription(AValue: Boolean);
|
|
function QueryInterface(constref iid: TGuid; out obj): LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
function _AddRef: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
function _Release: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
protected
|
|
procedure InternalRead(Str:TStream; Img:TFPCustomImage); override;
|
|
public
|
|
property UpdateDescription: Boolean read GetUpdateDescription write SetUpdateDescription;
|
|
end;
|
|
|
|
{ TLazWriterTiff }
|
|
|
|
TLazWriterTiff = class(TFPWriterTiff, ILazImageWriter)
|
|
public
|
|
function QueryInterface(constref iid: TGuid; out obj): LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
function _AddRef: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
function _Release: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
protected
|
|
procedure InternalWrite(Stream: TStream; Img: TFPCustomImage); override;
|
|
public
|
|
procedure Initialize(AImage: TLazIntfImage);
|
|
procedure Finalize;
|
|
end;
|
|
|
|
{$ENDIF} //DisableLCLTIFF
|
|
|
|
{ TLazReaderIcnsPart }
|
|
|
|
TLazReaderIcnsPart = class(TFPCustomImageReader, ILazImageReader)
|
|
private
|
|
FUpdateDescription: Boolean;
|
|
FPalette: TFPPalette;
|
|
FImage: TLazIntfImage;
|
|
FData: PByte;
|
|
FCalcSize: Integer;
|
|
FDataSize: Integer;
|
|
FIconType: TicnsIconType;
|
|
FIconInfo: TicnsIconInfo;
|
|
protected
|
|
function InternalCheck(Str:TStream): boolean; override;
|
|
procedure InternalRead(Stream: TStream; Img: TFPCustomImage); override;
|
|
procedure SetupRead(AWidth, AHeight, ADepth: Integer; IsMask: Boolean);
|
|
function Create256ColorPalette: TFPPalette;
|
|
procedure DoReadRaw;
|
|
procedure DoReadRLE;
|
|
procedure DoReadJpeg2000;
|
|
procedure DoReadMask;
|
|
public
|
|
function GetUpdateDescription: Boolean;
|
|
procedure SetUpdateDescription(AValue: Boolean);
|
|
function QueryInterface(constref iid: TGuid; out obj): LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
function _AddRef: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
function _Release: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
public
|
|
constructor Create; override;
|
|
destructor Destroy; override;
|
|
property UpdateDescription: Boolean read GetUpdateDescription write SetUpdateDescription;
|
|
property IconType: TicnsIconType read FIconType;
|
|
property DataSize: Integer read FDataSize;
|
|
end;
|
|
|
|
// extra Rawimage utility functions
|
|
|
|
function QueryDescription(AFlags: TRawImageQueryFlags; AWidth: Integer = -1; AHeight: integer = -1): TRawImageDescription;
|
|
procedure QueryDescription(var ADesc: TRawImageDescription; AFlags: TRawImageQueryFlags; AWidth: Integer = -1; AHeight: integer = -1);
|
|
function GetDescriptionFromDevice(ADC: HDC; AWidth: Integer = -1; AHeight: integer = -1): TRawImageDescription;
|
|
function GetDescriptionFromBitmap(ABitmap: HBitmap; AWidth: Integer = -1; AHeight: integer = -1): TRawImageDescription;
|
|
function AddAlphaToDescription(var ADesc: TRawImageDescription; APrec: Byte): Boolean;
|
|
|
|
|
|
procedure DefaultReaderDescription(AWidth, AHeight: Integer; ADepth: Byte; out ADesc: TRawImageDescription);
|
|
|
|
|
|
function ReadCompleteStreamToString(Str: TStream; StartSize: integer): string;
|
|
procedure ReadCompleteStreamToStream(SrcStream, DestStream: TStream;
|
|
StartSize: integer);
|
|
|
|
function dbgs(const FPColor: TFPColor): string; overload;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Graphics, LCLIntf;
|
|
|
|
type
|
|
PFPColorBytes = ^TFPColorBytes;
|
|
TFPColorBytes = record
|
|
{$ifdef ENDIAN_LITTLE}
|
|
Rl, Rh, Gl, Gh, Bl, Bh, Al, Ah: Byte;
|
|
{$else}
|
|
Rh, Rl, Gh, Gl, Bh, Bl, Ah, Al: Byte;
|
|
{$endif}
|
|
end;
|
|
|
|
PFourBytes = ^TFourBytes;
|
|
TFourBytes = record
|
|
B0, B1, B2, B3: Byte;
|
|
end;
|
|
|
|
|
|
var
|
|
IsSpaceChar, IsNumberChar, IsHexNumberChar: array[char] of Boolean;
|
|
|
|
function ReadCompleteStreamToString(Str: TStream; StartSize: integer): string;
|
|
var
|
|
NewLength: Integer;
|
|
ReadLen: Integer;
|
|
begin
|
|
if (Str is TMemoryStream) or (Str is TFileStream) or (Str is TStringStream)
|
|
then begin
|
|
// read as one block
|
|
SetLength(Result,Str.Size-Str.Position);
|
|
if Result<>'' then
|
|
Str.Read(Result[1],length(Result));
|
|
end else begin
|
|
// read exponential
|
|
if StartSize=0 then StartSize:=1024;
|
|
SetLength(Result,StartSize);
|
|
NewLength:=0;
|
|
repeat
|
|
ReadLen:=Str.Read(Result[NewLength+1],length(Result)-NewLength);
|
|
inc(NewLength,ReadLen);
|
|
if NewLength<length(Result) then break;
|
|
SetLength(Result,length(Result)*2);
|
|
until false;
|
|
SetLength(Result,NewLength);
|
|
end;
|
|
end;
|
|
|
|
procedure ReadCompleteStreamToStream(SrcStream, DestStream: TStream;
|
|
StartSize: integer);
|
|
var
|
|
NewLength: Integer;
|
|
ReadLen: Integer;
|
|
Buffer: string;
|
|
begin
|
|
if (SrcStream is TMemoryStream) or (SrcStream is TFileStream)
|
|
or (SrcStream is TStringStream)
|
|
then begin
|
|
// read as one block
|
|
if DestStream is TMemoryStream then
|
|
TMemoryStream(DestStream).SetSize(DestStream.Size
|
|
+(SrcStream.Size-SrcStream.Position));
|
|
DestStream.CopyFrom(SrcStream,SrcStream.Size-SrcStream.Position);
|
|
end else begin
|
|
// read exponential
|
|
if StartSize<=0 then StartSize:=1024;
|
|
SetLength(Buffer,StartSize);
|
|
NewLength:=0;
|
|
repeat
|
|
ReadLen:=SrcStream.Read(Buffer[NewLength+1],length(Buffer)-NewLength);
|
|
inc(NewLength,ReadLen);
|
|
if NewLength<length(Buffer) then break;
|
|
SetLength(Buffer,length(Buffer)*2);
|
|
until false;
|
|
if NewLength>0 then
|
|
DestStream.Write(Buffer[1],NewLength);
|
|
end;
|
|
end;
|
|
|
|
function dbgs(const FPColor: TFPColor): string;
|
|
begin
|
|
Result:='r='+hexStr(FPColor.Red,4)+',g='+hexStr(FPColor.green,4)
|
|
+',b='+hexStr(FPColor.blue,4)+',a='+hexStr(FPColor.alpha,4);
|
|
end;
|
|
|
|
function QueryDescription(AFlags: TRawImageQueryFlags; AWidth: Integer = -1; AHeight: integer = -1): TRawImageDescription;
|
|
begin
|
|
Exclude(AFlags, riqfUpdate);
|
|
Result{%H-}.Init;
|
|
QueryDescription(Result, AFlags, AWidth, AHeight);
|
|
end;
|
|
|
|
procedure QueryDescription(var ADesc: TRawImageDescription; AFlags: TRawImageQueryFlags; AWidth: Integer = -1; AHeight: integer = -1);
|
|
begin
|
|
if RawImage_QueryDescription(AFlags, ADesc)
|
|
then begin
|
|
if AWidth <> -1 then ADesc.Width := AWidth;
|
|
if AHeight <> -1 then ADesc.Height := AHeight;
|
|
end
|
|
else begin
|
|
if not (riqfUpdate in AFlags) then ADesc.Init;
|
|
end;
|
|
end;
|
|
|
|
function GetDescriptionFromDevice(ADC: HDC; AWidth, AHeight: integer): TRawImageDescription;
|
|
begin
|
|
Result{%H-}.Init;
|
|
if not RawImage_DescriptionFromDevice(ADC, Result) then Exit;
|
|
if AWidth <> -1 then Result.Width := AWidth;
|
|
if AHeight <> -1 then Result.Height := AHeight;
|
|
end;
|
|
|
|
function GetDescriptionFromBitmap(ABitmap: HBitmap; AWidth: Integer = -1; AHeight: integer = -1): TRawImageDescription;
|
|
begin
|
|
Result{%H-}.Init;
|
|
if not RawImage_DescriptionFromBitmap(ABitmap, Result) then Exit;
|
|
if AWidth <> -1 then Result.Width := AWidth;
|
|
if AHeight <> -1 then Result.Height := AHeight;
|
|
end;
|
|
|
|
function AddAlphaToDescription(var ADesc: TRawImageDescription; APrec: Byte): Boolean;
|
|
function CreateBitMask(AShift, APrec: Byte): Cardinal; inline;
|
|
begin
|
|
Result := ($FFFFFFFF shr (32 - APrec)) shl AShift;
|
|
end;
|
|
var
|
|
Mask: Cardinal;
|
|
begin
|
|
Result:=false;
|
|
if ADesc.AlphaPrec >= APrec then Exit;
|
|
if ADesc.BitsPerPixel <> 32 then Exit;
|
|
if ADesc.Depth <> 24 then Exit;
|
|
|
|
Mask := CreateBitMask(ADesc.RedShift, ADesc.RedPrec)
|
|
or CreateBitMask(ADesc.GreenShift, ADesc.GreenPrec)
|
|
or CreateBitMask(ADesc.BlueShift, ADesc.BluePrec);
|
|
|
|
if (Mask and $FF = 0)
|
|
then begin
|
|
ADesc.AlphaShift := 0;
|
|
Result := True;
|
|
end
|
|
else
|
|
if (Mask and $FF000000 = 0)
|
|
then begin
|
|
ADesc.AlphaShift := 24;
|
|
Result := True;
|
|
end;
|
|
if Result
|
|
then begin
|
|
ADesc.AlphaPrec := APrec;
|
|
ADesc.Depth := 32;
|
|
end;
|
|
end;
|
|
|
|
procedure CheckAlphaDescription(AImage: TFPCustomImage);
|
|
var
|
|
Desc: TRawImageDescription;
|
|
begin
|
|
if not (AImage is TLazIntfImage) then Exit;
|
|
|
|
Desc := TLazIntfImage(AImage).DataDescription;
|
|
if Desc.AlphaPrec >= 8 then Exit;
|
|
|
|
if not AddAlphaToDescription(Desc, 8)
|
|
then begin
|
|
Desc.Init_BPP32_B8G8R8A8_BIO_TTB(Desc.Width, Desc.Height);
|
|
// copy mask description
|
|
with TLazIntfImage(AImage).DataDescription do
|
|
begin
|
|
Desc.MaskBitsPerPixel := MaskBitsPerPixel;
|
|
Desc.MaskShift := MaskShift;
|
|
Desc.MaskLineEnd := MaskLineEnd;
|
|
Desc.MaskBitOrder := MaskBitOrder;
|
|
end;
|
|
end;
|
|
|
|
TLazIntfImage(AImage).DataDescription := Desc;
|
|
end;
|
|
|
|
procedure DefaultReaderDescription(AWidth, AHeight: Integer; ADepth: Byte; out ADesc: TRawImageDescription);
|
|
begin
|
|
// Default description, assume 24bit for palettebased
|
|
// Maybe when RawImage palette is supported, other descriptions need to be adjusted.
|
|
|
|
ADesc.Init_BPP24_B8G8R8_M1_BIO_TTB(AWidth, AHeight);
|
|
|
|
case ADepth of
|
|
1: begin
|
|
ADesc.Depth := 1;
|
|
ADesc.BitsPerPixel := 1;
|
|
ADesc.Format := ricfGray;
|
|
ADesc.LineEnd := rileWordBoundary;
|
|
ADesc.RedPrec := 1;
|
|
ADesc.RedShift := 0;
|
|
ADesc.GreenPrec := 1;
|
|
ADesc.GreenShift := 0;
|
|
ADesc.BluePrec := 1;
|
|
ADesc.BlueShift := 0;
|
|
end;
|
|
2..4: begin
|
|
// ADesc.Depth := 4;
|
|
// ADesc.BitsPerPixel := 4;
|
|
end;
|
|
5..8: begin
|
|
// ADesc.Depth := 8;
|
|
// ADesc.BitsPerPixel := 8;
|
|
end;
|
|
9..15: begin
|
|
ADesc.Depth := 15;
|
|
ADesc.BitsPerPixel := 16;
|
|
ADesc.RedPrec := 5;
|
|
ADesc.RedShift := 10;
|
|
ADesc.GreenPrec := 5;
|
|
ADesc.GreenShift := 5;
|
|
ADesc.BluePrec := 5;
|
|
ADesc.BlueShift := 0;
|
|
end;
|
|
16: begin
|
|
ADesc.Depth := 16;
|
|
ADesc.BitsPerPixel := 16;
|
|
ADesc.RedPrec := 5;
|
|
ADesc.RedShift := 10;
|
|
ADesc.GreenPrec := 6;
|
|
ADesc.GreenShift := 5;
|
|
ADesc.BluePrec := 5;
|
|
ADesc.BlueShift := 0;
|
|
end;
|
|
17..24: begin
|
|
// already default
|
|
end;
|
|
else
|
|
ADesc.Depth := 32;
|
|
ADesc.BitsPerPixel := 32;
|
|
ADesc.AlphaPrec := 8;
|
|
ADesc.AlphaShift := 24;
|
|
end;
|
|
end;
|
|
|
|
// ReadRawImageBits_* routines are called multiple times, once for each channel
|
|
// Therefore Shift means the Shift in the raw image of the channel
|
|
// TheData points to beginning of the image data
|
|
// Position is the position in bytes to the start of the pixel in TheData
|
|
// Prec is the precision of the channel
|
|
// Bits is the value of the channel, which is the output
|
|
|
|
|
|
procedure ReadRawImageBits_1_2_4_BIO(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal;
|
|
var Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
OneByte: Byte;
|
|
begin
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
P:=@(TheData[Position.Byte]);
|
|
|
|
OneByte:=P^;
|
|
Bits:=Word(cardinal(OneByte shr (Shift+Position.Bit)) and PrecMask);
|
|
|
|
if Prec<16 then begin
|
|
// add missing bits
|
|
Bits:=(Bits shl (16-Prec));
|
|
Bits:=Bits or MissingBits[Prec,Bits shr 13];
|
|
end;
|
|
end;
|
|
|
|
procedure ReadRawImageBits_1_2_4_BNIO(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal;
|
|
var Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
OneByte: Byte;
|
|
begin
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
P:=@(TheData[Position.Byte]);
|
|
|
|
OneByte:=P^;
|
|
Bits:=Word(cardinal(OneByte shr (Shift+7-Position.Bit)) and PrecMask);
|
|
|
|
if Prec<16 then begin
|
|
// add missing bits
|
|
Bits:=(Bits shl (16-Prec));
|
|
Bits:=Bits or MissingBits[Prec,Bits shr 13];
|
|
end;
|
|
end;
|
|
|
|
procedure ReadRawImageBits_8(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal;
|
|
var Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
OneByte: Byte;
|
|
begin
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
P:=@(TheData[Position.Byte]);
|
|
|
|
OneByte:=P^;
|
|
Bits:=Word(cardinal(OneByte shr Shift) and PrecMask);
|
|
|
|
if Prec<16 then begin
|
|
// add missing bits
|
|
Bits:=(Bits shl (16-Prec));
|
|
Bits:=Bits or MissingBits[Prec,Bits shr 13];
|
|
end;
|
|
end;
|
|
|
|
procedure ReadRawImageBits_16(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal;
|
|
var Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
TwoBytes: Word;
|
|
begin
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
P:=@(TheData[Position.Byte]);
|
|
|
|
TwoBytes:=PWord(P)^;
|
|
Bits:=Word(cardinal(TwoBytes shr Shift) and PrecMask);
|
|
|
|
if Prec<16 then begin
|
|
// add missing bits
|
|
Bits:=(Bits shl (16-Prec));
|
|
Bits:=Bits or MissingBits[Prec,Bits shr 13];
|
|
end;
|
|
end;
|
|
|
|
procedure ReadRawImageBits_ReversedBytes_16(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal;
|
|
var Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
TwoBytes: Word;
|
|
begin
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
P:=@(TheData[Position.Byte]);
|
|
|
|
TwoBytes:=PWord(P)^;
|
|
TwoBytes:=(TwoBytes shr 8) or ((TwoBytes and $ff) shl 8); // switch byte order
|
|
Bits:=Word(cardinal(TwoBytes shr Shift) and PrecMask);
|
|
|
|
if Prec<16 then begin
|
|
// add missing bits
|
|
Bits:=(Bits shl (16-Prec));
|
|
Bits:=Bits or MissingBits[Prec,Bits shr 13];
|
|
end;
|
|
end;
|
|
|
|
procedure ReadRawImageBits_24(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal;
|
|
var Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
FourBytes: Cardinal;
|
|
begin
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
P:=@(TheData[Position.Byte]);
|
|
|
|
{$ifdef Endian_Little}
|
|
FourBytes:=DWord(PWord(P)^) or (DWord((P+2)^) shl 16);
|
|
{$else}
|
|
FourBytes:=(DWord(PWord(P)^) shl 8) or DWord((P+2)^);
|
|
{$endif}
|
|
Bits:=Word(cardinal(FourBytes shr Shift) and PrecMask);
|
|
|
|
if Prec<16 then begin
|
|
// add missing bits
|
|
Bits:=(Bits shl (16-Prec));
|
|
Bits:=Bits or MissingBits[Prec,Bits shr 13];
|
|
end;
|
|
end;
|
|
|
|
procedure ReadRawImageBits_ReversedBytes_24(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal;
|
|
var Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
FourBytes: Cardinal;
|
|
begin
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
P:=@(TheData[Position.Byte]);
|
|
|
|
{$ifdef Endian_Little}
|
|
FourBytes:=(DWord(PWord(P)^) shl 8) or DWord((P+2)^);
|
|
{$else}
|
|
FourBytes:=DWord(PWord(P)^) or (DWord((P+2)^) shl 16);
|
|
{$endif}
|
|
|
|
Bits:=Word(cardinal(FourBytes shr Shift) and PrecMask);
|
|
|
|
if Prec<16 then begin
|
|
// add missing bits
|
|
Bits:=(Bits shl (16-Prec));
|
|
Bits:=Bits or MissingBits[Prec,Bits shr 13];
|
|
end;
|
|
end;
|
|
|
|
procedure ReadRawImageBits_32(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal;
|
|
var Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
FourBytes: Cardinal;
|
|
begin
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
P:=@(TheData[Position.Byte]);
|
|
|
|
FourBytes:=PDWord(P)^;
|
|
Bits:=Word(cardinal(FourBytes shr Shift) and PrecMask);
|
|
|
|
if Prec<16 then begin
|
|
// add missing bits
|
|
Bits:=(Bits shl (16-Prec));
|
|
Bits:=Bits or MissingBits[Prec,Bits shr 13];
|
|
end;
|
|
end;
|
|
|
|
procedure ReadRawImageBits_ReversedBytes_32(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal;
|
|
var Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
FourBytes: Cardinal;
|
|
begin
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
P:=@(TheData[Position.Byte]);
|
|
|
|
FourBytes:=PDWord(P)^;
|
|
|
|
// switch byte order
|
|
FourBytes:=(FourBytes shr 24) or ((FourBytes shr 8) and $FF00)
|
|
or ((FourBytes and $ff00) shl 8) or ((FourBytes and $ff) shl 24);
|
|
|
|
Bits:=Word(cardinal(FourBytes shr Shift) and PrecMask);
|
|
|
|
if Prec<16 then begin
|
|
// add missing bits
|
|
Bits:=(Bits shl (16-Prec));
|
|
Bits:=Bits or MissingBits[Prec,Bits shr 13];
|
|
end;
|
|
end;
|
|
|
|
procedure ReadRawImageBits_48(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal;
|
|
var Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
EightBytes: QWord;
|
|
begin
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
P:=@(TheData[Position.Byte]);
|
|
|
|
{$ifdef Endian_Little}
|
|
EightBytes:=QWord(PDWord(P)^) or (QWord(PWord(P+4)^) shl 32);
|
|
{$else}
|
|
EightBytes:=(QWord(PDWord(P)^) shl 16) or QWord(PWord(P+4)^);
|
|
{$endif}
|
|
Bits:=Word(cardinal(EightBytes shr Shift) and PrecMask);
|
|
|
|
if Prec<16 then begin
|
|
// add missing bits
|
|
Bits:=(Bits shl (16-Prec));
|
|
Bits:=Bits or MissingBits[Prec,Bits shr 13];
|
|
end;
|
|
end;
|
|
|
|
procedure ReadRawImageBits_ReversedBytes_48(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal;
|
|
var Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
EightBytes: QWord;
|
|
begin
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
P:=@(TheData[Position.Byte]);
|
|
|
|
{$ifdef Endian_Little}
|
|
EightBytes:=(QWord(PDWord(P)^) shl 16) or QWord(PWord(P+4)^);
|
|
{$else}
|
|
EightBytes:=QWord(PDWord(P)^) or (QWord(PWord(P+4)^) shl 32);
|
|
{$endif}
|
|
Bits:=Word(cardinal(EightBytes shr Shift) and PrecMask);
|
|
|
|
if Prec<16 then begin
|
|
// add missing bits
|
|
Bits:=(Bits shl (16-Prec));
|
|
Bits:=Bits or MissingBits[Prec,Bits shr 13];
|
|
end;
|
|
end;
|
|
|
|
procedure ReadRawImageBits_64(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal;
|
|
var Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
EightBytes: QWord;
|
|
begin
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
P:=@(TheData[Position.Byte]);
|
|
|
|
EightBytes:=PQWord(P)^;
|
|
Bits:=Word(Cardinal(EightBytes shr Shift) and PrecMask);
|
|
|
|
if Prec<16 then begin
|
|
// add missing bits
|
|
Bits:=(Bits shl (16-Prec));
|
|
Bits:=Bits or MissingBits[Prec,Bits shr 13];
|
|
end;
|
|
end;
|
|
|
|
procedure ReadRawImageBits_ReversedBytes_64(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal;
|
|
var Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
EightBytes: QWord;
|
|
begin
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
P:=@(TheData[Position.Byte]);
|
|
|
|
EightBytes:=PQWord(P)^;
|
|
|
|
// switch byte order
|
|
EightBytes:=swapendian(EightBytes);
|
|
|
|
Bits:=Word(Cardinal(EightBytes shr Shift) and PrecMask);
|
|
|
|
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_1_2_4_BIO(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal; Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
OneByte: Byte;
|
|
ShiftLeft: Integer;
|
|
begin
|
|
P:=@(TheData[Position.Byte]);
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
Bits:=Bits shr (16-Prec);
|
|
|
|
OneByte:=P^;
|
|
ShiftLeft:=Shift+Position.Bit;
|
|
PrecMask:=not (PrecMask shl ShiftLeft);
|
|
OneByte:=OneByte and PrecMask; // clear old
|
|
OneByte:=OneByte or (Bits shl ShiftLeft); // set new
|
|
P^:=OneByte;
|
|
end;
|
|
|
|
procedure WriteRawImageBits_1_2_4_BNIO(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal; Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
OneByte: Byte;
|
|
ShiftLeft: Integer;
|
|
begin
|
|
P:=@(TheData[Position.Byte]);
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
Bits:=Bits shr (16-Prec);
|
|
|
|
OneByte:=P^;
|
|
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;
|
|
end;
|
|
|
|
procedure WriteRawImageBits_8(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal; Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
OneByte: Byte;
|
|
begin
|
|
P:=@(TheData[Position.Byte]);
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
Bits:=Bits shr (16-Prec);
|
|
|
|
OneByte:=P^;
|
|
PrecMask:=not (PrecMask shl Shift);
|
|
OneByte:=OneByte and PrecMask; // clear old
|
|
OneByte:=OneByte or (Bits shl Shift); // set new
|
|
P^:=OneByte;
|
|
end;
|
|
|
|
procedure WriteRawImageBits_16(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal; Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
TwoBytes: Word;
|
|
begin
|
|
P:=@(TheData[Position.Byte]);
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
Bits:=Bits shr (16-Prec);
|
|
|
|
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;
|
|
end;
|
|
|
|
procedure WriteRawImageBits_ReversedBytes_16(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal; Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
TwoBytes: Word;
|
|
begin
|
|
P:=@(TheData[Position.Byte]);
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
Bits:=Bits shr (16-Prec);
|
|
|
|
TwoBytes:=PWord(P)^;
|
|
TwoBytes:=(TwoBytes shr 8) or ((TwoBytes and $ff) shl 8); // switch byte order
|
|
PrecMask:=not (PrecMask shl Shift);
|
|
TwoBytes:=TwoBytes and PrecMask; // clear old
|
|
TwoBytes:=TwoBytes or (Bits shl Shift); // set new
|
|
TwoBytes:=(TwoBytes shr 8) or ((TwoBytes and $ff) shl 8); // switch byte order
|
|
PWord(P)^:=TwoBytes;
|
|
end;
|
|
|
|
procedure WriteRawImageBits_24(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal; Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
FourBytes: Cardinal;
|
|
begin
|
|
P:=@(TheData[Position.Byte]);
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
Bits:=Bits shr (16-Prec);
|
|
|
|
{$ifdef Endian_Little}
|
|
FourBytes:=DWord(PWord(P)^) or (DWord((P+2)^) shl 16);
|
|
{$else}
|
|
FourBytes:=(DWord(PWord(P)^) shl 8) or DWord((P+2)^);
|
|
{$endif}
|
|
|
|
PrecMask:=not (PrecMask shl Shift);
|
|
FourBytes:=FourBytes and PrecMask; // clear old
|
|
FourBytes:=FourBytes or cardinal(Bits shl Shift); // set new
|
|
|
|
{$ifdef Endian_little}
|
|
PWord(P)^ := Word(FourBytes);
|
|
P[2] := Byte(FourBytes shr 16);
|
|
{$else}
|
|
PWord(P)^ := Word(FourBytes shr 8);
|
|
P[2] := Byte(FourBytes);
|
|
{$endif}
|
|
end;
|
|
|
|
procedure WriteRawImageBits_ReversedBytes_24(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal; Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
FourBytes: Cardinal;
|
|
begin
|
|
P:=@(TheData[Position.Byte]);
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
Bits:=Bits shr (16-Prec);
|
|
|
|
{$ifdef Endian_Little}
|
|
FourBytes:=(DWord(PWord(P)^) shl 8) or DWord(P^);
|
|
{$else}
|
|
FourBytes:=DWord(PWord(P)^) or (DWord((P+2)^) shl 16);
|
|
{$endif}
|
|
|
|
PrecMask:=not (PrecMask shl Shift);
|
|
FourBytes:=FourBytes and PrecMask; // clear old
|
|
FourBytes:=FourBytes or cardinal(Bits shl Shift); // set new
|
|
|
|
{$ifdef Endian_little}
|
|
PWord(P)^ := Word(FourBytes shr 8);
|
|
P^ := Byte(FourBytes);
|
|
{$else}
|
|
PWord(P)^ := Word(FourBytes);
|
|
(P+2)^ := Byte(FourBytes shr 16);
|
|
{$endif}
|
|
end;
|
|
|
|
procedure WriteRawImageBits_32(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal; Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
FourBytes: Cardinal;
|
|
begin
|
|
if Prec=16
|
|
then begin
|
|
// fast update
|
|
P:=@(TheData[Position.Byte]);
|
|
inc(P,2-Shift shr 3);
|
|
PWORD(P)^:=Bits;
|
|
Exit;
|
|
end;
|
|
|
|
P:=@(TheData[Position.Byte]);
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
Bits:=Bits shr (16-Prec);
|
|
|
|
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;
|
|
end;
|
|
|
|
procedure WriteRawImageBits_ReversedBytes_32(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal; Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: Cardinal;
|
|
FourBytes: Cardinal;
|
|
begin
|
|
P:=@(TheData[Position.Byte]);
|
|
PrecMask:=(Cardinal(1) shl Prec)-1;
|
|
Bits:=Bits shr (16-Prec);
|
|
|
|
FourBytes:=PDWord(P)^;
|
|
|
|
// switch byte order
|
|
FourBytes:=(FourBytes shr 24) or ((FourBytes shr 8) and $FF00)
|
|
or ((FourBytes and $ff00) shl 8) or ((FourBytes and $ff) shl 24);
|
|
|
|
PrecMask:=not (PrecMask shl Shift);
|
|
FourBytes:=FourBytes and PrecMask; // clear old
|
|
FourBytes:=FourBytes or cardinal(Bits shl Shift); // set new
|
|
|
|
// switch byte order
|
|
FourBytes:=(FourBytes shr 24) or ((FourBytes shr 8) and $FF00)
|
|
or ((FourBytes and $ff00) shl 8) or ((FourBytes and $ff) shl 24);
|
|
PDWord(P)^:=FourBytes;
|
|
end;
|
|
|
|
procedure WriteRawImageBits_48(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal; Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: QWord;
|
|
EightBytes: QWord;
|
|
begin
|
|
P:=@(TheData[Position.Byte]);
|
|
PrecMask:=(QWord(1) shl Prec)-1;
|
|
Bits:=Bits shr (16-Prec);
|
|
|
|
{$ifdef Endian_Little}
|
|
EightBytes:=QWord(PDWord(P)^) or (QWord(PWord(P+4)^) shl 32);
|
|
{$else}
|
|
EightBytes:=(QWord(PDWord(P)^) shl 16) or QWord(PWord(P+4)^);
|
|
{$endif}
|
|
|
|
PrecMask:=not (PrecMask shl Shift);
|
|
EightBytes:=EightBytes and PrecMask; // clear old
|
|
EightBytes:=EightBytes or QWord(Bits) shl Shift; // set new
|
|
|
|
{$ifdef Endian_little}
|
|
PDWord(P)^ := DWord(EightBytes);
|
|
PWord(P+4)^ := Word(EightBytes shr 32);
|
|
{$else}
|
|
PDWord(P)^ := DWord(EightBytes shr 16);
|
|
PWord(P+4)^ := Word(EightBytes);
|
|
{$endif}
|
|
end;
|
|
|
|
procedure WriteRawImageBits_ReversedBytes_48(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal; Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: QWord;
|
|
EightBytes: QWord;
|
|
begin
|
|
P:=@(TheData[Position.Byte]);
|
|
PrecMask:=(QWord(1) shl Prec)-1;
|
|
Bits:=Bits shr (16-Prec);
|
|
|
|
{$ifdef Endian_Little}
|
|
EightBytes:=(QWord(PDWord(P)^) shl 16) or QWord(PWord(P+4)^);
|
|
{$else}
|
|
EightBytes:=QWord(PDWord(P)^) or (QWord(PWord(P+4)^) shl 32);
|
|
{$endif}
|
|
|
|
PrecMask:=not (PrecMask shl Shift);
|
|
EightBytes:=EightBytes and PrecMask; // clear old
|
|
EightBytes:=EightBytes or QWord(Bits) shl Shift; // set new
|
|
|
|
{$ifdef Endian_little}
|
|
PDWord(P)^ := DWord(EightBytes shr 16);
|
|
PWord(P+4)^ := Word(EightBytes);
|
|
{$else}
|
|
PDWord(P)^ := DWord(EightBytes);
|
|
PWord(P+4)^ := Word(EightBytes shr 32);
|
|
{$endif}
|
|
end;
|
|
|
|
procedure WriteRawImageBits_64(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal; Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: QWord;
|
|
EightBytes: QWord;
|
|
begin
|
|
P:=@(TheData[Position.Byte]);
|
|
PrecMask:=(Qword(1) shl Prec)-1;
|
|
Bits:=Bits shr (16-Prec);
|
|
|
|
EightBytes:=PQWord(P)^;
|
|
PrecMask:=not (PrecMask shl Shift);
|
|
EightBytes:=EightBytes and PrecMask; // clear old
|
|
EightBytes:=EightBytes or QWord(Bits) shl Shift; // set new
|
|
PQWord(P)^:=EightBytes;
|
|
end;
|
|
|
|
procedure WriteRawImageBits_ReversedBytes_64(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal; Bits: word);
|
|
var
|
|
P: PByte;
|
|
PrecMask: QWord;
|
|
EightBytes: QWord;
|
|
begin
|
|
P:=@(TheData[Position.Byte]);
|
|
PrecMask:=(QWord(1) shl Prec)-1;
|
|
Bits:=Bits shr (16-Prec);
|
|
|
|
EightBytes:=PQWord(P)^;
|
|
|
|
// switch byte order
|
|
EightBytes:=swapendian(EightBytes);
|
|
|
|
PrecMask:=not (PrecMask shl Shift);
|
|
EightBytes:=EightBytes and PrecMask; // clear old
|
|
EightBytes:=EightBytes or QWord(Bits) shl Shift; // set new
|
|
|
|
// switch byte order
|
|
EightBytes:=swapendian(EightBytes);
|
|
PQWord(P)^:=EightBytes;
|
|
end;
|
|
|
|
|
|
procedure ReadRawImageBits_NULL(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal;
|
|
var Bits: word);
|
|
begin
|
|
Bits:=0;
|
|
|
|
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_NULL(TheData: PByte;
|
|
const Position: TRawImagePosition;
|
|
Prec, Shift: cardinal; Bits: word);
|
|
begin
|
|
end;
|
|
|
|
{ TLazIntfImage }
|
|
|
|
procedure TLazIntfImage.SetDataDescription(const ADescription: TRawImageDescription);
|
|
begin
|
|
if CompareMem(@FRawImage.Description, @ADescription, SizeOf(TRawImageDescription))
|
|
then Exit;
|
|
|
|
CheckDescription(ADescription, True);
|
|
BeginUpdate;
|
|
try
|
|
FreeData;
|
|
FRawImage.Description := ADescription;
|
|
ChooseGetSetColorFunctions;
|
|
InternalSetSize(ADescription.Width, ADescription.Height);
|
|
CreateData;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.ChooseRawBitsProc(BitsPerPixel: cardinal;
|
|
ByteOrder: TRawImageByteOrder; BitOrder: TRawImageBitOrder;
|
|
out ProcReadRawImageBits: TOnReadRawImageBits;
|
|
out ProcWriteRawImageBits: TOnWriteRawImageBits);
|
|
begin
|
|
case BitsPerPixel of
|
|
|
|
1,2,4:
|
|
begin
|
|
if BitOrder = riboBitsInOrder then
|
|
begin
|
|
ProcReadRawImageBits := @ReadRawImageBits_1_2_4_BIO;
|
|
ProcWriteRawImageBits := @WriteRawImageBits_1_2_4_BIO;
|
|
end else begin
|
|
ProcReadRawImageBits := @ReadRawImageBits_1_2_4_BNIO;
|
|
ProcWriteRawImageBits := @WriteRawImageBits_1_2_4_BNIO;
|
|
end;
|
|
end;
|
|
|
|
8:
|
|
begin
|
|
ProcReadRawImageBits := @ReadRawImageBits_8;
|
|
ProcWriteRawImageBits := @WriteRawImageBits_8;
|
|
end;
|
|
|
|
16:
|
|
begin
|
|
if DefaultByteOrder=ByteOrder then begin
|
|
ProcReadRawImageBits := @ReadRawImageBits_16;
|
|
ProcWriteRawImageBits := @WriteRawImageBits_16;
|
|
end else begin
|
|
ProcReadRawImageBits := @ReadRawImageBits_ReversedBytes_16;
|
|
ProcWriteRawImageBits := @WriteRawImageBits_ReversedBytes_16;
|
|
end;
|
|
end;
|
|
|
|
24:
|
|
begin
|
|
if DefaultByteOrder=ByteOrder then begin
|
|
ProcReadRawImageBits := @ReadRawImageBits_24;
|
|
ProcWriteRawImageBits := @WriteRawImageBits_24;
|
|
end else begin
|
|
ProcReadRawImageBits := @ReadRawImageBits_ReversedBytes_24;
|
|
ProcWriteRawImageBits := @WriteRawImageBits_ReversedBytes_24;
|
|
end;
|
|
end;
|
|
|
|
32:
|
|
begin
|
|
if DefaultByteOrder=ByteOrder then begin
|
|
ProcReadRawImageBits := @ReadRawImageBits_32;
|
|
ProcWriteRawImageBits := @WriteRawImageBits_32;
|
|
end else begin
|
|
ProcReadRawImageBits := @ReadRawImageBits_ReversedBytes_32;
|
|
ProcWriteRawImageBits := @WriteRawImageBits_ReversedBytes_32;
|
|
end;
|
|
end;
|
|
|
|
48:
|
|
begin
|
|
if DefaultByteOrder=ByteOrder then begin
|
|
ProcReadRawImageBits := @ReadRawImageBits_48;
|
|
ProcWriteRawImageBits := @WriteRawImageBits_48;
|
|
end else begin
|
|
ProcReadRawImageBits := @ReadRawImageBits_ReversedBytes_48;
|
|
ProcWriteRawImageBits := @WriteRawImageBits_ReversedBytes_48;
|
|
end;
|
|
end;
|
|
|
|
64:
|
|
begin
|
|
if DefaultByteOrder=ByteOrder then begin
|
|
ProcReadRawImageBits := @ReadRawImageBits_64;
|
|
ProcWriteRawImageBits := @WriteRawImageBits_64;
|
|
end else begin
|
|
ProcReadRawImageBits := @ReadRawImageBits_ReversedBytes_64;
|
|
ProcWriteRawImageBits := @WriteRawImageBits_ReversedBytes_64;
|
|
end;
|
|
end;
|
|
|
|
else
|
|
{$IFNDEF DisableChecks}
|
|
DebugLn('WARNING: TLazIntfImage.ChooseRawBitsProc Unsupported BitsPerPixel=',dbgs(BitsPerPixel));
|
|
{$ENDIF}
|
|
ProcReadRawImageBits := @ReadRawImageBits_NULL;
|
|
ProcWriteRawImageBits := @WriteRawImageBits_NULL;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.ChooseGetSetColorFunctions;
|
|
|
|
function ChooseRGBA_32Bpp: Boolean;
|
|
var
|
|
Positions: Byte;
|
|
begin
|
|
Result := False;
|
|
with FRawImage.Description do
|
|
begin
|
|
if Depth <> 32 then Exit;
|
|
if BitsPerPixel <> 32 then Exit;
|
|
if LineOrder <> riloTopToBottom then Exit;
|
|
if AlphaPrec <> 8 then Exit;
|
|
if RedPrec <> 8 then Exit;
|
|
if GreenPrec <> 8 then Exit;
|
|
if BluePrec <> 8 then Exit;
|
|
if AlphaShift and 7 <> 0 then Exit;
|
|
if RedShift and 7 <> 0 then Exit;
|
|
if GreenShift and 7 <> 0 then Exit;
|
|
if BlueShift and 7 <> 0 then Exit;
|
|
|
|
Positions := (((AlphaShift shr 3) and 3) shl 6
|
|
or ((RedShift shr 3) and 3) shl 4
|
|
or ((GreenShift shr 3) and 3) shl 2
|
|
or ((BlueShift shr 3) and 3)) and $FF;
|
|
|
|
if ByteOrder = riboMSBFirst
|
|
then Positions := not Positions; // reverse positions
|
|
end;
|
|
|
|
// the locations of A,R,G,B are now coded in 2 bits each: AARRGGBB
|
|
// the 2-bit value (0..3) represents the location of the channel,
|
|
// counting from left
|
|
case Positions of
|
|
{AARRGGBB}
|
|
%00011011: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_A8R8G8B8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_A8R8G8B8_BIO_TTB;
|
|
end;
|
|
{AARRGGBB}
|
|
%00111001: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_A8B8G8R8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_A8B8G8R8_BIO_TTB;
|
|
end;
|
|
{AARRGGBB}
|
|
%00100111: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_A8G8R8B8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_A8G8R8B8_BIO_TTB;
|
|
end;
|
|
{AARRGGBB}
|
|
%00110110: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_A8G8B8R8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_A8G8B8R8_BIO_TTB;
|
|
end;
|
|
{AARRGGBB}
|
|
%00011110: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_A8R8B8G8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_A8R8B8G8_BIO_TTB;
|
|
end;
|
|
{AARRGGBB}
|
|
%00101101: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_A8B8R8G8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_A8B8R8G8_BIO_TTB;
|
|
end;
|
|
{AARRGGBB}
|
|
%11100100: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_B8G8R8A8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_B8G8R8A8_BIO_TTB;
|
|
end;
|
|
{AARRGGBB}
|
|
%11000110: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_R8G8B8A8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_R8G8B8A8_BIO_TTB;
|
|
end;
|
|
{AARRGGBB}
|
|
%11100001: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_G8B8R8A8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_G8B8R8A8_BIO_TTB;
|
|
end;
|
|
{AARRGGBB}
|
|
%11010010: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_G8R8B8A8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_G8R8B8A8_BIO_TTB;
|
|
end;
|
|
{AARRGGBB}
|
|
%11011000: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_B8R8G8A8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_B8R8G8A8_BIO_TTB;
|
|
end;
|
|
{AARRGGBB}
|
|
%11001001: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_R8B8G8A8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_R8B8G8A8_BIO_TTB;
|
|
end;
|
|
else
|
|
Exit;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function ChooseRGB_32Bpp: Boolean;
|
|
var
|
|
Positions: Byte;
|
|
begin
|
|
Result := False;
|
|
with FRawImage.Description do
|
|
begin
|
|
if Depth <> 24 then Exit;
|
|
if BitsPerPixel <> 32 then Exit;
|
|
if LineOrder <> riloTopToBottom then Exit;
|
|
if RedPrec <> 8 then Exit;
|
|
if GreenPrec <> 8 then Exit;
|
|
if BluePrec <> 8 then Exit;
|
|
if RedShift and 7 <> 0 then Exit;
|
|
if GreenShift and 7 <> 0 then Exit;
|
|
if BlueShift and 7 <> 0 then Exit;
|
|
|
|
Positions := (((RedShift shr 3) and 3) shl 4
|
|
or ((GreenShift shr 3) and 3) shl 2
|
|
or ((BlueShift shr 3) and 3)) and $FF;
|
|
|
|
if ByteOrder = riboMSBFirst
|
|
then Positions := not Positions and %00111111; // reverse positions
|
|
end;
|
|
|
|
// the locations of R,G,B are now coded in 2 bits each: xxRRBBGG
|
|
// the 2-bit value (0..3) represents the location of the channel,
|
|
// counting from left
|
|
case Positions of
|
|
{xxRRGGBB}
|
|
%00011011: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_X8R8G8B8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_X8R8G8B8_BIO_TTB;
|
|
end;
|
|
{xxRRGGBB}
|
|
%00111001: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_X8B8G8R8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_X8B8G8R8_BIO_TTB;
|
|
end;
|
|
{xxRRGGBB}
|
|
%00100111: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_X8G8R8B8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_X8G8R8B8_BIO_TTB;
|
|
end;
|
|
{xxRRGGBB}
|
|
%00110110: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_X8G8B8R8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_X8G8B8R8_BIO_TTB;
|
|
end;
|
|
{xxRRGGBB}
|
|
%00011110: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_X8R8B8G8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_X8R8B8G8_BIO_TTB;
|
|
end;
|
|
{xxRRGGBB}
|
|
%00101101: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_X8B8R8G8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_X8B8R8G8_BIO_TTB;
|
|
end;
|
|
{xxRRGGBB}
|
|
%00100100: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_B8G8R8X8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_B8G8R8X8_BIO_TTB;
|
|
end;
|
|
{xxRRGGBB}
|
|
%00000110: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_R8G8B8X8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_R8G8B8X8_BIO_TTB;
|
|
end;
|
|
{xxRRGGBB}
|
|
%00100001: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_G8B8R8X8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_G8B8R8X8_BIO_TTB;
|
|
end;
|
|
{xxRRGGBB}
|
|
%00010010: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_G8R8B8X8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_G8R8B8X8_BIO_TTB;
|
|
end;
|
|
{xxRRGGBB}
|
|
%00011000: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_B8R8G8X8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_B8R8G8X8_BIO_TTB;
|
|
end;
|
|
{xxRRGGBB}
|
|
%00001001: begin
|
|
FGetInternalColorProc := @GetColor_BPP32_R8B8G8X8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP32_R8B8G8X8_BIO_TTB;
|
|
end;
|
|
else
|
|
Exit;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function ChooseRGB_24Bpp: Boolean;
|
|
var
|
|
Positions: Byte;
|
|
begin
|
|
Result := False;
|
|
with FRawImage.Description do
|
|
begin
|
|
if Depth <> 24 then Exit;
|
|
if BitsPerPixel <> 24 then Exit;
|
|
if LineOrder <> riloTopToBottom then Exit;
|
|
if RedPrec <> 8 then Exit;
|
|
if GreenPrec <> 8 then Exit;
|
|
if BluePrec <> 8 then Exit;
|
|
if RedShift and 7 <> 0 then Exit;
|
|
if GreenShift and 7 <> 0 then Exit;
|
|
if BlueShift and 7 <> 0 then Exit;
|
|
|
|
if ByteOrder = riboMSBFirst
|
|
then
|
|
Positions := ((2-((RedShift shr 3) and 3)) shl 4
|
|
or (2-((GreenShift shr 3) and 3)) shl 2
|
|
or (2-((BlueShift shr 3) and 3))) and $FF
|
|
else
|
|
Positions := (((RedShift shr 3) and 3) shl 4
|
|
or ((GreenShift shr 3) and 3) shl 2
|
|
or ((BlueShift shr 3) and 3)) and $FF;
|
|
end;
|
|
|
|
|
|
// the locations of R,G,B are now coded in 2 bits each: xxRRBBGG
|
|
// the 2-bit value (0..3) represents the location of the channel,
|
|
// counting from left
|
|
case Positions of
|
|
{xxRRGGBB}
|
|
%00100100: begin
|
|
FGetInternalColorProc := @GetColor_BPP24_B8G8R8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP24_B8G8R8_BIO_TTB;
|
|
end;
|
|
{xxRRGGBB}
|
|
%00000110: begin
|
|
FGetInternalColorProc := @GetColor_BPP24_R8G8B8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP24_R8G8B8_BIO_TTB;
|
|
end;
|
|
{xxRRGGBB}
|
|
%00100001: begin
|
|
FGetInternalColorProc := @GetColor_BPP24_G8B8R8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP24_G8B8R8_BIO_TTB;
|
|
end;
|
|
{xxRRGGBB}
|
|
%00010010: begin
|
|
FGetInternalColorProc := @GetColor_BPP24_G8R8B8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP24_G8R8B8_BIO_TTB;
|
|
end;
|
|
{xxRRGGBB}
|
|
%00011000: begin
|
|
FGetInternalColorProc := @GetColor_BPP24_B8R8G8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP24_B8R8G8_BIO_TTB;
|
|
end;
|
|
{xxRRGGBB}
|
|
%00001001: begin
|
|
FGetInternalColorProc := @GetColor_BPP24_R8B8G8_BIO_TTB;
|
|
FSetInternalColorProc := @SetColor_BPP24_R8B8G8_BIO_TTB;
|
|
end;
|
|
else
|
|
Exit;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
procedure ChooseRGBAFunctions;
|
|
begin
|
|
with FRawImage.Description do
|
|
begin
|
|
ChooseRawBitsProc(BitsPerPixel, ByteOrder, BitOrder,
|
|
FReadRawImageBits, FWriteRawImageBits);
|
|
|
|
if AlphaPrec > 0
|
|
then begin
|
|
FGetInternalColorProc := @GetColor_RGBA_NoPalette;
|
|
FSetInternalColorProc := @SetColor_RGBA_NoPalette;
|
|
end
|
|
else begin
|
|
FGetInternalColorProc := @GetColor_RGB_NoPalette;
|
|
FSetInternalColorProc := @SetColor_RGB_NoPalette;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
// Default: use the generic functions, that can handle all kinds of RawImages
|
|
FGetInternalColorProc := @GetColor_Generic;
|
|
FSetInternalColorProc := @SetColor_Generic;
|
|
|
|
if FUpdateCount > 0
|
|
then begin
|
|
FGetSetColorFunctionsUpdateNeeded := true;
|
|
Exit;
|
|
end;
|
|
FGetSetColorFunctionsUpdateNeeded := false;
|
|
|
|
with FRawImage.Description do
|
|
begin
|
|
if MaskBitsPerPixel > 0
|
|
then ChooseRawBitsProc(MaskBitsPerPixel, ByteOrder, MaskBitOrder,
|
|
FMaskReadRawImageBits, FMaskWriteRawImageBits);
|
|
|
|
if PaletteColorCount = 0
|
|
then begin
|
|
case Format of
|
|
ricfRGBA: begin
|
|
if not (ChooseRGBA_32Bpp or ChooseRGB_32Bpp or ChooseRGB_24Bpp)
|
|
then ChooseRGBAFunctions;
|
|
end;
|
|
ricfGray: begin
|
|
ChooseRawBitsProc(BitsPerPixel,
|
|
ByteOrder,
|
|
BitOrder,
|
|
FReadRawImageBits, FWriteRawImageBits);
|
|
|
|
if AlphaPrec = 0
|
|
then begin
|
|
FGetInternalColorProc := @GetColor_Gray_NoPalette;
|
|
FSetInternalColorProc := @SetColor_Gray_NoPalette;
|
|
end
|
|
else begin
|
|
FGetInternalColorProc := @GetColor_GrayAlpha_NoPalette;
|
|
FSetInternalColorProc := @SetColor_GrayAlpha_NoPalette;
|
|
end;
|
|
end;
|
|
end;
|
|
end
|
|
else begin
|
|
// palette
|
|
// ToDo
|
|
{$IFNDEF DisableChecks}
|
|
DebugLn('WARNING: TLazIntfImage.ChooseGetSetColorFunctions Palette is unsupported');
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_Generic(x, y: integer; out Value: TFPColor);
|
|
var
|
|
Position: TRawImagePosition;
|
|
begin
|
|
GetXYDataPosition(x,y,Position);
|
|
|
|
if FRawImage.Description.PaletteColorCount = 0
|
|
then begin
|
|
FRawimage.ReadChannels(Position, Value.Red, Value.Green, Value.Blue, Value.Alpha);
|
|
end
|
|
else begin
|
|
// ToDo: read index, then palette
|
|
Value.Red:=0;
|
|
Value.Green:=0;
|
|
Value.Blue:=0;
|
|
Value.Alpha:=0;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetMask_Generic(x, y: integer; out AValue: Boolean);
|
|
var
|
|
Position: TRawImagePosition;
|
|
begin
|
|
if FRawImage.Description.MaskBitsPerPixel = 0
|
|
then begin
|
|
Avalue := False;
|
|
end
|
|
else begin
|
|
GetXYMaskPosition(x,y,Position);
|
|
FRawimage.ReadMask(Position, AValue);
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_Generic(x, y: integer; const Value: TFPColor);
|
|
var
|
|
Position: TRawImagePosition;
|
|
begin
|
|
GetXYDataPosition(x,y,Position);
|
|
|
|
if FRawImage.Description.PaletteColorCount = 0
|
|
then begin
|
|
FRawImage.WriteChannels(Position, Value.Red, Value.Green, Value.Blue, Value.Alpha);
|
|
end
|
|
else begin
|
|
// ToDo: Palette
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetMask_Generic(x, y: integer; const AValue: Boolean);
|
|
var
|
|
Position: TRawImagePosition;
|
|
begin
|
|
if FRawImage.Description.MaskBitsPerPixel = 0 then Exit;
|
|
|
|
GetXYMaskPosition(x,y,Position);
|
|
FRawImage.WriteMask(Position, AValue);
|
|
end;
|
|
|
|
|
|
procedure TLazIntfImage.GetColor_RGBA_NoPalette(x, y: integer; out Value: TFPColor);
|
|
var
|
|
Position: TRawImagePosition;
|
|
begin
|
|
GetXYDataPosition(x,y,Position);
|
|
with FRawImage.Description do
|
|
begin
|
|
FReadRawImageBits(FRawImage.Data, Position, RedPrec, RedShift, Value.Red);
|
|
FReadRawImageBits(FRawImage.Data, Position, GreenPrec, GreenShift, Value.Green);
|
|
FReadRawImageBits(FRawImage.Data, Position, BluePrec, BlueShift, Value.Blue);
|
|
FReadRawImageBits(FRawImage.Data, Position, AlphaPrec, AlphaShift, Value.Alpha);
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_RGB_NoPalette(x, y: integer; out Value: TFPColor);
|
|
var
|
|
Position: TRawImagePosition;
|
|
begin
|
|
GetXYDataPosition(x,y,Position);
|
|
with FRawImage.Description do
|
|
begin
|
|
FReadRawImageBits(FRawImage.Data, Position, RedPrec, RedShift, Value.Red);
|
|
FReadRawImageBits(FRawImage.Data, Position, GreenPrec, GreenShift, Value.Green);
|
|
FReadRawImageBits(FRawImage.Data, Position, BluePrec, BlueShift, Value.Blue);
|
|
end;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_Gray_NoPalette(x, y: integer; out Value: TFPColor);
|
|
var
|
|
Position: TRawImagePosition;
|
|
begin
|
|
GetXYDataPosition(x,y,Position);
|
|
with FRawImage.Description do
|
|
FReadRawImageBits(FRawImage.Data, Position, RedPrec, RedShift, Value.Red);
|
|
Value.Green := Value.Red;
|
|
Value.Blue := Value.Red;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_GrayAlpha_NoPalette(x, y: integer; out Value: TFPColor);
|
|
var
|
|
Position: TRawImagePosition;
|
|
begin
|
|
GetXYDataPosition(x,y,Position);
|
|
with FRawImage.Description do
|
|
begin
|
|
FReadRawImageBits(FRawImage.Data, Position, RedPrec, RedShift, Value.Red);
|
|
FReadRawImageBits(FRawImage.Data, Position, AlphaPrec, AlphaShift, Value.Alpha);
|
|
end;
|
|
Value.Green := Value.Red;
|
|
Value.Blue := Value.Red;
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_A8B8G8R8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Ah := B0;
|
|
VBytes.Al := B0;
|
|
VBytes.Bh := B1;
|
|
VBytes.Bl := B1;
|
|
VBytes.Rh := B2;
|
|
VBytes.Rl := B2;
|
|
VBytes.Gh := B3;
|
|
VBytes.Gl := B3;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_A8B8R8G8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Ah := B0;
|
|
VBytes.Al := B0;
|
|
VBytes.Bh := B1;
|
|
VBytes.Bl := B1;
|
|
VBytes.Rh := B2;
|
|
VBytes.Rl := B2;
|
|
VBytes.Gh := B3;
|
|
VBytes.Gl := B3;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_A8G8B8R8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Ah := B0;
|
|
VBytes.Al := B0;
|
|
VBytes.Gh := B1;
|
|
VBytes.Gl := B1;
|
|
VBytes.Bh := B2;
|
|
VBytes.Bl := B2;
|
|
VBytes.Rh := B3;
|
|
VBytes.Rl := B3;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_A8G8R8B8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Ah := B0;
|
|
VBytes.Al := B0;
|
|
VBytes.Gh := B1;
|
|
VBytes.Gl := B1;
|
|
VBytes.Rh := B2;
|
|
VBytes.Rl := B2;
|
|
VBytes.Bh := B3;
|
|
VBytes.Bl := B3;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_A8R8B8G8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Ah := B0;
|
|
VBytes.Al := B0;
|
|
VBytes.Rh := B1;
|
|
VBytes.Rl := B1;
|
|
VBytes.Bh := B2;
|
|
VBytes.Bl := B2;
|
|
VBytes.Gh := B3;
|
|
VBytes.Gl := B3;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_A8R8G8B8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Ah := B0;
|
|
VBytes.Al := B0;
|
|
VBytes.Rh := B1;
|
|
VBytes.Rl := B1;
|
|
VBytes.Gh := B2;
|
|
VBytes.Gl := B2;
|
|
VBytes.Bh := B3;
|
|
VBytes.Bl := B3;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_B8G8R8A8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Bh := B0;
|
|
VBytes.Bl := B0;
|
|
VBytes.Gh := B1;
|
|
VBytes.Gl := B1;
|
|
VBytes.Rh := B2;
|
|
VBytes.Rl := B2;
|
|
VBytes.Ah := B3;
|
|
VBytes.Al := B3;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_B8R8G8A8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Bh := B0;
|
|
VBytes.Bl := B0;
|
|
VBytes.Rh := B1;
|
|
VBytes.Rl := B1;
|
|
VBytes.Gh := B2;
|
|
VBytes.Gl := B2;
|
|
VBytes.Ah := B3;
|
|
VBytes.Al := B3;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_G8B8R8A8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Gh := B0;
|
|
VBytes.Gl := B0;
|
|
VBytes.Bh := B1;
|
|
VBytes.Bl := B1;
|
|
VBytes.Rh := B2;
|
|
VBytes.Rl := B2;
|
|
VBytes.Ah := B3;
|
|
VBytes.Al := B3;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_G8R8B8A8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Gh := B0;
|
|
VBytes.Gl := B0;
|
|
VBytes.Rh := B1;
|
|
VBytes.Rl := B1;
|
|
VBytes.Bh := B2;
|
|
VBytes.Bl := B2;
|
|
VBytes.Ah := B3;
|
|
VBytes.Al := B3;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_R8B8G8A8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Rh := B0;
|
|
VBytes.Rl := B0;
|
|
VBytes.Bh := B1;
|
|
VBytes.Bl := B1;
|
|
VBytes.Gh := B2;
|
|
VBytes.Gl := B2;
|
|
VBytes.Ah := B3;
|
|
VBytes.Al := B3;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_R8G8B8A8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Rh := B0;
|
|
VBytes.Rl := B0;
|
|
VBytes.Gh := B1;
|
|
VBytes.Gl := B1;
|
|
VBytes.Bh := B2;
|
|
VBytes.Bl := B2;
|
|
VBytes.Ah := B3;
|
|
VBytes.Al := B3;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_X8B8G8R8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Bh := B1;
|
|
VBytes.Bl := B1;
|
|
VBytes.Rh := B2;
|
|
VBytes.Rl := B2;
|
|
VBytes.Gh := B3;
|
|
VBytes.Gl := B3;
|
|
end;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_X8B8R8G8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Bh := B1;
|
|
VBytes.Bl := B1;
|
|
VBytes.Rh := B2;
|
|
VBytes.Rl := B2;
|
|
VBytes.Gh := B3;
|
|
VBytes.Gl := B3;
|
|
end;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_X8G8B8R8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Gh := B1;
|
|
VBytes.Gl := B1;
|
|
VBytes.Bh := B2;
|
|
VBytes.Bl := B2;
|
|
VBytes.Rh := B3;
|
|
VBytes.Rl := B3;
|
|
end;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_X8G8R8B8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Gh := B1;
|
|
VBytes.Gl := B1;
|
|
VBytes.Rh := B2;
|
|
VBytes.Rl := B2;
|
|
VBytes.Bh := B3;
|
|
VBytes.Bl := B3;
|
|
end;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_X8R8B8G8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Rh := B1;
|
|
VBytes.Rl := B1;
|
|
VBytes.Bh := B2;
|
|
VBytes.Bl := B2;
|
|
VBytes.Gh := B3;
|
|
VBytes.Gl := B3;
|
|
end;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_X8R8G8B8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Rh := B1;
|
|
VBytes.Rl := B1;
|
|
VBytes.Gh := B2;
|
|
VBytes.Gl := B2;
|
|
VBytes.Bh := B3;
|
|
VBytes.Bl := B3;
|
|
end;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_B8G8R8X8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Bh := B0;
|
|
VBytes.Bl := B0;
|
|
VBytes.Gh := B1;
|
|
VBytes.Gl := B1;
|
|
VBytes.Rh := B2;
|
|
VBytes.Rl := B2;
|
|
end;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_B8R8G8X8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Bh := B0;
|
|
VBytes.Bl := B0;
|
|
VBytes.Rh := B1;
|
|
VBytes.Rl := B1;
|
|
VBytes.Gh := B2;
|
|
VBytes.Gl := B2;
|
|
end;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_G8B8R8X8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Gh := B0;
|
|
VBytes.Gl := B0;
|
|
VBytes.Bh := B1;
|
|
VBytes.Bl := B1;
|
|
VBytes.Rh := B2;
|
|
VBytes.Rl := B2;
|
|
end;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_G8R8B8X8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Gh := B0;
|
|
VBytes.Gl := B0;
|
|
VBytes.Rh := B1;
|
|
VBytes.Rl := B1;
|
|
VBytes.Bh := B2;
|
|
VBytes.Bl := B2;
|
|
end;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_R8B8G8X8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Rh := B0;
|
|
VBytes.Rl := B0;
|
|
VBytes.Bh := B1;
|
|
VBytes.Bl := B1;
|
|
VBytes.Gh := B2;
|
|
VBytes.Gl := B2;
|
|
end;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP32_R8G8B8X8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
VBytes.Rh := B0;
|
|
VBytes.Rl := B0;
|
|
VBytes.Gh := B1;
|
|
VBytes.Gl := B1;
|
|
VBytes.Bh := B2;
|
|
VBytes.Bl := B2;
|
|
end;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP24_B8G8R8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=24 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=24
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x * 3))^ do
|
|
begin
|
|
VBytes.Bh := B0;
|
|
VBytes.Bl := B0;
|
|
VBytes.Gh := B1;
|
|
VBytes.Gl := B1;
|
|
VBytes.Rh := B2;
|
|
VBytes.Rl := B2;
|
|
end;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP24_B8R8G8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=24 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=24
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x * 3))^ do
|
|
begin
|
|
VBytes.Bh := B0;
|
|
VBytes.Bl := B0;
|
|
VBytes.Rh := B1;
|
|
VBytes.Rl := B1;
|
|
VBytes.Gh := B2;
|
|
VBytes.Gl := B2;
|
|
end;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP24_G8B8R8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=24 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=24
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x * 3))^ do
|
|
begin
|
|
VBytes.Gh := B0;
|
|
VBytes.Gl := B0;
|
|
VBytes.Bh := B1;
|
|
VBytes.Bl := B1;
|
|
VBytes.Rh := B2;
|
|
VBytes.Rl := B2;
|
|
end;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP24_G8R8B8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=24 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=24
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x * 3))^ do
|
|
begin
|
|
VBytes.Gh := B0;
|
|
VBytes.Gl := B0;
|
|
VBytes.Rh := B1;
|
|
VBytes.Rl := B1;
|
|
VBytes.Bh := B2;
|
|
VBytes.Bl := B2;
|
|
end;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP24_R8B8G8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=24 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=24
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x * 3))^ do
|
|
begin
|
|
VBytes.Rh := B0;
|
|
VBytes.Rl := B0;
|
|
VBytes.Bh := B1;
|
|
VBytes.Bl := B1;
|
|
VBytes.Gh := B2;
|
|
VBytes.Gl := B2;
|
|
end;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_BPP24_R8G8B8_BIO_TTB(x, y: integer; out Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=24 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=24
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x * 3))^ do
|
|
begin
|
|
VBytes.Rh := B0;
|
|
VBytes.Rl := B0;
|
|
VBytes.Gh := B1;
|
|
VBytes.Gl := B1;
|
|
VBytes.Bh := B2;
|
|
VBytes.Bl := B2;
|
|
end;
|
|
// no alpha -> set opaque
|
|
Value.Alpha:=high(Value.Alpha);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetColor_NULL(x, y: integer; out Value: TFPColor);
|
|
//var
|
|
// Position: TRawImagePosition;
|
|
begin
|
|
// GetXYDataPosition(x,y,Position);
|
|
Value.Red:=0;
|
|
Value.Green:=0;
|
|
Value.Blue:=0;
|
|
Value.Alpha:=0;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_RGBA_NoPalette(x, y: integer; const Value: TFPColor);
|
|
var
|
|
Position: TRawImagePosition;
|
|
begin
|
|
GetXYDataPosition(x,y,Position);
|
|
with FRawImage.Description do
|
|
begin
|
|
FWriteRawImageBits(FRawImage.Data, Position, RedPrec, RedShift, Value.Red);
|
|
FWriteRawImageBits(FRawImage.Data, Position, GreenPrec, GreenShift, Value.Green);
|
|
FWriteRawImageBits(FRawImage.Data, Position, BluePrec, BlueShift, Value.Blue);
|
|
FWriteRawImageBits(FRawImage.Data, Position, AlphaPrec, AlphaShift, Value.Alpha)
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_RGB_NoPalette(x, y: integer; const Value: TFPColor);
|
|
var
|
|
Position: TRawImagePosition;
|
|
begin
|
|
GetXYDataPosition(x,y,Position);
|
|
with FRawImage.Description do
|
|
begin
|
|
FWriteRawImageBits(FRawImage.Data, Position, RedPrec, RedShift, Value.Red);
|
|
FWriteRawImageBits(FRawImage.Data, Position, GreenPrec, GreenShift, Value.Green);
|
|
FWriteRawImageBits(FRawImage.Data, Position, BluePrec, BlueShift, Value.Blue);
|
|
end;
|
|
// no alpha -> ignore
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_Gray_NoPalette(x, y: integer; const Value: TFPColor);
|
|
var
|
|
Position: TRawImagePosition;
|
|
begin
|
|
GetXYDataPosition(x,y,Position);
|
|
with FRawImage.Description do
|
|
FWriteRawImageBits(FRawImage.Data, Position, RedPrec, RedShift, Value.Red);
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_GrayAlpha_NoPalette(x, y: integer; const Value: TFPColor);
|
|
var
|
|
Position: TRawImagePosition;
|
|
begin
|
|
GetXYDataPosition(x,y,Position);
|
|
with FRawImage.Description do
|
|
begin
|
|
FWriteRawImageBits(FRawImage.Data, Position, RedPrec, RedShift, Value.Red);
|
|
FWriteRawImageBits(FRawImage.Data, Position, AlphaPrec, AlphaShift, Value.Alpha)
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TLazIntfImage.SetColor_NULL(x, y: integer; const Value: TFPColor);
|
|
begin
|
|
// NULL, not implemented
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_A8R8G8B8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B0 := VBytes.Ah;
|
|
B1 := VBytes.Rh;
|
|
B2 := VBytes.Gh;
|
|
B3 := VBytes.Bh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_A8B8G8R8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B0 := VBytes.Ah;
|
|
B1 := VBytes.Bh;
|
|
B2 := VBytes.Gh;
|
|
B3 := VBytes.Rh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_A8B8R8G8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B0 := VBytes.Ah;
|
|
B1 := VBytes.Bh;
|
|
B2 := VBytes.Rh;
|
|
B3 := VBytes.Gh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_A8G8B8R8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B0 := VBytes.Ah;
|
|
B1 := VBytes.Gh;
|
|
B2 := VBytes.Bh;
|
|
B3 := VBytes.Rh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_A8G8R8B8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B0 := VBytes.Ah;
|
|
B1 := VBytes.Gh;
|
|
B2 := VBytes.Rh;
|
|
B3 := VBytes.Bh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_A8R8B8G8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B0 := VBytes.Ah;
|
|
B1 := VBytes.Rh;
|
|
B2 := VBytes.Bh;
|
|
B3 := VBytes.Gh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_B8G8R8A8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B0 := VBytes.Bh;
|
|
B1 := VBytes.Gh;
|
|
B2 := VBytes.Rh;
|
|
B3 := VBytes.Ah;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_B8R8G8A8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B0 := VBytes.Bh;
|
|
B1 := VBytes.Rh;
|
|
B2 := VBytes.Gh;
|
|
B3 := VBytes.Ah;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_G8B8R8A8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B0 := VBytes.Gh;
|
|
B1 := VBytes.Bh;
|
|
B2 := VBytes.Rh;
|
|
B3 := VBytes.Ah;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_G8R8B8A8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B0 := VBytes.Gh;
|
|
B1 := VBytes.Rh;
|
|
B2 := VBytes.Bh;
|
|
B3 := VBytes.Ah;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_R8B8G8A8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B0 := VBytes.Rh;
|
|
B1 := VBytes.Bh;
|
|
B2 := VBytes.Gh;
|
|
B3 := VBytes.Ah;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_R8G8B8A8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B0 := VBytes.Rh;
|
|
B1 := VBytes.Gh;
|
|
B2 := VBytes.Bh;
|
|
B3 := VBytes.Ah;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_X8R8G8B8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B1 := VBytes.Rh;
|
|
B2 := VBytes.Gh;
|
|
B3 := VBytes.Bh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_X8B8G8R8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B1 := VBytes.Bh;
|
|
B2 := VBytes.Gh;
|
|
B3 := VBytes.Rh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_X8B8R8G8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B1 := VBytes.Bh;
|
|
B2 := VBytes.Rh;
|
|
B3 := VBytes.Gh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_X8G8B8R8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B1 := VBytes.Gh;
|
|
B2 := VBytes.Bh;
|
|
B3 := VBytes.Rh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_X8G8R8B8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B1 := VBytes.Gh;
|
|
B2 := VBytes.Rh;
|
|
B3 := VBytes.Bh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_X8R8B8G8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B1 := VBytes.Rh;
|
|
B2 := VBytes.Bh;
|
|
B3 := VBytes.Gh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_B8G8R8X8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B0 := VBytes.Bh;
|
|
B1 := VBytes.Gh;
|
|
B2 := VBytes.Rh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_B8R8G8X8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B0 := VBytes.Bh;
|
|
B1 := VBytes.Rh;
|
|
B2 := VBytes.Gh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_G8B8R8X8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B0 := VBytes.Gh;
|
|
B1 := VBytes.Bh;
|
|
B2 := VBytes.Rh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_G8R8B8X8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B0 := VBytes.Gh;
|
|
B1 := VBytes.Rh;
|
|
B2 := VBytes.Bh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_R8B8G8X8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B0 := VBytes.Rh;
|
|
B1 := VBytes.Bh;
|
|
B2 := VBytes.Gh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP32_R8G8B8X8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do
|
|
begin
|
|
B0 := VBytes.Rh;
|
|
B1 := VBytes.Gh;
|
|
B2 := VBytes.Bh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP24_B8G8R8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x * 3))^ do
|
|
begin
|
|
B0 := VBytes.Bh;
|
|
B1 := VBytes.Gh;
|
|
B2 := VBytes.Rh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP24_B8R8G8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x * 3))^ do
|
|
begin
|
|
B0 := VBytes.Bh;
|
|
B1 := VBytes.Rh;
|
|
B2 := VBytes.Gh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP24_G8B8R8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x * 3))^ do
|
|
begin
|
|
B0 := VBytes.Gh;
|
|
B1 := VBytes.Bh;
|
|
B2 := VBytes.Rh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP24_G8R8B8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x * 3))^ do
|
|
begin
|
|
B0 := VBytes.Gh;
|
|
B1 := VBytes.Rh;
|
|
B2 := VBytes.Bh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP24_R8B8G8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x * 3))^ do
|
|
begin
|
|
B0 := VBytes.Rh;
|
|
B1 := VBytes.Bh;
|
|
B2 := VBytes.Gh;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetColor_BPP24_R8G8B8_BIO_TTB(x, y: integer; const Value: TFPColor);
|
|
// Format=ricfRGBA HasPalette=false Depth=32 PaletteColorCount=0
|
|
// BitOrder=riboBitsInOrder LineOrder=riloTopToBottom
|
|
// BitsPerPixel=32
|
|
var
|
|
VBytes: TFPColorBytes absolute Value;
|
|
begin
|
|
with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x * 3))^ do
|
|
begin
|
|
B0 := VBytes.Rh;
|
|
B1 := VBytes.Gh;
|
|
B2 := VBytes.Bh;
|
|
end;
|
|
end;
|
|
|
|
function TLazIntfImage.GetTColors(x, y: integer): TGraphicsColor;
|
|
begin
|
|
Result:=FPColorToTColor(Colors[x,y]);
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetTColors(x, y: integer; const AValue: TGraphicsColor);
|
|
begin
|
|
Colors[x,y]:=TColorToFPColor(AValue);
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetUsePalette(Value: boolean);
|
|
begin
|
|
inherited // we can SetUsePalette(False); // Can't handle palettes at the moment
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetInternalColor(x, y: integer; const Value: TFPColor);
|
|
begin
|
|
{if (x=0) and (y=0) then begin
|
|
// a common bug in the readers is that Alpha is reversed
|
|
DebugLn('TLazIntfImage.SetInternalColor ',x,',',y,' ',Value.Red,',',Value.Green,',',Value.Blue,',',Value.Alpha);
|
|
if Value.Alpha<>alphaOpaque then
|
|
RaiseGDBException('');
|
|
end;}
|
|
FSetInternalColorProc(x,y,Value);
|
|
{if y=Height-1 then
|
|
DebugLn(['TLazIntfImage.SetInternalColor x=',x,' y=',y,' ',dbgs(Value),' ',dbgs(GetInternalColor(x,y))]);}
|
|
end;
|
|
|
|
function TLazIntfImage.GetInternalColor(x, y: integer): TFPColor;
|
|
begin
|
|
FGetInternalColorProc(x,y,Result);
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetInternalPixel(x, y: integer; Value: integer);
|
|
begin
|
|
if Palette = nil then Exit;
|
|
if FRawImage.Description.PaletteColorCount = 0
|
|
then begin
|
|
// Non palettebased image so set the color
|
|
SetInternalColor(x, y, Palette.Color[Value]);
|
|
end
|
|
else begin
|
|
// TODO: Setting of palette colors
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetMasked(x, y: integer; const AValue: Boolean);
|
|
begin
|
|
// CheckIndex(x,y);
|
|
SetMask_Generic(x, y, AValue);
|
|
FMaskSet := FMaskSet or AValue;
|
|
end;
|
|
|
|
function TLazIntfImage.GetInternalPixel(x, y: integer): integer;
|
|
begin
|
|
if Palette = nil then Exit(0);
|
|
|
|
if FRawImage.Description.PaletteColorCount = 0
|
|
then begin
|
|
// Non palettebased image so lookup the color
|
|
Result := Palette.IndexOf(GetInternalColor(x, y));
|
|
end
|
|
else begin
|
|
// TODO: Setting of palette colors
|
|
Result := 0;
|
|
end;
|
|
end;
|
|
|
|
function TLazIntfImage.GetMasked(x, y: integer): Boolean;
|
|
begin
|
|
// CheckIndex (x,y);
|
|
GetMask_Generic(x, y, Result);
|
|
end;
|
|
|
|
procedure TLazIntfImage.FreeData;
|
|
begin
|
|
//DebugLn(Format('[TLazIntfImage.FreeData] Self=%x Data=%x', [PtrUInt(Self), PtrUInt(FRawImage.Data)]));
|
|
if FDataOwner
|
|
then ReallocMem(FRawImage.Data, 0)
|
|
else FRawImage.Data := nil;
|
|
FRawImage.DataSize := 0;
|
|
|
|
if FLineStarts <> nil then Dispose(FLineStarts);
|
|
FLineStarts := nil;
|
|
|
|
if FDataOwner and (FRawImage.Mask <> nil)
|
|
then ReallocMem(FRawImage.Mask, 0)
|
|
else FRawImage.Mask := nil;
|
|
FRawImage.MaskSize := 0;
|
|
|
|
if FMaskLineStarts <> nil then Dispose(FMaskLineStarts);
|
|
FMaskLineStarts := nil;
|
|
FMaskSet := False;
|
|
|
|
if FDataOwner and (FRawImage.Palette <> nil)
|
|
then ReallocMem(FRawImage.Palette, 0)
|
|
else FRawImage.Palette := nil;
|
|
FRawImage.PaletteSize := 0;
|
|
|
|
// old RawImage data has been cleared/destroyed => so new data must be owned by us
|
|
FDataOwner := True;
|
|
end;
|
|
|
|
procedure TLazIntfImage.CreateData;
|
|
begin
|
|
if FUpdateCount > 0
|
|
then begin
|
|
FCreateAllDataNeeded := True;
|
|
Exit;
|
|
end;
|
|
FCreateAllDataNeeded := False;
|
|
|
|
FreeData;
|
|
|
|
New(FLineStarts);
|
|
FLineStarts^.Init(Width, Height, FRawImage.Description.BitsPerPixel, FRawImage.Description.LineEnd, FRawImage.Description.LineOrder);
|
|
New(FMaskLineStarts);
|
|
FMaskLineStarts^.Init(Width, Height, FRawImage.Description.MaskBitsPerPixel, FRawImage.Description.MaskLineEnd, FRawImage.Description.LineOrder);
|
|
|
|
FRawImage.CreateData(False);
|
|
end;
|
|
|
|
function TLazIntfImage.HasTransparency: boolean;
|
|
begin
|
|
Result := FMaskSet or FRawImage.IsTransparent(True);
|
|
end;
|
|
|
|
function TLazIntfImage.HasMask: boolean;
|
|
begin
|
|
Result := FMaskSet;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetDataDescriptionKeepData(
|
|
const ADescription: TRawImageDescription);
|
|
begin
|
|
FRawImage.Description:=ADescription;
|
|
end;
|
|
|
|
constructor TLazIntfImage.Create(AWidth, AHeight: integer);
|
|
begin
|
|
Create(AWidth, AHeight, []);
|
|
end;
|
|
|
|
constructor TLazIntfImage.Create(AWidth, AHeight: integer; AFlags: TRawImageQueryFlags);
|
|
begin
|
|
FDataOwner := True;
|
|
FGetInternalColorProc := @GetColor_NULL;
|
|
FSetInternalColorProc := @SetColor_NULL;
|
|
inherited Create(AWidth, AHeight);
|
|
|
|
if AFlags <> []
|
|
then begin
|
|
QueryDescription(FRawImage.Description, AFlags, AWidth, AHeight);
|
|
ChooseGetSetColorFunctions;
|
|
CreateData;
|
|
end;
|
|
end;
|
|
|
|
constructor TLazIntfImage.Create(ARawImage: TRawImage; ADataOwner: Boolean);
|
|
var
|
|
Desc: TRawImageDescription absolute ARawImage.Description;
|
|
begin
|
|
BeginUpdate;
|
|
FRawImage := ARawImage;
|
|
Create(Desc.Width, Desc.Height, []);
|
|
FDataOwner := ADataOwner;
|
|
FCreateAllDataNeeded := False;
|
|
EndUpdate;
|
|
New(FLineStarts);
|
|
FLineStarts^.Init(Width, Height, Desc.BitsPerPixel, Desc.LineEnd, Desc.LineOrder);
|
|
New(FMaskLineStarts);
|
|
FMaskLineStarts^.Init(Width, Height, Desc.MaskBitsPerPixel, Desc.MaskLineEnd, Desc.LineOrder);
|
|
ChooseGetSetColorFunctions;
|
|
end;
|
|
|
|
constructor TLazIntfImage.CreateCompatible(IntfImg: TLazIntfImage; AWidth,
|
|
AHeight: integer);
|
|
var
|
|
Desc: TRawImageDescription;
|
|
begin
|
|
Create(0,0);
|
|
Desc:=IntfImg.DataDescription;
|
|
Desc.Width:=AWidth;
|
|
Desc.Height:=AHeight;
|
|
DataDescription:=Desc;
|
|
end;
|
|
|
|
destructor TLazIntfImage.Destroy;
|
|
begin
|
|
FreeData;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TLazIntfImage.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TLazIntfImage then
|
|
DataDescription:=TLazIntfImage(Source).DataDescription;
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
procedure TLazIntfImage.AlphaFromMask(AKeepAlpha: Boolean);
|
|
var
|
|
x, y, xStop, yStop: Integer;
|
|
Color: TFPColor;
|
|
begin
|
|
if FRawImage.Mask = nil then Exit;
|
|
if FRawImage.MaskSize = 0 then Exit;
|
|
|
|
xStop := Width - 1;
|
|
yStop := Height - 1;
|
|
|
|
if AKeepAlpha
|
|
then begin
|
|
for y:=0 to yStop do
|
|
for x:=0 to xStop do
|
|
begin
|
|
if not Masked[x,y] then Continue;
|
|
Color := Colors[x,y];
|
|
Color.alpha := Low(Color.alpha);
|
|
Colors[x,y] := Color;
|
|
end;
|
|
end
|
|
else begin
|
|
for y:=0 to yStop do
|
|
for x:=0 to xStop do
|
|
begin
|
|
Color := Colors[x,y];
|
|
if Masked[x,y]
|
|
then Color.alpha := Low(Color.alpha)
|
|
else Color.alpha := High(Color.alpha);
|
|
Colors[x,y] := Color;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.Mask(const AColor: TFPColor; AKeepOldMask: Boolean = False);
|
|
var
|
|
x, y: Integer;
|
|
begin
|
|
if AKeepOldMask then
|
|
for y := 0 to Height - 1 do
|
|
for x := 0 to Width - 1 do
|
|
Masked[x,y] := Masked[x,y] or (Colors[x,y] = AColor)
|
|
else
|
|
for y := 0 to Height - 1 do
|
|
for x := 0 to Width - 1 do
|
|
Masked[x,y] := Colors[x,y] = AColor;
|
|
end;
|
|
|
|
procedure TLazIntfImage.BeginUpdate;
|
|
begin
|
|
Inc(FUpdateCount);
|
|
end;
|
|
|
|
procedure TLazIntfImage.EndUpdate;
|
|
begin
|
|
if FUpdateCount = 0 then Exit;
|
|
Dec(FUpdateCount);
|
|
if FUpdateCount > 0 then Exit;
|
|
|
|
if FCreateAllDataNeeded then
|
|
CreateData;
|
|
if FGetSetColorFunctionsUpdateNeeded then
|
|
ChooseGetSetColorFunctions;
|
|
end;
|
|
|
|
procedure TLazIntfImage.InternalSetSize(AWidth, AHeight: integer);
|
|
procedure Error;
|
|
begin
|
|
raise FPImageException.Create('Invalid Size');
|
|
end;
|
|
begin
|
|
if (AWidth = Width) and (AHeight = Height) then exit;
|
|
if (AWidth<0) or (AHeight<0) then Error;
|
|
inherited SetSize(AWidth, AHeight);
|
|
|
|
FRawImage.Description.Width := Width;
|
|
FRawImage.Description.Height := Height;
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetSize(AWidth, AHeight: integer);
|
|
begin
|
|
InternalSetSize(AWidth, AHeight);
|
|
CreateData;
|
|
end;
|
|
|
|
function TLazIntfImage.CheckDescription(
|
|
const ADescription: TRawImageDescription; ExceptionOnError: boolean
|
|
): boolean;
|
|
|
|
procedure DoError(const Msg: string);
|
|
begin
|
|
if ExceptionOnError then Raise FPImageException.Create(Msg);
|
|
{$IFNDEF DisableChecks}
|
|
DebugLn('TLazIntfImage.CheckDescription: ',Msg);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
begin
|
|
Result:=false;
|
|
// check format
|
|
if (not (ADescription.Format
|
|
in [low(TRawImageColorFormat)..high(TRawImageColorFormat)]))
|
|
then begin
|
|
DoError('Invalid Raw Image Description Format'); exit;
|
|
end;
|
|
|
|
Result:=true;
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetXYDataPosition(x, y: integer; out Position: TRawImagePosition);
|
|
begin
|
|
Position := FLineStarts^.GetPosition(x, y);
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetXYMaskPosition(x, y: integer; out Position: TRawImagePosition);
|
|
begin
|
|
Position := FMaskLineStarts^.GetPosition(x, y);
|
|
end;
|
|
|
|
function TLazIntfImage.GetDataLineStart(y: integer): Pointer;
|
|
begin
|
|
if FRawimage.Description.LineOrder = riloBottomToTop then
|
|
y:=Height-y;
|
|
Result := FRawImage.Data+FLineStarts^.Positions[y].Byte;
|
|
end;
|
|
|
|
procedure TLazIntfImage.LoadFromDevice(DC: HDC);
|
|
var
|
|
R: TRect;
|
|
RawImage: TRawImage;
|
|
DeviceSize: TPoint;
|
|
begin
|
|
GetDeviceSize(DC, DeviceSize);
|
|
R := Rect(0,0,DeviceSize.X,DeviceSize.Y);
|
|
if not RawImage_FromDevice(RawImage, DC, R) then
|
|
raise FPImageException.Create('Failed to get raw image from device');
|
|
SetRawImage(RawImage);
|
|
end;
|
|
|
|
procedure TLazIntfImage.LoadFromBitmap(ABitmap, AMaskBitmap: HBitmap;
|
|
AWidth: integer; AHeight: integer);
|
|
var
|
|
R: TRect;
|
|
RawImage: TRawImage;
|
|
Desc: TRawImageDescription;
|
|
begin
|
|
if not RawImage_DescriptionFromBitmap(ABitmap, Desc) then
|
|
raise FPImageException.Create('Failed to get raw image description from bitmap');
|
|
|
|
if AWidth < 0 then AWidth := Desc.Width;
|
|
if AHeight < 0 then AHeight := Desc.Height;
|
|
R := Rect(0, 0, AWidth, AHeight);
|
|
if not RawImage_FromBitmap(RawImage, ABitmap, AMaskBitmap, @R) then
|
|
raise FPImageException.Create('Failed to get raw image from bitmap');
|
|
|
|
SetRawImage(RawImage);
|
|
end;
|
|
|
|
procedure TLazIntfImage.CreateBitmaps(out ABitmap, AMask: HBitmap; ASkipMask: boolean);
|
|
begin
|
|
if not RawImage_CreateBitmaps(FRawImage, ABitmap, AMask, ASkipMask)
|
|
then raise FPImageException.Create('Failed to create handles');
|
|
end;
|
|
|
|
procedure TLazIntfImage.SetRawImage(const ARawImage: TRawImage; ADataOwner: Boolean);
|
|
var
|
|
Desc: TRawImageDescription absolute ARawImage.Description;
|
|
begin
|
|
if FRawImage.IsEqual(ARawImage) then Exit;
|
|
|
|
BeginUpdate;
|
|
try
|
|
FreeData;
|
|
FRawImage := ARawImage;
|
|
FDataOwner := ADataOwner;
|
|
SetSize(Desc.Width, Desc.Height);
|
|
FCreateAllDataNeeded := False;
|
|
New(FLineStarts);
|
|
FLineStarts^.Init(Width, Height, Desc.BitsPerPixel, Desc.LineEnd, Desc.LineOrder);
|
|
New(FMaskLineStarts);
|
|
FMaskLineStarts^.Init(Width, Height, Desc.MaskBitsPerPixel, Desc.MaskLineEnd, Desc.LineOrder);
|
|
ChooseGetSetColorFunctions;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.GetRawImage(out ARawImage: TRawImage; ATransferOwnership: Boolean);
|
|
begin
|
|
ARawImage := FRawImage;
|
|
if ATransferOwnership
|
|
then FDataOwner := False;
|
|
end;
|
|
|
|
procedure TLazIntfImage.FillPixels(const Color: TFPColor);
|
|
var
|
|
ColorChar: char;
|
|
ColorWord: Word;
|
|
Cnt: Integer;
|
|
i: Integer;
|
|
ColorDWord: Cardinal;
|
|
y: Integer;
|
|
x: Integer;
|
|
begin
|
|
if (Width=0) or (Height=0) or (FRawImage.Data=nil) then exit;
|
|
|
|
case FRawImage.Description.BitsPerPixel of
|
|
|
|
8:
|
|
begin
|
|
SetInternalColor(0,0,Color);
|
|
ColorChar:=Char(FRawImage.Data[0]);
|
|
FillChar(FRawImage.Data^,FRawImage.DataSize,ColorChar);
|
|
end;
|
|
|
|
16:
|
|
begin
|
|
SetInternalColor(0,0,Color);
|
|
ColorWord:=PWord(FRawImage.Data)[0];
|
|
Cnt:=FRawImage.DataSize div 2;
|
|
for i:=0 to Cnt-1 do
|
|
PWord(FRawImage.Data)[i]:=ColorWord;
|
|
end;
|
|
|
|
32:
|
|
begin
|
|
SetInternalColor(0,0,Color);
|
|
ColorDWord:=PDWord(FRawImage.Data)[0];
|
|
Cnt:=FRawImage.DataSize div 4;
|
|
for i:=0 to Cnt-1 do
|
|
PDWord(FRawImage.Data)[i]:=ColorDWord;
|
|
end;
|
|
|
|
else
|
|
for y:=0 to Height-1 do
|
|
for x:=0 to Width-1 do
|
|
SetInternalColor(x,y,Color);
|
|
end;
|
|
|
|
// ToDo: mask
|
|
end;
|
|
|
|
{
|
|
Merges an image to a canvas using alpha blend acording to a separate image
|
|
containing the alpha channel. White pixels in the alpha channel will correspond
|
|
to the source image pixel being fully drawn, grey ones are merged and
|
|
black ones ignored.
|
|
|
|
If ASourceAlpha = nil then it will utilize the alpha channel from ASource
|
|
}
|
|
procedure TLazIntfImage.AlphaBlend(ASource, ASourceAlpha: TLazIntfImage;
|
|
const ADestX, ADestY: Integer);
|
|
var
|
|
x, y, CurX, CurY: Integer;
|
|
MaskValue, InvMaskValue: Word;
|
|
CurColor: TFPColor;
|
|
lDrawWidth, lDrawHeight: Integer;
|
|
begin
|
|
// Take care not to draw outside the destination area
|
|
lDrawWidth := Min(Self.Width - ADestX, ASource.Width);
|
|
lDrawHeight := Min(Self.Height - ADestY, ASource.Height);
|
|
for y := 0 to lDrawHeight - 1 do
|
|
begin
|
|
for x := 0 to lDrawWidth - 1 do
|
|
begin
|
|
CurX := ADestX + x;
|
|
CurY := ADestY + y;
|
|
|
|
// Never draw outside the destination
|
|
if (CurX < 0) or (CurY < 0) then Continue;
|
|
|
|
if ASourceAlpha <> nil then
|
|
MaskValue := ASourceAlpha.Colors[x, y].alpha
|
|
else
|
|
MaskValue := ASource.Colors[x, y].alpha;
|
|
|
|
InvMaskValue := $FFFF - MaskValue;
|
|
|
|
if MaskValue = $FFFF then
|
|
begin
|
|
Self.Colors[CurX, CurY] := ASource.Colors[x, y];
|
|
end
|
|
else if MaskValue > $00 then
|
|
begin
|
|
CurColor := Self.Colors[CurX, CurY];
|
|
|
|
CurColor.Red := Round(
|
|
CurColor.Red * InvMaskValue / $FFFF +
|
|
ASource.Colors[x, y].Red * MaskValue / $FFFF);
|
|
|
|
CurColor.Green := Round(
|
|
CurColor.Green * InvMaskValue / $FFFF +
|
|
ASource.Colors[x, y].Green * MaskValue / $FFFF);
|
|
|
|
CurColor.Blue := Round(
|
|
CurColor.Blue * InvMaskValue / $FFFF +
|
|
ASource.Colors[x, y].Blue * MaskValue / $FFFF);
|
|
|
|
Self.Colors[CurX, CurY] := CurColor;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazIntfImage.CopyPixels(ASource: TFPCustomImage; XDst: Integer;
|
|
YDst: Integer; AlphaMask: Boolean; AlphaTreshold: Word);
|
|
var
|
|
SrcImg: TLazIntfImage absolute ASource;
|
|
SrcHasMask, DstHasMask, SrcMaskPix: Boolean;
|
|
x, y, xStart, yStart, xStop, yStop: Integer;
|
|
c: TFPColor;
|
|
Position: TRawImagePosition;
|
|
begin
|
|
{
|
|
if (Src.Width<>Width) or (Src.Height<>Height) then
|
|
SetSize(Src.Width,Src.Height);
|
|
}
|
|
if (ASource is TLazIntfImage)
|
|
and FRawImage.Description.IsEqual(SrcImg.FRawImage.Description)
|
|
and (XDst = 0) and (YDst = 0) then
|
|
begin
|
|
// same description -> copy
|
|
if FRawImage.Data <> nil then
|
|
System.Move(SrcImg.FRawImage.Data^,FRawImage.Data^,FRawImage.DataSize);
|
|
if FRawImage.Mask <> nil then
|
|
System.Move(SrcImg.FRawImage.Mask^,FRawImage.Mask^,FRawImage.MaskSize);
|
|
Exit;
|
|
end;
|
|
|
|
// copy pixels
|
|
XStart := IfThen(XDst < 0, -XDst, 0);
|
|
YStart := IfThen(YDst < 0, -YDst, 0);
|
|
XStop := IfThen(Width - XDst < ASource.Width, Width - XDst, ASource.Width) - 1;
|
|
YStop := IfTHen(Height - YDst < ASource.Height, Height - YDst, ASource.Height) - 1;
|
|
|
|
if ASource is TLazIntfImage then
|
|
begin
|
|
SrcHasMask := SrcImg.FRawImage.Description.MaskBitsPerPixel > 0;
|
|
DstHasMask := FRawImage.Description.MaskBitsPerPixel > 0;
|
|
// Optimization for common case. Inner loop is called millions of times in a big app.
|
|
for y:=yStart to yStop do
|
|
for x:=xStart to xStop do
|
|
begin
|
|
SrcImg.FGetInternalColorProc(x,y,c); // c := SrcImg.Colors[x,y];
|
|
if DstHasMask then // This can be optimized if needed.
|
|
Masked[x+XDst,y+YDst] := SrcHasMask and SrcImg.Masked[x,y]
|
|
else
|
|
if SrcHasMask and (c.alpha = $FFFF) then
|
|
begin // copy mask to alpha channel
|
|
SrcImg.GetXYMaskPosition(x,y,Position); //if SrcImg.Masked[x,y] then
|
|
SrcImg.FRawimage.ReadMask(Position, SrcMaskPix);
|
|
if SrcMaskPix then
|
|
c.alpha := 0;
|
|
end;
|
|
FSetInternalColorProc(x+XDst, y+YDst, c); // Colors[x+XDst,y+YDst] := c;
|
|
if AlphaMask and DstHasMask and (c.alpha < AlphaTreshold) then begin
|
|
GetXYMaskPosition(x+XDst, y+YDst, Position); // Masked[x+XDst,y+YDst]:=True;
|
|
FRawImage.WriteMask(Position, True);
|
|
FMaskSet := True;
|
|
end;
|
|
end;
|
|
end
|
|
else begin
|
|
for y:=yStart to yStop do
|
|
for x:=xStart to xStop do
|
|
begin
|
|
c := ASource.Colors[x,y];
|
|
Colors[x+XDst,y+YDst] := c;
|
|
if AlphaMask and (c.alpha < AlphaTreshold) then
|
|
Masked[x+XDst,y+YDst] := True;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TLazReaderXPM }
|
|
|
|
type
|
|
TXPMPixelToColorEntry = record
|
|
Color: TFPColor;
|
|
end;
|
|
PXPMPixelToColorEntry = ^TXPMPixelToColorEntry;
|
|
|
|
procedure TLazReaderXPM.ClearPixelToColorTree;
|
|
var
|
|
Entry: PXPMPixelToColorEntry;
|
|
ArrNode: TArrayNode;
|
|
begin
|
|
if FPixelToColorTree<>nil then begin
|
|
ArrNode:=FPixelToColorTree.Root;
|
|
while ArrNode<>nil do begin
|
|
Entry:=PXPMPixelToColorEntry(ArrNode.Data);
|
|
if Entry<>nil then begin
|
|
//DebugLn('TLazReaderXPM.ClearPixelToColorTree A ',DbgS(ArrNode),' ',DbgS(Entry));
|
|
Dispose(Entry);
|
|
end;
|
|
ArrNode:=ArrNode.FindNextUTF8;
|
|
end;
|
|
FPixelToColorTree.Free;
|
|
FPixelToColorTree:=nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazReaderXPM.InternalRead(Str: TStream; Img: TFPCustomImage);
|
|
type
|
|
TSrcLine = record
|
|
StartPos: integer;
|
|
EndPos: integer;
|
|
end;
|
|
|
|
var
|
|
SrcPos: integer;
|
|
Src: String;
|
|
SrcLen: Integer;
|
|
CurLineNumber, LastLineStart: integer;
|
|
HasAlpha: Boolean;
|
|
|
|
procedure RaiseXPMReadError(const Msg: string; ReadPos: integer);
|
|
var
|
|
CurColumn: Integer;
|
|
begin
|
|
CurColumn:=ReadPos-LastLineStart+1;
|
|
raise Exception.Create(Msg
|
|
+' in xpm stream at line '+IntToStr(CurLineNumber)
|
|
+' column '+IntToStr(CurColumn));
|
|
end;
|
|
|
|
// read next string constant "" and skip comments
|
|
function ReadNextLine(var Line: TSrcLine;
|
|
ExceptionOnNotFound: Boolean): boolean;
|
|
begin
|
|
while SrcPos<=SrcLen do begin
|
|
case Src[SrcPos] of
|
|
|
|
#10,#13:
|
|
begin
|
|
// count linenumbers for nicer error output
|
|
inc(SrcPos);
|
|
inc(CurLineNumber);
|
|
if (SrcPos<=SrcLen) and (Src[SrcPos] in [#10,#13])
|
|
and (Src[SrcPos]<>Src[SrcPos-1]) then
|
|
inc(SrcPos);
|
|
LastLineStart:=SrcPos;
|
|
end;
|
|
|
|
'/':
|
|
begin
|
|
if (SrcPos<SrcLen) and (Src[SrcPos+1]='*') then begin
|
|
// this is a C comment
|
|
// -> skip comment
|
|
inc(SrcPos,2);
|
|
while (SrcPos<SrcLen) do begin
|
|
if (Src[SrcPos]='*') and (Src[SrcPos+1]='/') then begin
|
|
// comment end found
|
|
inc(SrcPos,2);
|
|
break;
|
|
end;
|
|
inc(SrcPos);
|
|
end;
|
|
end else
|
|
RaiseXPMReadError('syntax error',SrcPos);
|
|
end;
|
|
|
|
'"':
|
|
begin
|
|
// start of a string constant
|
|
inc(SrcPos);
|
|
Line.StartPos:=SrcPos;
|
|
while (SrcPos<SrcLen) do begin
|
|
if (Src[SrcPos]='"') and (Src[SrcPos-1]<>'\') then begin
|
|
// string end found
|
|
Line.EndPos:=SrcPos;
|
|
//DebugLn(' ',copy(Src,Line.StartPos-1,Line.EndPos-Line.StartPos+2));
|
|
inc(SrcPos);
|
|
Result:=true;
|
|
exit;
|
|
end;
|
|
inc(SrcPos);
|
|
end;
|
|
end;
|
|
|
|
else
|
|
inc(SrcPos);
|
|
end;
|
|
end;
|
|
Result:=false;
|
|
if ExceptionOnNotFound then
|
|
Raise Exception.Create('Unexpected end of xpm stream');
|
|
end;
|
|
|
|
function ReadNumber(var ReadPos: integer;
|
|
ExceptionOnNotFound: Boolean): integer;
|
|
begin
|
|
// skip spaces
|
|
while IsSpaceChar[Src[ReadPos]] do inc(ReadPos);
|
|
// read number
|
|
Result:=0;
|
|
if IsNumberChar[Src[ReadPos]] then begin
|
|
repeat
|
|
Result:=Result*10+ord(Src[ReadPos])-Ord('0');
|
|
inc(ReadPos);
|
|
until not IsNumberChar[Src[ReadPos]];
|
|
end else if ExceptionOnNotFound then
|
|
RaiseXPMReadError('number expected',ReadPos);
|
|
end;
|
|
|
|
procedure ReadHeader;
|
|
var
|
|
FirstLine: TSrcLine;
|
|
begin
|
|
ReadNextLine(FirstLine,true);
|
|
FWidth:=ReadNumber(FirstLine.StartPos,true);
|
|
FHeight:=ReadNumber(FirstLine.StartPos,true);
|
|
FColorCount:=ReadNumber(FirstLine.StartPos,true);
|
|
FCharsPerPixel:=ReadNumber(FirstLine.StartPos,true);
|
|
fXHot:=ReadNumber(FirstLine.StartPos,false);
|
|
fYHot:=ReadNumber(FirstLine.StartPos,fXHot<>0);
|
|
//DebugLn('ReadHeader A Width=',FWidth,' Height=',FHeight,' ColorCount=',FColorCount,' CharsPerPixel=',FCharsPerPixel);
|
|
// ToDo: parse XPMExt tag
|
|
end;
|
|
|
|
function HexToColor(HexStart, HexEnd: integer): TFPColor;
|
|
|
|
procedure ReadHexNumber(var StartPos: integer; Len: integer;
|
|
var Number: word);
|
|
var
|
|
c: Char;
|
|
i: Integer;
|
|
begin
|
|
Number:=0;
|
|
for i:=1 to 4 do begin
|
|
Number:=Number shl 4;
|
|
if i<=Len then begin
|
|
c:=Src[StartPos];
|
|
case c of
|
|
'0'..'9': inc(Number,ord(c)-ord('0'));
|
|
'A'..'F': inc(Number,ord(c)-ord('A')+10);
|
|
'a'..'f': inc(Number,ord(c)-ord('a')+10);
|
|
end;
|
|
inc(StartPos);
|
|
end;
|
|
end;
|
|
// fill missing bits
|
|
case Len of
|
|
1: Number:=Number or (Number shr 4) or (Number shr 8) or (Number shr 12);
|
|
2: Number:=Number or (Number shr 8);
|
|
3: Number:=Number or (Number shr 12);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
HexLen: Integer;
|
|
SampleLen: Integer;
|
|
SampleStart: Integer;
|
|
begin
|
|
HexLen:=HexEnd-HexStart;
|
|
case HexLen of
|
|
3: SampleLen:=1;
|
|
6: SampleLen:=2;
|
|
9: SampleLen:=3;
|
|
12:SampleLen:=4;
|
|
else
|
|
RaiseXPMReadError('hexnumber expected',HexStart);
|
|
end;
|
|
SampleStart:=HexStart;
|
|
ReadHexNumber(SampleStart,SampleLen,Result.Red);
|
|
ReadHexNumber(SampleStart,SampleLen,Result.Green);
|
|
ReadHexNumber(SampleStart,SampleLen,Result.Blue);
|
|
Result.Alpha:=alphaOpaque;
|
|
end;
|
|
|
|
function TextToColor(TextStart, TextEnd: integer): TFPColor;
|
|
var
|
|
s: String;
|
|
begin
|
|
s := lowercase(copy(Src,TextStart,TextEnd-TextStart));
|
|
if s = 'transparent' then
|
|
Result := FPImage.colTransparent
|
|
else if s = 'none' then
|
|
Result := FPImage.colTransparent
|
|
else if s = 'black' then
|
|
result := FPImage.colBlack
|
|
else if s = 'blue' then
|
|
Result := FPImage.colBlue
|
|
else if s = 'green' then
|
|
Result := FPImage.colGreen
|
|
else if s = 'cyan' then
|
|
Result := FPImage.colCyan
|
|
else if s = 'red' then
|
|
Result := FPImage.colRed
|
|
else if s = 'magenta' then
|
|
Result := FPImage.colMagenta
|
|
else if s = 'yellow' then
|
|
Result := FPImage.colYellow
|
|
else if s = 'white' then
|
|
Result := FPImage.colWhite
|
|
else if s = 'gray' then
|
|
Result := FPImage.colGray
|
|
else if s = 'lightgray' then
|
|
Result := FPImage.colLtGray
|
|
else if (s = 'darkgray') or (s='grey') then
|
|
Result := FPImage.colDKGray
|
|
else if s = 'darkblue' then
|
|
Result := FPImage.colDkBlue
|
|
else if s = 'darkgreen' then
|
|
Result := FPImage.colDkGreen
|
|
else if s = 'darkcyan' then
|
|
Result := FPImage.colDkCyan
|
|
else if s = 'darkred' then
|
|
Result := FPImage.colDkRed
|
|
else if s = 'darkmagenta' then
|
|
Result := FPImage.colDkMagenta
|
|
else if s = 'darkyellow' then
|
|
Result := FPImage.colDkYellow
|
|
else if s = 'maroon' then
|
|
Result := FPImage.colMaroon
|
|
else if s = 'lightgreen' then
|
|
Result := FPImage.colLtGreen
|
|
else if s = 'olive' then
|
|
Result := FPImage.colOlive
|
|
else if s = 'navy' then
|
|
Result := FPImage.colNavy
|
|
else if s = 'purple' then
|
|
Result := FPImage.colPurple
|
|
else if s = 'teal' then
|
|
Result := FPImage.colTeal
|
|
else if s = 'silver' then
|
|
Result := FPImage.colSilver
|
|
else if s = 'lime' then
|
|
Result := FPImage.colLime
|
|
else if s = 'fuchsia' then
|
|
Result := FPImage.colFuchsia
|
|
else if s = 'aqua' then
|
|
Result := FPImage.colAqua
|
|
else
|
|
Result := FPImage.colTransparent;
|
|
end;
|
|
|
|
procedure AddColor(PixelStart: integer; const AColor: TFPColor;
|
|
IntArray: PInteger);
|
|
var
|
|
NewEntry: PXPMPixelToColorEntry;
|
|
i: Integer;
|
|
begin
|
|
{DebugLn('TLazReaderXPM.InternalRead.AddColor A "',DbgStr(copy(Src,PixelStart,FCharsPerPixel)),'"=',
|
|
DbgS(AColor.Red),',',
|
|
DbgS(AColor.Green),',',
|
|
DbgS(AColor.Blue),',',
|
|
DbgS(AColor.Alpha));}
|
|
New(NewEntry);
|
|
NewEntry^.Color:=AColor;
|
|
// add entry to Array Tree
|
|
if FPixelToColorTree=nil then
|
|
FPixelToColorTree:=TArrayNodesTree.Create;
|
|
for i:=0 to FCharsPerPixel-1 do
|
|
IntArray[i]:=ord(Src[PixelStart+i]);
|
|
FPixelToColorTree.SetNode(IntArray,FCharsPerPixel,NewEntry);
|
|
//if FPixelToColorTree.FindData(IntArray,FCharsPerPixel)<>NewEntry then RaiseGDBException('');
|
|
end;
|
|
|
|
procedure ReadPalette(IntArray: PInteger);
|
|
var
|
|
i: Integer;
|
|
Line: TSrcLine;
|
|
ReadPos: Integer;
|
|
ColorStart: Integer;
|
|
ColorEnd: Integer;
|
|
NewColor: TFPColor;
|
|
PixelStart: Integer;
|
|
begin
|
|
for i:=1 to FColorCount do begin
|
|
ReadNextLine(Line,true);
|
|
ReadPos:=Line.StartPos;
|
|
// read pixel string
|
|
PixelStart:=ReadPos;
|
|
inc(ReadPos,FCharsPerPixel);
|
|
// skip spaces
|
|
while IsSpaceChar[Src[ReadPos]] do inc(ReadPos);
|
|
// read 'c' (sometimes the 'c' is an 's')
|
|
if not (Src[ReadPos] in ['c','s']) then
|
|
RaiseXPMReadError('"c" expected',ReadPos);
|
|
inc(ReadPos);
|
|
// skip spaces
|
|
while IsSpaceChar[Src[ReadPos]] do inc(ReadPos);
|
|
// read color string
|
|
ColorStart:=ReadPos;
|
|
if Src[ReadPos]='#' then begin
|
|
inc(ColorStart);
|
|
// read as hexnumber
|
|
repeat
|
|
inc(ReadPos);
|
|
until not (IsHexNumberChar[Src[ReadPos]]);
|
|
ColorEnd:=ReadPos;
|
|
NewColor:=HexToColor(ColorStart,ColorEnd);
|
|
end
|
|
else begin
|
|
// read as text
|
|
repeat
|
|
inc(ReadPos);
|
|
until not (Src[ReadPos] in ['A'..'Z','a'..'z']);
|
|
ColorEnd:=ReadPos;
|
|
NewColor:=TextToColor(ColorStart,ColorEnd);
|
|
end;
|
|
AddColor(PixelStart,NewColor,IntArray);
|
|
|
|
HasAlpha := HasAlpha or (NewColor.alpha <> alphaOpaque);
|
|
end;
|
|
end;
|
|
|
|
procedure ReadPixels(IntArray: PInteger);
|
|
var
|
|
y: Integer;
|
|
Line: TSrcLine;
|
|
ReadPos: Integer;
|
|
x: Integer;
|
|
i: Integer;
|
|
CurColor: TFPColor;
|
|
CurEntry: PXPMPixelToColorEntry;
|
|
begin
|
|
Img.SetSize(FWidth, FHeight);
|
|
for y := 0 to FHeight - 1 do
|
|
begin
|
|
if not FContinue then
|
|
Exit;
|
|
ReadNextLine(Line,true);
|
|
ReadPos:=Line.StartPos;
|
|
if Line.EndPos-Line.StartPos<FCharsPerPixel*FWidth then
|
|
RaiseXPMReadError('line too short',ReadPos);
|
|
for x:=0 to FWidth-1 do
|
|
begin
|
|
//DebugLn('ReadPixels x=',dbgs(x),' y=',dbgs(y),' color="',DbgStr(copy(Src,ReadPos,FCharsPerPixel)),'"');
|
|
for i:=0 to FCharsPerPixel-1 do begin
|
|
IntArray[i]:=ord(Src[ReadPos]);
|
|
inc(ReadPos);
|
|
end;
|
|
CurEntry:=PXPMPixelToColorEntry(
|
|
FPixelToColorTree.FindData(IntArray,FCharsPerPixel));
|
|
if CurEntry<>nil then
|
|
CurColor:=CurEntry^.Color
|
|
else
|
|
RaiseXPMReadError('invalid color',ReadPos-FCharsPerPixel);
|
|
{if CurEntry2<>CurEntry then begin
|
|
DebugLn('x=',x,' y=',y,' Pixel=',Entry^.Pixel,
|
|
' RefPixel=',CurEntry^.Pixel,
|
|
' Color=',
|
|
DbgS(CurColor.Red),',',
|
|
DbgS(CurColor.Green),',',
|
|
DbgS(CurColor.Blue),',',
|
|
DbgS(CurColor.Alpha));
|
|
DebugLn('Entry2: Pixel=',CurEntry2^.Pixel,
|
|
' RefPixel=',CurEntry2^.Pixel,
|
|
' Color=',
|
|
DbgS(CurEntry2^.Color.Red),',',
|
|
DbgS(CurEntry2^.Color.Green),',',
|
|
DbgS(CurEntry2^.Color.Blue),',',
|
|
DbgS(CurEntry2^.Color.Alpha));
|
|
end;}
|
|
|
|
{DebugLn('x=',x,' y=',y,' Pixel=',Entry^.Pixel,
|
|
' RefPixel=',PXPMPixelToColorEntry(Node.Data)^.Pixel,
|
|
' Color=',
|
|
DbgS(CurColor.Red),',',
|
|
DbgS(CurColor.Green),',',
|
|
DbgS(CurColor.Blue),',',
|
|
DbgS(CurColor.Alpha));}
|
|
Img.Colors[x,y]:=CurColor;
|
|
end;
|
|
Progress(psRunning, trunc(100.0 * (Y + 1) / FHeight), False, Rect(0, 0, FWidth - 1, y), 'reading XPM pixels', FContinue);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
IntArray: array of Integer;
|
|
Desc: TRawImageDescription;
|
|
begin
|
|
FContinue := True;
|
|
Progress(psStarting, 0, False, Rect(0,0,0,0), '', FContinue);
|
|
|
|
ClearPixelToColorTree;
|
|
Src:=ReadCompleteStreamToString(Str,1024);
|
|
SrcLen:=length(Src);
|
|
SrcPos:=1;
|
|
CurLineNumber:=1;
|
|
LastLineStart:=1;
|
|
ReadHeader;
|
|
|
|
SetLength(IntArray, FCharsPerPixel+1);
|
|
|
|
HasAlpha := False;
|
|
ReadPalette(@IntArray[0]);
|
|
|
|
if FUpdateDescription and (theImage is TLazIntfImage)
|
|
then begin
|
|
if HasAlpha
|
|
then DefaultReaderDescription(FWidth, FHeight, 32, Desc)
|
|
else DefaultReaderDescription(FWidth, FHeight, 24, Desc);
|
|
// MWE: keep mask ?
|
|
// if FMaskMode = lrmmNone
|
|
// then Desc.MaskBitsPerPixel := 0;
|
|
TLazIntfImage(theImage).DataDescription := Desc;
|
|
end
|
|
else begin
|
|
if HasAlpha
|
|
then CheckAlphaDescription(TheImage);
|
|
end;
|
|
//FPixelToColorTree.ConsistencyCheck;
|
|
ReadPixels(@IntArray[0]);
|
|
|
|
Progress(psEnding, 100, false, Rect(0,0,0,0), '', FContinue);
|
|
end;
|
|
|
|
function TLazReaderXPM.QueryInterface(constref iid: TGuid; out obj): longint; {$IFDEF WINDOWs}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
if GetInterface(iid, obj)
|
|
then Result := S_OK
|
|
else Result := E_NOINTERFACE;
|
|
end;
|
|
|
|
procedure TLazReaderXPM.SetUpdateDescription(AValue: Boolean);
|
|
begin
|
|
FUpdateDescription := AValue;
|
|
end;
|
|
|
|
function TLazReaderXPM._AddRef: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
function TLazReaderXPM._Release: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
function TLazReaderXPM.InternalCheck(Str: TStream): boolean;
|
|
var s : string[9];
|
|
l : integer;
|
|
begin
|
|
try
|
|
l := str.Read (s[1],9);
|
|
s[0] := char(l);
|
|
if l <> 9 then
|
|
result := False
|
|
else
|
|
result := (s = '/* XPM */');
|
|
except
|
|
result := false;
|
|
end;
|
|
end;
|
|
|
|
constructor TLazReaderXPM.Create;
|
|
begin
|
|
inherited Create;
|
|
end;
|
|
|
|
destructor TLazReaderXPM.Destroy;
|
|
begin
|
|
ClearPixelToColorTree;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TLazReaderXPM.GetUpdateDescription: Boolean;
|
|
begin
|
|
Result := FUpdateDescription;
|
|
end;
|
|
|
|
{ TLazAVLPalette }
|
|
|
|
type
|
|
TLazAVLPaletteEntry = record
|
|
Palette: TLazAVLPalette;
|
|
Index: integer;
|
|
end;
|
|
PLazAVLPaletteEntry = ^TLazAVLPaletteEntry;
|
|
|
|
function CompareLazAVLPaletteEntries(Entry1, Entry2: PLazAVLPaletteEntry): integer;
|
|
begin
|
|
Result := Entry1^.Palette.CompareEntries(Entry1^.Index, Entry2^.Index);
|
|
end;
|
|
|
|
function ComparePFPColorAndLazAVLPalEntry(PColor: PFPColor; Entry: PLazAVLPaletteEntry): integer;
|
|
begin
|
|
Result := Entry^.Palette.CompareColorWithEntries(PColor^, Entry^.Index);
|
|
end;
|
|
|
|
procedure TLazAVLPalette.SetCount(NewCount: integer);
|
|
var
|
|
NewAVLPalEntry: PLazAVLPaletteEntry;
|
|
AVLNode: TAvlTreeNode;
|
|
CurAVLPalEntry: PLazAVLPaletteEntry;
|
|
Index: Integer;
|
|
begin
|
|
if FCount=NewCount then exit;
|
|
// remove unused colors from 'color to index' tree
|
|
if FAVLPalette<>nil then begin
|
|
for Index:=FCount-1 downto NewCount do begin
|
|
AVLNode:=FAVLNodes[Index];
|
|
CurAVLPalEntry:=PLazAVLPaletteEntry(AVLNode.Data);
|
|
FAVLPalette.Delete(AVLNode);
|
|
FAVLNodes[Index]:=nil;
|
|
Dispose(CurAVLPalEntry);
|
|
end;
|
|
end;
|
|
inherited SetCount(NewCount);
|
|
// create tree if not already done
|
|
if (FAVLPalette=nil) and (FCount>0) then
|
|
FAVLPalette:=TAvlTree.Create(TListSortCompare(@CompareLazAVLPaletteEntries));
|
|
if FAVLPalette=nil then exit;
|
|
// add new colors to 'color to index' tree and 'index to node' array
|
|
while FAVLPalette.Count<FCount do begin
|
|
Index:=FAVLPalette.Count;
|
|
New(NewAVLPalEntry);
|
|
NewAVLPalEntry^.Palette:=Self;
|
|
NewAVLPalEntry^.Index:=Index;
|
|
FAVLNodes[Index]:=FAVLPalette.Add(NewAVLPalEntry);
|
|
end;
|
|
end;
|
|
|
|
procedure TLazAVLPalette.SetColor(Index: integer; const NewColor: TFPColor);
|
|
var
|
|
Node: TAvlTreeNode;
|
|
Entry: PLazAVLPaletteEntry;
|
|
begin
|
|
if Index=FCount then
|
|
Add(NewColor)
|
|
else begin
|
|
CheckIndex(Index);
|
|
if FData^[Index]=NewColor then exit;
|
|
// remove node from tree
|
|
Node:=FAVLNodes[Index];
|
|
Entry:=PLazAVLPaletteEntry(Node.Data);
|
|
FAVLPalette.Delete(Node);
|
|
// change color
|
|
FData^[index] := NewColor;
|
|
// add node
|
|
FAVLNodes[Index]:=FAVLPalette.Add(Entry);
|
|
end;
|
|
end;
|
|
|
|
destructor TLazAVLPalette.Destroy;
|
|
begin
|
|
SetCount(0);
|
|
FAVLPalette.Free;
|
|
FAVLPalette:=nil;
|
|
if FCapacity>0 then
|
|
FreeMem(FAVLNodes);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TLazAVLPalette.IndexOf(const AColor: TFPColor): integer;
|
|
var
|
|
Node: TAvlTreeNode;
|
|
begin
|
|
if FAVLPalette<>nil then
|
|
Node:=FAVLPalette.FindKey(@AColor,TListSortCompare(@ComparePFPColorAndLazAVLPalEntry))
|
|
else
|
|
Node:=nil;
|
|
if Node<>nil then
|
|
Result:=PLazAVLPaletteEntry(Node.Data)^.Index
|
|
else
|
|
Result:=Add(AColor);
|
|
end;
|
|
|
|
function TLazAVLPalette.Add(const NewColor: TFPColor): integer;
|
|
begin
|
|
Result:=FCount;
|
|
if FCount=FCapacity then EnlargeData;
|
|
SetCount(FCount+1);
|
|
SetColor(Result,NewColor);
|
|
end;
|
|
|
|
function TLazAVLPalette.CompareEntries(Index1, Index2: integer): integer;
|
|
begin
|
|
Result:=CompareColors(FData^[Index1],FData^[Index2]);
|
|
end;
|
|
|
|
function TLazAVLPalette.CompareColorWithEntries(const AColor: TFPColor;
|
|
Index: integer): integer;
|
|
begin
|
|
Result:=CompareColors(AColor,FData^[Index]);
|
|
end;
|
|
|
|
procedure TLazAVLPalette.EnlargeData;
|
|
var
|
|
NewCapacity: Integer;
|
|
begin
|
|
if FCapacity<16 then
|
|
NewCapacity:=32
|
|
else if FCapacity<64 then
|
|
NewCapacity:=128
|
|
else
|
|
NewCapacity:=FCapacity*2;
|
|
ReallocMem(FData,SizeOf(TFPColor)*NewCapacity);
|
|
ReallocMem(FAVLNodes,SizeOf(Pointer)*NewCapacity);
|
|
FCapacity:=NewCapacity;
|
|
end;
|
|
|
|
procedure TLazAVLPalette.CheckConsistency;
|
|
var
|
|
Node: TAvlTreeNode;
|
|
Entry: PLazAVLPaletteEntry;
|
|
i: Integer;
|
|
begin
|
|
if FAVLPalette<>nil then begin
|
|
FAVLPalette.ConsistencyCheck;
|
|
if FAVLPalette.Count<>FCount then
|
|
RaiseGDBException('TLazAVLPalette.ConsistencyCheck');
|
|
end;
|
|
if FAVLNodes<>nil then begin
|
|
for i:=0 to FCapacity-1 do begin
|
|
Node:=FAVLNodes[i];
|
|
if i>=FCount then begin
|
|
continue;
|
|
end;
|
|
if Node=nil then
|
|
RaiseGDBException('TLazAVLPalette.ConsistencyCheck');
|
|
Entry:=PLazAVLPaletteEntry(Node.Data);
|
|
if Entry=nil then
|
|
RaiseGDBException('TLazAVLPalette.ConsistencyCheck');
|
|
if Entry^.Index<>i then
|
|
RaiseGDBException('TLazAVLPalette.ConsistencyCheck');
|
|
if Entry^.Palette<>Self then
|
|
RaiseGDBException('TLazAVLPalette.ConsistencyCheck');
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TLazWriterXPM }
|
|
|
|
const
|
|
DefXPMPalChars = '.,-*abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
|
+'0123456789@#;:=+%$()[]';
|
|
|
|
procedure TLazWriterXPM.SetNibblesPerSample(const AValue: word);
|
|
begin
|
|
if FNibblesPerSample=AValue then exit;
|
|
FNibblesPerSample:=AValue;
|
|
if FNibblesPerSample>4 then FNibblesPerSample:=4;
|
|
FRightShiftSample:=(4-FNibblesPerSample)*4;
|
|
end;
|
|
|
|
procedure TLazWriterXPM.InternalWrite(Str: TStream; Img: TFPCustomImage);
|
|
var
|
|
Palette: TLazAVLPalette;
|
|
PixelStrings: ^AnsiString;
|
|
ColorStrings: ^AnsiString;
|
|
CharsPerPixel: Integer;
|
|
LineEnd: string;
|
|
|
|
function GetColor(x,y: integer): TFPColor;
|
|
begin
|
|
Result:=Img.Colors[x,y];
|
|
if (Result.Alpha>=(alphaOpaque shr 1)) then
|
|
Result.Alpha:=alphaOpaque
|
|
else
|
|
Result:=colTransparent;
|
|
Result.Red:=Result.Red shr FRightShiftSample;
|
|
Result.Green:=Result.Green shr FRightShiftSample;
|
|
Result.Blue:=Result.Blue shr FRightShiftSample;
|
|
end;
|
|
|
|
function SampleToHex(Sample: word): string;
|
|
begin
|
|
Result:=HexStr(Sample,FNibblesPerSample);
|
|
end;
|
|
|
|
procedure BuildPalette;
|
|
var
|
|
x: Integer;
|
|
y: Integer;
|
|
PixelStringsSize: Integer;
|
|
i: Integer;
|
|
Rest: Integer;
|
|
c: char;
|
|
CharPos: Integer;
|
|
ColorStringsSize: Integer;
|
|
Color: TFPColor;
|
|
begin
|
|
// create Palette
|
|
Palette:=TLazAVLPalette.Create(0);
|
|
for y:=0 to Img.Height-1 do
|
|
for x:=0 to Img.Width-1 do
|
|
Palette.IndexOf(GetColor(x,y));
|
|
// calclulate CharsPerPixel
|
|
CharsPerPixel:=0;
|
|
i:=Palette.Count;
|
|
while i>0 do begin
|
|
i:=i div length(DefXPMPalChars);
|
|
inc(CharsPerPixel);
|
|
end;
|
|
// create pixel strings
|
|
PixelStringsSize:=SizeOf(Pointer)*Palette.Count;
|
|
ReAllocMem(PixelStrings,PixelStringsSize);
|
|
FillChar(PixelStrings^,PixelStringsSize,0);
|
|
for i:=0 to Palette.Count-1 do begin
|
|
SetLength(PixelStrings[i],CharsPerPixel);
|
|
Rest:=i;
|
|
for CharPos:=CharsPerPixel downto 1 do begin
|
|
c:=DefXPMPalChars[(Rest mod length(DefXPMPalChars))+1];
|
|
PixelStrings[i][CharPos]:=c;
|
|
Rest:=Rest div length(DefXPMPalChars);
|
|
end;
|
|
end;
|
|
// create color strings
|
|
ColorStringsSize:=SizeOf(Pointer)*Palette.Count;
|
|
ReAllocMem(ColorStrings,ColorStringsSize);
|
|
FillChar(ColorStrings^,ColorStringsSize,0);
|
|
for i:=0 to Palette.Count-1 do begin
|
|
Color:=Palette[i];
|
|
if Color.Alpha=0 then begin
|
|
ColorStrings[i]:='None';
|
|
end else begin
|
|
ColorStrings[i]:='#'+SampleToHex(Color.Red)+SampleToHex(Color.Green)
|
|
+SampleToHex(Color.Blue);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure WriteString(const s: string);
|
|
begin
|
|
Str.Write(s[1],length(s));
|
|
end;
|
|
|
|
procedure WriteHeader;
|
|
var
|
|
s: String;
|
|
begin
|
|
s:='/* XPM */'+LineEnd;
|
|
s:=s+'static char *graphic[] = {'+LineEnd;
|
|
s:=s+'"'+IntToStr(Img.Width)+' '+IntToStr(Img.Height)
|
|
+' '+IntToStr(Palette.Count)+' '+IntToStr(CharsPerPixel)+'"';
|
|
if Palette.Count>0 then s:=s+',';
|
|
s:=s+LineEnd;
|
|
WriteString(s);
|
|
end;
|
|
|
|
procedure WritePalette;
|
|
var
|
|
s: string;
|
|
SrcPos: Integer;
|
|
|
|
procedure WriteToSrc(const AddString: string);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i:=1 to length(AddString) do begin
|
|
s[SrcPos]:=AddString[i];
|
|
inc(SrcPos);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
PaletteLineLen: Integer;
|
|
i: Integer;
|
|
SrcLen: Integer;
|
|
begin
|
|
// calculate needed memory
|
|
PaletteLineLen:=length('"')+CharsPerPixel+length(' c ')+length('",'+LineEnd);
|
|
SrcLen:=0;
|
|
for i:=0 to Palette.Count-1 do begin
|
|
inc(SrcLen,PaletteLineLen);
|
|
inc(SrcLen,length(ColorStrings[i]));
|
|
end;
|
|
// build palette source
|
|
SetLength(s,SrcLen);
|
|
SrcPos:=1;
|
|
for i:=0 to Palette.Count-1 do begin
|
|
WriteToSrc('"');
|
|
WriteToSrc(PixelStrings[i]);
|
|
WriteToSrc(' c ');
|
|
WriteToSrc(ColorStrings[i]);
|
|
WriteToSrc('",');
|
|
WriteToSrc(LineEnd);
|
|
end;
|
|
if SrcPos<>length(s)+1 then
|
|
RaiseGDBException('TLazWriterXPM.InternalWrite consistency ERROR SrcPos<>length(s)');
|
|
WriteString(s);
|
|
end;
|
|
|
|
procedure WritePixels;
|
|
var
|
|
s: string;
|
|
SrcPos: Integer;
|
|
|
|
procedure WriteToSrc(const AddString: string);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i:=1 to length(AddString) do begin
|
|
s[SrcPos]:=AddString[i];
|
|
inc(SrcPos);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
y: Integer;
|
|
x: Integer;
|
|
i: Integer;
|
|
SrcLenPerLine: Integer;
|
|
SrcLen: Integer;
|
|
begin
|
|
// calculate needed memory
|
|
SrcLenPerLine:=length('"')+CharsPerPixel*Img.Width+length('",')+length(LineEnd);
|
|
SrcLen:=Img.Height*SrcLenPerLine;
|
|
// build palette source
|
|
SetLength(s,SrcLen);
|
|
SrcPos:=1;
|
|
for y:=0 to Img.Height-1 do
|
|
begin
|
|
WriteToSrc('"');
|
|
for x:=0 to Img.Width-1 do
|
|
begin
|
|
i := Palette.IndexOf(GetColor(x,y));
|
|
WriteToSrc(PixelStrings[i]);
|
|
end;
|
|
Progress(psRunning, trunc(100.0 * ((y + 1) / Img.Height)),
|
|
False, Rect(0,0,Img.Width-1,y), 'writing XPM pixels', FContinue);
|
|
if y<Img.Height-1 then
|
|
WriteToSrc('",'+LineEnd)
|
|
else
|
|
WriteToSrc('"}'+LineEnd);
|
|
end;
|
|
if SrcPos<>length(s)+1 then
|
|
RaiseGDBException('TLazWriterXPM.InternalWrite consistency ERROR SrcPos<>length(s)');
|
|
WriteString(s);
|
|
end;
|
|
|
|
var
|
|
i: Integer;
|
|
begin
|
|
FContinue := True;
|
|
Progress(psStarting, 0, False, Rect(0,0,0,0), '', FContinue);
|
|
|
|
Palette:=nil;
|
|
PixelStrings:=nil;
|
|
ColorStrings:=nil;
|
|
LineEnd:=#10;
|
|
try
|
|
BuildPalette;
|
|
WriteHeader;
|
|
WritePalette;
|
|
WritePixels;
|
|
finally
|
|
if PixelStrings<>nil then begin
|
|
for i:=0 to Palette.Count-1 do begin
|
|
PixelStrings[i]:='';
|
|
ColorStrings[i]:='';
|
|
end;
|
|
ReAllocMem(PixelStrings,0);
|
|
ReAllocMem(ColorStrings,0);
|
|
end;
|
|
Palette.Free;
|
|
end;
|
|
Progress(psEnding, 100, false, Rect(0,0,0,0), '', FContinue);
|
|
end;
|
|
|
|
constructor TLazWriterXPM.Create;
|
|
begin
|
|
inherited Create;
|
|
FNibblesPerSample:=2;
|
|
FRightShiftSample:=8;
|
|
end;
|
|
|
|
{ TArrayNode }
|
|
|
|
constructor TArrayNode.Create;
|
|
begin
|
|
//DebugLn('TArrayNode.Create ',Capacity,' Self=',DbgS(Self));
|
|
end;
|
|
|
|
destructor TArrayNode.Destroy;
|
|
begin
|
|
DeleteChilds;
|
|
UnbindFromParent;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TArrayNode.DeleteChilds;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if Children<>nil then begin
|
|
for i:=0 to Capacity-1 do
|
|
Children[i].Free;
|
|
FreeMem(Children);
|
|
Children:=nil;
|
|
Capacity:=0;
|
|
end;
|
|
end;
|
|
|
|
procedure TArrayNode.UnbindFromParent;
|
|
begin
|
|
if Parent<>nil then begin
|
|
Parent.Children[Value-Parent.StartValue]:=nil;
|
|
Parent:=nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TArrayNode.CreateChildNode(ChildValue: integer);
|
|
var
|
|
NewNode: TArrayNode;
|
|
Index: Integer;
|
|
begin
|
|
NewNode:=TArrayNode.Create;
|
|
NewNode.Value:=ChildValue;
|
|
NewNode.Parent:=Self;
|
|
Index:=ChildValue-StartValue;
|
|
Children[Index]:=NewNode;
|
|
end;
|
|
|
|
function TArrayNode.GetChildNode(ChildValue: integer; CreateIfNotExists: boolean
|
|
): TArrayNode;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
Result:=nil;
|
|
Index:=ChildValue-StartValue;
|
|
if (Index<0) or (Index>=Capacity) then begin
|
|
// out of range
|
|
if not CreateIfNotExists then exit;
|
|
Expand(ChildValue);
|
|
Index:=ChildValue-StartValue;
|
|
end;
|
|
Result:=Children[Index];
|
|
if (Result=nil) and CreateIfNotExists then begin
|
|
CreateChildNode(ChildValue);
|
|
Result:=Children[Index];
|
|
end;
|
|
end;
|
|
|
|
procedure TArrayNode.Expand(ValueToInclude: integer);
|
|
var
|
|
Index: Integer;
|
|
NewChilds: PArrayNode;
|
|
NewSize: Integer;
|
|
i: Integer;
|
|
NewStartValue: Integer;
|
|
NewCapacity: Integer;
|
|
OldSize: Integer;
|
|
begin
|
|
//DebugLn('TArrayNode.Expand A ',ValueToInclude,' Capacity=',Capacity,' StartValue=',StartValue);
|
|
if Children=nil then begin
|
|
NewStartValue:=ValueToInclude;
|
|
NewCapacity:=4;
|
|
end else begin
|
|
Index:=ValueToInclude-StartValue;
|
|
if (Index>=0) and (Index<Capacity) then exit;
|
|
NewStartValue:=StartValue;
|
|
NewCapacity:=Capacity;
|
|
if NewStartValue>ValueToInclude then begin
|
|
inc(NewCapacity,NewStartValue-ValueToInclude);
|
|
NewStartValue:=ValueToInclude;
|
|
end else begin
|
|
Index:=ValueToInclude-NewStartValue;
|
|
if Index>=NewCapacity then
|
|
NewCapacity:=Index+1;
|
|
end;
|
|
// make NewCapacity a power of 2
|
|
for i:=1 to 30 do begin
|
|
if (1 shl i)>=NewCapacity then begin
|
|
NewCapacity:=1 shl i;
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
NewSize:=SizeOf(Pointer)*NewCapacity;
|
|
GetMem(NewChilds,NewSize);
|
|
FillChar(NewChilds^,NewSize,0);
|
|
if Children<>nil then begin
|
|
OldSize:=SizeOf(Pointer)*Capacity;
|
|
System.Move(Children^,NewChilds[StartValue-NewStartValue],OldSize);
|
|
FreeMem(Children);
|
|
end;
|
|
Children:=NewChilds;
|
|
StartValue:=NewStartValue;
|
|
Capacity:=NewCapacity;
|
|
end;
|
|
|
|
function TArrayNode.FindPrevSibling: TArrayNode;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result:=nil;
|
|
if Parent=nil then exit;
|
|
i:=Value-Parent.StartValue-1;
|
|
while (i>=0) do begin
|
|
if Parent.Children[i]<>nil then begin
|
|
Result:=Parent.Children[i];
|
|
exit;
|
|
end;
|
|
dec(i);
|
|
end;
|
|
end;
|
|
|
|
function TArrayNode.FindNextSibling: TArrayNode;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result:=nil;
|
|
if Parent=nil then exit;
|
|
i:=Value-Parent.StartValue+1;
|
|
while (i<Parent.Capacity) do begin
|
|
if Parent.Children[i]<>nil then begin
|
|
Result:=Parent.Children[i];
|
|
exit;
|
|
end;
|
|
inc(i);
|
|
end;
|
|
end;
|
|
|
|
function TArrayNode.FindNextUTF8: TArrayNode;
|
|
var
|
|
SiblingNode: TArrayNode;
|
|
begin
|
|
Result:=FindFirstChild;
|
|
if Result<>nil then exit;
|
|
SiblingNode:=Self;
|
|
while SiblingNode<>nil do begin
|
|
Result:=SiblingNode.FindNextSibling;
|
|
if Result<>nil then exit;
|
|
SiblingNode:=SiblingNode.Parent;
|
|
end;
|
|
end;
|
|
|
|
function TArrayNode.FindPrev: TArrayNode;
|
|
begin
|
|
Result:=FindPrevSibling;
|
|
if Result=nil then begin
|
|
Result:=Parent;
|
|
exit;
|
|
end;
|
|
Result:=Result.FindLastSubChild;
|
|
end;
|
|
|
|
function TArrayNode.FindFirstChild: TArrayNode;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result:=nil;
|
|
if Capacity=0 then exit;
|
|
i:=0;
|
|
while i<Capacity do begin
|
|
if Children[i]<>nil then begin
|
|
Result:=Children[i];
|
|
exit;
|
|
end;
|
|
inc(i);
|
|
end;
|
|
end;
|
|
|
|
function TArrayNode.FindLastChild: TArrayNode;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result:=nil;
|
|
if Capacity=0 then exit;
|
|
i:=Capacity-1;
|
|
while i>=0 do begin
|
|
if Children[i]<>nil then begin
|
|
Result:=Children[i];
|
|
exit;
|
|
end;
|
|
dec(i);
|
|
end;
|
|
end;
|
|
|
|
function TArrayNode.FindLastSubChild: TArrayNode;
|
|
var
|
|
ANode: TArrayNode;
|
|
begin
|
|
ANode:=Self;
|
|
while ANode<>nil do begin
|
|
Result:=ANode;
|
|
ANode:=ANode.FindLastChild;
|
|
end;
|
|
end;
|
|
|
|
function TArrayNode.FindFirstSibling: TArrayNode;
|
|
begin
|
|
if Parent=nil then
|
|
Result:=nil
|
|
else
|
|
Result:=Parent.FindFirstChild;
|
|
end;
|
|
|
|
function TArrayNode.FindLastSibling: TArrayNode;
|
|
begin
|
|
if Parent=nil then
|
|
Result:=nil
|
|
else
|
|
Result:=Parent.FindLastChild;
|
|
end;
|
|
|
|
procedure TArrayNode.ConsistencyCheck;
|
|
|
|
procedure R(const Msg: string);
|
|
begin
|
|
RaiseGDBException(Msg);
|
|
end;
|
|
|
|
var
|
|
i: Integer;
|
|
ChildNode: TArrayNode;
|
|
begin
|
|
if Children<>nil then begin
|
|
if Capacity<=0 then R('Capacity too small');
|
|
for i:=0 to Capacity-1 do begin
|
|
ChildNode:=Children[i];
|
|
if ChildNode<>nil then begin
|
|
if ChildNode.Value<>i+StartValue then
|
|
R('Value wrong');
|
|
if ChildNode.Parent<>Self then
|
|
R('Parent wrong');
|
|
ChildNode.ConsistencyCheck;
|
|
end;
|
|
end;
|
|
end else begin
|
|
if Capacity<>0 then R('Capacity wrong');
|
|
end;
|
|
end;
|
|
|
|
{ TArrayNodesTree }
|
|
|
|
function TArrayNodesTree.FindNode(Path: PInteger; Count: integer
|
|
): TArrayNode;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result:=Root;
|
|
i:=0;
|
|
while (Result<>nil) and (i<Count) do begin
|
|
Result:=Result.GetChildNode(Path[i],false);
|
|
inc(i);
|
|
end;
|
|
end;
|
|
|
|
function TArrayNodesTree.FindData(Path: PInteger; Count: integer): Pointer;
|
|
var
|
|
ANode: TArrayNode;
|
|
begin
|
|
ANode:=FindNode(Path,Count);
|
|
if ANode<>nil then
|
|
Result:=ANode.Data
|
|
else
|
|
Result:=nil;
|
|
end;
|
|
|
|
function TArrayNodesTree.SetNode(Path: PInteger; Count: integer;
|
|
Data: Pointer): TArrayNode;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if Root=nil then
|
|
Root:=TArrayNode.Create;
|
|
Result:=Root;
|
|
for i:=0 to Count-1 do begin
|
|
//DebugLn('TArrayNodesTree.SetNode A ',DbgS(Result));
|
|
Result:=Result.GetChildNode(Path[i],true);
|
|
end;
|
|
Result.Data:=Data;
|
|
end;
|
|
|
|
procedure TArrayNodesTree.Delete(Node: TArrayNode);
|
|
begin
|
|
if Node=nil then exit;
|
|
if Node=Root then Root:=nil;
|
|
Node.Free;
|
|
end;
|
|
|
|
procedure TArrayNodesTree.Clear;
|
|
begin
|
|
Delete(Root);
|
|
end;
|
|
|
|
constructor TArrayNodesTree.Create;
|
|
begin
|
|
|
|
end;
|
|
|
|
destructor TArrayNodesTree.Destroy;
|
|
begin
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TArrayNodesTree.ConsistencyCheck;
|
|
begin
|
|
if Root<>nil then
|
|
Root.ConsistencyCheck;
|
|
end;
|
|
|
|
{ TLazReaderBMP }
|
|
|
|
function TLazReaderBMP.InternalCheck(Stream: TStream): boolean;
|
|
var
|
|
BFH: TBitMapFileHeader;
|
|
offbits: DWORD;
|
|
begin
|
|
Stream.Read(BFH, SizeOf(BFH));
|
|
Result := BFH.bfType = LEtoN(BMmagic); // Just check magic number
|
|
|
|
{ Store the data offset. BFH is poorly aligned (dictated by the .bmp file
|
|
format), which can cause problems for architectures such as SPARC and some
|
|
ARM implementations which have strict alignment requirements. That is why
|
|
the code below uses an intermediate variable, rather than a direct call to
|
|
LEtoN(BFH.bfOffBits) which will try to pass a misaligned parameter. }
|
|
if Result and (BFH.bfOffBits <> 0)
|
|
then begin
|
|
offbits := BFH.bfOffBits;
|
|
FDataOffset := Stream.Position + LEtoN(offbits) - SizeOf(BFH)
|
|
end
|
|
end;
|
|
|
|
procedure TLazReaderBMP.InternalReadHead;
|
|
begin
|
|
inherited InternalReadHead;
|
|
if FDataOffset <> 0
|
|
then TheStream.Position := FDataOffset;
|
|
end;
|
|
|
|
{$IF FPC_FullVersion < 30301}
|
|
{ Workaround for TFPReaderBMP not implementing InternalSize in FPC before 3.3.1}
|
|
class function TLazReaderBMP.InternalSize (Stream: TStream): TPoint;
|
|
var
|
|
fileHdr: TBitmapFileHeader;
|
|
infoHdr: TBitmapInfoHeader;
|
|
n: Int64;
|
|
StartPos: Int64;
|
|
begin
|
|
Result := Point(0, 0);
|
|
|
|
StartPos := Stream.Position;
|
|
try
|
|
n := Stream.Read(fileHdr, SizeOf(fileHdr));
|
|
if n <> SizeOf(fileHdr) then exit;
|
|
if {$IFDEF ENDIAN_BIG}swap(fileHdr.bfType){$ELSE}fileHdr.bfType{$ENDIF} <> BMmagic then exit;
|
|
n := Stream.Read(infoHdr, SizeOf(infoHdr));
|
|
if n <> SizeOf(infoHdr) then exit;
|
|
{$IFDEF ENDIAN_BIG}
|
|
Result := Point(swap(infoHdr.biWidth), swap(infoHdr.biHeight));
|
|
{$ELSE}
|
|
Result := Point(infoHdr.biWidth, infoHdr.biHeight);
|
|
{$ENDIF}
|
|
finally
|
|
Stream.Position := StartPos;
|
|
end;
|
|
end;
|
|
{$IFEND}
|
|
|
|
{ TLazWriterBMP }
|
|
|
|
procedure TLazWriterBMP.Finalize;
|
|
begin
|
|
end;
|
|
|
|
procedure TLazWriterBMP.Initialize(AImage: TLazIntfImage);
|
|
begin
|
|
// set BPP
|
|
// we can also look at PixelFormat, but it can be inexact
|
|
BitsPerPixel := AImage.DataDescription.Depth;
|
|
end;
|
|
|
|
function TLazWriterBMP.QueryInterface(constref iid: TGuid; out obj): longint; {$IFDEF WINDOWs}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
if GetInterface(iid, obj)
|
|
then Result := S_OK
|
|
else Result := E_NOINTERFACE;
|
|
end;
|
|
|
|
function TLazWriterBMP._AddRef: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
function TLazWriterBMP._Release: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
{ TLazReaderDIB }
|
|
|
|
procedure TLazReaderDIB.InitLineBuf;
|
|
begin
|
|
FreeLineBuf;
|
|
|
|
if Info.BitCount < 8
|
|
then FReadSize := ((Info.BitCount * Info.Width + 31) shr 5) shl 2
|
|
else FReadSize := (((Info.BitCount shr 3) * Info.Width + 3) shr 2) shl 2;
|
|
|
|
// allocate 3 bytes more so we can always use a cardinal to read (in case of bitfields)
|
|
GetMem(FLineBuf, FReadSize+3);
|
|
end;
|
|
|
|
procedure TLazReaderDIB.FreeLineBuf;
|
|
begin
|
|
FreeMem(FLineBuf);
|
|
FLineBuf := nil;
|
|
end;
|
|
|
|
function TLazReaderDIB.GetUpdateDescription: Boolean;
|
|
begin
|
|
Result := FUpdateDescription;
|
|
end;
|
|
|
|
procedure TLazReaderDIB.ReadScanLine(Row: Integer);
|
|
procedure DoRLE4;
|
|
var
|
|
Head: array[0..1] of Byte;
|
|
Value, NibbleCount, ByteCount: Byte;
|
|
WriteNibble: Boolean; // Set when only lower nibble needs to be written
|
|
BufPtr, DstPtr: PByte;
|
|
Buf: array[0..127] of Byte; // temp buffer to read nibbles
|
|
begin
|
|
DstPtr := @LineBuf[0];
|
|
WriteNibble := False;
|
|
while True do
|
|
begin
|
|
TheStream.Read(Head[0], 2);
|
|
NibbleCount := Head[0];
|
|
|
|
if NibbleCount > 0 then
|
|
begin
|
|
if WriteNibble
|
|
then begin
|
|
// low nibble needs to be written
|
|
// swap pixels so that they are in order after this nibble
|
|
Value := (Head[1] shl 4) or (Head[1] shr 4);
|
|
DstPtr^ := (DstPtr^ and $F0) or (Value and $0F);
|
|
Inc(DstPtr);
|
|
// we have written one
|
|
Dec(NibbleCount);
|
|
end
|
|
else begin
|
|
Value := Head[1];
|
|
end;
|
|
ByteCount := (NibbleCount + 1) div 2;
|
|
FillChar(DstPtr^, ByteCount , Value);
|
|
// if we have written an odd number of nibbles we still have to write one
|
|
WriteNibble := NibbleCount and 1 = 1;
|
|
Inc(DstPtr, ByteCount);
|
|
// correct DstPtr if we still need to write a nibble
|
|
if WriteNibble then Dec(DstPtr);
|
|
end
|
|
else begin
|
|
NibbleCount := Head[1];
|
|
case NibbleCount of
|
|
0, 1: break; // End of scanline or end of bitmap
|
|
2: raise FPImageException.Create('RLE code #2 is not supported');
|
|
else
|
|
ByteCount := (NibbleCount + 1) div 2;
|
|
|
|
if WriteNibble
|
|
then begin
|
|
// we cannot read directly into destination, so use temp buf
|
|
TheStream.Read(Buf[0], ByteCount);
|
|
BufPtr := @Buf[0];
|
|
repeat
|
|
DstPtr^ := (DstPtr^ and $F0) or (BufPtr^ shr 4);
|
|
Inc(DstPtr);
|
|
Dec(NibbleCount);
|
|
if NibbleCount = 0
|
|
then begin
|
|
// if we have written both nibbles
|
|
WriteNibble := False;
|
|
Break;
|
|
end;
|
|
DstPtr^ := (BufPtr^ shl 4);
|
|
Inc(BufPtr);
|
|
Dec(NibbleCount);
|
|
until NibbleCount = 0;
|
|
end
|
|
else begin
|
|
TheStream.Read(DstPtr^, ByteCount);
|
|
// if we have written an odd number of nibbles we still have to write one
|
|
WriteNibble := NibbleCount and 1 = 1;
|
|
Inc(DstPtr, ByteCount);
|
|
// correct DstPtr if we still need to write a nibble
|
|
if WriteNibble then Dec(DstPtr);
|
|
end;
|
|
|
|
// keep stream at word boundary
|
|
if ByteCount and 1 = 1
|
|
then TheStream.Seek(1, soCurrent);
|
|
end;
|
|
end;
|
|
|
|
end
|
|
end;
|
|
|
|
procedure DoRLE8;
|
|
var
|
|
Head: array[0..1] of Byte;
|
|
Value, Count: Byte;
|
|
DstPtr: PByte;
|
|
begin
|
|
DstPtr := @LineBuf[0];
|
|
while True do
|
|
begin
|
|
TheStream.Read(Head[0], 2);
|
|
Count := Head[0];
|
|
if Count > 0
|
|
then begin
|
|
Value := Head[1];
|
|
FillChar(DstPtr^, Count, Value);
|
|
end
|
|
else begin
|
|
Count := Head[1];
|
|
case Count of
|
|
0, 1: break; // End of scanline or end of bitmap
|
|
2: raise FPImageException.Create('RLE code #2 is not supported');
|
|
else
|
|
TheStream.Read(DstPtr^, Count);
|
|
// keep stream at word boundary
|
|
if Count and 1 = 1
|
|
then TheStream.Seek(1, soCurrent);
|
|
end;
|
|
end;
|
|
|
|
Inc(DstPtr, Count);
|
|
end
|
|
end;
|
|
begin
|
|
// Add here support for compressed lines. The 'readsize' is the same in the end.
|
|
|
|
// MWE: Note: when doing so, keep in mind that the bufer is expected to be in Little Endian.
|
|
// for better performance, the conversion is done when writing the buffer.
|
|
|
|
if Info.Encoding = lrdeRLE
|
|
then begin
|
|
case Info.BitCount of
|
|
4: DoRLE4;
|
|
8: DoRLE8;
|
|
//24: DoRLE24;
|
|
end;
|
|
end
|
|
else begin
|
|
TheStream.Read(LineBuf[0], ReadSize);
|
|
end;
|
|
end;
|
|
|
|
function TLazReaderDIB.BitfieldsToFPColor(const AColor: Cardinal): TFPcolor;
|
|
var
|
|
V: Word;
|
|
begin
|
|
//--- red ---
|
|
V := ((AColor and Info.PixelMasks.R) shl (32 - Info.MaskShift.R - Info.MaskSize.R)) shr 16;
|
|
Result.Red := V;
|
|
repeat
|
|
V := V shr Info.MaskSize.R;
|
|
Result.Red := Result.Red or V;
|
|
until V = 0;
|
|
|
|
//--- green ---
|
|
V := ((AColor and Info.PixelMasks.G) shl (32 - Info.MaskShift.G - Info.MaskSize.G)) shr 16;
|
|
Result.Green := V;
|
|
repeat
|
|
V := V shr Info.MaskSize.G;
|
|
Result.Green := Result.Green or V;
|
|
until V = 0;
|
|
|
|
//--- blue ---
|
|
V := ((AColor and Info.PixelMasks.B) shl (32 - Info.MaskShift.B - Info.MaskSize.B)) shr 16;
|
|
Result.Blue := V;
|
|
repeat
|
|
V := V shr Info.MaskSize.B;
|
|
Result.Blue := Result.Blue or V;
|
|
until V = 0;
|
|
|
|
//--- alpha ---
|
|
if Info.MaskSize.A = 0
|
|
then begin
|
|
Result.Alpha := AlphaOpaque;
|
|
end
|
|
else begin
|
|
V := ((AColor and Info.PixelMasks.A) shl (32 - Info.MaskShift.A - Info.MaskSize.A)) shr 16;
|
|
Result.Alpha := V;
|
|
repeat
|
|
V := V shr Info.MaskSize.A;
|
|
Result.Alpha := Result.Alpha or V;
|
|
until V = 0;
|
|
end;
|
|
end;
|
|
|
|
function TLazReaderDIB.RGBToFPColor(const AColor: TColorRGB): TFPcolor;
|
|
var
|
|
RBytes: TFPColorBytes absolute Result;
|
|
begin
|
|
RBytes.Bh := AColor.B;
|
|
RBytes.Bl := AColor.B;
|
|
RBytes.Gh := AColor.G;
|
|
RBytes.Gl := AColor.G;
|
|
RBytes.Rh := AColor.R;
|
|
RBytes.Rl := AColor.R;
|
|
Result.Alpha := AlphaOpaque;
|
|
end;
|
|
|
|
function TLazReaderDIB.RGBToFPColor(const AColor: TColorRGBA): TFPcolor;
|
|
var
|
|
RBytes: TFPColorBytes absolute Result;
|
|
begin
|
|
RBytes.Bh := AColor.B;
|
|
RBytes.Bl := AColor.B;
|
|
RBytes.Gh := AColor.G;
|
|
RBytes.Gl := AColor.G;
|
|
RBytes.Rh := AColor.R;
|
|
RBytes.Rl := AColor.R;
|
|
if Info.MaskSize.A = 0
|
|
then Result.Alpha := AlphaOpaque
|
|
else begin
|
|
RBytes.Ah := AColor.A;
|
|
// fpreadbmp says reverse: RBytes.Ah := 255-AColor.A;
|
|
RBytes.Al := RBytes.Ah;
|
|
end;
|
|
end;
|
|
|
|
function TLazReaderDIB.RGBToFPColor(const AColor: Word): TFPcolor;
|
|
var
|
|
V1, V2: Cardinal;
|
|
begin
|
|
// 5 bit for red -> 16 bit for TFPColor
|
|
V1 := (AColor shl 1) and $F800; // 15..11
|
|
V2 := V1;
|
|
V1 := V1 shr 5; // 10..6
|
|
V2 := V2 or V1;
|
|
V1 := V1 shr 5; // 5..1
|
|
V2 := V2 or V1;
|
|
V1 := V1 shr 5; // 0
|
|
Result.Red := Word(V2 or V1);
|
|
// 5 bit for red -> 16 bit for TFPColor
|
|
V1 := (AColor shl 6) and $F800; // 15..11
|
|
V2 := V1;
|
|
V1 := V1 shr 5; // 10..6
|
|
V2 := V2 or V1;
|
|
V1 := V1 shr 5; // 5..1
|
|
V2 := V2 or V1;
|
|
V1 := V1 shr 5; // 0
|
|
Result.Green := Word(V2 or V1);
|
|
// 5 bit for blue -> 16 bit for TFPColor
|
|
V1 := (AColor shl 11) and $F800; // 15..11
|
|
V2 := V1;
|
|
V1 := V1 shr 5;
|
|
V2 := V2 or V1; // 10..6
|
|
V1 := V1 shr 5;
|
|
V2 := V2 or V1; // 5..1
|
|
V1 := V1 shr 5;
|
|
Result.Blue := Word(V2 or V1); // 0
|
|
// opaque, no mask
|
|
Result.Alpha:=alphaOpaque;
|
|
end;
|
|
|
|
procedure TLazReaderDIB.SetUpdateDescription(AValue: Boolean);
|
|
begin
|
|
FUpdateDescription := AValue;
|
|
end;
|
|
|
|
procedure TLazReaderDIB.WriteScanLine(Row: Cardinal);
|
|
// using cardinals generates compacter code
|
|
var
|
|
Column: Cardinal;
|
|
Color: TFPColor;
|
|
Index: Byte;
|
|
begin
|
|
if FMaskMode = lrmmNone
|
|
then begin
|
|
case Info.BitCount of
|
|
1 :
|
|
for Column := 0 to TheImage.Width - 1 do
|
|
TheImage.colors[Column,Row] := FPalette[Ord(LineBuf[Column div 8] and ($80 shr (Column and 7)) <> 0)];
|
|
4 :
|
|
for Column := 0 to TheImage.Width - 1 do
|
|
TheImage.colors[Column,Row] := FPalette[(LineBuf[Column div 2] shr (((not Column) and 1)*4)) and $0f];
|
|
8 :
|
|
for Column := 0 to TheImage.Width - 1 do
|
|
TheImage.colors[Column,Row] := FPalette[LineBuf[Column]];
|
|
else
|
|
if Info.Encoding = lrdeBitfield
|
|
then begin
|
|
// always cast to cardinal without conversion
|
|
// this way the value will have the same order as the bitfields
|
|
case Info.BitCount of
|
|
16:
|
|
for Column := 0 to TheImage.Width - 1 do
|
|
TheImage.colors[Column,Row] := BitfieldsToFPColor(PCardinal(@PWord(LineBuf)[Column])^);
|
|
24:
|
|
for Column := 0 to TheImage.Width - 1 do
|
|
TheImage.colors[Column,Row] := BitfieldsToFPColor(PCardinal(@PColorRGB(LineBuf)[Column])^);
|
|
32:
|
|
for Column := 0 to TheImage.Width - 1 do
|
|
begin
|
|
Color := BitfieldsToFPColor(PCardinal(@PColorRGBA(LineBuf)[Column])^);
|
|
TheImage.colors[Column,Row] := Color;
|
|
FIgnoreAlpha := FIgnoreAlpha and (Color.alpha = alphaTransparent);
|
|
end;
|
|
end;
|
|
end
|
|
else begin
|
|
case Info.BitCount of
|
|
16:
|
|
for Column := 0 to TheImage.Width - 1 do
|
|
TheImage.colors[Column,Row] := RGBToFPColor({$ifdef FPC_BIG_ENDIAN}LeToN{$endif}(PWord(LineBuf)[Column]));
|
|
24:
|
|
for Column := 0 to TheImage.Width - 1 do
|
|
TheImage.colors[Column,Row] := RGBToFPColor(PColorRGB(LineBuf)[Column]);
|
|
32:
|
|
for Column := 0 to TheImage.Width - 1 do
|
|
begin
|
|
Color := RGBToFPColor(PColorRGBA(LineBuf)[Column]);
|
|
TheImage.colors[Column,Row] := Color;
|
|
FIgnoreAlpha := FIgnoreAlpha and (Color.alpha = alphaTransparent);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end
|
|
else begin
|
|
case Info.BitCount of
|
|
1 :
|
|
for Column := 0 to TheImage.Width - 1 do
|
|
begin
|
|
Index := Ord(LineBuf[Column div 8] and ($80 shr (Column and 7)) <> 0);
|
|
FImage.colors[Column,Row] := FPalette[Index];
|
|
FImage.Masked[Column,Row] := Index = FMaskIndex;
|
|
end;
|
|
4 :
|
|
for Column := 0 to TheImage.Width - 1 do
|
|
begin
|
|
Index := (LineBuf[Column div 2] shr (((not Column) and 1)*4)) and $0f;
|
|
FImage.colors[Column,Row] := FPalette[Index];
|
|
FImage.Masked[Column,Row] := Index = FMaskIndex;
|
|
end;
|
|
8 :
|
|
for Column := 0 to TheImage.Width - 1 do
|
|
begin
|
|
Index := LineBuf[Column];
|
|
FImage.colors[Column,Row] := FPalette[Index];
|
|
FImage.Masked[Column,Row] := Index = FMaskIndex;
|
|
end;
|
|
else
|
|
if Info.Encoding = lrdeBitfield
|
|
then begin
|
|
// always cast to cardinal without conversion
|
|
// this way the value will have the same order as the bitfields
|
|
case Info.BitCount of
|
|
16:
|
|
for Column := 0 to TheImage.Width - 1 do
|
|
begin
|
|
Color := BitfieldsToFPColor(PCardinal(@PWord(LineBuf)[Column])^);
|
|
FImage.colors[Column,Row] := Color;
|
|
FImage.Masked[Column,Row] := Color = FMaskColor;
|
|
end;
|
|
24:
|
|
for Column := 0 to TheImage.Width - 1 do
|
|
begin
|
|
Color := BitfieldsToFPColor(PCardinal(@PColorRGB(LineBuf)[Column])^);
|
|
FImage.colors[Column,Row] := Color;
|
|
FImage.Masked[Column,Row] := Color = FMaskColor;
|
|
end;
|
|
32:
|
|
for Column := 0 to TheImage.Width - 1 do
|
|
begin
|
|
Color := BitfieldsToFPColor(PCardinal(@PColorRGBA(LineBuf)[Column])^);
|
|
FImage.colors[Column,Row] := Color;
|
|
FImage.Masked[Column,Row] := Color = FMaskColor;
|
|
FIgnoreAlpha := FIgnoreAlpha and (Color.alpha = alphaTransparent);
|
|
end;
|
|
end;
|
|
end
|
|
else begin
|
|
case Info.BitCount of
|
|
16:
|
|
for Column := 0 to TheImage.Width - 1 do
|
|
begin
|
|
Color := RGBToFPColor({$ifdef FPC_BIG_ENDIAN}LeToN{$endif}(PWord(LineBuf)[Column]));
|
|
FImage.colors[Column,Row] := Color;
|
|
FImage.Masked[Column,Row] := Color = FMaskColor;
|
|
end;
|
|
24:
|
|
for Column := 0 to TheImage.Width - 1 do
|
|
begin
|
|
Color := RGBToFPColor(PColorRGB(LineBuf)[Column]);
|
|
FImage.colors[Column,Row] := Color;
|
|
FImage.Masked[Column,Row] := Color = FMaskColor;
|
|
end;
|
|
32:
|
|
for Column := 0 to TheImage.Width - 1 do
|
|
begin
|
|
Color := RGBToFPColor(PColorRGBA(LineBuf)[Column]);
|
|
FImage.colors[Column,Row] := Color;
|
|
FImage.Masked[Column,Row] := Color = FMaskColor;
|
|
FIgnoreAlpha := FIgnoreAlpha and (Color.alpha = alphaTransparent);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TLazReaderDIB._AddRef: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
function TLazReaderDIB._Release: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
procedure TLazReaderDIB.InternalRead(Stream: TStream; Img: TFPCustomImage);
|
|
var
|
|
Desc: TRawImageDescription;
|
|
Depth: Byte;
|
|
begin
|
|
FContinue := True;
|
|
Progress(psStarting, 0, False, Rect(0,0,0,0), '', FContinue);
|
|
FImage := TheImage as TLazIntfImage;
|
|
FIgnoreAlpha := True;
|
|
Depth := 0;
|
|
InternalReadHead;
|
|
|
|
if FUpdateDescription
|
|
then begin
|
|
if (Info.BitCount = 32) and (Info.MaskSize.A = 0)
|
|
then Depth := 24
|
|
else Depth := Info.BitCount;
|
|
DefaultReaderDescription(Info.Width, Info.Height, Depth, Desc);
|
|
FImage.DataDescription := Desc;
|
|
end;
|
|
|
|
InternalReadBody;
|
|
|
|
// if there is no alpha in real (all alpha values = 0) then update the description
|
|
if FUpdateDescription and FIgnoreAlpha and (Depth = 32) then
|
|
begin
|
|
Desc.AlphaPrec:=0;
|
|
FImage.SetDataDescriptionKeepData(Desc);
|
|
end;
|
|
|
|
Progress(psEnding, 100, false, Rect(0,0,0,0), '', FContinue);
|
|
end;
|
|
|
|
procedure TLazReaderDIB.InternalReadHead;
|
|
const
|
|
SUnknownCompression = 'Bitmap with unknown compression (%d)';
|
|
SUnsupportedCompression = 'Bitmap with unsupported compression (%s)';
|
|
SWrongCombination = 'Bitmap with wrong combination of bit count (%d) and compression (%s)';
|
|
SUnsupportedPixelMask = 'Bitmap with non-standard pixel masks not supported';
|
|
|
|
SEncoding: array[TLazReaderDIBEncoding] of string = (
|
|
'RGB',
|
|
'RLE',
|
|
'Bitfield',
|
|
'Jpeg',
|
|
'Png',
|
|
'Huffman'
|
|
);
|
|
|
|
function ValidCompression: Boolean;
|
|
begin
|
|
case Info.BitCount of
|
|
1: Result := FDibInfo.Encoding in [lrdeRGB, lrdeHuffman];
|
|
4,8: Result := FDibInfo.Encoding in [lrdeRGB, lrdeRLE];
|
|
16: Result := FDibInfo.Encoding in [lrdeRGB, lrdeBitfield];
|
|
24: Result := FDibInfo.Encoding in [lrdeRGB, lrdeBitfield, lrdeRLE];
|
|
32: Result := FDibInfo.Encoding in [lrdeRGB, lrdeBitfield];
|
|
else
|
|
raise FPImageException.CreateFmt('Wrong bitmap bit count: %d', [Info.BitCount]);
|
|
end;
|
|
end;
|
|
|
|
procedure GetMaskShiftSize(AMask: LongWord; var AShift, ASize: Byte);
|
|
begin
|
|
AShift := 0;
|
|
repeat
|
|
if (AMask and 1) <> 0 then Break;
|
|
AMask := AMask shr 1;
|
|
Inc(AShift);
|
|
until AShift >= 32;
|
|
|
|
ASize := 0;
|
|
repeat
|
|
if (AMask and 1) = 0 then Break;
|
|
AMask := AMask shr 1;
|
|
Inc(ASize);
|
|
until AShift + ASize >= 32;
|
|
end;
|
|
|
|
procedure ReadPalette(APaletteIsOS2: Boolean);
|
|
var
|
|
ColorSize: Byte;
|
|
C: TColorRGBA;
|
|
n, len, maxlen: Integer;
|
|
begin
|
|
SetLength(FPalette, 0);
|
|
if Info.PaletteCount = 0 then Exit;
|
|
|
|
if APaletteIsOS2
|
|
then ColorSize := 3
|
|
else ColorSize := 4;
|
|
|
|
if FDibInfo.BitCount > 8
|
|
then begin
|
|
// Bitmaps can have a color table stored in the palette entries,
|
|
// skip them, since we don't use it
|
|
TheStream.Seek(Info.PaletteCount * ColorSize, soCurrent);
|
|
Exit;
|
|
end;
|
|
|
|
maxlen := 1 shl Info.BitCount;
|
|
if Info.PaletteCount <= maxlen
|
|
then len := maxlen
|
|
else len := Info.PaletteCount; // more colors ???
|
|
|
|
SetLength(FPalette, len);
|
|
|
|
for n := 0 to Info.PaletteCount - 1 do
|
|
begin
|
|
TheStream.Read(C, ColorSize);
|
|
C.A := $FF; //palette has no alpha
|
|
FPalette[n] := RGBToFPColor(C);
|
|
end;
|
|
|
|
// fill remaining with black color, so we don't have to check for out of index values
|
|
for n := Info.PaletteCount to maxlen - 1 do
|
|
FPalette[n] := colBlack;
|
|
end;
|
|
|
|
var
|
|
BIH: TBitmapInfoHeader;
|
|
BCH: TBitmapCoreHeader;
|
|
H: Integer;
|
|
StreamStart: Int64;
|
|
begin
|
|
StreamStart := theStream.Position;
|
|
TheStream.Read(BIH.biSize,SizeOf(BIH.biSize));
|
|
{$IFDEF FPC_BIG_ENDIAN}
|
|
BIH.biSize := LEtoN(BIH.biSize);
|
|
{$ENDIF}
|
|
|
|
if BIH.biSize = 12
|
|
then begin
|
|
// OS2 V1 header
|
|
TheStream.Read(BCH.bcWidth, BIH.biSize - SizeOf(BIH.biSize));
|
|
|
|
FDibInfo.Width := LEtoN(BCH.bcWidth);
|
|
FDibInfo.Height := LEtoN(BCH.bcHeight);
|
|
FDibInfo.BitCount := LEtoN(BCH.bcBitCount);
|
|
FDibInfo.Encoding := lrdeRGB;
|
|
FDibInfo.UpsideDown := True;
|
|
|
|
if FDibInfo.BitCount > 8
|
|
then FDibInfo.PaletteCount := 0
|
|
else FDibInfo.PaletteCount := 1 shl FDibInfo.BitCount;
|
|
end
|
|
else begin
|
|
// Windows Vx header or OSX V2, all start with BitmapInfoHeader
|
|
TheStream.Read(BIH.biWidth, SizeOf(BIH) - SizeOf(BIH.biSize));
|
|
|
|
FDibInfo.Width := LEtoN(BIH.biWidth);
|
|
H := LEtoN(BIH.biHeight);
|
|
// by default bitmaps are stored upside down
|
|
if H >= 0
|
|
then begin
|
|
FDibInfo.UpsideDown := True;
|
|
FDibInfo.Height := H;
|
|
end
|
|
else begin
|
|
FDibInfo.UpsideDown := False;
|
|
FDibInfo.Height := -H;
|
|
end;
|
|
|
|
FDibInfo.BitCount := LEtoN(BIH.biBitCount);
|
|
case LEtoN(BIH.biCompression) of
|
|
BI_RGB : FDibInfo.Encoding := lrdeRGB;
|
|
4, {BCA_RLE24}
|
|
BI_RLE8,
|
|
BI_RLE4 : FDibInfo.Encoding := lrdeRLE;
|
|
{BCA_HUFFMAN1D, }
|
|
BI_BITFIELDS : begin
|
|
// OS2 can use huffman encoding for mono bitmaps
|
|
// bitfields only work for 16 and 32
|
|
if FDibInfo.BitCount = 1
|
|
then FDibInfo.Encoding := lrdeHuffman
|
|
else FDibInfo.Encoding := lrdeBitfield;
|
|
end;
|
|
else
|
|
raise FPImageException.CreateFmt(SUnknownCompression, [LEtoN(BIH.biCompression)]);
|
|
end;
|
|
|
|
if not (FDibInfo.Encoding in [lrdeRGB, lrdeRLE, lrdeBitfield])
|
|
then raise FPImageException.CreateFmt(SUnsupportedCompression, [SEncoding[FDibInfo.Encoding]]);
|
|
|
|
FDibInfo.PaletteCount := LEtoN(BIH.biClrUsed);
|
|
if (FDibInfo.PaletteCount = 0)
|
|
and (FDibInfo.BitCount <= 8)
|
|
then FDibInfo.PaletteCount := 1 shl FDibInfo.BitCount;
|
|
end;
|
|
|
|
if not ValidCompression
|
|
then raise FPImageException.CreateFmt(SWrongCombination, [FDibInfo.BitCount, SEncoding[FDibInfo.Encoding]]);
|
|
|
|
if BIH.biSize >= 108
|
|
then begin
|
|
// at least a V4 header -> has alpha mask, which is always valid (read other masks too)
|
|
TheStream.Read(FDibInfo.PixelMasks, 4 * SizeOf(FDibInfo.PixelMasks.R));
|
|
GetMaskShiftSize(FDibInfo.PixelMasks.A, FDibInfo.MaskShift.A, FDibInfo.MaskSize.A);
|
|
end
|
|
else begin
|
|
// officially no alpha support, but that breaks older LCL compatibility
|
|
// so add it
|
|
if Info.BitCount = 32
|
|
then begin
|
|
{$ifdef ENDIAN_BIG}
|
|
FDibInfo.PixelMasks.A := $000000FF;
|
|
{$else}
|
|
FDibInfo.PixelMasks.A := $FF000000;
|
|
{$endif}
|
|
GetMaskShiftSize(FDibInfo.PixelMasks.A, FDibInfo.MaskShift.A, FDibInfo.MaskSize.A);
|
|
end
|
|
else begin
|
|
FDibInfo.PixelMasks.A := 0;
|
|
FDibInfo.MaskShift.A := 0;
|
|
FDibInfo.MaskSize.A := 0;
|
|
end;
|
|
end;
|
|
|
|
if Info.Encoding = lrdeBitfield
|
|
then begin
|
|
if BIH.biSize < 108
|
|
then begin
|
|
// not read yet
|
|
TheStream.Read(FDibInfo.PixelMasks, 3 * SizeOf(FDibInfo.PixelMasks.R));
|
|
// check if added mask is valid
|
|
if (Info.PixelMasks.R or Info.PixelMasks.G or Info.PixelMasks.B) and Info.PixelMasks.A <> 0
|
|
then begin
|
|
// Alpha mask overlaps others
|
|
FDibInfo.PixelMasks.A := 0;
|
|
FDibInfo.MaskShift.A := 0;
|
|
FDibInfo.MaskSize.A := 0;
|
|
end;
|
|
end;
|
|
GetMaskShiftSize(FDibInfo.PixelMasks.R, FDibInfo.MaskShift.R, FDibInfo.MaskSize.R);
|
|
GetMaskShiftSize(FDibInfo.PixelMasks.G, FDibInfo.MaskShift.G, FDibInfo.MaskSize.G);
|
|
GetMaskShiftSize(FDibInfo.PixelMasks.B, FDibInfo.MaskShift.B, FDibInfo.MaskSize.B);
|
|
|
|
TheStream.Seek(StreamStart + BIH.biSize, soBeginning);
|
|
end
|
|
else begin
|
|
TheStream.Seek(StreamStart + BIH.biSize, soBeginning);
|
|
ReadPalette(BIH.biSize = 12);
|
|
end;
|
|
|
|
if Info.MaskSize.A <> 0 {Info.BitCount = 32}
|
|
then CheckAlphaDescription(TheImage);
|
|
end;
|
|
|
|
function TLazReaderDIB.QueryInterface(constref iid: TGuid; out obj): longint; {$IFDEF WINDOWs}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
if GetInterface(iid, obj)
|
|
then Result := S_OK
|
|
else Result := E_NOINTERFACE;
|
|
end;
|
|
|
|
procedure TLazReaderDIB.InternalReadBody;
|
|
|
|
procedure SaveTransparentColor;
|
|
begin
|
|
if FMaskMode <> lrmmAuto then Exit;
|
|
|
|
// define transparent color: 1-8 use palette, 15-24 use fixed color
|
|
case Info.BitCount of
|
|
1: FMaskIndex := (LineBuf[0] shr 7) and 1;
|
|
4: FMaskIndex := (LineBuf[0] shr 4) and $f;
|
|
8: FMaskIndex := LineBuf[0];
|
|
else
|
|
FMaskIndex := -1;
|
|
if Info.Encoding = lrdeBitfield
|
|
then begin
|
|
FMaskColor := BitfieldsToFPColor(PCardinal(LineBuf)[0]);
|
|
Exit;
|
|
end;
|
|
|
|
case Info.BitCount of
|
|
16: FMaskColor := RGBToFPColor({$ifdef FPC_BIG_ENDIAN}LeToN{$endif}(PWord(LineBuf)[0]));
|
|
24: FMaskColor := RGBToFPColor(PColorRGB(LineBuf)[0]);
|
|
32: FMaskColor := RGBToFPColor(PColorRGBA(LineBuf)[0]);
|
|
end;
|
|
|
|
Exit;
|
|
end;
|
|
if FMaskIndex <> -1
|
|
then FMaskColor := FPalette[FMaskIndex];
|
|
end;
|
|
|
|
procedure UpdateProgress(Row: Integer); inline;
|
|
begin
|
|
Progress(psRunning, trunc(100.0 * ((TheImage.Height - Row) / TheImage.Height)),
|
|
False, Rect(0, 0, TheImage.Width - 1, TheImage.Height - 1 - Row), 'reading BMP pixels', FContinue);
|
|
end;
|
|
|
|
var
|
|
Row : Cardinal;
|
|
begin
|
|
TheImage.SetSize(Info.Width, Info.Height);
|
|
|
|
if Info.Height = 0 then Exit;
|
|
if Info.Width = 0 then Exit;
|
|
|
|
InitLineBuf;
|
|
try
|
|
if not FContinue then Exit;
|
|
|
|
Row := Info.Height - 1;
|
|
ReadScanLine(Row);
|
|
SaveTransparentColor;
|
|
|
|
if Info.UpsideDown
|
|
then WriteScanLine(Row)
|
|
else WriteScanLine(Info.Height - 1 - Row);
|
|
|
|
UpdateProgress(Row);
|
|
|
|
while Row > 0 do
|
|
begin
|
|
if not FContinue then Exit;
|
|
Dec(Row);
|
|
ReadScanLine(Row); // Scanline in LineBuf with Size ReadSize.
|
|
|
|
if Info.UpsideDown
|
|
then WriteScanLine(Row)
|
|
else WriteScanLine(Info.Height - 1 - Row);
|
|
|
|
UpdateProgress(Row);
|
|
end;
|
|
finally
|
|
FreeLineBuf;
|
|
end;
|
|
end;
|
|
|
|
function TLazReaderDIB.InternalCheck(Stream: TStream): boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
constructor TLazReaderDIB.Create;
|
|
begin
|
|
inherited Create;
|
|
FMaskColor := colTransparent;
|
|
FContinue := True;
|
|
end;
|
|
|
|
destructor TLazReaderDIB.Destroy;
|
|
begin
|
|
FreeLineBuf;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{ TLazIntfImageMask }
|
|
|
|
procedure TLazIntfImageMask.SetInternalColor(x, y: integer; const Value: TFPColor);
|
|
begin
|
|
FImage.Masked[x, y] := Value.red < $8000;
|
|
end;
|
|
|
|
function TLazIntfImageMask.GetInternalColor(x, y: integer): TFPColor;
|
|
begin
|
|
if FImage.Masked[x, y]
|
|
then Result := FPImage.colWhite
|
|
else Result := FPImage.colBlack;
|
|
end;
|
|
|
|
procedure TLazIntfImageMask.SetInternalPixel(x, y: integer; Value: integer);
|
|
begin
|
|
FImage.Masked[x, y] := Value <> 0;
|
|
end;
|
|
|
|
function TLazIntfImageMask.GetInternalPixel(x, y: integer): integer;
|
|
begin
|
|
Result := Ord(FImage.Masked[x, y]);
|
|
end;
|
|
|
|
constructor TLazIntfImageMask.CreateWithImage(TheImage: TLazIntfImage);
|
|
begin
|
|
FImage:=TheImage;
|
|
inherited Create(FImage.Width,FImage.Height);
|
|
end;
|
|
|
|
{ TLazReaderIconDIB }
|
|
|
|
procedure TLazReaderIconDIB.InternalRead(Stream: TStream; Img: TFPCustomImage);
|
|
var
|
|
Desc: TRawImageDescription;
|
|
Row, Column: Integer;
|
|
NewColor: TFPColor;
|
|
BufPtr: PByte;
|
|
MaskBit: Byte;
|
|
begin
|
|
FImage := TheImage as TLazIntfImage;
|
|
InternalReadHead;
|
|
|
|
// Height field is doubled, to (sort of) accomodate mask
|
|
// MWE: it shoud be safer to verify the division agains the dirinfo.height
|
|
// anyway I haven't encountered an icon in the wild which doesn't have a mask
|
|
FDIBinfo.Height := FDIBinfo.Height div 2;
|
|
if FUpdateDescription
|
|
then begin
|
|
DefaultReaderDescription(Info.Width, Info.Height, Info.BitCount, Desc);
|
|
FImage.DataDescription := Desc;
|
|
end
|
|
else Desc := FImage.DataDescription;
|
|
InternalReadBody; { Now read standard bitmap }
|
|
|
|
// Mask immediately follows unless bitmap was 32 bit - monchrome bitmap with no header
|
|
// MWE: Correction, it seems that even 32bit icons can have a mask following
|
|
// if BFI.biBitCount >= 32 then Exit;
|
|
|
|
FDIBinfo.Encoding := lrdeRGB;
|
|
FDIBinfo.BitCount := 1;
|
|
InitLineBuf;
|
|
try
|
|
for Row := Desc.Height - 1 downto 0 do
|
|
begin
|
|
ReadScanLine(Row); // Scanline in LineBuf with Size ReadSize.
|
|
BufPtr := LineBuf;
|
|
MaskBit := $80;
|
|
for Column:=0 to Desc.Width - 1 do
|
|
begin
|
|
if BufPtr^ and MaskBit = 0
|
|
then begin
|
|
// opaque
|
|
FImage.Masked[Column, Row] := False;
|
|
end
|
|
else begin
|
|
// transparent
|
|
FImage.Masked[Column, Row] := True;
|
|
// add alpha when source wasn't 32bit
|
|
if (Desc.AlphaPrec <> 0)
|
|
and ((Desc.Depth < 32) or (Info.MaskSize.A = 0))
|
|
then begin
|
|
NewColor := FImage.Colors[Column, Row];
|
|
NewColor.Alpha := alphaTransparent;
|
|
FImage.Colors[Column, Row] := NewColor;
|
|
end;
|
|
end;
|
|
if MaskBit = 1
|
|
then begin
|
|
MaskBit := $80;
|
|
Inc(BufPtr);
|
|
end
|
|
else begin
|
|
MaskBit := MaskBit shr 1;
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
FreeLineBuf;
|
|
end;
|
|
end;
|
|
|
|
|
|
{ TLazReaderPNG }
|
|
|
|
procedure TLazReaderPNG.DoDecompress;
|
|
var
|
|
Desc: TRawImageDescription;
|
|
IsAlpha, IsGray: Boolean;
|
|
begin
|
|
if FUpdateDescription and (theImage is TLazIntfImage)
|
|
then begin
|
|
// init some default
|
|
|
|
IsGray := Header.ColorType and 3 = 0;
|
|
|
|
// Paul: if we have a mask in the description then we need to set it manually
|
|
// by Masked[x, y] := Color.Alpha = AlphaTransparent, but to do that we must
|
|
// read format ourself. fpReaders set alpha instead - they do not have Masked[].
|
|
// So if we want true description with mask we must teach our SetInternalColor
|
|
// method to handle Alpha if mask needed (or do it any other way). In other words
|
|
// this is now unimplemented and we'll get randomly masked image.
|
|
// As a temporary solution I'm enable alpha description if transparent color
|
|
// is present. This is indicated by UseTransparent property.
|
|
// When we will handle Mask in SetInternalColor please remove UseTransparent
|
|
// from the IsAlpha assignment.
|
|
|
|
IsAlpha := (Header.ColorType and 4 <> 0) or FAlphaPalette or UseTransparent;
|
|
|
|
if not IsAlpha and UseTransparent
|
|
then Desc.Init_BPP32_B8G8R8A8_M1_BIO_TTB(Header.Width, Header.height)
|
|
else Desc.Init_BPP32_B8G8R8A8_BIO_TTB(Header.Width, Header.height);
|
|
|
|
if IsGray
|
|
then Desc.Format := ricfGray;
|
|
if not IsAlpha
|
|
then Desc.AlphaPrec := 0;
|
|
|
|
// check palette
|
|
if (Header.ColorType and 1 <> 0)
|
|
then begin
|
|
// todo: palette
|
|
end
|
|
else begin
|
|
// no palette, adjust description
|
|
if IsGray
|
|
then begin
|
|
Desc.RedPrec := Header.BitDepth;
|
|
Desc.RedShift := 0;
|
|
if IsAlpha
|
|
then begin
|
|
Desc.BitsPerPixel := 2 * Header.BitDepth;
|
|
Desc.AlphaPrec := Header.BitDepth;
|
|
Desc.AlphaShift := Header.BitDepth;
|
|
end
|
|
else begin
|
|
Desc.BitsPerPixel := Header.BitDepth;
|
|
end;
|
|
Desc.Depth := Desc.BitsPerPixel;
|
|
end
|
|
else begin
|
|
if IsAlpha
|
|
then Desc.Depth := 4 * Header.BitDepth
|
|
else Desc.Depth := 3 * Header.BitDepth
|
|
end;
|
|
|
|
case Header.BitDepth of
|
|
1,2,4: begin
|
|
// only gray
|
|
end;
|
|
8: begin
|
|
// no change
|
|
end;
|
|
16: begin
|
|
if not IsGray then begin
|
|
Desc.BitsPerPixel := Desc.Depth;
|
|
Desc.RedPrec := 16;
|
|
Desc.RedShift := Desc.RedShift * 2;
|
|
Desc.GreenPrec := 16;
|
|
Desc.GreenShift := Desc.GreenShift * 2;
|
|
Desc.BluePrec := 16;
|
|
Desc.BlueShift := Desc.BlueShift * 2;
|
|
Desc.AlphaPrec := Desc.AlphaPrec * 2; // might be zero
|
|
Desc.AlphaShift := Desc.AlphaShift * 2;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
TLazIntfImage(theImage).DataDescription := Desc;
|
|
end;
|
|
|
|
inherited DoDecompress;
|
|
end;
|
|
|
|
function TLazReaderPNG.GetUpdateDescription: Boolean;
|
|
begin
|
|
Result := FUpdateDescription;
|
|
end;
|
|
|
|
procedure TLazReaderPNG.HandleAlpha;
|
|
begin
|
|
inherited HandleAlpha;
|
|
FAlphaPalette := Header.ColorType = 3;
|
|
end;
|
|
|
|
procedure TLazReaderPNG.InternalRead(Str: TStream; Img: TFPCustomImage);
|
|
begin
|
|
FAlphaPalette := False;
|
|
inherited InternalRead(Str, Img);
|
|
end;
|
|
|
|
function TLazReaderPNG.QueryInterface(constref iid: TGuid; out obj): longint; {$IFDEF WINDOWs}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
if GetInterface(iid, obj)
|
|
then Result := S_OK
|
|
else Result := E_NOINTERFACE;
|
|
end;
|
|
|
|
procedure TLazReaderPNG.SetUpdateDescription(AValue: Boolean);
|
|
begin
|
|
FUpdateDescription := AValue;
|
|
end;
|
|
|
|
function TLazReaderPNG._AddRef: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
function TLazReaderPNG._Release: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
{ TLazWriterPNG }
|
|
|
|
procedure TLazWriterPNG.Finalize;
|
|
begin
|
|
end;
|
|
|
|
procedure TLazWriterPNG.Initialize(AImage: TLazIntfImage);
|
|
begin
|
|
UseAlpha := AImage.DataDescription.AlphaPrec <> 0;
|
|
GrayScale := AImage.DataDescription.Format = ricfGray;
|
|
Indexed := AImage.DataDescription.Depth <= 8;
|
|
WordSized := (AImage.DataDescription.RedPrec > 8)
|
|
or (AImage.DataDescription.GreenPrec > 8)
|
|
or (AImage.DataDescription.BluePrec > 8);
|
|
end;
|
|
|
|
function TLazWriterPNG.QueryInterface(constref iid: TGuid; out obj): longint; {$IFDEF WINDOWs}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
if GetInterface(iid, obj)
|
|
then Result := S_OK
|
|
else Result := E_NOINTERFACE;
|
|
end;
|
|
|
|
function TLazWriterPNG._AddRef: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
function TLazWriterPNG._Release: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
{$IFNDEF DisableLCLTIFF}
|
|
|
|
{ TLazReaderTiff }
|
|
|
|
{$IFDEF OldTiffCreateImageHook}
|
|
procedure TLazReaderTiff.CreateImageHook(Sender: TFPReaderTiff; var NewImage: TFPCustomImage);
|
|
begin
|
|
if Assigned(FOrgEvent) then FOrgEvent(Sender, NewImage);
|
|
FirstImg.Img:=NewImage;
|
|
DoCreateImage(FirstImg);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure TLazReaderTiff.DoCreateImage(ImgFileDir: TTiffIFD);
|
|
var
|
|
Desc: TRawImageDescription;
|
|
IsAlpha, IsGray: Boolean;
|
|
begin
|
|
inherited;
|
|
|
|
if not FUpdateDescription then Exit;
|
|
if not (theImage is TLazIntfImage) then Exit;
|
|
|
|
// init some default
|
|
|
|
IsGray := ImgFileDir.PhotoMetricInterpretation in [0, 1];
|
|
IsAlpha := ImgFileDir.AlphaBits <> 0;
|
|
|
|
if IsAlpha
|
|
then Desc.Init_BPP32_B8G8R8A8_BIO_TTB(ImgFileDir.ImageWidth, ImgFileDir.ImageHeight)
|
|
else Desc.Init_BPP24_B8G8R8_BIO_TTB(ImgFileDir.ImageWidth, ImgFileDir.ImageHeight);
|
|
|
|
if IsGray
|
|
then Desc.Format := ricfGray;
|
|
|
|
// check mask
|
|
if ImgFileDir.PhotoMetricInterpretation = 4
|
|
then begin
|
|
// todo: mask
|
|
end
|
|
else
|
|
// check palette
|
|
if ImgFileDir.PhotoMetricInterpretation = 3
|
|
then begin
|
|
// todo: palette
|
|
end
|
|
else begin
|
|
// no palette, adjust description
|
|
if IsGray
|
|
then begin
|
|
Desc.RedPrec := ImgFileDir.GrayBits;
|
|
Desc.RedShift := 0;
|
|
if IsAlpha
|
|
then begin
|
|
Desc.Depth := ImgFileDir.GrayBits + ImgFileDir.AlphaBits;
|
|
Desc.AlphaPrec := ImgFileDir.AlphaBits;
|
|
Desc.AlphaShift := ImgFileDir.GrayBits;
|
|
end
|
|
else begin
|
|
Desc.Depth := ImgFileDir.GrayBits;
|
|
Desc.BitsPerPixel := ImgFileDir.GrayBits;
|
|
end;
|
|
end
|
|
else begin
|
|
Desc.Depth := ImgFileDir.RedBits + ImgFileDir.GreenBits + ImgFileDir.BlueBits + ImgFileDir.AlphaBits;
|
|
if Desc.Depth > 32
|
|
then begin
|
|
// switch to 64bit description
|
|
Desc.BitsPerPixel := Desc.BitsPerPixel * 2;
|
|
Desc.RedPrec := 16;
|
|
Desc.RedShift := Desc.RedShift * 2;
|
|
Desc.GreenPrec := 16;
|
|
Desc.GreenShift := Desc.GreenShift * 2;
|
|
Desc.BluePrec := 16;
|
|
Desc.BlueShift := Desc.BlueShift * 2;
|
|
Desc.AlphaPrec := Desc.AlphaPrec * 2; // might be zero
|
|
Desc.AlphaShift := Desc.AlphaShift * 2;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
TLazIntfImage(theImage).DataDescription := Desc;
|
|
end;
|
|
|
|
function TLazReaderTiff.GetUpdateDescription: Boolean;
|
|
begin
|
|
Result := FUpdateDescription;
|
|
end;
|
|
|
|
procedure TLazReaderTiff.InternalRead(Str: TStream; Img: TFPCustomImage);
|
|
begin
|
|
inherited InternalRead(Str, Img);
|
|
end;
|
|
|
|
function TLazReaderTiff.QueryInterface(constref iid: TGuid; out obj): longint; {$IFDEF WINDOWs}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
if GetInterface(iid, obj)
|
|
then Result := S_OK
|
|
else Result := E_NOINTERFACE;
|
|
end;
|
|
|
|
procedure TLazReaderTiff.SetUpdateDescription(AValue: Boolean);
|
|
begin
|
|
FUpdateDescription := AValue;
|
|
end;
|
|
|
|
function TLazReaderTiff._AddRef: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
function TLazReaderTiff._Release: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
{ TLazWriterTiff }
|
|
|
|
procedure TLazWriterTiff.Finalize;
|
|
begin
|
|
end;
|
|
|
|
procedure TLazWriterTiff.Initialize(AImage: TLazIntfImage);
|
|
begin
|
|
AImage.Extra[LazTiffSoftware] := 'TLazWriterTiff - Lazarus LCL: ' + lcl_version + ' - FPC: ' + {$I %FPCVERSION%};
|
|
end;
|
|
|
|
procedure TLazWriterTiff.InternalWrite(Stream: TStream; Img: TFPCustomImage);
|
|
var
|
|
S: String;
|
|
begin
|
|
AddImage(Img);
|
|
|
|
//add additional elements
|
|
|
|
S := Img.Extra[LazTiffHostComputer];
|
|
if S <> '' then AddEntryString(316, S);
|
|
S := Img.Extra[LazTiffMake];
|
|
if S <> '' then AddEntryString(271, S);
|
|
S := Img.Extra[LazTiffModel];
|
|
if S <> '' then AddEntryString(272, S);
|
|
S := Img.Extra[LazTiffSoftware];
|
|
if S <> '' then AddEntryString(305, S);
|
|
|
|
SaveToStream(Stream);
|
|
end;
|
|
|
|
function TLazWriterTiff.QueryInterface(constref iid: TGuid; out obj): longint; {$IFDEF WINDOWs}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
if GetInterface(iid, obj)
|
|
then Result := S_OK
|
|
else Result := E_NOINTERFACE;
|
|
end;
|
|
|
|
function TLazWriterTiff._AddRef: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
function TLazWriterTiff._Release: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
{$ENDIF} //DisableLCLTIFF
|
|
|
|
{ TLazReaderIcnsPart }
|
|
|
|
function TLazReaderIcnsPart.InternalCheck(Str: TStream): boolean;
|
|
begin
|
|
// todo: write check code
|
|
Result := True;
|
|
end;
|
|
|
|
procedure TLazReaderIcnsPart.InternalRead(Stream: TStream; Img: TFPCustomImage);
|
|
var
|
|
Desc: TRawImageDescription;
|
|
Element: TIconFamilyElement;
|
|
IsMask: Boolean;
|
|
begin
|
|
FImage := TheImage as TLazIntfImage;
|
|
|
|
Stream.Read(Element, SizeOf(Element));
|
|
Element.elementSize := BEtoN(Element.elementSize);
|
|
FIconType := GetIcnsIconType(Element.elementType);
|
|
FIconInfo := icnsIconTypeInfo[FIconType];
|
|
IsMask := FIconType in icnsMaskTypes;
|
|
|
|
if UpdateDescription
|
|
then begin
|
|
if IsMask then
|
|
begin
|
|
if FIconInfo.Depth = 1 then
|
|
DefaultReaderDescription(FIconInfo.Width, FIconInfo.Height, FIconInfo.Depth, Desc)
|
|
else
|
|
DefaultReaderDescription(FIconInfo.Width, FIconInfo.Height, 32, Desc);
|
|
end
|
|
else
|
|
DefaultReaderDescription(FIconInfo.Width, FIconInfo.Height, FIconInfo.Depth, Desc);
|
|
if (Desc.BitsPerPixel = 32) then
|
|
Desc.MaskBitsPerPixel := 0;
|
|
FImage.DataDescription := Desc;
|
|
end
|
|
else Desc := FImage.DataDescription;
|
|
|
|
SetupRead(FIconInfo.Width, FIconInfo.Height, FIconInfo.Depth, IsMask);
|
|
|
|
FDataSize := Element.elementSize - SizeOf(Element);
|
|
|
|
GetMem(FData, FDataSize);
|
|
try
|
|
Stream.Read(FData^, FDataSize);
|
|
if FIconType in icnsWithAlpha then
|
|
DoReadJpeg2000
|
|
else
|
|
if IsMask then
|
|
DoReadMask
|
|
else
|
|
if FIconType in icnsRGB then
|
|
DoReadRLE
|
|
else
|
|
DoReadRaw;
|
|
finally
|
|
FreeMem(FData);
|
|
FData := nil;
|
|
end;
|
|
end;
|
|
|
|
function TLazReaderIcnsPart.QueryInterface(constref iid: TGuid; out obj): longint; {$IFDEF WINDOWs}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
if GetInterface(iid, obj)
|
|
then Result := S_OK
|
|
else Result := E_NOINTERFACE;
|
|
end;
|
|
|
|
function TLazReaderIcnsPart._AddRef: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
function TLazReaderIcnsPart._Release: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
function TLazReaderIcnsPart.GetUpdateDescription: Boolean;
|
|
begin
|
|
Result := FUpdateDescription;
|
|
end;
|
|
|
|
procedure TLazReaderIcnsPart.SetUpdateDescription(AValue: Boolean);
|
|
begin
|
|
FUpdateDescription := AValue;
|
|
end;
|
|
|
|
procedure TLazReaderIcnsPart.SetupRead(AWidth, AHeight, ADepth: Integer; IsMask: Boolean);
|
|
begin
|
|
if FData <> nil then
|
|
FreeMem(FData);
|
|
FreeAndNil(FPalette);
|
|
if not IsMask then
|
|
case ADepth of
|
|
4: FPalette := CreateVGAPalette;
|
|
8: FPalette := Create256ColorPalette;
|
|
end;
|
|
|
|
FCalcSize := ((AWidth * AHeight * ADepth) shr 3);
|
|
TheImage.SetSize(AWidth, AHeight);
|
|
end;
|
|
|
|
procedure TLazReaderIcnsPart.DoReadRaw;
|
|
var
|
|
Row, Column: Integer;
|
|
shift: byte;
|
|
b: PByte;
|
|
begin
|
|
// only 4 and 8 are stored as raw image format
|
|
case FIconInfo.Depth of
|
|
4 :
|
|
begin
|
|
b := FData;
|
|
shift := 4;
|
|
for Row := 0 to FIconInfo.Height - 1 do
|
|
for Column := 0 to FIconInfo.Width - 1 do
|
|
begin
|
|
FImage.colors[Column, Row] := FPalette[(b^ shr shift) mod 16];
|
|
if shift = 0 then
|
|
begin
|
|
shift := 4;
|
|
inc(b);
|
|
end
|
|
else
|
|
shift := 0;
|
|
end;
|
|
end;
|
|
8 :
|
|
begin
|
|
b := FData;
|
|
for Row := 0 to FIconInfo.Height - 1 do
|
|
for Column := 0 to FIconInfo.Width - 1 do
|
|
begin
|
|
FImage.colors[Column, Row] := FPalette[b^];
|
|
inc(b);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TLazReaderIcnsPart.DoReadRLE;
|
|
var
|
|
ADecompData: PDWord;
|
|
ARGBAData: PRGBAQuad;
|
|
Component, Shift: Byte;
|
|
PixelCount, j, l: Integer;
|
|
RepeatValue: DWord;
|
|
SourcePtr: PByte;
|
|
DestPtr: PDWord;
|
|
begin
|
|
// only 24 bit RGB is RLE encoded the same way as TIFF or TGA RLE
|
|
// data is encoded channel by channel:
|
|
// high bit = 0 => length = low 0..6 bits + 1; read length times next value
|
|
// high bit = 1 => length = value - 125 ; read one value and repeat length times
|
|
|
|
ADecompData := AllocMem(FCalcSize);
|
|
DestPtr := ADecompData;
|
|
|
|
if FIconType = iitThumbnail32BitData
|
|
then SourcePtr := @FData[4]
|
|
else SourcePtr := FData;
|
|
|
|
PixelCount := FIconInfo.Height * FIconInfo.Width;
|
|
|
|
for Component := 0 to 2 do
|
|
begin
|
|
DestPtr := ADecompData;
|
|
Shift := (2 - Component) * 8;
|
|
while DestPtr - ADecompData < PixelCount do
|
|
begin
|
|
l := SourcePtr^;
|
|
inc(SourcePtr);
|
|
if (l and $80) = 0 then // high bit = 0
|
|
begin
|
|
for j := 0 to l do
|
|
begin
|
|
DestPtr^ := DestPtr^ or (DWord(SourcePtr^) shl Shift);
|
|
inc(SourcePtr);
|
|
inc(DestPtr);
|
|
end;
|
|
end
|
|
else
|
|
begin // high bit = 1
|
|
l := l - 126;
|
|
RepeatValue := DWord(SourcePtr^) shl Shift;
|
|
inc(SourcePtr);
|
|
for j := 0 to l do
|
|
begin
|
|
DestPtr^ := DestPtr^ or RepeatValue;
|
|
inc(DestPtr);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
ARGBAData := PRGBAQuad(ADecompData);
|
|
for l := 0 to FIconInfo.Height - 1 do
|
|
for j := 0 to FIconInfo.Width - 1 do
|
|
begin
|
|
FImage.Colors[j, l] :=
|
|
FPColor(ARGBAData^.Red shl 8 or ARGBAData^.Red,
|
|
ARGBAData^.Green shl 8 or ARGBAData^.Green,
|
|
ARGBAData^.Blue shl 8 or ARGBAData^.Blue,
|
|
alphaOpaque);
|
|
inc(ARGBAData);
|
|
end;
|
|
FreeMem(ADecompData);
|
|
end;
|
|
|
|
procedure TLazReaderIcnsPart.DoReadJpeg2000;
|
|
begin
|
|
// TODO: according to some research in the web we need to read jpeg 2000 data
|
|
end;
|
|
|
|
procedure TLazReaderIcnsPart.DoReadMask;
|
|
var
|
|
Row, Column: Integer;
|
|
shift: byte;
|
|
b: PByte;
|
|
begin
|
|
case FIconInfo.Depth of
|
|
1:
|
|
begin
|
|
// actually here is stored 2 1-bit images, but we will get only first
|
|
shift := 7;
|
|
b := FData;
|
|
for Row := 0 to FIconInfo.Height - 1 do
|
|
begin
|
|
for Column := 0 to FIconInfo.Width - 1 do
|
|
begin
|
|
FImage.colors[Column, Row] := FPColor(0, 0, 0);
|
|
FImage.Masked[Column, Row] := (b^ shr shift) mod 2 = 0;
|
|
if shift = 0 then
|
|
begin
|
|
shift := 7;
|
|
inc(b);
|
|
end
|
|
else
|
|
dec(shift);
|
|
end;
|
|
end;
|
|
end;
|
|
8:
|
|
begin
|
|
b := FData;
|
|
for Row := 0 to FIconInfo.Height - 1 do
|
|
for Column := 0 to FIconInfo.Width - 1 do
|
|
begin
|
|
FImage.colors[Column, Row] := FPColor(0, 0, 0, (b^ shl 8) or b^);
|
|
inc(b);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TLazReaderIcnsPart.Create256ColorPalette: TFPPalette;
|
|
const
|
|
CHANNELVAL: array[0..15] of Word = (
|
|
$FFFF, $CCCC, $9999, $6666, $3333, $0000,
|
|
$EEEE, $DDDD, $BBBB, $AAAA, $8888,
|
|
$7777, $5555, $4444, $2222, $1111
|
|
);
|
|
|
|
var
|
|
rIdx, gIdx, bIdx: byte;
|
|
PalIdx: Byte;
|
|
begin
|
|
Result := TFPPalette.Create(256);
|
|
PalIdx := 0;
|
|
for rIdx := 0 to 5 do
|
|
begin
|
|
for gIdx := 0 to 5 do
|
|
begin
|
|
for bIdx := 0 to 5 do
|
|
begin
|
|
Result[PalIdx] := FPColor(CHANNELVAL[rIdx], CHANNELVAL[gIdx], CHANNELVAL[bIdx]);
|
|
Inc(PalIdx);
|
|
end;
|
|
end;
|
|
end;
|
|
for rIdx := 6 to 15 do
|
|
begin
|
|
Result[PalIdx] := FPColor(CHANNELVAL[rIdx], 0, 0);
|
|
Inc(PalIdx);
|
|
end;
|
|
for gIdx := 6 to 15 do
|
|
begin
|
|
Result[PalIdx] := FPColor(0, CHANNELVAL[gIdx], 0);
|
|
Inc(PalIdx);
|
|
end;
|
|
for bIdx := 6 to 15 do
|
|
begin
|
|
Result[PalIdx] := FPColor(0, 0, CHANNELVAL[bIdx]);
|
|
Inc(PalIdx);
|
|
end;
|
|
for rIdx := 6 to 15 do
|
|
begin
|
|
Result[PalIdx] := FPColor(CHANNELVAL[rIdx], CHANNELVAL[rIdx], CHANNELVAL[rIdx]);
|
|
Inc(PalIdx);
|
|
end;
|
|
Result[PalIdx] := FPColor(0, 0, 0);
|
|
end;
|
|
|
|
constructor TLazReaderIcnsPart.Create;
|
|
begin
|
|
inherited Create;
|
|
FData := nil;
|
|
FPalette := nil;
|
|
FCalcSize := 0;
|
|
FIconType := iitNone;
|
|
end;
|
|
|
|
destructor TLazReaderIcnsPart.Destroy;
|
|
begin
|
|
FPalette.Free;
|
|
FreeMem(FData);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
//------------------------------------------------------------------------------
|
|
procedure InternalInit;
|
|
var
|
|
c: Char;
|
|
begin
|
|
for c:=Low(char) to High(char) do begin
|
|
IsSpaceChar[c]:=c in [' ',#9,#10,#13];
|
|
IsNumberChar[c]:=c in ['0'..'9'];
|
|
IsHexNumberChar[c]:=c in ['0'..'9','A'..'F','a'..'f'];
|
|
end;
|
|
end;
|
|
|
|
initialization
|
|
InternalInit;
|
|
|
|
end.
|