- Merged changes from Turley (elevate with random altitude)
- Rearranged the TfrmElevateSettings dialog - Fixed transparency settings of the images in the TfrmLogin dialog - Fixed TfrmRegionControl to not react on mouse clicks if no region is selected - Updated Vampyre Imaging Lib to recent SVN - Added missing cedserver_config_2_3 project file
This commit is contained in:
parent
fcb7c8a794
commit
0e841f864d
|
@ -1,61 +1,120 @@
|
||||||
object frmElevateSettings: TfrmElevateSettings
|
object frmElevateSettings: TfrmElevateSettings
|
||||||
Left = 290
|
Left = 290
|
||||||
Height = 65
|
Height = 115
|
||||||
Top = 171
|
Top = 171
|
||||||
Width = 131
|
Width = 231
|
||||||
HorzScrollBar.Page = 130
|
HorzScrollBar.Page = 230
|
||||||
HorzScrollBar.Range = 122
|
HorzScrollBar.Range = 122
|
||||||
VertScrollBar.Page = 64
|
VertScrollBar.Page = 114
|
||||||
VertScrollBar.Range = 59
|
VertScrollBar.Range = 59
|
||||||
ActiveControl = rbRaise
|
ActiveControl = rbRaise
|
||||||
AutoScroll = False
|
AutoScroll = False
|
||||||
BorderIcons = []
|
BorderIcons = []
|
||||||
BorderStyle = bsToolWindow
|
BorderStyle = bsToolWindow
|
||||||
Caption = 'Elevate'
|
Caption = 'Elevate'
|
||||||
ClientHeight = 65
|
ClientHeight = 115
|
||||||
ClientWidth = 131
|
ClientWidth = 231
|
||||||
Font.Height = -11
|
Font.Height = -11
|
||||||
OnClose = FormClose
|
OnClose = FormClose
|
||||||
OnDeactivate = FormDeactivate
|
OnDeactivate = FormDeactivate
|
||||||
LCLVersion = '0.9.25'
|
LCLVersion = '0.9.25'
|
||||||
object rbRaise: TRadioButton
|
object Panel1: TPanel
|
||||||
Left = 8
|
Left = 8
|
||||||
Height = 21
|
Height = 67
|
||||||
Top = 8
|
Top = 8
|
||||||
Width = 58
|
Width = 215
|
||||||
|
Align = alTop
|
||||||
|
BorderSpacing.Around = 8
|
||||||
|
BevelOuter = bvNone
|
||||||
|
ClientHeight = 67
|
||||||
|
ClientWidth = 215
|
||||||
|
TabOrder = 0
|
||||||
|
object Panel2: TPanel
|
||||||
|
Height = 67
|
||||||
|
Width = 162
|
||||||
|
Align = alClient
|
||||||
|
BevelOuter = bvNone
|
||||||
|
ClientHeight = 67
|
||||||
|
ClientWidth = 162
|
||||||
|
ParentFont = True
|
||||||
|
TabOrder = 0
|
||||||
|
object rbRaise: TRadioButton
|
||||||
|
Height = 21
|
||||||
|
Width = 162
|
||||||
|
Align = alTop
|
||||||
Caption = 'Raise'
|
Caption = 'Raise'
|
||||||
Checked = True
|
Checked = True
|
||||||
ParentFont = True
|
|
||||||
State = cbChecked
|
State = cbChecked
|
||||||
TabOrder = 0
|
TabOrder = 2
|
||||||
end
|
end
|
||||||
object rbLower: TRadioButton
|
object rbLower: TRadioButton
|
||||||
Left = 8
|
|
||||||
Height = 21
|
Height = 21
|
||||||
Top = 24
|
Top = 21
|
||||||
Width = 59
|
Width = 162
|
||||||
|
Align = alTop
|
||||||
Caption = 'Lower'
|
Caption = 'Lower'
|
||||||
ParentFont = True
|
ParentFont = True
|
||||||
|
TabOrder = 0
|
||||||
|
end
|
||||||
|
object rbSet: TRadioButton
|
||||||
|
Height = 21
|
||||||
|
Top = 42
|
||||||
|
Width = 162
|
||||||
|
Align = alTop
|
||||||
|
Caption = 'Set'
|
||||||
|
ParentFont = True
|
||||||
TabOrder = 1
|
TabOrder = 1
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
object Panel3: TPanel
|
||||||
|
Left = 162
|
||||||
|
Height = 67
|
||||||
|
Width = 53
|
||||||
|
Align = alRight
|
||||||
|
BevelOuter = bvNone
|
||||||
|
ClientHeight = 67
|
||||||
|
ClientWidth = 53
|
||||||
|
TabOrder = 1
|
||||||
object seZ: TSpinEdit
|
object seZ: TSpinEdit
|
||||||
Left = 72
|
Left = 7
|
||||||
Height = 23
|
Height = 23
|
||||||
Top = 22
|
Top = 20
|
||||||
Width = 50
|
Width = 47
|
||||||
MaxValue = 127
|
MaxValue = 127
|
||||||
MinValue = -128
|
MinValue = -128
|
||||||
ParentFont = True
|
ParentFont = True
|
||||||
TabOrder = 3
|
TabOrder = 0
|
||||||
Value = 1
|
Value = 1
|
||||||
end
|
end
|
||||||
object rbSet: TRadioButton
|
end
|
||||||
|
end
|
||||||
|
object Panel4: TPanel
|
||||||
Left = 8
|
Left = 8
|
||||||
Height = 21
|
Height = 23
|
||||||
Top = 40
|
Top = 83
|
||||||
Width = 43
|
Width = 215
|
||||||
Caption = 'Set'
|
Align = alTop
|
||||||
|
BorderSpacing.Around = 8
|
||||||
|
BevelOuter = bvNone
|
||||||
|
ClientHeight = 23
|
||||||
|
ClientWidth = 215
|
||||||
|
TabOrder = 1
|
||||||
|
object cbRandomHeight: TCheckBox
|
||||||
|
Height = 23
|
||||||
|
Width = 168
|
||||||
|
Align = alClient
|
||||||
|
Caption = 'Add Random Altitude'
|
||||||
ParentFont = True
|
ParentFont = True
|
||||||
TabOrder = 2
|
TabOrder = 0
|
||||||
|
end
|
||||||
|
object seRandomHeight: TSpinEdit
|
||||||
|
Left = 168
|
||||||
|
Height = 23
|
||||||
|
Width = 47
|
||||||
|
Align = alRight
|
||||||
|
OnChange = seRandomHeightChange
|
||||||
|
ParentFont = True
|
||||||
|
TabOrder = 1
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
* CDDL HEADER END
|
* CDDL HEADER END
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Portions Copyright 2007 Andreas Schneider
|
* Portions Copyright 2008 Andreas Schneider
|
||||||
*)
|
*)
|
||||||
unit UfrmElevateSettings;
|
unit UfrmElevateSettings;
|
||||||
|
|
||||||
|
@ -31,19 +31,26 @@ interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, LMessages,
|
Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, LMessages,
|
||||||
LCLIntf, StdCtrls, Spin;
|
LCLIntf, StdCtrls, Spin, ExtCtrls;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
{ TfrmElevateSettings }
|
{ TfrmElevateSettings }
|
||||||
|
|
||||||
TfrmElevateSettings = class(TForm)
|
TfrmElevateSettings = class(TForm)
|
||||||
rbSet: TRadioButton;
|
cbRandomHeight: TCheckBox;
|
||||||
|
Panel1: TPanel;
|
||||||
|
Panel2: TPanel;
|
||||||
|
Panel3: TPanel;
|
||||||
|
Panel4: TPanel;
|
||||||
rbRaise: TRadioButton;
|
rbRaise: TRadioButton;
|
||||||
rbLower: TRadioButton;
|
rbLower: TRadioButton;
|
||||||
|
rbSet: TRadioButton;
|
||||||
|
seRandomHeight: TSpinEdit;
|
||||||
seZ: TSpinEdit;
|
seZ: TSpinEdit;
|
||||||
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
|
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
|
||||||
procedure FormDeactivate(Sender: TObject);
|
procedure FormDeactivate(Sender: TObject);
|
||||||
|
procedure seRandomHeightChange(Sender: TObject);
|
||||||
protected
|
protected
|
||||||
procedure MouseLeave(var msg: TLMessage); message CM_MouseLeave;
|
procedure MouseLeave(var msg: TLMessage); message CM_MouseLeave;
|
||||||
public
|
public
|
||||||
|
@ -68,6 +75,11 @@ begin
|
||||||
Close;
|
Close;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TfrmElevateSettings.seRandomHeightChange(Sender: TObject);
|
||||||
|
begin
|
||||||
|
cbRandomHeight.Checked := True;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TfrmElevateSettings.MouseLeave(var msg: TLMessage);
|
procedure TfrmElevateSettings.MouseLeave(var msg: TLMessage);
|
||||||
begin
|
begin
|
||||||
if not PtInRect(ClientRect, ScreenToClient(Mouse.CursorPos)) then
|
if not PtInRect(ClientRect, ScreenToClient(Mouse.CursorPos)) then
|
||||||
|
|
|
@ -961,14 +961,14 @@ begin
|
||||||
FRealWidth := AWidth;
|
FRealWidth := AWidth;
|
||||||
FRealHeight := AHeight;
|
FRealHeight := AHeight;
|
||||||
GetGLTextureCaps(caps);
|
GetGLTextureCaps(caps);
|
||||||
if caps.PowerOfTwo then
|
if caps.NonPowerOfTwo then
|
||||||
begin
|
|
||||||
if IsPow2(AWidth) then FWidth := AWidth else FWidth := NextPow2(AWidth);
|
|
||||||
if IsPow2(AHeight) then FHeight := AHeight else FHeight := NextPow2(AHeight);
|
|
||||||
end else
|
|
||||||
begin
|
begin
|
||||||
FWidth := AWidth;
|
FWidth := AWidth;
|
||||||
FHeight := AHeight;
|
FHeight := AHeight;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
if IsPow2(AWidth) then FWidth := AWidth else FWidth := NextPow2(AWidth);
|
||||||
|
if IsPow2(AHeight) then FHeight := AHeight else FHeight := NextPow2(AHeight);
|
||||||
end;
|
end;
|
||||||
FGraphic := TSingleImage.CreateFromParams(FWidth, FHeight, ifA8R8G8B8);
|
FGraphic := TSingleImage.CreateFromParams(FWidth, FHeight, ifA8R8G8B8);
|
||||||
AGraphic.CopyTo(0, 0, AWidth, AHeight, FGraphic, 0, 0);
|
AGraphic.CopyTo(0, 0, AWidth, AHeight, FGraphic, 0, 0);
|
||||||
|
|
|
@ -91,14 +91,14 @@ begin
|
||||||
FRealWidth := AGraphic.Width;
|
FRealWidth := AGraphic.Width;
|
||||||
FRealHeight := AGraphic.Height;
|
FRealHeight := AGraphic.Height;
|
||||||
GetGLTextureCaps(caps);
|
GetGLTextureCaps(caps);
|
||||||
if caps.PowerOfTwo then
|
if caps.NonPowerOfTwo then
|
||||||
begin
|
|
||||||
if IsPow2(FRealWidth) then FWidth := FRealWidth else FWidth := NextPow2(FRealWidth);
|
|
||||||
if IsPow2(FRealHeight) then FHeight := FRealHeight else FHeight := NextPow2(FRealHeight);
|
|
||||||
end else
|
|
||||||
begin
|
begin
|
||||||
FWidth := FRealHeight;
|
FWidth := FRealHeight;
|
||||||
FHeight := FRealHeight;
|
FHeight := FRealHeight;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
if IsPow2(FRealWidth) then FWidth := FRealWidth else FWidth := NextPow2(FRealWidth);
|
||||||
|
if IsPow2(FRealHeight) then FHeight := FRealHeight else FHeight := NextPow2(FRealHeight);
|
||||||
end;
|
end;
|
||||||
FGraphic := TSingleImage.CreateFromParams(FWidth, FHeight, ifA8R8G8B8);
|
FGraphic := TSingleImage.CreateFromParams(FWidth, FHeight, ifA8R8G8B8);
|
||||||
AGraphic.CopyTo(0, 0, FRealWidth, FRealHeight, FGraphic, 0, 0);
|
AGraphic.CopyTo(0, 0, FRealWidth, FRealHeight, FGraphic, 0, 0);
|
||||||
|
|
|
@ -16,8 +16,8 @@ object frmLogin: TfrmLogin
|
||||||
ShowInTaskBar = stAlways
|
ShowInTaskBar = stAlways
|
||||||
LCLVersion = '0.9.25'
|
LCLVersion = '0.9.25'
|
||||||
object lblCopyright: TLabel
|
object lblCopyright: TLabel
|
||||||
Height = 25
|
Height = 26
|
||||||
Top = 240
|
Top = 239
|
||||||
Width = 489
|
Width = 489
|
||||||
Align = alBottom
|
Align = alBottom
|
||||||
Alignment = taCenter
|
Alignment = taCenter
|
||||||
|
@ -151,6 +151,7 @@ object frmLogin: TfrmLogin
|
||||||
233023312332233323342335517451745174222C0A2251745174517451745174
|
233023312332233323342335517451745174222C0A2251745174517451745174
|
||||||
51745174517451745174517451745174517451745174227D3B0A
|
51745174517451745174517451745174517451745174227D3B0A
|
||||||
}
|
}
|
||||||
|
Transparent = True
|
||||||
end
|
end
|
||||||
object imgUsername: TImage
|
object imgUsername: TImage
|
||||||
Left = 6
|
Left = 6
|
||||||
|
@ -242,6 +243,7 @@ object frmLogin: TfrmLogin
|
||||||
233123322333233423355174517451745174222C0A2251745174517451745174
|
233123322333233423355174517451745174222C0A2251745174517451745174
|
||||||
51745174517451745174517451745174517451745174227D3B0A
|
51745174517451745174517451745174517451745174227D3B0A
|
||||||
}
|
}
|
||||||
|
Transparent = True
|
||||||
end
|
end
|
||||||
object imgPassword: TImage
|
object imgPassword: TImage
|
||||||
Left = 6
|
Left = 6
|
||||||
|
@ -323,6 +325,7 @@ object frmLogin: TfrmLogin
|
||||||
5174222C0A2251742349234A236E234B51745174517451745174517451745174
|
5174222C0A2251742349234A236E234B51745174517451745174517451745174
|
||||||
517451745174227D3B0A
|
517451745174227D3B0A
|
||||||
}
|
}
|
||||||
|
Transparent = True
|
||||||
end
|
end
|
||||||
object edHost: TEdit
|
object edHost: TEdit
|
||||||
Left = 101
|
Left = 101
|
||||||
|
@ -432,11 +435,11 @@ object frmLogin: TfrmLogin
|
||||||
end
|
end
|
||||||
object GroupBox1: TGroupBox
|
object GroupBox1: TGroupBox
|
||||||
Left = 336
|
Left = 336
|
||||||
Height = 84
|
Height = 88
|
||||||
Top = 112
|
Top = 112
|
||||||
Width = 145
|
Width = 145
|
||||||
Caption = 'Profiles'
|
Caption = 'Profiles'
|
||||||
ClientHeight = 69
|
ClientHeight = 73
|
||||||
ClientWidth = 141
|
ClientWidth = 141
|
||||||
ParentFont = True
|
ParentFont = True
|
||||||
TabOrder = 3
|
TabOrder = 3
|
||||||
|
|
|
@ -619,6 +619,8 @@ begin
|
||||||
|
|
||||||
if tile is TMapCell then
|
if tile is TMapCell then
|
||||||
begin
|
begin
|
||||||
|
if frmElevateSettings.cbRandomHeight.Checked then
|
||||||
|
Inc(z, Random(frmElevateSettings.seRandomHeight.Value));
|
||||||
dmNetwork.Send(TDrawMapPacket.Create(tile.X, tile.Y,
|
dmNetwork.Send(TDrawMapPacket.Create(tile.X, tile.Y,
|
||||||
z, tile.TileID));
|
z, tile.TileID));
|
||||||
end else
|
end else
|
||||||
|
|
|
@ -12,6 +12,7 @@ object frmRegionControl: TfrmRegionControl
|
||||||
OnDestroy = FormDestroy
|
OnDestroy = FormDestroy
|
||||||
OnShow = FormShow
|
OnShow = FormShow
|
||||||
Position = poOwnerFormCenter
|
Position = poOwnerFormCenter
|
||||||
|
ShowInTaskBar = stAlways
|
||||||
LCLVersion = '0.9.25'
|
LCLVersion = '0.9.25'
|
||||||
object Panel1: TPanel
|
object Panel1: TPanel
|
||||||
Height = 359
|
Height = 359
|
||||||
|
|
|
@ -345,6 +345,8 @@ var
|
||||||
areaInfo: PRect;
|
areaInfo: PRect;
|
||||||
p: TPoint;
|
p: TPoint;
|
||||||
begin
|
begin
|
||||||
|
if vstRegions.GetFirstSelected = nil then Exit;
|
||||||
|
|
||||||
FAreaMove := [];
|
FAreaMove := [];
|
||||||
p := Point(X * 8, Y * 8);
|
p := Point(X * 8, Y * 8);
|
||||||
match := nil;
|
match := nil;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
$Id: Imaging.pas 99 2007-06-26 04:12:01Z galfar $
|
$Id: Imaging.pas 124 2008-04-21 09:47:07Z galfar $
|
||||||
Vampyre Imaging Library
|
Vampyre Imaging Library
|
||||||
by Marek Mauder
|
by Marek Mauder
|
||||||
http://imaginglib.sourceforge.net
|
http://imaginglib.sourceforge.net
|
||||||
|
@ -1573,6 +1573,8 @@ function GenerateMipMaps(const Image: TImageData; Levels: LongInt;
|
||||||
var MipMaps: TDynImageDataArray): Boolean;
|
var MipMaps: TDynImageDataArray): Boolean;
|
||||||
var
|
var
|
||||||
Width, Height, I, Count: LongInt;
|
Width, Height, I, Count: LongInt;
|
||||||
|
Info: TImageFormatInfo;
|
||||||
|
CompatibleCopy: TImageData;
|
||||||
begin
|
begin
|
||||||
Result := False;
|
Result := False;
|
||||||
if TestImage(Image) then
|
if TestImage(Image) then
|
||||||
|
@ -1585,6 +1587,20 @@ begin
|
||||||
if (Levels <= 0) or (Levels > Count) then
|
if (Levels <= 0) or (Levels > Count) then
|
||||||
Levels := Count;
|
Levels := Count;
|
||||||
|
|
||||||
|
// If we have special format image we create copy to allow pixel access.
|
||||||
|
// This is also done in FillMipMapLevel which is called for each level
|
||||||
|
// but then the main big image would be converted to compatible
|
||||||
|
// for every level.
|
||||||
|
GetImageFormatInfo(Image.Format, Info);
|
||||||
|
if Info.IsSpecial then
|
||||||
|
begin
|
||||||
|
InitImage(CompatibleCopy);
|
||||||
|
CloneImage(Image, CompatibleCopy);
|
||||||
|
ConvertImage(CompatibleCopy, ifDefault);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
CompatibleCopy := Image;
|
||||||
|
|
||||||
FreeImagesInArray(MipMaps);
|
FreeImagesInArray(MipMaps);
|
||||||
SetLength(MipMaps, Levels);
|
SetLength(MipMaps, Levels);
|
||||||
CloneImage(Image, MipMaps[0]);
|
CloneImage(Image, MipMaps[0]);
|
||||||
|
@ -1595,8 +1611,17 @@ begin
|
||||||
Height := Height shr 1;
|
Height := Height shr 1;
|
||||||
if Width < 1 then Width := 1;
|
if Width < 1 then Width := 1;
|
||||||
if Height < 1 then Height := 1;
|
if Height < 1 then Height := 1;
|
||||||
FillMipMapLevel(MipMaps[I - 1], Width, Height, MipMaps[I]);
|
FillMipMapLevel(CompatibleCopy, Width, Height, MipMaps[I]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if CompatibleCopy.Format <> MipMaps[0].Format then
|
||||||
|
begin
|
||||||
|
// Must convert smaller levels to proper format
|
||||||
|
for I := 1 to High(MipMaps) do
|
||||||
|
ConvertImage(MipMaps[I], MipMaps[0].Format);
|
||||||
|
FreeImage(CompatibleCopy);
|
||||||
|
end;
|
||||||
|
|
||||||
Result := True;
|
Result := True;
|
||||||
except
|
except
|
||||||
RaiseImaging(SErrorGenerateMipMaps, [Levels, ImageToStr(Image)]);
|
RaiseImaging(SErrorGenerateMipMaps, [Levels, ImageToStr(Image)]);
|
||||||
|
@ -3262,15 +3287,13 @@ finalization
|
||||||
File Notes:
|
File Notes:
|
||||||
|
|
||||||
-- TODOS ----------------------------------------------------
|
-- TODOS ----------------------------------------------------
|
||||||
- make searching for the closest color in palette much faster - MapImageToPal
|
- nothing now
|
||||||
- investigate CopyPixel and ComparePixels inline problems - line 550
|
|
||||||
- add to low level interface function
|
-- 0.24.3 Changes/Bug Fixes ---------------------------------
|
||||||
CreateImageFromRawData(W, H, Bpp, Data, Align, Flipped, Endian, ...)
|
- GenerateMipMaps now generates all smaller levels from
|
||||||
and CreateRawDataFromImage() - use these in BMP loading (align)
|
original big image (better results when using more advanced filters).
|
||||||
and PNG loading (endian)
|
Also conversion to compatible image format is now done here not
|
||||||
- add loading of multi images from file sequence
|
in FillMipMapLevel (that is called for every mipmap level).
|
||||||
- do not load all frames when only one is required, possible?
|
|
||||||
(LoadImageFromFile on MNG/DDS)
|
|
||||||
|
|
||||||
-- 0.23 Changes/Bug Fixes -----------------------------------
|
-- 0.23 Changes/Bug Fixes -----------------------------------
|
||||||
- MakePaletteForImages now works correctly for indexed and special format images
|
- MakePaletteForImages now works correctly for indexed and special format images
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
$Id: ImagingBitmap.pas 94 2007-06-21 19:29:49Z galfar $
|
$Id: ImagingBitmap.pas 129 2008-08-06 20:01:30Z galfar $
|
||||||
Vampyre Imaging Library
|
Vampyre Imaging Library
|
||||||
by Marek Mauder
|
by Marek Mauder
|
||||||
http://imaginglib.sourceforge.net
|
http://imaginglib.sourceforge.net
|
||||||
|
@ -484,7 +484,7 @@ begin
|
||||||
FPalSize := 1 shl BI.BitCount;
|
FPalSize := 1 shl BI.BitCount;
|
||||||
Read(Handle, Palette, FPalSize * SizeOf(TColor32Rec));
|
Read(Handle, Palette, FPalSize * SizeOf(TColor32Rec));
|
||||||
end;
|
end;
|
||||||
for I := 0 to FPalSize - 1 do
|
for I := 0 to Info.PaletteEntries - 1 do
|
||||||
Palette[I].A := $FF;
|
Palette[I].A := $FF;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -802,6 +802,10 @@ initialization
|
||||||
- nothing now
|
- nothing now
|
||||||
- Add option to choose to save V3 or V4 headers.
|
- Add option to choose to save V3 or V4 headers.
|
||||||
|
|
||||||
|
-- 0.25.0 Changes/Bug Fixes ---------------------------------
|
||||||
|
- Fixed problem with indexed BMP loading - some pal entries
|
||||||
|
could end up with alpha=0.
|
||||||
|
|
||||||
-- 0.23 Changes/Bug Fixes -----------------------------------
|
-- 0.23 Changes/Bug Fixes -----------------------------------
|
||||||
- Now saves bitmaps as bottom-up for better compatibility
|
- Now saves bitmaps as bottom-up for better compatibility
|
||||||
(mainly Lazarus' TImage!).
|
(mainly Lazarus' TImage!).
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
$Id: ImagingCanvases.pas 103 2007-09-15 01:11:14Z galfar $
|
$Id: ImagingCanvases.pas 131 2008-08-14 15:14:24Z galfar $
|
||||||
Vampyre Imaging Library
|
Vampyre Imaging Library
|
||||||
by Marek Mauder
|
by Marek Mauder
|
||||||
http://imaginglib.sourceforge.net
|
http://imaginglib.sourceforge.net
|
||||||
|
@ -62,8 +62,10 @@ const
|
||||||
pcDkGray = $FF808080;
|
pcDkGray = $FF808080;
|
||||||
|
|
||||||
MaxPenWidth = 256;
|
MaxPenWidth = 256;
|
||||||
|
|
||||||
type
|
type
|
||||||
EImagingCanvasError = class(EImagingError);
|
EImagingCanvasError = class(EImagingError);
|
||||||
|
EImagingCanvasBlendingError = class(EImagingError);
|
||||||
|
|
||||||
{ Fill mode used when drawing filled objects on canvas.}
|
{ Fill mode used when drawing filled objects on canvas.}
|
||||||
TFillMode = (
|
TFillMode = (
|
||||||
|
@ -77,6 +79,26 @@ type
|
||||||
pmClear // No drawing done
|
pmClear // No drawing done
|
||||||
);
|
);
|
||||||
|
|
||||||
|
{ Source and destination blending factors for drawing functions with blending.
|
||||||
|
Blending formula: SrcColor * SrcFactor + DestColor * DestFactor }
|
||||||
|
TBlendingFactor = (
|
||||||
|
bfIgnore, // Don't care
|
||||||
|
bfZero, // For Src and Dest, Factor = (0, 0, 0, 0)
|
||||||
|
bfOne, // For Src and Dest, Factor = (1, 1, 1, 1)
|
||||||
|
bfSrcAlpha, // For Src and Dest, Factor = (Src.A, Src.A, Src.A, Src.A)
|
||||||
|
bfOneMinusSrcAlpha, // For Src and Dest, Factor = (1 - Src.A, 1 - Src.A, 1 - Src.A, 1 - Src.A)
|
||||||
|
bfDstAlpha, // For Src and Dest, Factor = (Dest.A, Dest.A, Dest.A, Dest.A)
|
||||||
|
bfOneMinusDstAlpha, // For Src and Dest, Factor = (1 - Dest.A, 1 - Dest.A, 1 - Dest.A, 1 - Dest.A)
|
||||||
|
bfSrcColor, // For Dest, Factor = (Src.R, Src.R, Src.B, Src.A)
|
||||||
|
bfOneMinusSrcColor, // For Dest, Factor = (1 - Src.R, 1 - Src.G, 1 - Src.B, 1 - Src.A)
|
||||||
|
bfDstColor, // For Src, Factor = (Dest.R, Dest.G, Dest.B, Dest.A)
|
||||||
|
bfOneMinusDstColor // For Src, Factor = (1 - Dest.R, 1 - Dest.G, 1 - Dest.B, 1 - Dest.A)
|
||||||
|
);
|
||||||
|
|
||||||
|
{ Procedure for custom pixel write modes with blending.}
|
||||||
|
TPixelWriteProc = procedure(const SrcPix: TColorFPRec; DestPtr: PByte;
|
||||||
|
DestInfo: PImageFormatInfo; SrcFactor, DestFactor: TBlendingFactor);
|
||||||
|
|
||||||
{ Represents 3x3 convolution filter kernel.}
|
{ Represents 3x3 convolution filter kernel.}
|
||||||
TConvolutionFilter3x3 = record
|
TConvolutionFilter3x3 = record
|
||||||
Kernel: array[0..2, 0..2] of LongInt;
|
Kernel: array[0..2, 0..2] of LongInt;
|
||||||
|
@ -91,6 +113,13 @@ type
|
||||||
Bias: Single;
|
Bias: Single;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TPointTransformFunction = function(const Pixel: TColorFPRec;
|
||||||
|
Param1, Param2, Param3: Single): TColorFPRec;
|
||||||
|
|
||||||
|
TDynFPPixelArray = array of TColorFPRec;
|
||||||
|
|
||||||
|
TSelectPixelFunction = function(var Pixels: TDynFPPixelArray): TColorFPRec;
|
||||||
|
|
||||||
{ Base canvas class for drawing objects, applying effects, and other.
|
{ Base canvas class for drawing objects, applying effects, and other.
|
||||||
Constructor takes TBaseImage (or pointer to TImageData). Source image
|
Constructor takes TBaseImage (or pointer to TImageData). Source image
|
||||||
bits are not copied but referenced so all canvas functions affect
|
bits are not copied but referenced so all canvas functions affect
|
||||||
|
@ -104,11 +133,6 @@ type
|
||||||
can use one of fast canvas clases. These descendants of TImagingCanvas
|
can use one of fast canvas clases. These descendants of TImagingCanvas
|
||||||
work only for few select formats (or only one) but they are optimized thus
|
work only for few select formats (or only one) but they are optimized thus
|
||||||
much faster.
|
much faster.
|
||||||
|
|
||||||
--
|
|
||||||
Canvas in this Imaging version (0.20) is very basic and its purpose is to
|
|
||||||
act like sort of a preview of things to come.
|
|
||||||
Update 0.22: Some new stuff added but not much yet.
|
|
||||||
}
|
}
|
||||||
TImagingCanvas = class(TObject)
|
TImagingCanvas = class(TObject)
|
||||||
private
|
private
|
||||||
|
@ -125,6 +149,7 @@ type
|
||||||
procedure SetFillColor32(const Value: TColor32); {$IFDEF USE_INLINE}inline;{$ENDIF}
|
procedure SetFillColor32(const Value: TColor32); {$IFDEF USE_INLINE}inline;{$ENDIF}
|
||||||
procedure SetFillColorFP(const Value: TColorFPRec); {$IFDEF USE_INLINE}inline;{$ENDIF}
|
procedure SetFillColorFP(const Value: TColorFPRec); {$IFDEF USE_INLINE}inline;{$ENDIF}
|
||||||
procedure SetClipRect(const Value: TRect);
|
procedure SetClipRect(const Value: TRect);
|
||||||
|
procedure CheckBeforeBlending(SrcFactor, DestFactor: TBlendingFactor; DestCanvas: TImagingCanvas);
|
||||||
protected
|
protected
|
||||||
FPData: PImageData;
|
FPData: PImageData;
|
||||||
FClipRect: TRect;
|
FClipRect: TRect;
|
||||||
|
@ -151,6 +176,11 @@ type
|
||||||
like ellipses and circles.}
|
like ellipses and circles.}
|
||||||
procedure HorzLineInternal(X1, X2, Y: LongInt; Color: Pointer; Bpp: LongInt); virtual;
|
procedure HorzLineInternal(X1, X2, Y: LongInt; Color: Pointer; Bpp: LongInt); virtual;
|
||||||
procedure CopyPixelInternal(X, Y: LongInt; Pixel: Pointer; Bpp: LongInt); {$IFDEF USE_INLINE}inline;{$ENDIF}
|
procedure CopyPixelInternal(X, Y: LongInt; Pixel: Pointer; Bpp: LongInt); {$IFDEF USE_INLINE}inline;{$ENDIF}
|
||||||
|
procedure DrawInternal(const SrcRect: TRect; DestCanvas: TImagingCanvas;
|
||||||
|
DestX, DestY: Integer; SrcFactor, DestFactor: TBlendingFactor; PixelWriteProc: TPixelWriteProc);
|
||||||
|
procedure StretchDrawInternal(const SrcRect: TRect; DestCanvas: TImagingCanvas;
|
||||||
|
const DestRect: TRect; SrcFactor, DestFactor: TBlendingFactor;
|
||||||
|
Filter: TResizeFilter; PixelWriteProc: TPixelWriteProc);
|
||||||
public
|
public
|
||||||
constructor CreateForData(ImageDataPointer: PImageData);
|
constructor CreateForData(ImageDataPointer: PImageData);
|
||||||
constructor CreateForImage(Image: TBaseImage);
|
constructor CreateForImage(Image: TBaseImage);
|
||||||
|
@ -177,6 +207,8 @@ type
|
||||||
procedure FrameRect(const Rect: TRect);
|
procedure FrameRect(const Rect: TRect);
|
||||||
{ Fills given rectangle with current fill settings.}
|
{ Fills given rectangle with current fill settings.}
|
||||||
procedure FillRect(const Rect: TRect); virtual;
|
procedure FillRect(const Rect: TRect); virtual;
|
||||||
|
{ Fills given rectangle with current fill settings and pixel blending.}
|
||||||
|
procedure FillRectBlend(const Rect: TRect; SrcFactor, DestFactor: TBlendingFactor);
|
||||||
{ Draws rectangle which is outlined by using the current pen settings and
|
{ Draws rectangle which is outlined by using the current pen settings and
|
||||||
filled by using the current fill settings.}
|
filled by using the current fill settings.}
|
||||||
procedure Rectangle(const Rect: TRect);
|
procedure Rectangle(const Rect: TRect);
|
||||||
|
@ -185,6 +217,34 @@ type
|
||||||
of ellipse to be drawn.}
|
of ellipse to be drawn.}
|
||||||
procedure Ellipse(const Rect: TRect);
|
procedure Ellipse(const Rect: TRect);
|
||||||
|
|
||||||
|
{ Draws contents of this canvas onto another canvas with pixel blending.
|
||||||
|
Blending factors are chosen using TBlendingFactor parameters.
|
||||||
|
Resulting destination pixel color is:
|
||||||
|
SrcColor * SrcFactor + DstColor * DstFactor}
|
||||||
|
procedure DrawBlend(const SrcRect: TRect; DestCanvas: TImagingCanvas;
|
||||||
|
DestX, DestY: Integer; SrcFactor, DestFactor: TBlendingFactor);
|
||||||
|
{ Draws contents of this canvas onto another one with typical alpha
|
||||||
|
blending (Src 'over' Dest, factors are bfSrcAlpha and bfOneMinusSrcAlpha.)}
|
||||||
|
procedure DrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas; DestX, DestY: Integer);
|
||||||
|
{ Draws contents of this canvas onto another one using additive blending
|
||||||
|
(source and dest factors are bfOne).}
|
||||||
|
procedure DrawAdd(const SrcRect: TRect; DestCanvas: TImagingCanvas; DestX, DestY: Integer);
|
||||||
|
{ Draws stretched and filtered contents of this canvas onto another canvas
|
||||||
|
with pixel blending. Blending factors are chosen using TBlendingFactor parameters.
|
||||||
|
Resulting destination pixel color is:
|
||||||
|
SrcColor * SrcFactor + DstColor * DstFactor}
|
||||||
|
procedure StretchDrawBlend(const SrcRect: TRect; DestCanvas: TImagingCanvas;
|
||||||
|
const DestRect: TRect; SrcFactor, DestFactor: TBlendingFactor;
|
||||||
|
Filter: TResizeFilter = rfBilinear);
|
||||||
|
{ Draws contents of this canvas onto another one with typical alpha
|
||||||
|
blending (Src 'over' Dest, factors are bfSrcAlpha and bfOneMinusSrcAlpha.)}
|
||||||
|
procedure StretchDrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas;
|
||||||
|
const DestRect: TRect; Filter: TResizeFilter = rfBilinear);
|
||||||
|
{ Draws contents of this canvas onto another one using additive blending
|
||||||
|
(source and dest factors are bfOne).}
|
||||||
|
procedure StretchDrawAdd(const SrcRect: TRect; DestCanvas: TImagingCanvas;
|
||||||
|
const DestRect: TRect; Filter: TResizeFilter = rfBilinear);
|
||||||
|
|
||||||
{ Convolves canvas' image with given 3x3 filter kernel. You can use
|
{ Convolves canvas' image with given 3x3 filter kernel. You can use
|
||||||
predefined filter kernels or define your own.}
|
predefined filter kernels or define your own.}
|
||||||
procedure ApplyConvolution3x3(const Filter: TConvolutionFilter3x3);
|
procedure ApplyConvolution3x3(const Filter: TConvolutionFilter3x3);
|
||||||
|
@ -201,6 +261,36 @@ type
|
||||||
procedure ApplyConvolution(Kernel: PLongInt; KernelSize, Divisor: LongInt;
|
procedure ApplyConvolution(Kernel: PLongInt; KernelSize, Divisor: LongInt;
|
||||||
Bias: Single = 0.0; ClampChannels: Boolean = True); virtual;
|
Bias: Single = 0.0; ClampChannels: Boolean = True); virtual;
|
||||||
|
|
||||||
|
{ Applies custom non-linear filter. Filter size is diameter of pixel
|
||||||
|
neighborhood. Typical values are 3, 5, or 7. }
|
||||||
|
procedure ApplyNonLinearFilter(FilterSize: Integer; SelectFunc: TSelectPixelFunction);
|
||||||
|
{ Applies median non-linear filter with user defined pixel neighborhood.
|
||||||
|
Selects median pixel from the neighborhood as new pixel
|
||||||
|
(current implementation is quite slow).}
|
||||||
|
procedure ApplyMedianFilter(FilterSize: Integer);
|
||||||
|
{ Applies min non-linear filter with user defined pixel neighborhood.
|
||||||
|
Selects min pixel from the neighborhood as new pixel.}
|
||||||
|
procedure ApplyMinFilter(FilterSize: Integer);
|
||||||
|
{ Applies max non-linear filter with user defined pixel neighborhood.
|
||||||
|
Selects max pixel from the neighborhood as new pixel.}
|
||||||
|
procedure ApplyMaxFilter(FilterSize: Integer);
|
||||||
|
|
||||||
|
{ Transforms pixels one by one by given function. Pixel neighbors are
|
||||||
|
not taken into account. Param 1-3 are optional parameters
|
||||||
|
for transform function.}
|
||||||
|
procedure PointTransform(Transform: TPointTransformFunction;
|
||||||
|
Param1, Param2, Param3: Single);
|
||||||
|
{ Modifies image contrast and brightness. Parameters should be
|
||||||
|
in range <-100; 100>.}
|
||||||
|
procedure ModifyContrastBrightness(Contrast, Brightness: Single);
|
||||||
|
{ Gamma correction of individual color channels. Range is (0, +inf),
|
||||||
|
1.0 means no change.}
|
||||||
|
procedure GammaCorection(Red, Green, Blue: Single);
|
||||||
|
{ Inverts colors of all image pixels, makes negative image.}
|
||||||
|
procedure InvertColors;
|
||||||
|
{ Simple single level thresholding with threshold level for each color channel.}
|
||||||
|
procedure Threshold(Red, Green, Blue: Single);
|
||||||
|
|
||||||
{ Color used when drawing lines, frames, and outlines of objects.}
|
{ Color used when drawing lines, frames, and outlines of objects.}
|
||||||
property PenColor32: TColor32 read FPenColor32 write SetPenColor32;
|
property PenColor32: TColor32 read FPenColor32 write SetPenColor32;
|
||||||
{ Color used when drawing lines, frames, and outlines of objects.}
|
{ Color used when drawing lines, frames, and outlines of objects.}
|
||||||
|
@ -384,6 +474,7 @@ const
|
||||||
(-1, -2, -1));
|
(-1, -2, -1));
|
||||||
Divisor: 4);
|
Divisor: 4);
|
||||||
|
|
||||||
|
{ Kernel for 3x3 contour enhancement filter.}
|
||||||
FilterTraceControur3x3: TConvolutionFilter3x3 = (
|
FilterTraceControur3x3: TConvolutionFilter3x3 = (
|
||||||
Kernel: ((-6, -6, -2),
|
Kernel: ((-6, -6, -2),
|
||||||
(-1, 32, -1),
|
(-1, 32, -1),
|
||||||
|
@ -466,7 +557,173 @@ begin
|
||||||
Result := FindBestCanvasForImage(Image.Format);
|
Result := FindBestCanvasForImage(Image.Format);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TImagingCanvas }
|
{ Canvas helper functions }
|
||||||
|
|
||||||
|
procedure PixelBlendProc(const SrcPix: TColorFPRec; DestPtr: PByte;
|
||||||
|
DestInfo: PImageFormatInfo; SrcFactor, DestFactor: TBlendingFactor);
|
||||||
|
var
|
||||||
|
DestPix, FSrc, FDst: TColorFPRec;
|
||||||
|
begin
|
||||||
|
// Get set pixel color
|
||||||
|
DestPix := DestInfo.GetPixelFP(DestPtr, DestInfo, nil);
|
||||||
|
// Determine current blending factors
|
||||||
|
case SrcFactor of
|
||||||
|
bfZero: FSrc := ColorFP(0, 0, 0, 0);
|
||||||
|
bfOne: FSrc := ColorFP(1, 1, 1, 1);
|
||||||
|
bfSrcAlpha: FSrc := ColorFP(SrcPix.A, SrcPix.A, SrcPix.A, SrcPix.A);
|
||||||
|
bfOneMinusSrcAlpha: FSrc := ColorFP(1 - SrcPix.A, 1 - SrcPix.A, 1 - SrcPix.A, 1 - SrcPix.A);
|
||||||
|
bfDstAlpha: FSrc := ColorFP(DestPix.A, DestPix.A, DestPix.A, DestPix.A);
|
||||||
|
bfOneMinusDstAlpha: FSrc := ColorFP(1 - DestPix.A, 1 - DestPix.A, 1 - DestPix.A, 1 - DestPix.A);
|
||||||
|
bfDstColor: FSrc := ColorFP(DestPix.A, DestPix.R, DestPix.G, DestPix.B);
|
||||||
|
bfOneMinusDstColor: FSrc := ColorFP(1 - DestPix.A, 1 - DestPix.R, 1 - DestPix.G, 1 - DestPix.B);
|
||||||
|
end;
|
||||||
|
case DestFactor of
|
||||||
|
bfZero: FDst := ColorFP(0, 0, 0, 0);
|
||||||
|
bfOne: FDst := ColorFP(1, 1, 1, 1);
|
||||||
|
bfSrcAlpha: FDst := ColorFP(SrcPix.A, SrcPix.A, SrcPix.A, SrcPix.A);
|
||||||
|
bfOneMinusSrcAlpha: FDst := ColorFP(1 - SrcPix.A, 1 - SrcPix.A, 1 - SrcPix.A, 1 - SrcPix.A);
|
||||||
|
bfDstAlpha: FDst := ColorFP(DestPix.A, DestPix.A, DestPix.A, DestPix.A);
|
||||||
|
bfOneMinusDstAlpha: FDst := ColorFP(1 - DestPix.A, 1 - DestPix.A, 1 - DestPix.A, 1 - DestPix.A);
|
||||||
|
bfSrcColor: FDst := ColorFP(SrcPix.A, SrcPix.R, SrcPix.G, SrcPix.B);
|
||||||
|
bfOneMinusSrcColor: FDst := ColorFP(1 - SrcPix.A, 1 - SrcPix.R, 1 - SrcPix.G, 1 - SrcPix.B);
|
||||||
|
end;
|
||||||
|
// Compute blending formula
|
||||||
|
DestPix.R := SrcPix.R * FSrc.R + DestPix.R * FDst.R;
|
||||||
|
DestPix.G := SrcPix.G * FSrc.G + DestPix.G * FDst.G;
|
||||||
|
DestPix.B := SrcPix.B * FSrc.B + DestPix.B * FDst.B;
|
||||||
|
DestPix.A := SrcPix.A * FSrc.A + DestPix.A * FDst.A;
|
||||||
|
// Write blended pixel
|
||||||
|
DestInfo.SetPixelFP(DestPtr, DestInfo, nil, DestPix);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure PixelAlphaProc(const SrcPix: TColorFPRec; DestPtr: PByte;
|
||||||
|
DestInfo: PImageFormatInfo; SrcFactor, DestFactor: TBlendingFactor);
|
||||||
|
var
|
||||||
|
DestPix: TColorFPRec;
|
||||||
|
begin
|
||||||
|
DestPix := DestInfo.GetPixelFP(DestPtr, DestInfo, nil);
|
||||||
|
// Blend the two pixels (Src 'over' Dest alpha composition operation)
|
||||||
|
DestPix.R := SrcPix.R * SrcPix.A + DestPix.R * DestPix.A * (1.0 - SrcPix.A);
|
||||||
|
DestPix.G := SrcPix.G * SrcPix.A + DestPix.G * DestPix.A * (1.0 - SrcPix.A);
|
||||||
|
DestPix.B := SrcPix.B * SrcPix.A + DestPix.B * DestPix.A * (1.0 - SrcPix.A);
|
||||||
|
DestPix.A := SrcPix.A + DestPix.A * (1.0 - SrcPix.A);
|
||||||
|
// Write blended pixel
|
||||||
|
DestInfo.SetPixelFP(DestPtr, DestInfo, nil, DestPix);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure PixelAddProc(const SrcPix: TColorFPRec; DestPtr: PByte;
|
||||||
|
DestInfo: PImageFormatInfo; SrcFactor, DestFactor: TBlendingFactor);
|
||||||
|
var
|
||||||
|
DestPix: TColorFPRec;
|
||||||
|
begin
|
||||||
|
// Just add Src and Dest
|
||||||
|
DestPix := DestInfo.GetPixelFP(DestPtr, DestInfo, nil);
|
||||||
|
DestPix.R := SrcPix.R + DestPix.R;
|
||||||
|
DestPix.G := SrcPix.G + DestPix.G;
|
||||||
|
DestPix.B := SrcPix.B + DestPix.B;
|
||||||
|
DestPix.A := SrcPix.A + DestPix.A;
|
||||||
|
DestInfo.SetPixelFP(DestPtr, DestInfo, nil, DestPix);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CompareColors(const C1, C2: TColorFPRec): Single; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
||||||
|
begin
|
||||||
|
Result := (C1.R * GrayConv.R + C1.G * GrayConv.G + C1.B * GrayConv.B) -
|
||||||
|
(C2.R * GrayConv.R + C2.G * GrayConv.G + C2.B * GrayConv.B);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function MedianSelect(var Pixels: TDynFPPixelArray): TColorFPRec;
|
||||||
|
|
||||||
|
procedure QuickSort(L, R: Integer);
|
||||||
|
var
|
||||||
|
I, J: Integer;
|
||||||
|
P, Temp: TColorFPRec;
|
||||||
|
begin
|
||||||
|
repeat
|
||||||
|
I := L;
|
||||||
|
J := R;
|
||||||
|
P := Pixels[(L + R) shr 1];
|
||||||
|
repeat
|
||||||
|
while CompareColors(Pixels[I], P) < 0 do Inc(I);
|
||||||
|
while CompareColors(Pixels[J], P) > 0 do Dec(J);
|
||||||
|
if I <= J then
|
||||||
|
begin
|
||||||
|
Temp := Pixels[I];
|
||||||
|
Pixels[I] := Pixels[J];
|
||||||
|
Pixels[J] := Temp;
|
||||||
|
Inc(I);
|
||||||
|
Dec(J);
|
||||||
|
end;
|
||||||
|
until I > J;
|
||||||
|
if L < J then
|
||||||
|
QuickSort(L, J);
|
||||||
|
L := I;
|
||||||
|
until I >= R;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
// First sort pixels
|
||||||
|
QuickSort(0, High(Pixels));
|
||||||
|
// Select middle pixel
|
||||||
|
Result := Pixels[Length(Pixels) div 2];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function MinSelect(var Pixels: TDynFPPixelArray): TColorFPRec;
|
||||||
|
var
|
||||||
|
I: Integer;
|
||||||
|
begin
|
||||||
|
Result := Pixels[0];
|
||||||
|
for I := 1 to High(Pixels) do
|
||||||
|
begin
|
||||||
|
if CompareColors(Pixels[I], Result) < 0 then
|
||||||
|
Result := Pixels[I];
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function MaxSelect(var Pixels: TDynFPPixelArray): TColorFPRec;
|
||||||
|
var
|
||||||
|
I: Integer;
|
||||||
|
begin
|
||||||
|
Result := Pixels[0];
|
||||||
|
for I := 1 to High(Pixels) do
|
||||||
|
begin
|
||||||
|
if CompareColors(Pixels[I], Result) > 0 then
|
||||||
|
Result := Pixels[I];
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TransformContrastBrightness(const Pixel: TColorFPRec; C, B, Ignore: Single): TColorFPRec;
|
||||||
|
begin
|
||||||
|
Result.A := Pixel.A;
|
||||||
|
Result.R := Pixel.R * C + B;
|
||||||
|
Result.G := Pixel.G * C + B;
|
||||||
|
Result.B := Pixel.B * C + B;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TransformGamma(const Pixel: TColorFPRec; R, G, B: Single): TColorFPRec;
|
||||||
|
begin
|
||||||
|
Result.A := Pixel.A;
|
||||||
|
Result.R := Power(Pixel.R, 1.0 / R);
|
||||||
|
Result.G := Power(Pixel.G, 1.0 / G);
|
||||||
|
Result.B := Power(Pixel.B, 1.0 / B);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TransformInvert(const Pixel: TColorFPRec; A, B, C: Single): TColorFPRec;
|
||||||
|
begin
|
||||||
|
Result.A := Pixel.A;
|
||||||
|
Result.R := 1.0 - Pixel.R;
|
||||||
|
Result.G := 1.0 - Pixel.G;
|
||||||
|
Result.B := 1.0 - Pixel.B;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TransformThreshold(const Pixel: TColorFPRec; R, G, B: Single): TColorFPRec;
|
||||||
|
begin
|
||||||
|
Result.A := Pixel.A;
|
||||||
|
Result.R := IffFloat(Pixel.R >= R, 1.0, 0.0);
|
||||||
|
Result.G := IffFloat(Pixel.G >= G, 1.0, 0.0);
|
||||||
|
Result.B := IffFloat(Pixel.B >= B, 1.0, 0.0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TImagingCanvas class implementation }
|
||||||
|
|
||||||
constructor TImagingCanvas.CreateForData(ImageDataPointer: PImageData);
|
constructor TImagingCanvas.CreateForData(ImageDataPointer: PImageData);
|
||||||
begin
|
begin
|
||||||
|
@ -568,6 +825,17 @@ begin
|
||||||
IntersectRect(FClipRect, FClipRect, Rect(0, 0, FPData.Width, FPData.Height));
|
IntersectRect(FClipRect, FClipRect, Rect(0, 0, FPData.Width, FPData.Height));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TImagingCanvas.CheckBeforeBlending(SrcFactor,
|
||||||
|
DestFactor: TBlendingFactor; DestCanvas: TImagingCanvas);
|
||||||
|
begin
|
||||||
|
if SrcFactor in [bfSrcColor, bfOneMinusSrcColor] then
|
||||||
|
raise EImagingCanvasBlendingError.Create('Invalid source blending factor. Check the documentation for TBlendingFactor.');
|
||||||
|
if DestFactor in [bfDstColor, bfOneMinusDstColor] then
|
||||||
|
raise EImagingCanvasBlendingError.Create('Invalid destination blending factor. Check the documentation for TBlendingFactor.');
|
||||||
|
if DestCanvas.FormatInfo.IsIndexed then
|
||||||
|
raise EImagingCanvasBlendingError.Create('Blending destination canvas cannot be in indexed mode.');
|
||||||
|
end;
|
||||||
|
|
||||||
function TImagingCanvas.GetPixelPointer(X, Y: LongInt): Pointer;
|
function TImagingCanvas.GetPixelPointer(X, Y: LongInt): Pointer;
|
||||||
begin
|
begin
|
||||||
Result := @PByteArray(FPData.Bits)[(Y * FPData.Width + X) * FFormatInfo.BytesPerPixel]
|
Result := @PByteArray(FPData.Bits)[(Y * FPData.Width + X) * FFormatInfo.BytesPerPixel]
|
||||||
|
@ -810,6 +1078,28 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TImagingCanvas.FillRectBlend(const Rect: TRect; SrcFactor,
|
||||||
|
DestFactor: TBlendingFactor);
|
||||||
|
var
|
||||||
|
DstRect: TRect;
|
||||||
|
X, Y: Integer;
|
||||||
|
Line: PByte;
|
||||||
|
begin
|
||||||
|
if (FFillMode <> fmClear) and IntersectRect(DstRect, Rect, FClipRect) then
|
||||||
|
begin
|
||||||
|
CheckBeforeBlending(SrcFactor, DestFactor, Self);
|
||||||
|
for Y := DstRect.Top to DstRect.Bottom - 1 do
|
||||||
|
begin
|
||||||
|
Line := @PByteArray(FPData.Bits)[(Y * FPData.Width + DstRect.Left) * FFormatInfo.BytesPerPixel];
|
||||||
|
for X := DstRect.Left to DstRect.Right - 1 do
|
||||||
|
begin
|
||||||
|
PixelBlendProc(FFillColorFP, Line, @FFormatInfo, SrcFactor, DestFactor);
|
||||||
|
Inc(Line, FFormatInfo.BytesPerPixel);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TImagingCanvas.Rectangle(const Rect: TRect);
|
procedure TImagingCanvas.Rectangle(const Rect: TRect);
|
||||||
begin
|
begin
|
||||||
FillRect(Rect);
|
FillRect(Rect);
|
||||||
|
@ -885,6 +1175,186 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TImagingCanvas.DrawInternal(const SrcRect: TRect;
|
||||||
|
DestCanvas: TImagingCanvas; DestX, DestY: Integer; SrcFactor,
|
||||||
|
DestFactor: TBlendingFactor; PixelWriteProc: TPixelWriteProc);
|
||||||
|
var
|
||||||
|
X, Y, SrcX, SrcY, Width, Height, SrcBpp, DestBpp: Integer;
|
||||||
|
PSrc: TColorFPRec;
|
||||||
|
SrcPointer, DestPointer: PByte;
|
||||||
|
begin
|
||||||
|
CheckBeforeBlending(SrcFactor, DestFactor, DestCanvas);
|
||||||
|
SrcX := SrcRect.Left;
|
||||||
|
SrcY := SrcRect.Top;
|
||||||
|
Width := SrcRect.Right - SrcRect.Left;
|
||||||
|
Height := SrcRect.Bottom - SrcRect.Top;
|
||||||
|
SrcBpp := FFormatInfo.BytesPerPixel;
|
||||||
|
DestBpp := DestCanvas.FFormatInfo.BytesPerPixel;
|
||||||
|
// Clip src and dst rects
|
||||||
|
ClipCopyBounds(SrcX, SrcY, Width, Height, DestX, DestY,
|
||||||
|
FPData.Width, FPData.Height, DestCanvas.ClipRect);
|
||||||
|
|
||||||
|
for Y := 0 to Height - 1 do
|
||||||
|
begin
|
||||||
|
// Get src and dst scanlines
|
||||||
|
SrcPointer := @PByteArray(FPData.Bits)[((SrcY + Y) * FPData.Width + SrcX) * SrcBpp];
|
||||||
|
DestPointer := @PByteArray(DestCanvas.FPData.Bits)[((DestY + Y) * DestCanvas.FPData.Width + DestX) * DestBpp];
|
||||||
|
|
||||||
|
for X := 0 to Width - 1 do
|
||||||
|
begin
|
||||||
|
PSrc := FFormatInfo.GetPixelFP(SrcPointer, @FFormatInfo, FPData.Palette);
|
||||||
|
// Call pixel writer procedure - combine source and dest pixels
|
||||||
|
PixelWriteProc(PSrc, DestPointer, @DestCanvas.FFormatInfo, SrcFactor, DestFactor);
|
||||||
|
// Increment pixel pointers
|
||||||
|
Inc(SrcPointer, SrcBpp);
|
||||||
|
Inc(DestPointer, DestBpp);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TImagingCanvas.DrawBlend(const SrcRect: TRect; DestCanvas: TImagingCanvas;
|
||||||
|
DestX, DestY: Integer; SrcFactor, DestFactor: TBlendingFactor);
|
||||||
|
begin
|
||||||
|
DrawInternal(SrcRect, DestCanvas, DestX, DestY, SrcFactor, DestFactor, PixelBlendProc);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TImagingCanvas.DrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas;
|
||||||
|
DestX, DestY: Integer);
|
||||||
|
begin
|
||||||
|
DrawInternal(SrcRect, DestCanvas, DestX, DestY, bfIgnore, bfIgnore, PixelAlphaProc);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TImagingCanvas.DrawAdd(const SrcRect: TRect;
|
||||||
|
DestCanvas: TImagingCanvas; DestX, DestY: Integer);
|
||||||
|
begin
|
||||||
|
DrawInternal(SrcRect, DestCanvas, DestX, DestY, bfIgnore, bfIgnore, PixelAddProc);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TImagingCanvas.StretchDrawInternal(const SrcRect: TRect;
|
||||||
|
DestCanvas: TImagingCanvas; const DestRect: TRect;
|
||||||
|
SrcFactor, DestFactor: TBlendingFactor; Filter: TResizeFilter;
|
||||||
|
PixelWriteProc: TPixelWriteProc);
|
||||||
|
const
|
||||||
|
FilterMapping: array[TResizeFilter] of TSamplingFilter =
|
||||||
|
(sfNearest, sfLinear, DefaultCubicFilter);
|
||||||
|
var
|
||||||
|
X, Y, I, J, SrcX, SrcY, SrcWidth, SrcHeight: Integer;
|
||||||
|
DestX, DestY, DestWidth, DestHeight, SrcBpp, DestBpp: Integer;
|
||||||
|
SrcPix, PDest: TColorFPRec;
|
||||||
|
MapX, MapY: TMappingTable;
|
||||||
|
XMinimum, XMaximum: Integer;
|
||||||
|
LineBuffer: array of TColorFPRec;
|
||||||
|
ClusterX, ClusterY: TCluster;
|
||||||
|
Weight, AccumA, AccumR, AccumG, AccumB: Single;
|
||||||
|
DestLine: PByte;
|
||||||
|
FilterFunction: TFilterFunction;
|
||||||
|
Radius: Single;
|
||||||
|
begin
|
||||||
|
CheckBeforeBlending(SrcFactor, DestFactor, DestCanvas);
|
||||||
|
SrcX := SrcRect.Left;
|
||||||
|
SrcY := SrcRect.Top;
|
||||||
|
SrcWidth := SrcRect.Right - SrcRect.Left;
|
||||||
|
SrcHeight := SrcRect.Bottom - SrcRect.Top;
|
||||||
|
DestX := DestRect.Left;
|
||||||
|
DestY := DestRect.Top;
|
||||||
|
DestWidth := DestRect.Right - DestRect.Left;
|
||||||
|
DestHeight := DestRect.Bottom - DestRect.Top;
|
||||||
|
SrcBpp := FFormatInfo.BytesPerPixel;
|
||||||
|
DestBpp := DestCanvas.FFormatInfo.BytesPerPixel;
|
||||||
|
// Get actual resampling filter and radius
|
||||||
|
FilterFunction := SamplingFilterFunctions[FilterMapping[Filter]];
|
||||||
|
Radius := SamplingFilterRadii[FilterMapping[Filter]];
|
||||||
|
// Clip src and dst rects
|
||||||
|
ClipStretchBounds(SrcX, SrcY, SrcWidth, SrcHeight, DestX, DestY, DestWidth, DestHeight,
|
||||||
|
FPData.Width, FPData.Height, DestCanvas.ClipRect);
|
||||||
|
// Generate mapping tables
|
||||||
|
MapX := BuildMappingTable(DestX, DestX + DestWidth, SrcX, SrcX + SrcWidth,
|
||||||
|
FPData.Width, FilterFunction, Radius, False);
|
||||||
|
MapY := BuildMappingTable(DestY, DestY + DestHeight, SrcY, SrcY + SrcHeight,
|
||||||
|
FPData.Height, FilterFunction, Radius, False);
|
||||||
|
FindExtremes(MapX, XMinimum, XMaximum);
|
||||||
|
SetLength(LineBuffer, XMaximum - XMinimum + 1);
|
||||||
|
|
||||||
|
for J := 0 to DestHeight - 1 do
|
||||||
|
begin
|
||||||
|
ClusterY := MapY[J];
|
||||||
|
for X := XMinimum to XMaximum do
|
||||||
|
begin
|
||||||
|
AccumA := 0.0;
|
||||||
|
AccumR := 0.0;
|
||||||
|
AccumG := 0.0;
|
||||||
|
AccumB := 0.0;
|
||||||
|
for Y := 0 to Length(ClusterY) - 1 do
|
||||||
|
begin
|
||||||
|
Weight := ClusterY[Y].Weight;
|
||||||
|
SrcPix := FFormatInfo.GetPixelFP(@PByteArray(FPData.Bits)[(ClusterY[Y].Pos * FPData.Width + X) * SrcBpp],
|
||||||
|
@FFormatInfo, FPData.Palette);
|
||||||
|
AccumB := AccumB + SrcPix.B * Weight;
|
||||||
|
AccumG := AccumG + SrcPix.G * Weight;
|
||||||
|
AccumR := AccumR + SrcPix.R * Weight;
|
||||||
|
AccumA := AccumA + SrcPix.A * Weight;
|
||||||
|
end;
|
||||||
|
with LineBuffer[X - XMinimum] do
|
||||||
|
begin
|
||||||
|
A := AccumA;
|
||||||
|
R := AccumR;
|
||||||
|
G := AccumG;
|
||||||
|
B := AccumB;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
DestLine := @PByteArray(DestCanvas.FPData.Bits)[((J + DestY) * DestCanvas.FPData.Width + DestX) * DestBpp];
|
||||||
|
|
||||||
|
for I := 0 to DestWidth - 1 do
|
||||||
|
begin
|
||||||
|
ClusterX := MapX[I];
|
||||||
|
AccumA := 0.0;
|
||||||
|
AccumR := 0.0;
|
||||||
|
AccumG := 0.0;
|
||||||
|
AccumB := 0.0;
|
||||||
|
for X := 0 to Length(ClusterX) - 1 do
|
||||||
|
begin
|
||||||
|
Weight := ClusterX[X].Weight;
|
||||||
|
with LineBuffer[ClusterX[X].Pos - XMinimum] do
|
||||||
|
begin
|
||||||
|
AccumB := AccumB + B * Weight;
|
||||||
|
AccumG := AccumG + G * Weight;
|
||||||
|
AccumR := AccumR + R * Weight;
|
||||||
|
AccumA := AccumA + A * Weight;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
SrcPix.A := AccumA;
|
||||||
|
SrcPix.R := AccumR;
|
||||||
|
SrcPix.G := AccumG;
|
||||||
|
SrcPix.B := AccumB;
|
||||||
|
|
||||||
|
// Write resulting blended pixel
|
||||||
|
PixelWriteProc(SrcPix, DestLine, @DestCanvas.FFormatInfo, SrcFactor, DestFactor);
|
||||||
|
Inc(DestLine, DestBpp);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TImagingCanvas.StretchDrawBlend(const SrcRect: TRect;
|
||||||
|
DestCanvas: TImagingCanvas; const DestRect: TRect;
|
||||||
|
SrcFactor, DestFactor: TBlendingFactor; Filter: TResizeFilter);
|
||||||
|
begin
|
||||||
|
StretchDrawInternal(SrcRect, DestCanvas, DestRect, SrcFactor, DestFactor, Filter, PixelBlendProc);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TImagingCanvas.StretchDrawAlpha(const SrcRect: TRect;
|
||||||
|
DestCanvas: TImagingCanvas; const DestRect: TRect; Filter: TResizeFilter);
|
||||||
|
begin
|
||||||
|
StretchDrawInternal(SrcRect, DestCanvas, DestRect, bfIgnore, bfIgnore, Filter, PixelAlphaProc);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TImagingCanvas.StretchDrawAdd(const SrcRect: TRect;
|
||||||
|
DestCanvas: TImagingCanvas; const DestRect: TRect; Filter: TResizeFilter);
|
||||||
|
begin
|
||||||
|
StretchDrawInternal(SrcRect, DestCanvas, DestRect, bfIgnore, bfIgnore, Filter, PixelAddProc);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TImagingCanvas.ApplyConvolution(Kernel: PLongInt; KernelSize,
|
procedure TImagingCanvas.ApplyConvolution(Kernel: PLongInt; KernelSize,
|
||||||
Divisor: LongInt; Bias: Single; ClampChannels: Boolean);
|
Divisor: LongInt; Bias: Single; ClampChannels: Boolean);
|
||||||
var
|
var
|
||||||
|
@ -917,11 +1387,11 @@ begin
|
||||||
|
|
||||||
for J := 0 to KernelSize - 1 do
|
for J := 0 to KernelSize - 1 do
|
||||||
begin
|
begin
|
||||||
PosY := ClampInt(Y + J - SizeDiv2, FClipRect.Top, FClipRect.Bottom);
|
PosY := ClampInt(Y + J - SizeDiv2, FClipRect.Top, FClipRect.Bottom - 1);
|
||||||
|
|
||||||
for I := 0 to KernelSize - 1 do
|
for I := 0 to KernelSize - 1 do
|
||||||
begin
|
begin
|
||||||
PosX := ClampInt(X + I - SizeDiv2, FClipRect.Left, FClipRect.Right);
|
PosX := ClampInt(X + I - SizeDiv2, FClipRect.Left, FClipRect.Right - 1);
|
||||||
SrcPointer := @PByteArray(TempImage.Bits)[PosY * WidthBytes + PosX * Bpp];
|
SrcPointer := @PByteArray(TempImage.Bits)[PosY * WidthBytes + PosX * Bpp];
|
||||||
|
|
||||||
// Get pixels from neighbourhood of current pixel and add their
|
// Get pixels from neighbourhood of current pixel and add their
|
||||||
|
@ -966,12 +1436,126 @@ begin
|
||||||
ApplyConvolution(@Filter.Kernel, 5, Filter.Divisor, Filter.Bias, True);
|
ApplyConvolution(@Filter.Kernel, 5, Filter.Divisor, Filter.Bias, True);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TImagingCanvas.ApplyNonLinearFilter(FilterSize: Integer; SelectFunc: TSelectPixelFunction);
|
||||||
|
var
|
||||||
|
X, Y, I, J, PosY, PosX, SizeDiv2, WidthBytes, Bpp: LongInt;
|
||||||
|
Pixel: TColorFPRec;
|
||||||
|
TempImage: TImageData;
|
||||||
|
DstPointer, SrcPointer: PByte;
|
||||||
|
NeighPixels: TDynFPPixelArray;
|
||||||
|
begin
|
||||||
|
SizeDiv2 := FilterSize div 2;
|
||||||
|
Bpp := FFormatInfo.BytesPerPixel;
|
||||||
|
WidthBytes := FPData.Width * Bpp;
|
||||||
|
SetLength(NeighPixels, FilterSize * FilterSize);
|
||||||
|
|
||||||
|
InitImage(TempImage);
|
||||||
|
CloneImage(FPData^, TempImage);
|
||||||
|
|
||||||
|
try
|
||||||
|
// For every pixel in clip rect
|
||||||
|
for Y := FClipRect.Top to FClipRect.Bottom - 1 do
|
||||||
|
begin
|
||||||
|
DstPointer := @PByteArray(FPData.Bits)[Y * WidthBytes + FClipRect.Left * Bpp];
|
||||||
|
|
||||||
|
for X := FClipRect.Left to FClipRect.Right - 1 do
|
||||||
|
begin
|
||||||
|
for J := 0 to FilterSize - 1 do
|
||||||
|
begin
|
||||||
|
PosY := ClampInt(Y + J - SizeDiv2, FClipRect.Top, FClipRect.Bottom - 1);
|
||||||
|
|
||||||
|
for I := 0 to FilterSize - 1 do
|
||||||
|
begin
|
||||||
|
PosX := ClampInt(X + I - SizeDiv2, FClipRect.Left, FClipRect.Right - 1);
|
||||||
|
SrcPointer := @PByteArray(TempImage.Bits)[PosY * WidthBytes + PosX * Bpp];
|
||||||
|
|
||||||
|
// Get pixels from neighbourhood of current pixel and store them
|
||||||
|
Pixel := FFormatInfo.GetPixelFP(SrcPointer, @FFormatInfo, TempImage.Palette);
|
||||||
|
NeighPixels[J * FilterSize + I] := Pixel;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Choose pixel using custom function
|
||||||
|
Pixel := SelectFunc(NeighPixels);
|
||||||
|
// Set resulting pixel color
|
||||||
|
FFormatInfo.SetPixelFP(DstPointer, @FFormatInfo, FPData.Palette, Pixel);
|
||||||
|
|
||||||
|
Inc(DstPointer, Bpp);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
finally
|
||||||
|
FreeImage(TempImage);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TImagingCanvas.ApplyMedianFilter(FilterSize: Integer);
|
||||||
|
begin
|
||||||
|
ApplyNonLinearFilter(FilterSize, MedianSelect);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TImagingCanvas.ApplyMinFilter(FilterSize: Integer);
|
||||||
|
begin
|
||||||
|
ApplyNonLinearFilter(FilterSize, MinSelect);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TImagingCanvas.ApplyMaxFilter(FilterSize: Integer);
|
||||||
|
begin
|
||||||
|
ApplyNonLinearFilter(FilterSize, MaxSelect);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TImagingCanvas.PointTransform(Transform: TPointTransformFunction;
|
||||||
|
Param1, Param2, Param3: Single);
|
||||||
|
var
|
||||||
|
X, Y, Bpp, WidthBytes: Integer;
|
||||||
|
PixPointer: PByte;
|
||||||
|
Pixel: TColorFPRec;
|
||||||
|
begin
|
||||||
|
Bpp := FFormatInfo.BytesPerPixel;
|
||||||
|
WidthBytes := FPData.Width * Bpp;
|
||||||
|
|
||||||
|
// For every pixel in clip rect
|
||||||
|
for Y := FClipRect.Top to FClipRect.Bottom - 1 do
|
||||||
|
begin
|
||||||
|
PixPointer := @PByteArray(FPData.Bits)[Y * WidthBytes + FClipRect.Left * Bpp];
|
||||||
|
for X := FClipRect.Left to FClipRect.Right - 1 do
|
||||||
|
begin
|
||||||
|
Pixel := FFormatInfo.GetPixelFP(PixPointer, @FFormatInfo, FPData.Palette);
|
||||||
|
|
||||||
|
FFormatInfo.SetPixelFP(PixPointer, @FFormatInfo, FPData.Palette,
|
||||||
|
Transform(Pixel, Param1, Param2, Param3));
|
||||||
|
|
||||||
|
Inc(PixPointer, Bpp);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TImagingCanvas.ModifyContrastBrightness(Contrast, Brightness: Single);
|
||||||
|
begin
|
||||||
|
PointTransform(TransformContrastBrightness, 1.0 + Contrast / 100,
|
||||||
|
Brightness / 100, 0.0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TImagingCanvas.GammaCorection(Red, Green, Blue: Single);
|
||||||
|
begin
|
||||||
|
PointTransform(TransformGamma, Red, Green, Blue);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TImagingCanvas.InvertColors;
|
||||||
|
begin
|
||||||
|
PointTransform(TransformInvert, 0, 0, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TImagingCanvas.Threshold(Red, Green, Blue: Single);
|
||||||
|
begin
|
||||||
|
PointTransform(TransformThreshold, Red, Green, Blue);
|
||||||
|
end;
|
||||||
|
|
||||||
class function TImagingCanvas.GetSupportedFormats: TImageFormats;
|
class function TImagingCanvas.GetSupportedFormats: TImageFormats;
|
||||||
begin
|
begin
|
||||||
Result := [ifIndex8..Pred(ifDXT1)];
|
Result := [ifIndex8..Pred(ifDXT1)];
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ TFastARGB32Canvas }
|
{ TFastARGB32Canvas }
|
||||||
|
|
||||||
destructor TFastARGB32Canvas.Destroy;
|
destructor TFastARGB32Canvas.Destroy;
|
||||||
|
@ -1029,10 +1613,16 @@ finalization
|
||||||
-- TODOS ----------------------------------------------------
|
-- TODOS ----------------------------------------------------
|
||||||
- more more more ...
|
- more more more ...
|
||||||
- implement pen width everywhere
|
- implement pen width everywhere
|
||||||
- add blending (image and object drawing)
|
- add blending (*image and object drawing)
|
||||||
- add image drawing
|
|
||||||
- more objects (arc, polygon)
|
- more objects (arc, polygon)
|
||||||
- add channel write/read masks (like apply conv only on Red channel,...)
|
|
||||||
|
-- 0.25.0 Changes/Bug Fixes ---------------------------------
|
||||||
|
- Fixed error that could cause AV in linear and nonlinear filters.
|
||||||
|
- Added blended rect filling function FillRectBlend.
|
||||||
|
- Added drawing function with blending (DrawAlpha, StretchDrawAlpha,
|
||||||
|
StretchDrawAdd, DrawBlend, StretchDrawBlend, ...)
|
||||||
|
- Added non-linear filters (min, max, median).
|
||||||
|
- Added point transforms (invert, contrast, gamma, brightness).
|
||||||
|
|
||||||
-- 0.21 Changes/Bug Fixes -----------------------------------
|
-- 0.21 Changes/Bug Fixes -----------------------------------
|
||||||
- Added some new filter kernels for convolution.
|
- Added some new filter kernels for convolution.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
$Id: ImagingClasses.pas 94 2007-06-21 19:29:49Z galfar $
|
$Id: ImagingClasses.pas 124 2008-04-21 09:47:07Z galfar $
|
||||||
Vampyre Imaging Library
|
Vampyre Imaging Library
|
||||||
by Marek Mauder
|
by Marek Mauder
|
||||||
http://imaginglib.sourceforge.net
|
http://imaginglib.sourceforge.net
|
||||||
|
@ -231,6 +231,8 @@ type
|
||||||
procedure ExchangeImages(Index1, Index2: LongInt);
|
procedure ExchangeImages(Index1, Index2: LongInt);
|
||||||
{ Deletes image at the given position in the image array.}
|
{ Deletes image at the given position in the image array.}
|
||||||
procedure DeleteImage(Index: LongInt);
|
procedure DeleteImage(Index: LongInt);
|
||||||
|
{ Rearranges images so that the first image will become last and vice versa.}
|
||||||
|
procedure ReverseImages;
|
||||||
|
|
||||||
{ Converts all images to another image data format.}
|
{ Converts all images to another image data format.}
|
||||||
procedure ConvertImages(Format: TImageFormat);
|
procedure ConvertImages(Format: TImageFormat);
|
||||||
|
@ -886,6 +888,14 @@ begin
|
||||||
Imaging.ResizeImage(FDataArray[I], NewWidth, NewHeight, Filter);
|
Imaging.ResizeImage(FDataArray[I], NewWidth, NewHeight, Filter);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TMultiImage.ReverseImages;
|
||||||
|
var
|
||||||
|
I: Integer;
|
||||||
|
begin
|
||||||
|
for I := 0 to GetImageCount div 2 do
|
||||||
|
ExchangeImages(I, GetImageCount - 1 - I);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TMultiImage.LoadFromFile(const FileName: string);
|
procedure TMultiImage.LoadFromFile(const FileName: string);
|
||||||
begin
|
begin
|
||||||
if GetImageCount = 0 then
|
if GetImageCount = 0 then
|
||||||
|
@ -931,6 +941,9 @@ end;
|
||||||
- put all low level stuff here like ReplaceColor etc, change
|
- put all low level stuff here like ReplaceColor etc, change
|
||||||
CopyTo to Copy, and add overload Copy(SrcRect, DstX, DstY) ...
|
CopyTo to Copy, and add overload Copy(SrcRect, DstX, DstY) ...
|
||||||
|
|
||||||
|
-- 0.24.3 Changes/Bug Fixes ---------------------------------
|
||||||
|
- Added TMultiImage.ReverseImages method.
|
||||||
|
|
||||||
-- 0.23 Changes/Bug Fixes -----------------------------------
|
-- 0.23 Changes/Bug Fixes -----------------------------------
|
||||||
- Added SwapChannels method to TBaseImage.
|
- Added SwapChannels method to TBaseImage.
|
||||||
- Added ReplaceColor method to TBaseImage.
|
- Added ReplaceColor method to TBaseImage.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
$Id: ImagingComponents.pas 110 2007-11-18 21:23:59Z galfar $
|
$Id: ImagingComponents.pas 132 2008-08-27 20:37:38Z galfar $
|
||||||
Vampyre Imaging Library
|
Vampyre Imaging Library
|
||||||
by Marek Mauder
|
by Marek Mauder
|
||||||
http://imaginglib.sourceforge.net
|
http://imaginglib.sourceforge.net
|
||||||
|
@ -114,7 +114,8 @@ type
|
||||||
{ Returns file extensions of this graphic class.}
|
{ Returns file extensions of this graphic class.}
|
||||||
class function GetFileExtensions: string; override;
|
class function GetFileExtensions: string; override;
|
||||||
{ Returns default MIME type of this graphic class.}
|
{ Returns default MIME type of this graphic class.}
|
||||||
function GetMimeType: string; override;
|
function GetMimeType: string; override; // uncomment for Laz 0.9.25 if you get error here
|
||||||
|
//function GetDefaultMimeType: string; override;
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
{ Default (the most common) file extension of this graphic class.}
|
{ Default (the most common) file extension of this graphic class.}
|
||||||
property DefaultFileExt: string read FDefaultFileExt;
|
property DefaultFileExt: string read FDefaultFileExt;
|
||||||
|
@ -150,6 +151,7 @@ type
|
||||||
procedure SaveToStream(Stream: TStream); override;
|
procedure SaveToStream(Stream: TStream); override;
|
||||||
class function GetFileFormat: TImageFileFormat; override;
|
class function GetFileFormat: TImageFileFormat; override;
|
||||||
{$IFDEF COMPONENT_SET_LCL}
|
{$IFDEF COMPONENT_SET_LCL}
|
||||||
|
//function GetMimeType: string; override; // uncomment for Laz 0.9.25 if you get error here
|
||||||
function GetDefaultMimeType: string; override;
|
function GetDefaultMimeType: string; override;
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
{ See ImagingJpegQuality option for details.}
|
{ See ImagingJpegQuality option for details.}
|
||||||
|
@ -231,6 +233,7 @@ type
|
||||||
procedure SaveToStream(Stream: TStream); override;
|
procedure SaveToStream(Stream: TStream); override;
|
||||||
class function GetFileFormat: TImageFileFormat; override;
|
class function GetFileFormat: TImageFileFormat; override;
|
||||||
{$IFDEF COMPONENT_SET_LCL}
|
{$IFDEF COMPONENT_SET_LCL}
|
||||||
|
//function GetMimeType: string; override; // uncomment for Laz 0.9.25 if you get error here
|
||||||
function GetDefaultMimeType: string; override;
|
function GetDefaultMimeType: string; override;
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
{ See ImagingMNGLossyCompression option for details.}
|
{ See ImagingMNGLossyCompression option for details.}
|
||||||
|
@ -637,7 +640,6 @@ var
|
||||||
{$IFDEF COMPONENT_SET_LCL}
|
{$IFDEF COMPONENT_SET_LCL}
|
||||||
RawImage: TRawImage;
|
RawImage: TRawImage;
|
||||||
LineLazBytes: LongInt;
|
LineLazBytes: LongInt;
|
||||||
rect: TRect;
|
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
begin
|
begin
|
||||||
{$IFDEF COMPONENT_SET_LCL}
|
{$IFDEF COMPONENT_SET_LCL}
|
||||||
|
@ -725,9 +727,8 @@ begin
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
{$IFDEF COMPONENT_SET_LCL}
|
{$IFDEF COMPONENT_SET_LCL}
|
||||||
// Get raw image from bitmap (mask handle must be 0 or expect violations)
|
// Get raw image from bitmap (mask handle must be 0 or expect violations)
|
||||||
{ If you get complitation error here upgrade to Lazarus 0.9.24+ }
|
if RawImage_FromBitmap(RawImage, Bitmap.Handle, 0, nil) then // uncommnet for Laz 0.9.25 if you get error here
|
||||||
rect := Classes.Rect(0, 0, Data.Width, Data.Height);
|
//if RawImage_FromBitmap(RawImage, Bitmap.Handle, 0, Classes.Rect(0, 0, Data.Width, Data.Height)) then
|
||||||
if RawImage_FromBitmap(RawImage, Bitmap.Handle, 0, @rect) then
|
|
||||||
begin
|
begin
|
||||||
LineLazBytes := GetBytesPerLine(Data.Width, RawImage.Description.BitsPerPixel,
|
LineLazBytes := GetBytesPerLine(Data.Width, RawImage.Description.BitsPerPixel,
|
||||||
RawImage.Description.LineEnd);
|
RawImage.Description.LineEnd);
|
||||||
|
@ -826,10 +827,15 @@ end;
|
||||||
var
|
var
|
||||||
P: TPoint;
|
P: TPoint;
|
||||||
begin
|
begin
|
||||||
|
// If you get compilation errors here with new Lazarus (rev 14368+)
|
||||||
|
// uncomment commented code and comment the active code below:
|
||||||
|
|
||||||
P := TGtkDeviceContext(Dest).Offset;
|
P := TGtkDeviceContext(Dest).Offset;
|
||||||
|
//P := GetDCOffset(TDeviceContext(Dest));
|
||||||
Inc(DstX, P.X);
|
Inc(DstX, P.X);
|
||||||
Inc(DstY, P.Y);
|
Inc(DstY, P.Y);
|
||||||
gdk_draw_rgb_32_image(TGtkDeviceContext(Dest).Drawable, TGtkDeviceContext(Dest).GC,
|
gdk_draw_rgb_32_image(TGtkDeviceContext(Dest).Drawable, TGtkDeviceContext(Dest).GC,
|
||||||
|
//gdk_draw_rgb_32_image(TDeviceContext(Dest).Drawable, TDeviceContext(Dest).GC,
|
||||||
DstX, DstY, SrcWidth, SrcHeight, GDK_RGB_DITHER_NONE,
|
DstX, DstY, SrcWidth, SrcHeight, GDK_RGB_DITHER_NONE,
|
||||||
@PLongWordArray(ImageData.Bits)[SrcY * ImageData.Width + SrcX], ImageData.Width * 4);
|
@PLongWordArray(ImageData.Bits)[SrcY * ImageData.Width + SrcX], ImageData.Width * 4);
|
||||||
end;
|
end;
|
||||||
|
@ -1014,7 +1020,8 @@ begin
|
||||||
Result := StringReplace(GetFileFormat.Extensions.CommaText, ',', ';', [rfReplaceAll]);
|
Result := StringReplace(GetFileFormat.Extensions.CommaText, ',', ';', [rfReplaceAll]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TImagingGraphicForSave.GetMimeType: string;
|
function TImagingGraphicForSave.GetMimeType: string; // uncomment for Laz 0.9.25 if you get error here
|
||||||
|
//function TImagingGraphicForSave.GetDefaultMimeType: string;
|
||||||
begin
|
begin
|
||||||
Result := 'image/' + FDefaultFileExt;
|
Result := 'image/' + FDefaultFileExt;
|
||||||
end;
|
end;
|
||||||
|
@ -1061,6 +1068,7 @@ begin
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{$IFDEF COMPONENT_SET_LCL}
|
{$IFDEF COMPONENT_SET_LCL}
|
||||||
|
//function TImagingJpeg.GetMimeType: string; // uncomment for Laz 0.9.25 if you get error here
|
||||||
function TImagingJpeg.GetDefaultMimeType: string;
|
function TImagingJpeg.GetDefaultMimeType: string;
|
||||||
begin
|
begin
|
||||||
Result := 'image/jpeg';
|
Result := 'image/jpeg';
|
||||||
|
@ -1193,6 +1201,7 @@ begin
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{$IFDEF COMPONENT_SET_LCL}
|
{$IFDEF COMPONENT_SET_LCL}
|
||||||
|
//function TImagingMNG.GetMimeType: string; // uncomment for Laz 0.9.25 if you get error here
|
||||||
function TImagingMNG.GetDefaultMimeType: string;
|
function TImagingMNG.GetDefaultMimeType: string;
|
||||||
begin
|
begin
|
||||||
Result := 'video/mng';
|
Result := 'video/mng';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
$Id: ImagingDds.pas 100 2007-06-28 21:09:52Z galfar $
|
$Id: ImagingDds.pas 129 2008-08-06 20:01:30Z galfar $
|
||||||
Vampyre Imaging Library
|
Vampyre Imaging Library
|
||||||
by Marek Mauder
|
by Marek Mauder
|
||||||
http://imaginglib.sourceforge.net
|
http://imaginglib.sourceforge.net
|
||||||
|
@ -102,7 +102,7 @@ const
|
||||||
DDSSupportedFormats: TImageFormats = [ifR8G8B8, ifA8R8G8B8, ifX8R8G8B8,
|
DDSSupportedFormats: TImageFormats = [ifR8G8B8, ifA8R8G8B8, ifX8R8G8B8,
|
||||||
ifA1R5G5B5, ifA4R4G4B4, ifX1R5G5B5, ifX4R4G4B4, ifR5G6B5, ifA16B16G16R16,
|
ifA1R5G5B5, ifA4R4G4B4, ifX1R5G5B5, ifX4R4G4B4, ifR5G6B5, ifA16B16G16R16,
|
||||||
ifR32F, ifA32B32G32R32F, ifR16F, ifA16B16G16R16F, ifR3G3B2, ifGray8, ifA8Gray8,
|
ifR32F, ifA32B32G32R32F, ifR16F, ifA16B16G16R16F, ifR3G3B2, ifGray8, ifA8Gray8,
|
||||||
ifGray16, ifDXT1, ifDXT3, ifDXT5];
|
ifGray16, ifDXT1, ifDXT3, ifDXT5, ifATI1N, ifATI2N];
|
||||||
|
|
||||||
const
|
const
|
||||||
{ Four character codes.}
|
{ Four character codes.}
|
||||||
|
@ -114,6 +114,10 @@ const
|
||||||
(Byte('3') shl 24));
|
(Byte('3') shl 24));
|
||||||
FOURCC_DXT5 = LongWord(Byte('D') or (Byte('X') shl 8) or (Byte('T') shl 16) or
|
FOURCC_DXT5 = LongWord(Byte('D') or (Byte('X') shl 8) or (Byte('T') shl 16) or
|
||||||
(Byte('5') shl 24));
|
(Byte('5') shl 24));
|
||||||
|
FOURCC_ATI1 = LongWord(Byte('A') or (Byte('T') shl 8) or (Byte('I') shl 16) or
|
||||||
|
(Byte('1') shl 24));
|
||||||
|
FOURCC_ATI2 = LongWord(Byte('A') or (Byte('T') shl 8) or (Byte('I') shl 16) or
|
||||||
|
(Byte('2') shl 24));
|
||||||
|
|
||||||
{ Some D3DFORMAT values used in DDS files as FourCC value.}
|
{ Some D3DFORMAT values used in DDS files as FourCC value.}
|
||||||
D3DFMT_A16B16G16R16 = 36;
|
D3DFMT_A16B16G16R16 = 36;
|
||||||
|
@ -350,6 +354,8 @@ begin
|
||||||
FOURCC_DXT1: SrcFormat := ifDXT1;
|
FOURCC_DXT1: SrcFormat := ifDXT1;
|
||||||
FOURCC_DXT3: SrcFormat := ifDXT3;
|
FOURCC_DXT3: SrcFormat := ifDXT3;
|
||||||
FOURCC_DXT5: SrcFormat := ifDXT5;
|
FOURCC_DXT5: SrcFormat := ifDXT5;
|
||||||
|
FOURCC_ATI1: SrcFormat := ifATI1N;
|
||||||
|
FOURCC_ATI2: SrcFormat := ifATI2N;
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
else if (Flags and DDPF_RGB) = DDPF_RGB then
|
else if (Flags and DDPF_RGB) = DDPF_RGB then
|
||||||
|
@ -663,6 +669,8 @@ begin
|
||||||
ifDXT1: Desc.PixelFormat.FourCC := FOURCC_DXT1;
|
ifDXT1: Desc.PixelFormat.FourCC := FOURCC_DXT1;
|
||||||
ifDXT3: Desc.PixelFormat.FourCC := FOURCC_DXT3;
|
ifDXT3: Desc.PixelFormat.FourCC := FOURCC_DXT3;
|
||||||
ifDXT5: Desc.PixelFormat.FourCC := FOURCC_DXT5;
|
ifDXT5: Desc.PixelFormat.FourCC := FOURCC_DXT5;
|
||||||
|
ifATI1N: Desc.PixelFormat.FourCC := FOURCC_ATI1;
|
||||||
|
ifATI2N: Desc.PixelFormat.FourCC := FOURCC_ATI2;
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
else if FmtInfo.HasGrayChannel then
|
else if FmtInfo.HasGrayChannel then
|
||||||
|
@ -815,6 +823,9 @@ initialization
|
||||||
-- TODOS ----------------------------------------------------
|
-- TODOS ----------------------------------------------------
|
||||||
- nothing now
|
- nothing now
|
||||||
|
|
||||||
|
-- 0.25.0 Changes/Bug Fixes ---------------------------------
|
||||||
|
- Added support for 3Dc ATI1/2 formats.
|
||||||
|
|
||||||
-- 0.23 Changes/Bug Fixes -----------------------------------
|
-- 0.23 Changes/Bug Fixes -----------------------------------
|
||||||
- Saved DDS with mipmaps now correctly defineds COMPLEX flag.
|
- Saved DDS with mipmaps now correctly defineds COMPLEX flag.
|
||||||
- Fixed loading of RGB DDS files that use pitch and have mipmaps -
|
- Fixed loading of RGB DDS files that use pitch and have mipmaps -
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
$Id: ImagingFormats.pas 94 2007-06-21 19:29:49Z galfar $
|
$Id: ImagingFormats.pas 129 2008-08-06 20:01:30Z galfar $
|
||||||
Vampyre Imaging Library
|
Vampyre Imaging Library
|
||||||
by Marek Mauder
|
by Marek Mauder
|
||||||
http://imaginglib.sourceforge.net
|
http://imaginglib.sourceforge.net
|
||||||
|
@ -76,6 +76,15 @@ type
|
||||||
sfGaussian, sfSpline, sfLanczos, sfMitchell, sfCatmullRom);
|
sfGaussian, sfSpline, sfLanczos, sfMitchell, sfCatmullRom);
|
||||||
{ Type of custom sampling function}
|
{ Type of custom sampling function}
|
||||||
TFilterFunction = function(Value: Single): Single;
|
TFilterFunction = function(Value: Single): Single;
|
||||||
|
const
|
||||||
|
{ Default resampling filter used for bicubic resizing.}
|
||||||
|
DefaultCubicFilter = sfCatmullRom;
|
||||||
|
var
|
||||||
|
{ Built-in filter functions.}
|
||||||
|
SamplingFilterFunctions: array[TSamplingFilter] of TFilterFunction;
|
||||||
|
{ Default radii of built-in filter functions.}
|
||||||
|
SamplingFilterRadii: array[TSamplingFilter] of Single;
|
||||||
|
|
||||||
{ Stretches rectangle in source image to rectangle in destination image
|
{ Stretches rectangle in source image to rectangle in destination image
|
||||||
with resampling. One of built-in resampling filters defined by
|
with resampling. One of built-in resampling filters defined by
|
||||||
Filter is used. Set WrapEdges to True for seamlessly tileable images.
|
Filter is used. Set WrapEdges to True for seamlessly tileable images.
|
||||||
|
@ -103,7 +112,7 @@ procedure FillMipMapLevel(const BiggerLevel: TImageData; Width, Height: LongInt;
|
||||||
var SmallerLevel: TImageData);
|
var SmallerLevel: TImageData);
|
||||||
|
|
||||||
|
|
||||||
{ Various helper format support functions }
|
{ Various helper & support functions }
|
||||||
|
|
||||||
{ Copies Src pixel to Dest pixel. It is faster than System.Move procedure.}
|
{ Copies Src pixel to Dest pixel. It is faster than System.Move procedure.}
|
||||||
procedure CopyPixel(Src, Dest: Pointer; BytesPerPixel: LongInt); {$IFDEF USE_INLINE}inline;{$ENDIF}
|
procedure CopyPixel(Src, Dest: Pointer; BytesPerPixel: LongInt); {$IFDEF USE_INLINE}inline;{$ENDIF}
|
||||||
|
@ -163,6 +172,23 @@ function ColorHalfToFloat(ColorHF: TColorHFRec): TColorFPRec; {$IFDEF USE_INLINE
|
||||||
{ Converts single-precision floating point color to half float color.}
|
{ Converts single-precision floating point color to half float color.}
|
||||||
function ColorFloatToHalf(ColorFP: TColorFPRec): TColorHFRec; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
function ColorFloatToHalf(ColorFP: TColorFPRec): TColorHFRec; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
||||||
|
|
||||||
|
{ Makes image PalEntries x 1 big where each pixel has color of one pal entry.}
|
||||||
|
procedure VisualizePalette(Pal: PPalette32; Entries: Integer; out PalImage: TImageData);
|
||||||
|
|
||||||
|
type
|
||||||
|
TPointRec = record
|
||||||
|
Pos: LongInt;
|
||||||
|
Weight: Single;
|
||||||
|
end;
|
||||||
|
TCluster = array of TPointRec;
|
||||||
|
TMappingTable = array of TCluster;
|
||||||
|
|
||||||
|
{ Helper function for resampling.}
|
||||||
|
function BuildMappingTable(DstLow, DstHigh, SrcLow, SrcHigh, SrcImageWidth: LongInt;
|
||||||
|
Filter: TFilterFunction; Radius: Single; WrapEdges: Boolean): TMappingTable;
|
||||||
|
{ Helper function for resampling.}
|
||||||
|
procedure FindExtremes(const Map: TMappingTable; var MinPos, MaxPos: LongInt);
|
||||||
|
|
||||||
|
|
||||||
{ Pixel readers/writers for different image formats }
|
{ Pixel readers/writers for different image formats }
|
||||||
|
|
||||||
|
@ -275,6 +301,22 @@ procedure IndexToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
|
||||||
DstInfo: PImageFormatInfo; SrcPal: PPalette32);
|
DstInfo: PImageFormatInfo; SrcPal: PPalette32);
|
||||||
|
|
||||||
|
|
||||||
|
{ Color constructor functions }
|
||||||
|
|
||||||
|
{ Constructs TColor24Rec color.}
|
||||||
|
function Color24(R, G, B: Byte): TColor24Rec; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
||||||
|
{ Constructs TColor32Rec color.}
|
||||||
|
function Color32(A, R, G, B: Byte): TColor32Rec; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
||||||
|
{ Constructs TColor48Rec color.}
|
||||||
|
function Color48(R, G, B: Word): TColor48Rec; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
||||||
|
{ Constructs TColor64Rec color.}
|
||||||
|
function Color64(A, R, G, B: Word): TColor64Rec; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
||||||
|
{ Constructs TColorFPRec color.}
|
||||||
|
function ColorFP(A, R, G, B: Single): TColorFPRec; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
||||||
|
{ Constructs TColorHFRec color.}
|
||||||
|
function ColorHF(A, R, G, B: THalfFloat): TColorHFRec; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
||||||
|
|
||||||
|
|
||||||
{ Special formats conversion functions }
|
{ Special formats conversion functions }
|
||||||
|
|
||||||
{ Converts image to/from/between special image formats (dxtc, ...).}
|
{ Converts image to/from/between special image formats (dxtc, ...).}
|
||||||
|
@ -285,6 +327,14 @@ procedure ConvertSpecial(var Image: TImageData; SrcInfo,
|
||||||
{ Inits all image format information. Called internally on startup.}
|
{ Inits all image format information. Called internally on startup.}
|
||||||
procedure InitImageFormats(var Infos: TImageFormatInfoArray);
|
procedure InitImageFormats(var Infos: TImageFormatInfoArray);
|
||||||
|
|
||||||
|
const
|
||||||
|
// Grayscale conversion channel weights
|
||||||
|
GrayConv: TColorFPRec = (B: 0.114; G: 0.587; R: 0.299; A: 0.0);
|
||||||
|
|
||||||
|
// Contants for converting integer colors to floating point
|
||||||
|
OneDiv8Bit: Single = 1.0 / 255.0;
|
||||||
|
OneDiv16Bit: Single = 1.0 / 65535.0;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
{ TImageFormatInfo member functions }
|
{ TImageFormatInfo member functions }
|
||||||
|
@ -317,14 +367,6 @@ procedure SetPixelFPChannel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette:
|
||||||
function GetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; forward;
|
function GetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; forward;
|
||||||
procedure SetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); forward;
|
procedure SetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); forward;
|
||||||
|
|
||||||
|
|
||||||
const
|
|
||||||
// grayscale conversion channel weights
|
|
||||||
GrayConv: TColorFPRec = (B: 0.114; G: 0.587; R: 0.299; A: 0.0);
|
|
||||||
// contants for converting integer colors to floating point
|
|
||||||
OneDiv8Bit: Single = 1.0 / 255.0;
|
|
||||||
OneDiv16Bit: Single = 1.0 / 65535.0;
|
|
||||||
|
|
||||||
var
|
var
|
||||||
PFR3G3B2: TPixelFormatInfo;
|
PFR3G3B2: TPixelFormatInfo;
|
||||||
PFX5R1G1B1: TPixelFormatInfo;
|
PFX5R1G1B1: TPixelFormatInfo;
|
||||||
|
@ -759,6 +801,26 @@ var
|
||||||
CheckDimensions: CheckDXTDimensions;
|
CheckDimensions: CheckDXTDimensions;
|
||||||
SpecialNearestFormat: ifGray8);
|
SpecialNearestFormat: ifGray8);
|
||||||
|
|
||||||
|
ATI1NInfo: TImageFormatInfo = (
|
||||||
|
Format: ifATI1N;
|
||||||
|
Name: 'ATI1N';
|
||||||
|
ChannelCount: 1;
|
||||||
|
HasAlphaChannel: False;
|
||||||
|
IsSpecial: True;
|
||||||
|
GetPixelsSize: GetDXTPixelsSize;
|
||||||
|
CheckDimensions: CheckDXTDimensions;
|
||||||
|
SpecialNearestFormat: ifGray8);
|
||||||
|
|
||||||
|
ATI2NInfo: TImageFormatInfo = (
|
||||||
|
Format: ifATI2N;
|
||||||
|
Name: 'ATI2N';
|
||||||
|
ChannelCount: 2;
|
||||||
|
HasAlphaChannel: False;
|
||||||
|
IsSpecial: True;
|
||||||
|
GetPixelsSize: GetDXTPixelsSize;
|
||||||
|
CheckDimensions: CheckDXTDimensions;
|
||||||
|
SpecialNearestFormat: ifA8R8G8B8);
|
||||||
|
|
||||||
{$WARNINGS ON}
|
{$WARNINGS ON}
|
||||||
|
|
||||||
function PixelFormat(ABitCount, RBitCount, GBitCount, BBitCount: Byte): TPixelFormatInfo; forward;
|
function PixelFormat(ABitCount, RBitCount, GBitCount, BBitCount: Byte): TPixelFormatInfo; forward;
|
||||||
|
@ -804,6 +866,8 @@ begin
|
||||||
Infos[ifDXT3] := @DXT3Info;
|
Infos[ifDXT3] := @DXT3Info;
|
||||||
Infos[ifDXT5] := @DXT5Info;
|
Infos[ifDXT5] := @DXT5Info;
|
||||||
Infos[ifBTC] := @BTCInfo;
|
Infos[ifBTC] := @BTCInfo;
|
||||||
|
Infos[ifATI1N] := @ATI1NInfo;
|
||||||
|
Infos[ifATI2N] := @ATI2NInfo;
|
||||||
|
|
||||||
PFR3G3B2 := PixelFormat(0, 3, 3, 2);
|
PFR3G3B2 := PixelFormat(0, 3, 3, 2);
|
||||||
PFX5R1G1B1 := PixelFormat(0, 1, 1, 1);
|
PFX5R1G1B1 := PixelFormat(0, 1, 1, 1);
|
||||||
|
@ -906,6 +970,57 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ Color constructor functions }
|
||||||
|
|
||||||
|
|
||||||
|
function Color24(R, G, B: Byte): TColor24Rec;
|
||||||
|
begin
|
||||||
|
Result.R := R;
|
||||||
|
Result.G := G;
|
||||||
|
Result.B := B;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function Color32(A, R, G, B: Byte): TColor32Rec;
|
||||||
|
begin
|
||||||
|
Result.A := A;
|
||||||
|
Result.R := R;
|
||||||
|
Result.G := G;
|
||||||
|
Result.B := B;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function Color48(R, G, B: Word): TColor48Rec;
|
||||||
|
begin
|
||||||
|
Result.R := R;
|
||||||
|
Result.G := G;
|
||||||
|
Result.B := B;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function Color64(A, R, G, B: Word): TColor64Rec;
|
||||||
|
begin
|
||||||
|
Result.A := A;
|
||||||
|
Result.R := R;
|
||||||
|
Result.G := G;
|
||||||
|
Result.B := B;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ColorFP(A, R, G, B: Single): TColorFPRec;
|
||||||
|
begin
|
||||||
|
Result.A := A;
|
||||||
|
Result.R := R;
|
||||||
|
Result.G := G;
|
||||||
|
Result.B := B;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ColorHF(A, R, G, B: THalfFloat): TColorHFRec;
|
||||||
|
begin
|
||||||
|
Result.A := A;
|
||||||
|
Result.R := R;
|
||||||
|
Result.G := G;
|
||||||
|
Result.B := B;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ Additional image manipulation functions (usually used internally by Imaging unit) }
|
{ Additional image manipulation functions (usually used internally by Imaging unit) }
|
||||||
|
|
||||||
const
|
const
|
||||||
|
@ -1184,12 +1299,17 @@ procedure ReduceColorsMedianCut(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
|
||||||
begin
|
begin
|
||||||
FillChar(DstPal^, SizeOf(TColor32Rec) * MaxColors, $FF);
|
FillChar(DstPal^, SizeOf(TColor32Rec) * MaxColors, $FF);
|
||||||
for I := 0 to MaxColors - 1 do
|
for I := 0 to MaxColors - 1 do
|
||||||
|
begin
|
||||||
|
if I < Boxes then
|
||||||
with Box[I].Represented do
|
with Box[I].Represented do
|
||||||
begin
|
begin
|
||||||
DstPal[I].A := A;
|
DstPal[I].A := A;
|
||||||
DstPal[I].R := R;
|
DstPal[I].R := R;
|
||||||
DstPal[I].G := G;
|
DstPal[I].G := G;
|
||||||
DstPal[I].B := B;
|
DstPal[I].B := B;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
DstPal[I].Color := $FF000000;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -1439,37 +1559,21 @@ begin
|
||||||
Result := 0.0;
|
Result := 0.0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
const
|
|
||||||
// Some built-in filter functions adn their default radii
|
|
||||||
FilterFunctions: array[TSamplingFilter] of TFilterFunction = (
|
|
||||||
FilterNearest, FilterLinear, FilterCosine, FilterHermite, FilterQuadratic,
|
|
||||||
FilterGaussian, FilterSpline, FilterLanczos, FilterMitchell, FilterCatmullRom);
|
|
||||||
FilterRadii: array[TSamplingFilter] of Single = (
|
|
||||||
1.0, 1.0, 1.0, 1.0, 1.5,
|
|
||||||
1.25, 2.0, 3.0, 2.0, 2.0);
|
|
||||||
|
|
||||||
procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth,
|
procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth,
|
||||||
SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth,
|
SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth,
|
||||||
DstHeight: LongInt; Filter: TSamplingFilter; WrapEdges: Boolean);
|
DstHeight: LongInt; Filter: TSamplingFilter; WrapEdges: Boolean);
|
||||||
begin
|
begin
|
||||||
// Calls the other function with filter function and radius defined by Filter
|
// Calls the other function with filter function and radius defined by Filter
|
||||||
StretchResample(SrcImage, SrcX, SrcY, SrcWidth, SrcHeight, DstImage, DstX, DstY,
|
StretchResample(SrcImage, SrcX, SrcY, SrcWidth, SrcHeight, DstImage, DstX, DstY,
|
||||||
DstWidth, DstHeight, FilterFunctions[Filter], FilterRadii[Filter]);
|
DstWidth, DstHeight, SamplingFilterFunctions[Filter], SamplingFilterRadii[Filter],
|
||||||
|
WrapEdges);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ The following resampling code is modified and extended code from Graphics32
|
|
||||||
library by Alex A. Denisov.}
|
|
||||||
type
|
|
||||||
TPointRec = record
|
|
||||||
Pos: LongInt;
|
|
||||||
Weight: Single;
|
|
||||||
end;
|
|
||||||
TCluster = array of TPointRec;
|
|
||||||
TMappingTable = array of TCluster;
|
|
||||||
|
|
||||||
var
|
var
|
||||||
FullEdge: Boolean = True;
|
FullEdge: Boolean = True;
|
||||||
|
|
||||||
|
{ The following resampling code is modified and extended code from Graphics32
|
||||||
|
library by Alex A. Denisov.}
|
||||||
function BuildMappingTable(DstLow, DstHigh, SrcLow, SrcHigh, SrcImageWidth: LongInt;
|
function BuildMappingTable(DstLow, DstHigh, SrcLow, SrcHigh, SrcImageWidth: LongInt;
|
||||||
Filter: TFilterFunction; Radius: Single; WrapEdges: Boolean): TMappingTable;
|
Filter: TFilterFunction; Radius: Single; WrapEdges: Boolean): TMappingTable;
|
||||||
var
|
var
|
||||||
|
@ -1595,6 +1699,25 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure FindExtremes(const Map: TMappingTable; var MinPos, MaxPos: LongInt);
|
||||||
|
var
|
||||||
|
I, J: LongInt;
|
||||||
|
begin
|
||||||
|
if Length(Map) > 0 then
|
||||||
|
begin
|
||||||
|
MinPos := Map[0][0].Pos;
|
||||||
|
MaxPos := MinPos;
|
||||||
|
for I := 0 to Length(Map) - 1 do
|
||||||
|
for J := 0 to Length(Map[I]) - 1 do
|
||||||
|
begin
|
||||||
|
if MinPos > Map[I][J].Pos then
|
||||||
|
MinPos := Map[I][J].Pos;
|
||||||
|
if MaxPos < Map[I][J].Pos then
|
||||||
|
MaxPos := Map[I][J].Pos;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth,
|
procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth,
|
||||||
SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth,
|
SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth,
|
||||||
DstHeight: LongInt; Filter: TFilterFunction; Radius: Single; WrapEdges: Boolean);
|
DstHeight: LongInt; Filter: TFilterFunction; Radius: Single; WrapEdges: Boolean);
|
||||||
|
@ -1614,26 +1737,6 @@ var
|
||||||
BytesPerChannel: LongInt;
|
BytesPerChannel: LongInt;
|
||||||
ChannelValueMax, InvChannelValueMax: Single;
|
ChannelValueMax, InvChannelValueMax: Single;
|
||||||
UseOptimizedVersion: Boolean;
|
UseOptimizedVersion: Boolean;
|
||||||
|
|
||||||
procedure FindExtremes(const Map: TMappingTable; var MinPos, MaxPos: LongInt);
|
|
||||||
var
|
|
||||||
I, J: LongInt;
|
|
||||||
begin
|
|
||||||
if Length(Map) > 0 then
|
|
||||||
begin
|
|
||||||
MinPos := Map[0][0].Pos;
|
|
||||||
MaxPos := MinPos;
|
|
||||||
for I := 0 to Length(Map) - 1 do
|
|
||||||
for J := 0 to Length(Map[I]) - 1 do
|
|
||||||
begin
|
|
||||||
if MinPos > Map[I][J].Pos then
|
|
||||||
MinPos := Map[I][J].Pos;
|
|
||||||
if MaxPos < Map[I][J].Pos then
|
|
||||||
MaxPos := Map[I][J].Pos;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
GetImageFormatInfo(SrcImage.Format, Info);
|
GetImageFormatInfo(SrcImage.Format, Info);
|
||||||
Assert(SrcImage.Format = DstImage.Format);
|
Assert(SrcImage.Format = DstImage.Format);
|
||||||
|
@ -2237,6 +2340,21 @@ begin
|
||||||
Result.B := FloatToHalf(ColorFP.B);
|
Result.B := FloatToHalf(ColorFP.B);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure VisualizePalette(Pal: PPalette32; Entries: Integer; out PalImage: TImageData);
|
||||||
|
var
|
||||||
|
I: Integer;
|
||||||
|
Pix: PColor32;
|
||||||
|
begin
|
||||||
|
InitImage(PalImage);
|
||||||
|
NewImage(Entries, 1, ifA8R8G8B8, PalImage);
|
||||||
|
Pix := PalImage.Bits;
|
||||||
|
for I := 0 to Entries - 1 do
|
||||||
|
begin
|
||||||
|
Pix^ := Pal[I].Color;
|
||||||
|
Inc(Pix);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ Pixel readers/writers for different image formats }
|
{ Pixel readers/writers for different image formats }
|
||||||
|
|
||||||
|
@ -3234,6 +3352,31 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure GetInterpolatedAlphas(var AlphaBlock: TDXTAlphaBlockInt);
|
||||||
|
begin
|
||||||
|
with AlphaBlock do
|
||||||
|
if Alphas[0] > Alphas[1] then
|
||||||
|
begin
|
||||||
|
// Interpolation of six alphas
|
||||||
|
Alphas[2] := (6 * Alphas[0] + 1 * Alphas[1] + 3) div 7;
|
||||||
|
Alphas[3] := (5 * Alphas[0] + 2 * Alphas[1] + 3) div 7;
|
||||||
|
Alphas[4] := (4 * Alphas[0] + 3 * Alphas[1] + 3) div 7;
|
||||||
|
Alphas[5] := (3 * Alphas[0] + 4 * Alphas[1] + 3) div 7;
|
||||||
|
Alphas[6] := (2 * Alphas[0] + 5 * Alphas[1] + 3) div 7;
|
||||||
|
Alphas[7] := (1 * Alphas[0] + 6 * Alphas[1] + 3) div 7;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
// Interpolation of four alphas, two alphas are set directly
|
||||||
|
Alphas[2] := (4 * Alphas[0] + 1 * Alphas[1] + 2) div 5;
|
||||||
|
Alphas[3] := (3 * Alphas[0] + 2 * Alphas[1] + 2) div 5;
|
||||||
|
Alphas[4] := (2 * Alphas[0] + 3 * Alphas[1] + 2) div 5;
|
||||||
|
Alphas[5] := (1 * Alphas[0] + 4 * Alphas[1] + 2) div 5;
|
||||||
|
Alphas[6] := 0;
|
||||||
|
Alphas[7] := $FF;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure DecodeDXT5(SrcBits, DestBits: PByte; Width, Height: LongInt);
|
procedure DecodeDXT5(SrcBits, DestBits: PByte; Width, Height: LongInt);
|
||||||
var
|
var
|
||||||
Sel, X, Y, I, J, K: LongInt;
|
Sel, X, Y, I, J, K: LongInt;
|
||||||
|
@ -3264,27 +3407,7 @@ begin
|
||||||
AMask[0] := PLongWord(@AlphaBlock.Alphas[2])^ and $00FFFFFF;
|
AMask[0] := PLongWord(@AlphaBlock.Alphas[2])^ and $00FFFFFF;
|
||||||
AMask[1] := PLongWord(@AlphaBlock.Alphas[5])^ and $00FFFFFF;
|
AMask[1] := PLongWord(@AlphaBlock.Alphas[5])^ and $00FFFFFF;
|
||||||
// alpha interpolation between two endpoint alphas
|
// alpha interpolation between two endpoint alphas
|
||||||
with AlphaBlock do
|
GetInterpolatedAlphas(AlphaBlock);
|
||||||
if Alphas[0] > Alphas[1] then
|
|
||||||
begin
|
|
||||||
// interpolation of six alphas
|
|
||||||
Alphas[2] := (6 * Alphas[0] + 1 * Alphas[1] + 3) div 7;
|
|
||||||
Alphas[3] := (5 * Alphas[0] + 2 * Alphas[1] + 3) div 7;
|
|
||||||
Alphas[4] := (4 * Alphas[0] + 3 * Alphas[1] + 3) div 7;
|
|
||||||
Alphas[5] := (3 * Alphas[0] + 4 * Alphas[1] + 3) div 7;
|
|
||||||
Alphas[6] := (2 * Alphas[0] + 5 * Alphas[1] + 3) div 7;
|
|
||||||
Alphas[7] := (1 * Alphas[0] + 6 * Alphas[1] + 3) div 7;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
// interpolation of four alphas, two alphas are set directly
|
|
||||||
Alphas[2] := (4 * Alphas[0] + 1 * Alphas[1] + 2) div 5;
|
|
||||||
Alphas[3] := (3 * Alphas[0] + 2 * Alphas[1] + 2) div 5;
|
|
||||||
Alphas[4] := (2 * Alphas[0] + 3 * Alphas[1] + 2) div 5;
|
|
||||||
Alphas[5] := (1 * Alphas[0] + 4 * Alphas[1] + 2) div 5;
|
|
||||||
Alphas[6] := 0;
|
|
||||||
Alphas[7] := $FF;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// we distribute the dxt block colors and alphas
|
// we distribute the dxt block colors and alphas
|
||||||
// across the 4x4 block of the destination image
|
// across the 4x4 block of the destination image
|
||||||
|
@ -3637,7 +3760,71 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure DecodeBTC(SrcBits, DestBits: PByte; Width, Height: LongInt);
|
procedure GetOneChannelBlock(var Block: TPixelBlock; SrcBits: Pointer; XPos, YPos,
|
||||||
|
Width, Height, BytesPP, ChannelIdx: Integer);
|
||||||
|
var
|
||||||
|
X, Y, I: Integer;
|
||||||
|
Src: PByte;
|
||||||
|
begin
|
||||||
|
I := 0;
|
||||||
|
// 4x4 pixel block is filled with information about every pixel in the block,
|
||||||
|
// but only one channel value is stored in Alpha field
|
||||||
|
for Y := 0 to 3 do
|
||||||
|
for X := 0 to 3 do
|
||||||
|
begin
|
||||||
|
Src := @PByteArray(SrcBits)[(YPos * 4 + Y) * Width * BytesPP +
|
||||||
|
(XPos * 4 + X) * BytesPP + ChannelIdx];
|
||||||
|
Block[I].Alpha := Src^;
|
||||||
|
Inc(I);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure EncodeATI1N(SrcBits: Pointer; DestBits: PByte; Width, Height: Integer);
|
||||||
|
var
|
||||||
|
X, Y: Integer;
|
||||||
|
AlphaBlock: TDXTAlphaBlockInt;
|
||||||
|
Pixels: TPixelBlock;
|
||||||
|
begin
|
||||||
|
for Y := 0 to Height div 4 - 1 do
|
||||||
|
for X := 0 to Width div 4 - 1 do
|
||||||
|
begin
|
||||||
|
// Encode one channel
|
||||||
|
GetOneChannelBlock(Pixels, SrcBits, X, Y, Width, Height, 1, 0);
|
||||||
|
GetAlphaEndPoints(Pixels, AlphaBlock.Alphas[1], AlphaBlock.Alphas[0]);
|
||||||
|
GetAlphaMask(AlphaBlock.Alphas[0], AlphaBlock.Alphas[1], Pixels,
|
||||||
|
PByteArray(@AlphaBlock.Alphas[2]));
|
||||||
|
PDXTAlphaBlockInt(DestBits)^ := AlphaBlock;
|
||||||
|
Inc(DestBits, SizeOf(AlphaBlock));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure EncodeATI2N(SrcBits: Pointer; DestBits: PByte; Width, Height: Integer);
|
||||||
|
var
|
||||||
|
X, Y: Integer;
|
||||||
|
AlphaBlock: TDXTAlphaBlockInt;
|
||||||
|
Pixels: TPixelBlock;
|
||||||
|
begin
|
||||||
|
for Y := 0 to Height div 4 - 1 do
|
||||||
|
for X := 0 to Width div 4 - 1 do
|
||||||
|
begin
|
||||||
|
// Encode Red/X channel
|
||||||
|
GetOneChannelBlock(Pixels, SrcBits, X, Y, Width, Height, 4, ChannelRed);
|
||||||
|
GetAlphaEndPoints(Pixels, AlphaBlock.Alphas[1], AlphaBlock.Alphas[0]);
|
||||||
|
GetAlphaMask(AlphaBlock.Alphas[0], AlphaBlock.Alphas[1], Pixels,
|
||||||
|
PByteArray(@AlphaBlock.Alphas[2]));
|
||||||
|
PDXTAlphaBlockInt(DestBits)^ := AlphaBlock;
|
||||||
|
Inc(DestBits, SizeOf(AlphaBlock));
|
||||||
|
// Encode Green/Y channel
|
||||||
|
GetOneChannelBlock(Pixels, SrcBits, X, Y, Width, Height, 4, ChannelGreen);
|
||||||
|
GetAlphaEndPoints(Pixels, AlphaBlock.Alphas[1], AlphaBlock.Alphas[0]);
|
||||||
|
GetAlphaMask(AlphaBlock.Alphas[0], AlphaBlock.Alphas[1], Pixels,
|
||||||
|
PByteArray(@AlphaBlock.Alphas[2]));
|
||||||
|
PDXTAlphaBlockInt(DestBits)^ := AlphaBlock;
|
||||||
|
Inc(DestBits, SizeOf(AlphaBlock));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DecodeBTC(SrcBits, DestBits: PByte; Width, Height: Integer);
|
||||||
var
|
var
|
||||||
X, Y, I, J, K: Integer;
|
X, Y, I, J, K: Integer;
|
||||||
Block: TBTCBlock;
|
Block: TBTCBlock;
|
||||||
|
@ -3665,25 +3852,101 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure SpecialToUnSpecial(const SrcImage: TImageData; DestBits: Pointer;
|
procedure DecodeATI1N(SrcBits, DestBits: PByte; Width, Height: Integer);
|
||||||
SrcInfo, DstInfo: PImageFormatInfo);
|
var
|
||||||
|
X, Y, I, J: Integer;
|
||||||
|
AlphaBlock: TDXTAlphaBlockInt;
|
||||||
|
AMask: array[0..1] of LongWord;
|
||||||
begin
|
begin
|
||||||
case SrcInfo.Format of
|
for Y := 0 to Height div 4 - 1 do
|
||||||
|
for X := 0 to Width div 4 - 1 do
|
||||||
|
begin
|
||||||
|
AlphaBlock := PDXTAlphaBlockInt(SrcBits)^;
|
||||||
|
Inc(SrcBits, SizeOf(AlphaBlock));
|
||||||
|
// 6 bit alpha mask is copied into two long words for
|
||||||
|
// easier usage
|
||||||
|
AMask[0] := PLongWord(@AlphaBlock.Alphas[2])^ and $00FFFFFF;
|
||||||
|
AMask[1] := PLongWord(@AlphaBlock.Alphas[5])^ and $00FFFFFF;
|
||||||
|
// alpha interpolation between two endpoint alphas
|
||||||
|
GetInterpolatedAlphas(AlphaBlock);
|
||||||
|
|
||||||
|
// we distribute the dxt block alphas
|
||||||
|
// across the 4x4 block of the destination image
|
||||||
|
for J := 0 to 3 do
|
||||||
|
for I := 0 to 3 do
|
||||||
|
begin
|
||||||
|
PByteArray(DestBits)[(Y shl 2 + J) * Width + (X shl 2 + I)] :=
|
||||||
|
AlphaBlock.Alphas[AMask[J shr 1] and 7];
|
||||||
|
AMask[J shr 1] := AMask[J shr 1] shr 3;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DecodeATI2N(SrcBits, DestBits: PByte; Width, Height: Integer);
|
||||||
|
var
|
||||||
|
X, Y, I, J: Integer;
|
||||||
|
Color: TColor32Rec;
|
||||||
|
AlphaBlock1, AlphaBlock2: TDXTAlphaBlockInt;
|
||||||
|
AMask1: array[0..1] of LongWord;
|
||||||
|
AMask2: array[0..1] of LongWord;
|
||||||
|
begin
|
||||||
|
for Y := 0 to Height div 4 - 1 do
|
||||||
|
for X := 0 to Width div 4 - 1 do
|
||||||
|
begin
|
||||||
|
// Read the first alpha block and get masks
|
||||||
|
AlphaBlock1 := PDXTAlphaBlockInt(SrcBits)^;
|
||||||
|
Inc(SrcBits, SizeOf(AlphaBlock1));
|
||||||
|
AMask1[0] := PLongWord(@AlphaBlock1.Alphas[2])^ and $00FFFFFF;
|
||||||
|
AMask1[1] := PLongWord(@AlphaBlock1.Alphas[5])^ and $00FFFFFF;
|
||||||
|
// Read the secind alpha block and get masks
|
||||||
|
AlphaBlock2 := PDXTAlphaBlockInt(SrcBits)^;
|
||||||
|
Inc(SrcBits, SizeOf(AlphaBlock2));
|
||||||
|
AMask2[0] := PLongWord(@AlphaBlock2.Alphas[2])^ and $00FFFFFF;
|
||||||
|
AMask2[1] := PLongWord(@AlphaBlock2.Alphas[5])^ and $00FFFFFF;
|
||||||
|
// alpha interpolation between two endpoint alphas
|
||||||
|
GetInterpolatedAlphas(AlphaBlock1);
|
||||||
|
GetInterpolatedAlphas(AlphaBlock2);
|
||||||
|
|
||||||
|
Color.A := $FF;
|
||||||
|
Color.B := 0;
|
||||||
|
|
||||||
|
// Distribute alpha block values across 4x4 pixel block,
|
||||||
|
// first alpha block represents Red channel, second is Green.
|
||||||
|
for J := 0 to 3 do
|
||||||
|
for I := 0 to 3 do
|
||||||
|
begin
|
||||||
|
Color.R := AlphaBlock1.Alphas[AMask1[J shr 1] and 7];
|
||||||
|
Color.G := AlphaBlock2.Alphas[AMask2[J shr 1] and 7];
|
||||||
|
PColor32RecArray(DestBits)[(Y shl 2 + J) * Width + (X shl 2 + I)] := Color;
|
||||||
|
AMask1[J shr 1] := AMask1[J shr 1] shr 3;
|
||||||
|
AMask2[J shr 1] := AMask2[J shr 1] shr 3;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure SpecialToUnSpecial(const SrcImage: TImageData; DestBits: Pointer;
|
||||||
|
SpecialFormat: TImageFormat);
|
||||||
|
begin
|
||||||
|
case SpecialFormat of
|
||||||
ifDXT1: DecodeDXT1(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
|
ifDXT1: DecodeDXT1(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
|
||||||
ifDXT3: DecodeDXT3(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
|
ifDXT3: DecodeDXT3(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
|
||||||
ifDXT5: DecodeDXT5(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
|
ifDXT5: DecodeDXT5(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
|
||||||
ifBTC: DecodeBTC (SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
|
ifBTC: DecodeBTC (SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
|
||||||
|
ifATI1N: DecodeATI1N(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
|
||||||
|
ifATI2N: DecodeATI2N(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure UnSpecialToSpecial(const DestImage: TImageData; SrcBits: Pointer;
|
procedure UnSpecialToSpecial(SrcBits: Pointer; const DestImage: TImageData;
|
||||||
SrcInfo, DstInfo: PImageFormatInfo);
|
SpecialFormat: TImageFormat);
|
||||||
begin
|
begin
|
||||||
case DstInfo.Format of
|
case SpecialFormat of
|
||||||
ifDXT1: EncodeDXT1(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
|
ifDXT1: EncodeDXT1(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
|
||||||
ifDXT3: EncodeDXT3(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
|
ifDXT3: EncodeDXT3(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
|
||||||
ifDXT5: EncodeDXT5(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
|
ifDXT5: EncodeDXT5(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
|
||||||
ifBTC: EncodeBTC (SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
|
ifBTC: EncodeBTC (SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
|
||||||
|
ifATI1N: EncodeATI1N(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
|
||||||
|
ifATI2N: EncodeATI2N(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -3691,35 +3954,58 @@ procedure ConvertSpecial(var Image: TImageData;
|
||||||
SrcInfo, DstInfo: PImageFormatInfo);
|
SrcInfo, DstInfo: PImageFormatInfo);
|
||||||
var
|
var
|
||||||
WorkImage: TImageData;
|
WorkImage: TImageData;
|
||||||
Width, Height: LongInt;
|
|
||||||
begin
|
procedure CheckSize(var Img: TImageData; Info: PImageFormatInfo);
|
||||||
// first convert image to default non-special format
|
var
|
||||||
if SrcInfo.IsSpecial then
|
Width, Height: Integer;
|
||||||
begin
|
begin
|
||||||
|
Width := Img.Width;
|
||||||
|
Height := Img.Height;
|
||||||
|
DstInfo.CheckDimensions(Info.Format, Width, Height);
|
||||||
|
ResizeImage(Img, Width, Height, rfNearest);
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if SrcInfo.IsSpecial and DstInfo.IsSpecial then
|
||||||
|
begin
|
||||||
|
// Convert source to nearest 'normal' format
|
||||||
InitImage(WorkImage);
|
InitImage(WorkImage);
|
||||||
NewImage(Image.Width, Image.Height, SrcInfo.SpecialNearestFormat, WorkImage);
|
NewImage(Image.Width, Image.Height, SrcInfo.SpecialNearestFormat, WorkImage);
|
||||||
SpecialToUnSpecial(Image, WorkImage.Bits, SrcInfo, DstInfo);
|
SpecialToUnSpecial(Image, WorkImage.Bits, SrcInfo.Format);
|
||||||
FreeImage(Image);
|
FreeImage(Image);
|
||||||
Image := WorkImage;
|
// Make sure output of SpecialToUnSpecial is the same as input of
|
||||||
|
// UnSpecialToSpecial
|
||||||
|
if SrcInfo.SpecialNearestFormat <> DstInfo.SpecialNearestFormat then
|
||||||
|
ConvertImage(WorkImage, DstInfo.SpecialNearestFormat);
|
||||||
|
// Convert work image to dest special format
|
||||||
|
CheckSize(WorkImage, DstInfo);
|
||||||
|
NewImage(WorkImage.Width, WorkImage.Height, DstInfo.Format, Image);
|
||||||
|
UnSpecialToSpecial(WorkImage.Bits, Image, DstInfo.Format);
|
||||||
|
FreeImage(WorkImage);
|
||||||
end
|
end
|
||||||
else
|
else if SrcInfo.IsSpecial and not DstInfo.IsSpecial then
|
||||||
ConvertImage(Image, DstInfo.SpecialNearestFormat);
|
|
||||||
// we have now image in default non-special format and
|
|
||||||
// if dest format is special we will convert to this special format
|
|
||||||
if DstInfo.IsSpecial then
|
|
||||||
begin
|
begin
|
||||||
Width := Image.Width;
|
// Convert source to nearest 'normal' format
|
||||||
Height := Image.Height;
|
|
||||||
DstInfo.CheckDimensions(DstInfo.Format, Width, Height);
|
|
||||||
InitImage(WorkImage);
|
InitImage(WorkImage);
|
||||||
NewImage(Width, Height, DstInfo.Format, WorkImage);
|
NewImage(Image.Width, Image.Height, SrcInfo.SpecialNearestFormat, WorkImage);
|
||||||
ResizeImage(Image, Width, Height, rfNearest);
|
SpecialToUnSpecial(Image, WorkImage.Bits, SrcInfo.Format);
|
||||||
UnSpecialToSpecial(WorkImage, Image.Bits, SrcInfo, DstInfo);
|
|
||||||
FreeImage(Image);
|
FreeImage(Image);
|
||||||
|
// Now convert to dest format
|
||||||
|
ConvertImage(WorkImage, DstInfo.Format);
|
||||||
Image := WorkImage;
|
Image := WorkImage;
|
||||||
end
|
end
|
||||||
else
|
else if not SrcInfo.IsSpecial and DstInfo.IsSpecial then
|
||||||
ConvertImage(Image, DstInfo.Format);
|
begin
|
||||||
|
// Convert source to nearest format
|
||||||
|
WorkImage := Image;
|
||||||
|
ConvertImage(WorkImage, DstInfo.SpecialNearestFormat);
|
||||||
|
// Now convert from nearest to dest
|
||||||
|
CheckSize(WorkImage, DstInfo);
|
||||||
|
InitImage(Image);
|
||||||
|
NewImage(WorkImage.Width, WorkImage.Height, DstInfo.Format, Image);
|
||||||
|
UnSpecialToSpecial(WorkImage.Bits, Image, DstInfo.Format);
|
||||||
|
FreeImage(WorkImage);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function GetStdPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt;
|
function GetStdPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt;
|
||||||
|
@ -3740,7 +4026,7 @@ begin
|
||||||
// multiples of four
|
// multiples of four
|
||||||
CheckDXTDimensions(Format, Width, Height);
|
CheckDXTDimensions(Format, Width, Height);
|
||||||
Result := Width * Height;
|
Result := Width * Height;
|
||||||
if Format = ifDXT1 then
|
if Format in [ifDXT1, ifATI1N] then
|
||||||
Result := Result div 2;
|
Result := Result div 2;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -3908,6 +4194,29 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
initialization
|
||||||
|
// Initialize default sampling filter function pointers and radii
|
||||||
|
SamplingFilterFunctions[sfNearest] := FilterNearest;
|
||||||
|
SamplingFilterFunctions[sfLinear] := FilterLinear;
|
||||||
|
SamplingFilterFunctions[sfCosine] := FilterCosine;
|
||||||
|
SamplingFilterFunctions[sfHermite] := FilterHermite;
|
||||||
|
SamplingFilterFunctions[sfQuadratic] := FilterQuadratic;
|
||||||
|
SamplingFilterFunctions[sfGaussian] := FilterGaussian;
|
||||||
|
SamplingFilterFunctions[sfSpline] := FilterSpline;
|
||||||
|
SamplingFilterFunctions[sfLanczos] := FilterLanczos;
|
||||||
|
SamplingFilterFunctions[sfMitchell] := FilterMitchell;
|
||||||
|
SamplingFilterFunctions[sfCatmullRom] := FilterCatmullRom;
|
||||||
|
SamplingFilterRadii[sfNearest] := 1.0;
|
||||||
|
SamplingFilterRadii[sfLinear] := 1.0;
|
||||||
|
SamplingFilterRadii[sfCosine] := 1.0;
|
||||||
|
SamplingFilterRadii[sfHermite] := 1.0;
|
||||||
|
SamplingFilterRadii[sfQuadratic] := 1.5;
|
||||||
|
SamplingFilterRadii[sfGaussian] := 1.25;
|
||||||
|
SamplingFilterRadii[sfSpline] := 2.0;
|
||||||
|
SamplingFilterRadii[sfLanczos] := 3.0;
|
||||||
|
SamplingFilterRadii[sfMitchell] := 2.0;
|
||||||
|
SamplingFilterRadii[sfCatmullRom] := 2.0;
|
||||||
|
|
||||||
{
|
{
|
||||||
File Notes:
|
File Notes:
|
||||||
|
|
||||||
|
@ -3915,6 +4224,17 @@ end;
|
||||||
- nothing now
|
- nothing now
|
||||||
- rewrite StretchRect for 8bit channels to use integer math?
|
- rewrite StretchRect for 8bit channels to use integer math?
|
||||||
|
|
||||||
|
-- 0.25.0 Changes/Bug Fixes -----------------------------------
|
||||||
|
- Made some resampling stuff public so that it can be used in canvas class.
|
||||||
|
- Added some color constructors.
|
||||||
|
- Added VisualizePalette helper function.
|
||||||
|
- Fixed ConvertSpecial, not very readable before and error when
|
||||||
|
converting special->special.
|
||||||
|
|
||||||
|
-- 0.24.3 Changes/Bug Fixes -----------------------------------
|
||||||
|
- Some refactorings a changes to DXT based formats.
|
||||||
|
- Added ifATI1N and ifATI2N image data formats support structures and functions.
|
||||||
|
|
||||||
-- 0.23 Changes/Bug Fixes -----------------------------------
|
-- 0.23 Changes/Bug Fixes -----------------------------------
|
||||||
- Added ifBTC image format support structures and functions.
|
- Added ifBTC image format support structures and functions.
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
$Id: ImagingGif.pas 111 2007-12-02 23:25:44Z galfar $
|
$Id: ImagingGif.pas 132 2008-08-27 20:37:38Z galfar $
|
||||||
Vampyre Imaging Library
|
Vampyre Imaging Library
|
||||||
by Marek Mauder
|
by Marek Mauder
|
||||||
http://imaginglib.sourceforge.net
|
http://imaginglib.sourceforge.net
|
||||||
|
@ -34,7 +34,7 @@ unit ImagingGif;
|
||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
SysUtils, Classes, Imaging, ImagingTypes, ImagingUtility;
|
SysUtils, Classes, Imaging, ImagingTypes, ImagingIO, ImagingUtility;
|
||||||
|
|
||||||
type
|
type
|
||||||
{ GIF (Graphics Interchange Format) loader/saver class. GIF was
|
{ GIF (Graphics Interchange Format) loader/saver class. GIF was
|
||||||
|
@ -48,7 +48,7 @@ type
|
||||||
TGIFFileFormat = class(TImageFileFormat)
|
TGIFFileFormat = class(TImageFileFormat)
|
||||||
private
|
private
|
||||||
function InterlaceStep(Y, Height: Integer; var Pass: Integer): Integer;
|
function InterlaceStep(Y, Height: Integer; var Pass: Integer): Integer;
|
||||||
procedure LZWDecompress(const IO: TIOFunctions; Handle: TImagingHandle;
|
procedure LZWDecompress(Stream: TStream; Handle: TImagingHandle;
|
||||||
Width, Height: Integer; Interlaced: Boolean; Data: Pointer);
|
Width, Height: Integer; Interlaced: Boolean; Data: Pointer);
|
||||||
procedure LZWCompress(const IO: TIOFunctions; Handle: TImagingHandle;
|
procedure LZWCompress(const IO: TIOFunctions; Handle: TImagingHandle;
|
||||||
Width, Height, BitCount: Integer; Interlaced: Boolean; Data: Pointer);
|
Width, Height, BitCount: Integer; Interlaced: Boolean; Data: Pointer);
|
||||||
|
@ -246,7 +246,7 @@ begin
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ GIF LZW decompresion code is from JVCL JvGIF.pas unit.}
|
{ GIF LZW decompresion code is from JVCL JvGIF.pas unit.}
|
||||||
procedure TGIFFileFormat.LZWDecompress(const IO: TIOFunctions; Handle: TImagingHandle; Width, Height: Integer;
|
procedure TGIFFileFormat.LZWDecompress(Stream: TStream; Handle: TImagingHandle; Width, Height: Integer;
|
||||||
Interlaced: Boolean; Data: Pointer);
|
Interlaced: Boolean; Data: Pointer);
|
||||||
var
|
var
|
||||||
MinCodeSize: Byte;
|
MinCodeSize: Byte;
|
||||||
|
@ -266,7 +266,8 @@ var
|
||||||
Bytes: Byte;
|
Bytes: Byte;
|
||||||
BytesToLose: Integer;
|
BytesToLose: Integer;
|
||||||
begin
|
begin
|
||||||
while Context.Inx + Context.CodeSize > Context.Size do
|
while (Context.Inx + Context.CodeSize > Context.Size) and
|
||||||
|
(Stream.Position < Stream.Size) do
|
||||||
begin
|
begin
|
||||||
// Not enough bits in buffer - refill it - Not very efficient, but infrequently called
|
// Not enough bits in buffer - refill it - Not very efficient, but infrequently called
|
||||||
BytesToLose := Context.Inx shr 3;
|
BytesToLose := Context.Inx shr 3;
|
||||||
|
@ -274,16 +275,16 @@ var
|
||||||
Move(Context.Buf[Word(BytesToLose)], Context.Buf[0], 3);
|
Move(Context.Buf[Word(BytesToLose)], Context.Buf[0], 3);
|
||||||
Context.Inx := Context.Inx and 7;
|
Context.Inx := Context.Inx and 7;
|
||||||
Context.Size := Context.Size - (BytesToLose shl 3);
|
Context.Size := Context.Size - (BytesToLose shl 3);
|
||||||
IO.Read(Handle, @Bytes, 1);
|
Stream.Read(Bytes, 1);
|
||||||
if Bytes > 0 then
|
if Bytes > 0 then
|
||||||
IO.Read(Handle, @Context.Buf[Word(Context.Size shr 3)], Bytes);
|
Stream.Read(Context.Buf[Word(Context.Size shr 3)], Bytes);
|
||||||
Context.Size := Context.Size + (Bytes shl 3);
|
Context.Size := Context.Size + (Bytes shl 3);
|
||||||
end;
|
end;
|
||||||
ByteIndex := Context.Inx shr 3;
|
ByteIndex := Context.Inx shr 3;
|
||||||
RawCode := Context.Buf[Word(ByteIndex)] +
|
RawCode := Context.Buf[Word(ByteIndex)] +
|
||||||
(Word(Context.Buf[Word(ByteIndex + 1)]) shl 8);
|
(Word(Context.Buf[Word(ByteIndex + 1)]) shl 8);
|
||||||
if Context.CodeSize > 8 then
|
if Context.CodeSize > 8 then
|
||||||
RawCode := RawCode + (Longint(Context.Buf[ByteIndex + 2]) shl 16);
|
RawCode := RawCode + (LongInt(Context.Buf[ByteIndex + 2]) shl 16);
|
||||||
RawCode := RawCode shr (Context.Inx and 7);
|
RawCode := RawCode shr (Context.Inx and 7);
|
||||||
Context.Inx := Context.Inx + Byte(Context.CodeSize);
|
Context.Inx := Context.Inx + Byte(Context.CodeSize);
|
||||||
Result := RawCode and Context.ReadMask;
|
Result := RawCode and Context.ReadMask;
|
||||||
|
@ -345,7 +346,7 @@ begin
|
||||||
GetMem(Suffix, SizeOf(TIntCodeTable));
|
GetMem(Suffix, SizeOf(TIntCodeTable));
|
||||||
GetMem(OutCode, SizeOf(TIntCodeTable) + SizeOf(Word));
|
GetMem(OutCode, SizeOf(TIntCodeTable) + SizeOf(Word));
|
||||||
try
|
try
|
||||||
IO.Read(Handle, @MinCodeSize, 1);
|
Stream.Read(MinCodeSize, 1);
|
||||||
if (MinCodeSize < 2) or (MinCodeSize > 9) then
|
if (MinCodeSize < 2) or (MinCodeSize > 9) then
|
||||||
RaiseImaging(SGIFDecodingError, []);
|
RaiseImaging(SGIFDecodingError, []);
|
||||||
// Initial read context
|
// Initial read context
|
||||||
|
@ -690,7 +691,8 @@ var
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure CopyFrameTransparent(const Image, Frame: TImageData; Left, Top, TransIndex: Integer);
|
procedure CopyFrameTransparent(const Image, Frame: TImageData; Left, Top,
|
||||||
|
TransIndex: Integer; Disposal: TDisposalMethod);
|
||||||
var
|
var
|
||||||
X, Y: Integer;
|
X, Y: Integer;
|
||||||
Src, Dst: PByte;
|
Src, Dst: PByte;
|
||||||
|
@ -703,7 +705,12 @@ var
|
||||||
Dst := @PByteArray(Image.Bits)[(Top + Y) * Image.Width + Left];
|
Dst := @PByteArray(Image.Bits)[(Top + Y) * Image.Width + Left];
|
||||||
for X := 0 to Frame.Width - 1 do
|
for X := 0 to Frame.Width - 1 do
|
||||||
begin
|
begin
|
||||||
if Src^ <> TransIndex then
|
// If disposal methos is undefined copy all pixels regardless of
|
||||||
|
// transparency (transparency of whole image will be determined by TranspIndex
|
||||||
|
// in image palette) - same effect as filling the image with trasp color
|
||||||
|
// instead of backround color beforehand.
|
||||||
|
// For other methods don't copy transparent pixels from frame to image.
|
||||||
|
if (Src^ <> TransIndex) or (Disposal = dmUndefined) then
|
||||||
Dst^ := Src^;
|
Dst^ := Src^;
|
||||||
Inc(Src);
|
Inc(Src);
|
||||||
Inc(Dst);
|
Inc(Dst);
|
||||||
|
@ -711,6 +718,28 @@ var
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure CopyLZWData(Dest: TStream);
|
||||||
|
var
|
||||||
|
CodeSize, BlockSize: Byte;
|
||||||
|
InputSize: Integer;
|
||||||
|
Buff: array[Byte] of Byte;
|
||||||
|
begin
|
||||||
|
InputSize := ImagingIO.GetInputSize(GetIO, Handle);
|
||||||
|
// Copy codesize to stream
|
||||||
|
GetIO.Read(Handle, @CodeSize, 1);
|
||||||
|
Dest.Write(CodeSize, 1);
|
||||||
|
repeat
|
||||||
|
// Read and write data blocks, last is block term value of 0
|
||||||
|
GetIO.Read(Handle, @BlockSize, 1);
|
||||||
|
Dest.Write(BlockSize, 1);
|
||||||
|
if BlockSize > 0 then
|
||||||
|
begin
|
||||||
|
GetIO.Read(Handle, @Buff[0], BlockSize);
|
||||||
|
Dest.Write(Buff[0], BlockSize);
|
||||||
|
end;
|
||||||
|
until (BlockSize = 0) or (GetIO.Tell(Handle) >= InputSize);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure ReadFrame;
|
procedure ReadFrame;
|
||||||
var
|
var
|
||||||
ImageDesc: TImageDescriptor;
|
ImageDesc: TImageDescriptor;
|
||||||
|
@ -719,6 +748,7 @@ var
|
||||||
LocalPal: TPalette32Size256;
|
LocalPal: TPalette32Size256;
|
||||||
BlockTerm: Byte;
|
BlockTerm: Byte;
|
||||||
Frame: TImageData;
|
Frame: TImageData;
|
||||||
|
LZWStream: TMemoryStream;
|
||||||
begin
|
begin
|
||||||
Idx := Length(Images);
|
Idx := Length(Images);
|
||||||
SetLength(Images, Idx + 1);
|
SetLength(Images, Idx + 1);
|
||||||
|
@ -806,15 +836,20 @@ var
|
||||||
@Header.BackgroundColorIndex);
|
@Header.BackgroundColorIndex);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
LZWStream := TMemoryStream.Create;
|
||||||
try
|
try
|
||||||
|
// Copy LZW data to temp stream, needed for correct decompression
|
||||||
|
CopyLZWData(LZWStream);
|
||||||
|
LZWStream.Position := 0;
|
||||||
// Data decompression finally
|
// Data decompression finally
|
||||||
LZWDecompress(GetIO, Handle, ImageDesc.Width, ImageDesc.Height, Interlaced, Frame.Bits);
|
LZWDecompress(LZWStream, Handle, ImageDesc.Width, ImageDesc.Height, Interlaced, Frame.Bits);
|
||||||
Read(Handle, @BlockTerm, SizeOf(BlockTerm));
|
|
||||||
// Now copy frame to logical screen with skipping of transparent pixels (if enabled)
|
// Now copy frame to logical screen with skipping of transparent pixels (if enabled)
|
||||||
TransIndex := Iff(HasTransparency, GraphicExt.TransparentColorIndex, MaxInt);
|
TransIndex := Iff(HasTransparency, GraphicExt.TransparentColorIndex, MaxInt);
|
||||||
CopyFrameTransparent(Images[Idx], Frame, ImageDesc.Left, ImageDesc.Top, TransIndex);
|
CopyFrameTransparent(Images[Idx], Frame, ImageDesc.Left, ImageDesc.Top,
|
||||||
|
TransIndex, Disposals[Idx]);
|
||||||
finally
|
finally
|
||||||
FreeImage(Frame);
|
FreeImage(Frame);
|
||||||
|
LZWStream.Free;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
@ -840,7 +875,6 @@ begin
|
||||||
Read(Handle, @GlobalPal[I].G, SizeOf(GlobalPal[I].G));
|
Read(Handle, @GlobalPal[I].G, SizeOf(GlobalPal[I].G));
|
||||||
Read(Handle, @GlobalPal[I].B, SizeOf(GlobalPal[I].B));
|
Read(Handle, @GlobalPal[I].B, SizeOf(GlobalPal[I].B));
|
||||||
end;
|
end;
|
||||||
GlobalPal[Header.BackgroundColorIndex].A := 0;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Read ID of the first block
|
// Read ID of the first block
|
||||||
|
@ -973,6 +1007,14 @@ initialization
|
||||||
-- TODOS ----------------------------------------------------
|
-- TODOS ----------------------------------------------------
|
||||||
- nothing now
|
- nothing now
|
||||||
|
|
||||||
|
-- 0.25.0 Changes/Bug Fixes ---------------------------------
|
||||||
|
- Fixed loading of some rare GIFs, problems with LZW
|
||||||
|
decompression.
|
||||||
|
|
||||||
|
-- 0.24.3 Changes/Bug Fixes ---------------------------------
|
||||||
|
- Better solution to transparency for some GIFs. Background not
|
||||||
|
transparent by default.
|
||||||
|
|
||||||
-- 0.24.1 Changes/Bug Fixes ---------------------------------
|
-- 0.24.1 Changes/Bug Fixes ---------------------------------
|
||||||
- Made backround color transparent by default (alpha = 0).
|
- Made backround color transparent by default (alpha = 0).
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
$Id: ImagingJpeg.pas 103 2007-09-15 01:11:14Z galfar $
|
$Id: ImagingJpeg.pas 128 2008-07-23 11:57:36Z galfar $
|
||||||
Vampyre Imaging Library
|
Vampyre Imaging Library
|
||||||
by Marek Mauder
|
by Marek Mauder
|
||||||
http://imaginglib.sourceforge.net
|
http://imaginglib.sourceforge.net
|
||||||
|
@ -46,7 +46,7 @@ unit ImagingJpeg;
|
||||||
{ Automatically use FPC's PasJpeg when compiling with Lazarus.}
|
{ Automatically use FPC's PasJpeg when compiling with Lazarus.}
|
||||||
|
|
||||||
{$IFDEF LCL}
|
{$IFDEF LCL}
|
||||||
{ $UNDEF IMJPEGLIB}
|
{$UNDEF IMJPEGLIB}
|
||||||
{$DEFINE PASJPEG}
|
{$DEFINE PASJPEG}
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ uses
|
||||||
|
|
||||||
{$IF Defined(FPC) and Defined(PASJPEG)}
|
{$IF Defined(FPC) and Defined(PASJPEG)}
|
||||||
{ When using FPC's pasjpeg in FPC the channel order is BGR instead of RGB}
|
{ When using FPC's pasjpeg in FPC the channel order is BGR instead of RGB}
|
||||||
{ $DEFINE RGBSWAPPED} // not needed now apparently
|
{$DEFINE RGBSWAPPED}
|
||||||
{$IFEND}
|
{$IFEND}
|
||||||
|
|
||||||
type
|
type
|
||||||
|
@ -375,10 +375,8 @@ var
|
||||||
Dest: PByte;
|
Dest: PByte;
|
||||||
jc: TJpegContext;
|
jc: TJpegContext;
|
||||||
Info: TImageFormatInfo;
|
Info: TImageFormatInfo;
|
||||||
Format: TImageFormat;
|
|
||||||
Col32: PColor32Rec;
|
Col32: PColor32Rec;
|
||||||
{$IFDEF RGBSWAPPED}
|
{$IFDEF RGBSWAPPED}
|
||||||
I: LongInt;
|
|
||||||
Pix: PColor24Rec;
|
Pix: PColor24Rec;
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
begin
|
begin
|
||||||
|
@ -556,6 +554,9 @@ initialization
|
||||||
-- TODOS ----------------------------------------------------
|
-- TODOS ----------------------------------------------------
|
||||||
- nothing now
|
- nothing now
|
||||||
|
|
||||||
|
-- 0.25.0 Changes/Bug Fixes ---------------------------------
|
||||||
|
-- FPC's PasJpeg wasn't really used in last version, fixed.
|
||||||
|
|
||||||
-- 0.24.1 Changes/Bug Fixes ---------------------------------
|
-- 0.24.1 Changes/Bug Fixes ---------------------------------
|
||||||
- Fixed loading of CMYK jpeg images. Could cause heap corruption
|
- Fixed loading of CMYK jpeg images. Could cause heap corruption
|
||||||
and loaded image looked wrong.
|
and loaded image looked wrong.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
$Id: ImagingNetworkGraphics.pas 90 2007-06-18 22:09:16Z galfar $
|
$Id: ImagingNetworkGraphics.pas 122 2008-03-14 14:05:42Z galfar $
|
||||||
Vampyre Imaging Library
|
Vampyre Imaging Library
|
||||||
by Marek Mauder
|
by Marek Mauder
|
||||||
http://imaginglib.sourceforge.net
|
http://imaginglib.sourceforge.net
|
||||||
|
@ -299,6 +299,7 @@ type
|
||||||
GlobalPaletteEntries: LongInt;
|
GlobalPaletteEntries: LongInt;
|
||||||
GlobalTransparency: Pointer;
|
GlobalTransparency: Pointer;
|
||||||
GlobalTransparencySize: LongInt;
|
GlobalTransparencySize: LongInt;
|
||||||
|
destructor Destroy; override;
|
||||||
procedure Clear;
|
procedure Clear;
|
||||||
function GetLastFrame: TFrameInfo;
|
function GetLastFrame: TFrameInfo;
|
||||||
function AddFrameInfo: TFrameInfo;
|
function AddFrameInfo: TFrameInfo;
|
||||||
|
@ -340,10 +341,6 @@ type
|
||||||
end;
|
end;
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
|
|
||||||
var
|
|
||||||
NGFileLoader: TNGFileLoader = nil;
|
|
||||||
NGFileSaver: TNGFileSaver = nil;
|
|
||||||
|
|
||||||
{ Helper routines }
|
{ Helper routines }
|
||||||
|
|
||||||
function PaethPredictor(A, B, C: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
function PaethPredictor(A, B, C: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
||||||
|
@ -455,6 +452,12 @@ end;
|
||||||
|
|
||||||
{ TNGFileHandler class implementation}
|
{ TNGFileHandler class implementation}
|
||||||
|
|
||||||
|
destructor TNGFileHandler.Destroy;
|
||||||
|
begin
|
||||||
|
Clear;
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TNGFileHandler.Clear;
|
procedure TNGFileHandler.Clear;
|
||||||
var
|
var
|
||||||
I: LongInt;
|
I: LongInt;
|
||||||
|
@ -1865,8 +1868,11 @@ end;
|
||||||
|
|
||||||
function TPNGFileFormat.LoadData(Handle: TImagingHandle;
|
function TPNGFileFormat.LoadData(Handle: TImagingHandle;
|
||||||
var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
|
var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
|
||||||
|
var
|
||||||
|
NGFileLoader: TNGFileLoader;
|
||||||
begin
|
begin
|
||||||
Result := False;
|
Result := False;
|
||||||
|
NGFileLoader := TNGFileLoader.Create;
|
||||||
try
|
try
|
||||||
// Use NG file parser to load file
|
// Use NG file parser to load file
|
||||||
if NGFileLoader.LoadFile(Handle) and (Length(NGFileLoader.Frames) > 0) then
|
if NGFileLoader.LoadFile(Handle) and (Length(NGFileLoader.Frames) > 0) then
|
||||||
|
@ -1881,7 +1887,7 @@ begin
|
||||||
Result := True;
|
Result := True;
|
||||||
end;
|
end;
|
||||||
finally
|
finally
|
||||||
NGFileLoader.Clear;
|
NGFileLoader.Free;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -1890,10 +1896,13 @@ function TPNGFileFormat.SaveData(Handle: TImagingHandle;
|
||||||
var
|
var
|
||||||
ImageToSave: TImageData;
|
ImageToSave: TImageData;
|
||||||
MustBeFreed: Boolean;
|
MustBeFreed: Boolean;
|
||||||
|
NGFileSaver: TNGFileSaver;
|
||||||
begin
|
begin
|
||||||
// Make image PNG compatible, store it in saver, and save it to file
|
// Make image PNG compatible, store it in saver, and save it to file
|
||||||
Result := MakeCompatible(Images[Index], ImageToSave, MustBeFreed);
|
Result := MakeCompatible(Images[Index], ImageToSave, MustBeFreed);
|
||||||
if Result then
|
if Result then
|
||||||
|
begin
|
||||||
|
NGFileSaver := TNGFileSaver.Create;
|
||||||
with NGFileSaver do
|
with NGFileSaver do
|
||||||
try
|
try
|
||||||
FileType := ngPNG;
|
FileType := ngPNG;
|
||||||
|
@ -1901,11 +1910,12 @@ begin
|
||||||
AddFrame(ImageToSave, False);
|
AddFrame(ImageToSave, False);
|
||||||
SaveFile(Handle);
|
SaveFile(Handle);
|
||||||
finally
|
finally
|
||||||
// Clear NG saver and compatible image
|
// Free NG saver and compatible image
|
||||||
Clear;
|
NGFileSaver.Free;
|
||||||
if MustBeFreed then
|
if MustBeFreed then
|
||||||
FreeImage(ImageToSave);
|
FreeImage(ImageToSave);
|
||||||
end;
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{$IFDEF LINK_MNG}
|
{$IFDEF LINK_MNG}
|
||||||
|
@ -1932,9 +1942,11 @@ end;
|
||||||
function TMNGFileFormat.LoadData(Handle: TImagingHandle;
|
function TMNGFileFormat.LoadData(Handle: TImagingHandle;
|
||||||
var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
|
var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
|
||||||
var
|
var
|
||||||
|
NGFileLoader: TNGFileLoader;
|
||||||
I, Len: LongInt;
|
I, Len: LongInt;
|
||||||
begin
|
begin
|
||||||
Result := False;
|
Result := False;
|
||||||
|
NGFileLoader := TNGFileLoader.Create;
|
||||||
try
|
try
|
||||||
// Use NG file parser to load file
|
// Use NG file parser to load file
|
||||||
if NGFileLoader.LoadFile(Handle) then
|
if NGFileLoader.LoadFile(Handle) then
|
||||||
|
@ -1965,13 +1977,14 @@ begin
|
||||||
Result := True;
|
Result := True;
|
||||||
end;
|
end;
|
||||||
finally
|
finally
|
||||||
NGFileLoader.Clear;
|
NGFileLoader.Free;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TMNGFileFormat.SaveData(Handle: TImagingHandle;
|
function TMNGFileFormat.SaveData(Handle: TImagingHandle;
|
||||||
const Images: TDynImageDataArray; Index: LongInt): Boolean;
|
const Images: TDynImageDataArray; Index: LongInt): Boolean;
|
||||||
var
|
var
|
||||||
|
NGFileSaver: TNGFileSaver;
|
||||||
I, LargestWidth, LargestHeight: LongInt;
|
I, LargestWidth, LargestHeight: LongInt;
|
||||||
ImageToSave: TImageData;
|
ImageToSave: TImageData;
|
||||||
MustBeFreed: Boolean;
|
MustBeFreed: Boolean;
|
||||||
|
@ -1980,6 +1993,7 @@ begin
|
||||||
LargestWidth := 0;
|
LargestWidth := 0;
|
||||||
LargestHeight := 0;
|
LargestHeight := 0;
|
||||||
|
|
||||||
|
NGFileSaver := TNGFileSaver.Create;
|
||||||
NGFileSaver.FileType := ngMNG;
|
NGFileSaver.FileType := ngMNG;
|
||||||
NGFileSaver.SetFileOptions(Self);
|
NGFileSaver.SetFileOptions(Self);
|
||||||
|
|
||||||
|
@ -2016,7 +2030,7 @@ begin
|
||||||
SaveFile(Handle);
|
SaveFile(Handle);
|
||||||
Result := True;
|
Result := True;
|
||||||
finally
|
finally
|
||||||
Clear;
|
NGFileSaver.Free;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -2044,8 +2058,11 @@ end;
|
||||||
|
|
||||||
function TJNGFileFormat.LoadData(Handle: TImagingHandle;
|
function TJNGFileFormat.LoadData(Handle: TImagingHandle;
|
||||||
var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
|
var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
|
||||||
|
var
|
||||||
|
NGFileLoader: TNGFileLoader;
|
||||||
begin
|
begin
|
||||||
Result := False;
|
Result := False;
|
||||||
|
NGFileLoader := TNGFileLoader.Create;
|
||||||
try
|
try
|
||||||
// Use NG file parser to load file
|
// Use NG file parser to load file
|
||||||
if NGFileLoader.LoadFile(Handle) and (Length(NGFileLoader.Frames) > 0) then
|
if NGFileLoader.LoadFile(Handle) and (Length(NGFileLoader.Frames) > 0) then
|
||||||
|
@ -2060,19 +2077,22 @@ begin
|
||||||
Result := True;
|
Result := True;
|
||||||
end;
|
end;
|
||||||
finally
|
finally
|
||||||
NGFileLoader.Clear;
|
NGFileLoader.Free;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TJNGFileFormat.SaveData(Handle: TImagingHandle;
|
function TJNGFileFormat.SaveData(Handle: TImagingHandle;
|
||||||
const Images: TDynImageDataArray; Index: LongInt): Boolean;
|
const Images: TDynImageDataArray; Index: LongInt): Boolean;
|
||||||
var
|
var
|
||||||
|
NGFileSaver: TNGFileSaver;
|
||||||
ImageToSave: TImageData;
|
ImageToSave: TImageData;
|
||||||
MustBeFreed: Boolean;
|
MustBeFreed: Boolean;
|
||||||
begin
|
begin
|
||||||
// Make image JNG compatible, store it in saver, and save it to file
|
// Make image JNG compatible, store it in saver, and save it to file
|
||||||
Result := MakeCompatible(Images[Index], ImageToSave, MustBeFreed);
|
Result := MakeCompatible(Images[Index], ImageToSave, MustBeFreed);
|
||||||
if Result then
|
if Result then
|
||||||
|
begin
|
||||||
|
NGFileSaver := TNGFileSaver.Create;
|
||||||
with NGFileSaver do
|
with NGFileSaver do
|
||||||
try
|
try
|
||||||
FileType := ngJNG;
|
FileType := ngJNG;
|
||||||
|
@ -2080,18 +2100,17 @@ begin
|
||||||
AddFrame(ImageToSave, True);
|
AddFrame(ImageToSave, True);
|
||||||
SaveFile(Handle);
|
SaveFile(Handle);
|
||||||
finally
|
finally
|
||||||
// Clear NG saver and compatible image
|
// Free NG saver and compatible image
|
||||||
Clear;
|
NGFileSaver.Free;
|
||||||
if MustBeFreed then
|
if MustBeFreed then
|
||||||
FreeImage(ImageToSave);
|
FreeImage(ImageToSave);
|
||||||
end;
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
NGFileLoader := TNGFileLoader.Create;
|
|
||||||
NGFileSaver := TNGFileSaver.Create;
|
|
||||||
RegisterImageFileFormat(TPNGFileFormat);
|
RegisterImageFileFormat(TPNGFileFormat);
|
||||||
{$IFDEF LINK_MNG}
|
{$IFDEF LINK_MNG}
|
||||||
RegisterImageFileFormat(TMNGFileFormat);
|
RegisterImageFileFormat(TMNGFileFormat);
|
||||||
|
@ -2100,8 +2119,6 @@ initialization
|
||||||
RegisterImageFileFormat(TJNGFileFormat);
|
RegisterImageFileFormat(TJNGFileFormat);
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
finalization
|
finalization
|
||||||
FreeAndNil(NGFileLoader);
|
|
||||||
FreeAndNil(NGFileSaver);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
File Notes:
|
File Notes:
|
||||||
|
@ -2109,6 +2126,9 @@ finalization
|
||||||
-- TODOS ----------------------------------------------------
|
-- TODOS ----------------------------------------------------
|
||||||
- nothing now
|
- nothing now
|
||||||
|
|
||||||
|
-- 0.24.3 Changes/Bug Fixes ---------------------------------
|
||||||
|
- Changes for better thread safety.
|
||||||
|
|
||||||
-- 0.23 Changes/Bug Fixes -----------------------------------
|
-- 0.23 Changes/Bug Fixes -----------------------------------
|
||||||
- Added loading of global palettes and transparencies in MNG files
|
- Added loading of global palettes and transparencies in MNG files
|
||||||
(and by doing so fixed crash when loading images with global PLTE or tRNS).
|
(and by doing so fixed crash when loading images with global PLTE or tRNS).
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
$Id: ImagingOpenGL.pas 106 2007-10-23 23:03:35Z galfar $
|
$Id: ImagingOpenGL.pas 128 2008-07-23 11:57:36Z galfar $
|
||||||
Vampyre Imaging Library
|
Vampyre Imaging Library
|
||||||
by Marek Mauder
|
by Marek Mauder
|
||||||
http://imaginglib.sourceforge.net
|
http://imaginglib.sourceforge.net
|
||||||
|
@ -33,7 +33,7 @@ unit ImagingOpenGL;
|
||||||
{$I ImagingOptions.inc}
|
{$I ImagingOptions.inc}
|
||||||
|
|
||||||
{ Define this symbol if you want to use dglOpenGL header.}
|
{ Define this symbol if you want to use dglOpenGL header.}
|
||||||
{ $DEFINE USE_DGL_HEADERS}
|
{.$DEFINE USE_DGL_HEADERS}
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
|
@ -49,12 +49,17 @@ uses
|
||||||
type
|
type
|
||||||
{ Various texture capabilities of installed OpenGL driver.}
|
{ Various texture capabilities of installed OpenGL driver.}
|
||||||
TGLTextureCaps = record
|
TGLTextureCaps = record
|
||||||
MaxTextureSize: LongInt;
|
MaxTextureSize: LongInt; // Max size of texture in pixels supported by HW
|
||||||
PowerOfTwo: Boolean;
|
NonPowerOfTwo: Boolean; // HW has full support for NPOT textures
|
||||||
DXTCompression: Boolean;
|
DXTCompression: Boolean; // HW supports S3TC/DXTC compressed textures
|
||||||
FloatTextures: Boolean;
|
ATI3DcCompression: Boolean; // HW supports ATI 3Dc compressed textures (ATI2N)
|
||||||
MaxAnisotropy: LongInt;
|
LATCCompression: Boolean; // HW supports LATC/RGTC compressed textures (ATI1N+ATI2N)
|
||||||
MaxSimultaneousTextures: LongInt;
|
FloatTextures: Boolean; // HW supports floating point textures
|
||||||
|
MaxAnisotropy: LongInt; // Max anisotropy for aniso texture filtering
|
||||||
|
MaxSimultaneousTextures: LongInt; // Number of texture units
|
||||||
|
ClampToEdge: Boolean; // GL_EXT_texture_edge_clamp
|
||||||
|
TextureLOD: Boolean; // GL_SGIS_texture_lod
|
||||||
|
VertexTextureUnits: Integer; // Texture units accessible in vertex programs
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Returns texture capabilities of installed OpenGL driver.}
|
{ Returns texture capabilities of installed OpenGL driver.}
|
||||||
|
@ -71,7 +76,7 @@ function IsGLExtensionSupported(const Extension: string): Boolean;
|
||||||
supported by hardware using GetGLTextureCaps, ImageFormatToGL does not
|
supported by hardware using GetGLTextureCaps, ImageFormatToGL does not
|
||||||
check this.}
|
check this.}
|
||||||
function ImageFormatToGL(Format: TImageFormat; var GLFormat: GLenum;
|
function ImageFormatToGL(Format: TImageFormat; var GLFormat: GLenum;
|
||||||
var GLType: GLenum; var GLInternal: GLint): Boolean;
|
var GLType: GLenum; var GLInternal: GLint; const Caps: TGLTextureCaps): Boolean;
|
||||||
|
|
||||||
{ All GL textures created by Imaging functions have default parameters set -
|
{ All GL textures created by Imaging functions have default parameters set -
|
||||||
that means that no glTexParameter calls are made so default filtering,
|
that means that no glTexParameter calls are made so default filtering,
|
||||||
|
@ -164,6 +169,14 @@ var
|
||||||
image->texture process (usually only pow2/nonpow2 stuff and when you
|
image->texture process (usually only pow2/nonpow2 stuff and when you
|
||||||
set custom Width & Height in CreateGLTextureFrom(Multi)Image).}
|
set custom Width & Height in CreateGLTextureFrom(Multi)Image).}
|
||||||
PasteNonPow2ImagesIntoPow2: Boolean = False;
|
PasteNonPow2ImagesIntoPow2: Boolean = False;
|
||||||
|
{ Standard behaviur if GL_ARB_texture_non_power_of_two extension is not supported
|
||||||
|
is to rescale image to power of 2 dimensions. NPOT extension is exposed only
|
||||||
|
when HW has full support for NPOT textures but some cards
|
||||||
|
(ATI Radeons, some other maybe) have partial NPOT support. Namely Radeons
|
||||||
|
can use NPOT textures but not mipmapped. If you know what you are doing
|
||||||
|
you can disable NPOT support check so the image won't be rescaled to POT
|
||||||
|
by seting DisableNPOTSupportCheck to True.}
|
||||||
|
DisableNPOTSupportCheck: Boolean = False;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
@ -239,6 +252,11 @@ const
|
||||||
GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = $83F1;
|
GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = $83F1;
|
||||||
GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = $83F2;
|
GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = $83F2;
|
||||||
GL_COMPRESSED_RGBA_S3TC_DXT5_EXT = $83F3;
|
GL_COMPRESSED_RGBA_S3TC_DXT5_EXT = $83F3;
|
||||||
|
GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI = $8837;
|
||||||
|
GL_COMPRESSED_LUMINANCE_LATC1_EXT = $8C70;
|
||||||
|
GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT = $8C71;
|
||||||
|
GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT = $8C72;
|
||||||
|
GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT = $8C73;
|
||||||
|
|
||||||
// various GL extension constants
|
// various GL extension constants
|
||||||
GL_MAX_TEXTURE_UNITS = $84E2;
|
GL_MAX_TEXTURE_UNITS = $84E2;
|
||||||
|
@ -311,36 +329,49 @@ end;
|
||||||
|
|
||||||
function GetGLTextureCaps(var Caps: TGLTextureCaps): Boolean;
|
function GetGLTextureCaps(var Caps: TGLTextureCaps): Boolean;
|
||||||
begin
|
begin
|
||||||
// check DXTC support and load extension functions if necesary
|
// Check DXTC support and load extension functions if necesary
|
||||||
Caps.DXTCompression := IsGLExtensionSupported('GL_ARB_texture_compression') and
|
Caps.DXTCompression := IsGLExtensionSupported('GL_ARB_texture_compression') and
|
||||||
IsGLExtensionSupported('GL_EXT_texture_compression_s3tc');
|
IsGLExtensionSupported('GL_EXT_texture_compression_s3tc');
|
||||||
if Caps.DXTCompression then
|
if Caps.DXTCompression then
|
||||||
glCompressedTexImage2D := GetGLProcAddress('glCompressedTexImage2D');
|
glCompressedTexImage2D := GetGLProcAddress('glCompressedTexImage2D');
|
||||||
Caps.DXTCompression := Caps.DXTCompression and (@glCompressedTexImage2D <> nil);
|
Caps.DXTCompression := Caps.DXTCompression and (@glCompressedTexImage2D <> nil);
|
||||||
// check non power of 2 textures
|
Caps.ATI3DcCompression := Caps.DXTCompression and
|
||||||
Caps.PowerOfTwo := not IsGLExtensionSupported('GL_ARB_texture_non_power_of_two');
|
IsGLExtensionSupported('GL_ATI_texture_compression_3dc');
|
||||||
// check for floating point textures support
|
Caps.LATCCompression := Caps.DXTCompression and
|
||||||
|
IsGLExtensionSupported('GL_EXT_texture_compression_latc');
|
||||||
|
// Check non power of 2 textures
|
||||||
|
Caps.NonPowerOfTwo := IsGLExtensionSupported('GL_ARB_texture_non_power_of_two');
|
||||||
|
// Check for floating point textures support
|
||||||
Caps.FloatTextures := IsGLExtensionSupported('GL_ARB_texture_float');
|
Caps.FloatTextures := IsGLExtensionSupported('GL_ARB_texture_float');
|
||||||
// get max texture size
|
// Get max texture size
|
||||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, @Caps.MaxTextureSize);
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, @Caps.MaxTextureSize);
|
||||||
// get max anisotropy
|
// Get max anisotropy
|
||||||
if IsGLExtensionSupported('GL_EXT_texture_filter_anisotropic') then
|
if IsGLExtensionSupported('GL_EXT_texture_filter_anisotropic') then
|
||||||
glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, @Caps.MaxAnisotropy)
|
glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, @Caps.MaxAnisotropy)
|
||||||
else
|
else
|
||||||
Caps.MaxAnisotropy := 0;
|
Caps.MaxAnisotropy := 0;
|
||||||
// get number of texture units
|
// Get number of texture units
|
||||||
if IsGLExtensionSupported('GL_ARB_multitexture') then
|
if IsGLExtensionSupported('GL_ARB_multitexture') then
|
||||||
glGetIntegerv(GL_MAX_TEXTURE_UNITS, @Caps.MaxSimultaneousTextures)
|
glGetIntegerv(GL_MAX_TEXTURE_UNITS, @Caps.MaxSimultaneousTextures)
|
||||||
else
|
else
|
||||||
Caps.MaxSimultaneousTextures := 1;
|
Caps.MaxSimultaneousTextures := 1;
|
||||||
// get max texture size
|
// Get number of vertex texture units
|
||||||
|
if IsGLExtensionSupported('GL_ARB_vertex_shader') then
|
||||||
|
glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, @Caps.VertexTextureUnits)
|
||||||
|
else
|
||||||
|
Caps.VertexTextureUnits := 1;
|
||||||
|
// Get max texture size
|
||||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, @Caps.MaxTextureSize);
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, @Caps.MaxTextureSize);
|
||||||
|
// Clamp texture to edge?
|
||||||
|
Caps.ClampToEdge := IsGLExtensionSupported('GL_EXT_texture_edge_clamp');
|
||||||
|
// Texture LOD extension?
|
||||||
|
Caps.TextureLOD := IsGLExtensionSupported('GL_SGIS_texture_lod');
|
||||||
|
|
||||||
Result := True;
|
Result := True;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function ImageFormatToGL(Format: TImageFormat; var GLFormat: GLenum;
|
function ImageFormatToGL(Format: TImageFormat; var GLFormat: GLenum;
|
||||||
var GLType: GLenum; var GLInternal: GLint): Boolean;
|
var GLType: GLenum; var GLInternal: GLint; const Caps: TGLTextureCaps): Boolean;
|
||||||
begin
|
begin
|
||||||
GLFormat := 0;
|
GLFormat := 0;
|
||||||
GLType := 0;
|
GLType := 0;
|
||||||
|
@ -437,6 +468,13 @@ begin
|
||||||
ifDXT1: GLInternal := GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
|
ifDXT1: GLInternal := GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
|
||||||
ifDXT3: GLInternal := GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
ifDXT3: GLInternal := GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
||||||
ifDXT5: GLInternal := GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
ifDXT5: GLInternal := GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||||
|
ifATI1N: GLInternal := GL_COMPRESSED_LUMINANCE_LATC1_EXT;
|
||||||
|
ifATI2N:
|
||||||
|
begin
|
||||||
|
GLInternal := GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT;
|
||||||
|
if not Caps.LATCCompression and Caps.ATI3DcCompression then
|
||||||
|
GLInternal := GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
Result := GLInternal <> 0;
|
Result := GLInternal <> 0;
|
||||||
end;
|
end;
|
||||||
|
@ -500,7 +538,7 @@ function CreateGLTextureFromMultiImage(const Images: TDynImageDataArray;
|
||||||
Width, Height: LongInt; MipMaps: Boolean; MainLevelIndex: LongInt; OverrideFormat: TImageFormat;
|
Width, Height: LongInt; MipMaps: Boolean; MainLevelIndex: LongInt; OverrideFormat: TImageFormat;
|
||||||
CreatedWidth, CreatedHeight: PLongInt): GLuint;
|
CreatedWidth, CreatedHeight: PLongInt): GLuint;
|
||||||
const
|
const
|
||||||
CompressedFormats: TImageFormats = [ifDXT1, ifDXT3, ifDXT5];
|
BlockCompressedFormats: TImageFormats = [ifDXT1, ifDXT3, ifDXT5, ifATI1N, ifATI2N];
|
||||||
var
|
var
|
||||||
I, MipLevels, PossibleLevels, ExistingLevels, CurrentWidth, CurrentHeight: LongInt;
|
I, MipLevels, PossibleLevels, ExistingLevels, CurrentWidth, CurrentHeight: LongInt;
|
||||||
Caps: TGLTextureCaps;
|
Caps: TGLTextureCaps;
|
||||||
|
@ -537,7 +575,7 @@ begin
|
||||||
// First check desired size and modify it if necessary
|
// First check desired size and modify it if necessary
|
||||||
if Width <= 0 then Width := Images[MainLevelIndex].Width;
|
if Width <= 0 then Width := Images[MainLevelIndex].Width;
|
||||||
if Height <= 0 then Height := Images[MainLevelIndex].Height;
|
if Height <= 0 then Height := Images[MainLevelIndex].Height;
|
||||||
if Caps.PowerOfTwo then
|
if not Caps.NonPowerOfTwo and not DisableNPOTSupportCheck then
|
||||||
begin
|
begin
|
||||||
// If device supports only power of 2 texture sizes
|
// If device supports only power of 2 texture sizes
|
||||||
Width := NextPow2(Width);
|
Width := NextPow2(Width);
|
||||||
|
@ -570,17 +608,21 @@ begin
|
||||||
Desired := ifA8R8G8B8;
|
Desired := ifA8R8G8B8;
|
||||||
if (Desired in [ifDXT1, ifDXT3, ifDXT5]) and not Caps.DXTCompression then
|
if (Desired in [ifDXT1, ifDXT3, ifDXT5]) and not Caps.DXTCompression then
|
||||||
Desired := ifA8R8G8B8;
|
Desired := ifA8R8G8B8;
|
||||||
|
if (Desired = ifATI1N) and not Caps.LATCCompression then
|
||||||
|
Desired := ifGray8;
|
||||||
|
if (Desired = ifATI2N) and not (Caps.ATI3DcCompression or Caps.LATCCompression) then
|
||||||
|
Desired := ifA8Gray8;
|
||||||
|
|
||||||
// Try to find GL format equivalent to image format and if it is not
|
// Try to find GL format equivalent to image format and if it is not
|
||||||
// found use one of default formats
|
// found use one of default formats
|
||||||
if not ImageFormatToGL(Desired, GLFormat, GLType, GLInternal) then
|
if not ImageFormatToGL(Desired, GLFormat, GLType, GLInternal, Caps) then
|
||||||
begin
|
begin
|
||||||
GetImageFormatInfo(Desired, Info);
|
GetImageFormatInfo(Desired, Info);
|
||||||
if Info.HasGrayChannel then
|
if Info.HasGrayChannel then
|
||||||
ConvTo := ifGray8
|
ConvTo := ifGray8
|
||||||
else
|
else
|
||||||
ConvTo := ifA8R8G8B8;
|
ConvTo := ifA8R8G8B8;
|
||||||
if not ImageFormatToGL(ConvTo, GLFormat, GLType, GLInternal) then
|
if not ImageFormatToGL(ConvTo, GLFormat, GLType, GLInternal, Caps) then
|
||||||
Exit;
|
Exit;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
@ -618,7 +660,7 @@ begin
|
||||||
// Check if input image for this mipmap level has the right
|
// Check if input image for this mipmap level has the right
|
||||||
// size and format
|
// size and format
|
||||||
NeedsConvert := not (Images[I].Format = ConvTo);
|
NeedsConvert := not (Images[I].Format = ConvTo);
|
||||||
if ConvTo in CompressedFormats then
|
if ConvTo in BlockCompressedFormats then
|
||||||
begin
|
begin
|
||||||
// Input images in DXTC will have min dimensions of 4, but we need
|
// Input images in DXTC will have min dimensions of 4, but we need
|
||||||
// current Width and Height to be lesser (for glCompressedTexImage2D)
|
// current Width and Height to be lesser (for glCompressedTexImage2D)
|
||||||
|
@ -659,7 +701,7 @@ begin
|
||||||
FillMipMapLevel(LevelsArray[I - 1], CurrentWidth, CurrentHeight, LevelsArray[I]);
|
FillMipMapLevel(LevelsArray[I - 1], CurrentWidth, CurrentHeight, LevelsArray[I]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if ConvTo in CompressedFormats then
|
if ConvTo in BlockCompressedFormats then
|
||||||
begin
|
begin
|
||||||
// Note: GL DXTC texture snaller than 4x4 must have width and height
|
// Note: GL DXTC texture snaller than 4x4 must have width and height
|
||||||
// as expected for non-DXTC texture (like 1x1 - we cannot
|
// as expected for non-DXTC texture (like 1x1 - we cannot
|
||||||
|
@ -838,6 +880,14 @@ initialization
|
||||||
not only A8R8G8B8
|
not only A8R8G8B8
|
||||||
- support for cube and 3D maps
|
- support for cube and 3D maps
|
||||||
|
|
||||||
|
-- 0.25.0 Changes/Bug Fixes ---------------------------------
|
||||||
|
- Added 3Dc compressed texture formats support.
|
||||||
|
- Added detection of 3Dc formats to texture caps.
|
||||||
|
|
||||||
|
-- 0.24.3 Changes/Bug Fixes ---------------------------------
|
||||||
|
- Added DisableNPOTSupportCheck option and related functionality.
|
||||||
|
- Added some new texture caps detection.
|
||||||
|
|
||||||
-- 0.24.1 Changes/Bug Fixes ---------------------------------
|
-- 0.24.1 Changes/Bug Fixes ---------------------------------
|
||||||
- Added PasteNonPow2ImagesIntoPow2 option and related functionality.
|
- Added PasteNonPow2ImagesIntoPow2 option and related functionality.
|
||||||
- Better NeedsResize determination for small DXTC textures -
|
- Better NeedsResize determination for small DXTC textures -
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{ $Id: ImagingOptions.inc 100 2007-06-28 21:09:52Z galfar $ }
|
{ $Id: ImagingOptions.inc 132 2008-08-27 20:37:38Z galfar $ }
|
||||||
|
|
||||||
{
|
{
|
||||||
User Options
|
User Options
|
||||||
|
@ -212,11 +212,6 @@
|
||||||
{$PACKENUM 4} // Min enum size: 4 B
|
{$PACKENUM 4} // Min enum size: 4 B
|
||||||
{$CALLING REGISTER} // default calling convention is register
|
{$CALLING REGISTER} // default calling convention is register
|
||||||
{$IFDEF CPU86}
|
{$IFDEF CPU86}
|
||||||
{$IFNDEF DYN_LIBRARY}
|
|
||||||
{$SMARTLINK ON} // smartlinking on, but not for dll/so -
|
|
||||||
// nothing gets exported from library when it is on
|
|
||||||
// in FPC 1.9.8
|
|
||||||
{$ENDIF}
|
|
||||||
{$ASMMODE INTEL} // intel assembler mode
|
{$ASMMODE INTEL} // intel assembler mode
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
$Id: ImagingPortableMaps.pas 107 2007-11-06 23:37:48Z galfar $
|
$Id: ImagingPortableMaps.pas 127 2008-05-31 01:57:13Z galfar $
|
||||||
Vampyre Imaging Library
|
Vampyre Imaging Library
|
||||||
by Marek Mauder
|
by Marek Mauder
|
||||||
http://imaginglib.sourceforge.net
|
http://imaginglib.sourceforge.net
|
||||||
|
@ -65,11 +65,10 @@ type
|
||||||
protected
|
protected
|
||||||
FIdNumbers: TChar2;
|
FIdNumbers: TChar2;
|
||||||
FSaveBinary: LongBool;
|
FSaveBinary: LongBool;
|
||||||
FMapInfo: TPortableMapInfo;
|
|
||||||
function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray;
|
function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray;
|
||||||
OnlyFirstLevel: Boolean): Boolean; override;
|
OnlyFirstLevel: Boolean): Boolean; override;
|
||||||
function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
|
function SaveDataInternal(Handle: TImagingHandle; const Images: TDynImageDataArray;
|
||||||
Index: LongInt): Boolean; override;
|
Index: LongInt; var MapInfo: TPortableMapInfo): Boolean;
|
||||||
public
|
public
|
||||||
constructor Create; override;
|
constructor Create; override;
|
||||||
function TestFormat(Handle: TImagingHandle): Boolean; override;
|
function TestFormat(Handle: TImagingHandle): Boolean; override;
|
||||||
|
@ -203,6 +202,8 @@ var
|
||||||
PixelFP: TColorFPRec;
|
PixelFP: TColorFPRec;
|
||||||
LineBuffer: array[0..LineBufferCapacity - 1] of Char;
|
LineBuffer: array[0..LineBufferCapacity - 1] of Char;
|
||||||
LineEnd, LinePos: LongInt;
|
LineEnd, LinePos: LongInt;
|
||||||
|
MapInfo: TPortableMapInfo;
|
||||||
|
LineBreak: string;
|
||||||
|
|
||||||
procedure CheckBuffer;
|
procedure CheckBuffer;
|
||||||
begin
|
begin
|
||||||
|
@ -262,7 +263,7 @@ var
|
||||||
C := LineBuffer[LinePos];
|
C := LineBuffer[LinePos];
|
||||||
Inc(LinePos);
|
Inc(LinePos);
|
||||||
until not (C in WhiteSpaces) or (LineEnd = 0);
|
until not (C in WhiteSpaces) or (LineEnd = 0);
|
||||||
// Dec pos, current is the beggining of the the string
|
// Dec pos, current is the begining of the the string
|
||||||
Dec(LinePos);
|
Dec(LinePos);
|
||||||
|
|
||||||
Result := S;
|
Result := S;
|
||||||
|
@ -273,6 +274,22 @@ var
|
||||||
Result := StrToInt(ReadString);
|
Result := StrToInt(ReadString);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure FindLineBreak;
|
||||||
|
var
|
||||||
|
C: Char;
|
||||||
|
begin
|
||||||
|
LineBreak := #10;
|
||||||
|
repeat
|
||||||
|
CheckBuffer;
|
||||||
|
C := LineBuffer[LinePos];
|
||||||
|
Inc(LinePos);
|
||||||
|
|
||||||
|
if C = #13 then
|
||||||
|
LineBreak := #13#10;
|
||||||
|
|
||||||
|
until C = #10;
|
||||||
|
end;
|
||||||
|
|
||||||
function ParseHeader: Boolean;
|
function ParseHeader: Boolean;
|
||||||
var
|
var
|
||||||
Id: TChar2;
|
Id: TChar2;
|
||||||
|
@ -284,34 +301,37 @@ var
|
||||||
Result := False;
|
Result := False;
|
||||||
with GetIO do
|
with GetIO do
|
||||||
begin
|
begin
|
||||||
FillChar(FMapInfo, SizeOf(FMapInfo), 0);
|
FillChar(MapInfo, SizeOf(MapInfo), 0);
|
||||||
Read(Handle, @Id, SizeOf(Id));
|
Read(Handle, @Id, SizeOf(Id));
|
||||||
|
FindLineBreak;
|
||||||
|
|
||||||
if Id[1] in ['1'..'6'] then
|
if Id[1] in ['1'..'6'] then
|
||||||
begin
|
begin
|
||||||
// Read header for PBM, PGM, and PPM files
|
// Read header for PBM, PGM, and PPM files
|
||||||
FMapInfo.Width := ReadIntValue;
|
MapInfo.Width := ReadIntValue;
|
||||||
FMapInfo.Height := ReadIntValue;
|
MapInfo.Height := ReadIntValue;
|
||||||
|
|
||||||
if Id[1] in ['1', '4'] then
|
if Id[1] in ['1', '4'] then
|
||||||
begin
|
begin
|
||||||
FMapInfo.MaxVal := 1;
|
MapInfo.MaxVal := 1;
|
||||||
FMapInfo.BitCount := 1
|
MapInfo.BitCount := 1
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
// Read channel max value, <=255 for 8bit images, >255 for 16bit images
|
// Read channel max value, <=255 for 8bit images, >255 for 16bit images
|
||||||
// but some programs think its max colors so put <=256 here
|
// but some programs think its max colors so put <=256 here
|
||||||
FMapInfo.MaxVal := ReadIntValue;
|
MapInfo.MaxVal := ReadIntValue;
|
||||||
FMapInfo.BitCount := Iff(FMapInfo.MaxVal <= 256, 8, 16);
|
MapInfo.BitCount := Iff(MapInfo.MaxVal <= 256, 8, 16);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
FMapInfo.Depth := 1;
|
MapInfo.Depth := 1;
|
||||||
case Id[1] of
|
case Id[1] of
|
||||||
'1', '4': FMapInfo.TupleType := ttBlackAndWhite;
|
'1', '4': MapInfo.TupleType := ttBlackAndWhite;
|
||||||
'2', '5': FMapInfo.TupleType := ttGrayScale;
|
'2', '5': MapInfo.TupleType := ttGrayScale;
|
||||||
'3', '6':
|
'3', '6':
|
||||||
begin
|
begin
|
||||||
FMapInfo.TupleType := ttRGB;
|
MapInfo.TupleType := ttRGB;
|
||||||
FMapInfo.Depth := 3;
|
MapInfo.Depth := 3;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
|
@ -320,24 +340,24 @@ var
|
||||||
// Read values from PAM header
|
// Read values from PAM header
|
||||||
// WIDTH
|
// WIDTH
|
||||||
if (ReadString <> SPAMWidth) then Exit;
|
if (ReadString <> SPAMWidth) then Exit;
|
||||||
FMapInfo.Width := ReadIntValue;
|
MapInfo.Width := ReadIntValue;
|
||||||
// HEIGHT
|
// HEIGHT
|
||||||
if (ReadString <> SPAMheight) then Exit;
|
if (ReadString <> SPAMheight) then Exit;
|
||||||
FMapInfo.Height := ReadIntValue;
|
MapInfo.Height := ReadIntValue;
|
||||||
// DEPTH
|
// DEPTH
|
||||||
if (ReadString <> SPAMDepth) then Exit;
|
if (ReadString <> SPAMDepth) then Exit;
|
||||||
FMapInfo.Depth := ReadIntValue;
|
MapInfo.Depth := ReadIntValue;
|
||||||
// MAXVAL
|
// MAXVAL
|
||||||
if (ReadString <> SPAMMaxVal) then Exit;
|
if (ReadString <> SPAMMaxVal) then Exit;
|
||||||
FMapInfo.MaxVal := ReadIntValue;
|
MapInfo.MaxVal := ReadIntValue;
|
||||||
FMapInfo.BitCount := Iff(FMapInfo.MaxVal <= 256, 8, 16);
|
MapInfo.BitCount := Iff(MapInfo.MaxVal <= 256, 8, 16);
|
||||||
// TUPLETYPE
|
// TUPLETYPE
|
||||||
if (ReadString <> SPAMTupleType) then Exit;
|
if (ReadString <> SPAMTupleType) then Exit;
|
||||||
TupleTypeName := ReadString;
|
TupleTypeName := ReadString;
|
||||||
for I := Low(TTupleType) to High(TTupleType) do
|
for I := Low(TTupleType) to High(TTupleType) do
|
||||||
if SameText(TupleTypeName, TupleTypeNames[I]) then
|
if SameText(TupleTypeName, TupleTypeNames[I]) then
|
||||||
begin
|
begin
|
||||||
FMapInfo.TupleType := I;
|
MapInfo.TupleType := I;
|
||||||
Break;
|
Break;
|
||||||
end;
|
end;
|
||||||
// ENDHDR
|
// ENDHDR
|
||||||
|
@ -346,33 +366,42 @@ var
|
||||||
else if Id[1] in ['F', 'f'] then
|
else if Id[1] in ['F', 'f'] then
|
||||||
begin
|
begin
|
||||||
// Read header of PFM file
|
// Read header of PFM file
|
||||||
FMapInfo.Width := ReadIntValue;
|
MapInfo.Width := ReadIntValue;
|
||||||
FMapInfo.Height := ReadIntValue;
|
MapInfo.Height := ReadIntValue;
|
||||||
OldSeparator := DecimalSeparator;
|
OldSeparator := DecimalSeparator;
|
||||||
DecimalSeparator := '.';
|
DecimalSeparator := '.';
|
||||||
Scale := StrToFloatDef(ReadString, 0);
|
Scale := StrToFloatDef(ReadString, 0);
|
||||||
DecimalSeparator := OldSeparator;
|
DecimalSeparator := OldSeparator;
|
||||||
FMapInfo.IsBigEndian := Scale > 0.0;
|
MapInfo.IsBigEndian := Scale > 0.0;
|
||||||
if Id[1] = 'F' then
|
if Id[1] = 'F' then
|
||||||
FMapInfo.TupleType := ttRGBFP
|
MapInfo.TupleType := ttRGBFP
|
||||||
else
|
else
|
||||||
FMapInfo.TupleType := ttGrayScaleFP;
|
MapInfo.TupleType := ttGrayScaleFP;
|
||||||
FMapInfo.Depth := Iff(FMapInfo.TupleType = ttRGBFP, 3, 1);
|
MapInfo.Depth := Iff(MapInfo.TupleType = ttRGBFP, 3, 1);
|
||||||
FMapInfo.BitCount := Iff(FMapInfo.TupleType = ttRGBFP, 96, 32);
|
MapInfo.BitCount := Iff(MapInfo.TupleType = ttRGBFP, 96, 32);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
FixInputPos;
|
FixInputPos;
|
||||||
FMapInfo.Binary := (Id[1] in ['4', '5', '6', '7', 'F', 'f']);
|
MapInfo.Binary := (Id[1] in ['4', '5', '6', '7', 'F', 'f']);
|
||||||
|
|
||||||
|
if MapInfo.Binary and not (Id[1] in ['F', 'f']) then
|
||||||
|
begin
|
||||||
|
// Mimic the behaviour of Photoshop and other editors/viewers:
|
||||||
|
// If linenreaks in file are DOS CR/LF 16bit binary values are
|
||||||
|
// little endian, Unix LF only linebreak indicates big endian.
|
||||||
|
MapInfo.IsBigEndian := LineBreak = #10;
|
||||||
|
end;
|
||||||
|
|
||||||
// Check if values found in header are valid
|
// Check if values found in header are valid
|
||||||
Result := (FMapInfo.Width > 0) and (FMapInfo.Height > 0) and
|
Result := (MapInfo.Width > 0) and (MapInfo.Height > 0) and
|
||||||
(FMapInfo.BitCount in [1, 8, 16, 32, 96]) and (FMapInfo.TupleType <> ttInvalid);
|
(MapInfo.BitCount in [1, 8, 16, 32, 96]) and (MapInfo.TupleType <> ttInvalid);
|
||||||
// Now check if image has proper number of channels (PAM)
|
// Now check if image has proper number of channels (PAM)
|
||||||
if Result then
|
if Result then
|
||||||
case FMapInfo.TupleType of
|
case MapInfo.TupleType of
|
||||||
ttBlackAndWhite, ttGrayScale: Result := FMapInfo.Depth = 1;
|
ttBlackAndWhite, ttGrayScale: Result := MapInfo.Depth = 1;
|
||||||
ttBlackAndWhiteAlpha, ttGrayScaleAlpha: Result := FMapInfo.Depth = 2;
|
ttBlackAndWhiteAlpha, ttGrayScaleAlpha: Result := MapInfo.Depth = 2;
|
||||||
ttRGB: Result := FMapInfo.Depth = 3;
|
ttRGB: Result := MapInfo.Depth = 3;
|
||||||
ttRGBAlpha: Result := FMapInfo.Depth = 4;
|
ttRGBAlpha: Result := MapInfo.Depth = 4;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
@ -388,24 +417,24 @@ begin
|
||||||
// Try to parse file header
|
// Try to parse file header
|
||||||
if not ParseHeader then Exit;
|
if not ParseHeader then Exit;
|
||||||
// Select appropriate data format based on values read from file header
|
// Select appropriate data format based on values read from file header
|
||||||
case FMapInfo.TupleType of
|
case MapInfo.TupleType of
|
||||||
ttBlackAndWhite: Format := ifGray8;
|
ttBlackAndWhite: Format := ifGray8;
|
||||||
ttBlackAndWhiteAlpha: Format := ifA8Gray8;
|
ttBlackAndWhiteAlpha: Format := ifA8Gray8;
|
||||||
ttGrayScale: Format := IffFormat(FMapInfo.BitCount = 8, ifGray8, ifGray16);
|
ttGrayScale: Format := IffFormat(MapInfo.BitCount = 8, ifGray8, ifGray16);
|
||||||
ttGrayScaleAlpha: Format := IffFormat(FMapInfo.BitCount = 8, ifA8Gray8, ifA16Gray16);
|
ttGrayScaleAlpha: Format := IffFormat(MapInfo.BitCount = 8, ifA8Gray8, ifA16Gray16);
|
||||||
ttRGB: Format := IffFormat(FMapInfo.BitCount = 8, ifR8G8B8, ifR16G16B16);
|
ttRGB: Format := IffFormat(MapInfo.BitCount = 8, ifR8G8B8, ifR16G16B16);
|
||||||
ttRGBAlpha: Format := IffFormat(FMapInfo.BitCount = 8, ifA8R8G8B8, ifA16R16G16B16);
|
ttRGBAlpha: Format := IffFormat(MapInfo.BitCount = 8, ifA8R8G8B8, ifA16R16G16B16);
|
||||||
ttGrayScaleFP: Format := ifR32F;
|
ttGrayScaleFP: Format := ifR32F;
|
||||||
ttRGBFP: Format := ifA32B32G32R32F;
|
ttRGBFP: Format := ifA32B32G32R32F;
|
||||||
end;
|
end;
|
||||||
// Exit if no matching data format was found
|
// Exit if no matching data format was found
|
||||||
if Format = ifUnknown then Exit;
|
if Format = ifUnknown then Exit;
|
||||||
|
|
||||||
NewImage(FMapInfo.Width, FMapInfo.Height, Format, Images[0]);
|
NewImage(MapInfo.Width, MapInfo.Height, Format, Images[0]);
|
||||||
Info := GetFormatInfo(Format);
|
Info := GetFormatInfo(Format);
|
||||||
|
|
||||||
// Now read pixels from file to dest image
|
// Now read pixels from file to dest image
|
||||||
if not FMapInfo.Binary then
|
if not MapInfo.Binary then
|
||||||
begin
|
begin
|
||||||
Dest := Bits;
|
Dest := Bits;
|
||||||
for I := 0 to Width * Height - 1 do
|
for I := 0 to Width * Height - 1 do
|
||||||
|
@ -414,7 +443,7 @@ begin
|
||||||
ifGray8:
|
ifGray8:
|
||||||
begin
|
begin
|
||||||
Dest^ := ReadIntValue;
|
Dest^ := ReadIntValue;
|
||||||
if FMapInfo.BitCount = 1 then
|
if MapInfo.BitCount = 1 then
|
||||||
// If source is 1bit mono image (where 0=white, 1=black)
|
// If source is 1bit mono image (where 0=white, 1=black)
|
||||||
// we must scale it to 8bits
|
// we must scale it to 8bits
|
||||||
Dest^ := 255 - Dest^ * 255;
|
Dest^ := 255 - Dest^ * 255;
|
||||||
|
@ -440,9 +469,9 @@ begin
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
if FMapInfo.BitCount > 1 then
|
if MapInfo.BitCount > 1 then
|
||||||
begin
|
begin
|
||||||
if not (FMapInfo.TupleType in [ttGrayScaleFP, ttRGBFP]) then
|
if not (MapInfo.TupleType in [ttGrayScaleFP, ttRGBFP]) then
|
||||||
begin
|
begin
|
||||||
// Just copy bytes from binary Portable Maps (non 1bit, non FP)
|
// Just copy bytes from binary Portable Maps (non 1bit, non FP)
|
||||||
Read(Handle, Bits, Size);
|
Read(Handle, Bits, Size);
|
||||||
|
@ -455,48 +484,43 @@ begin
|
||||||
// I will stick with Photoshops behaviour here
|
// I will stick with Photoshops behaviour here
|
||||||
for I := 0 to Width * Height - 1 do
|
for I := 0 to Width * Height - 1 do
|
||||||
begin
|
begin
|
||||||
Read(Handle, @PixelFP, FMapInfo.BitCount shr 3);
|
Read(Handle, @PixelFP, MapInfo.BitCount div 8);
|
||||||
if FMapInfo.TupleType = ttRGBFP then
|
if MapInfo.TupleType = ttRGBFP then
|
||||||
with PColorFPRec(Dest)^ do
|
with PColorFPRec(Dest)^ do
|
||||||
begin
|
begin
|
||||||
A := 1.0;
|
A := 1.0;
|
||||||
R := PixelFP.R;
|
R := PixelFP.R;
|
||||||
G := PixelFP.G;
|
G := PixelFP.G;
|
||||||
B := PixelFP.B;
|
B := PixelFP.B;
|
||||||
if FMapInfo.IsBigEndian then
|
if MapInfo.IsBigEndian then
|
||||||
SwapEndianLongWord(PLongWord(Dest), 3);
|
SwapEndianLongWord(PLongWord(Dest), 3);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
PSingle(Dest)^ := PixelFP.B;
|
PSingle(Dest)^ := PixelFP.B;
|
||||||
if FMapInfo.IsBigEndian then
|
if MapInfo.IsBigEndian then
|
||||||
SwapEndianLongWord(PLongWord(Dest), 1);
|
SwapEndianLongWord(PLongWord(Dest), 1);
|
||||||
end;
|
end;
|
||||||
Inc(Dest, Info.BytesPerPixel);
|
Inc(Dest, Info.BytesPerPixel);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if FMapInfo.TupleType in [ttBlackAndWhite, ttBlackAndWhiteAlpha] then
|
if MapInfo.TupleType in [ttBlackAndWhite, ttBlackAndWhiteAlpha] then
|
||||||
begin
|
begin
|
||||||
// Black and white PAM files must be scaled to 8bits. Note that
|
// Black and white PAM files must be scaled to 8bits. Note that
|
||||||
// in PAM files 1=white, 0=black (reverse of PBM)
|
// in PAM files 1=white, 0=black (reverse of PBM)
|
||||||
for I := 0 to Width * Height * Iff(FMapInfo.TupleType = ttBlackAndWhiteAlpha, 2, 1) - 1 do
|
for I := 0 to Width * Height * Iff(MapInfo.TupleType = ttBlackAndWhiteAlpha, 2, 1) - 1 do
|
||||||
PByteArray(Bits)[I] := PByteArray(Bits)[I] * 255;
|
PByteArray(Bits)[I] := PByteArray(Bits)[I] * 255;
|
||||||
end;
|
end
|
||||||
if FMapInfo.TupleType in [ttRGB, ttRGBAlpha] then
|
else if MapInfo.TupleType in [ttRGB, ttRGBAlpha] then
|
||||||
begin
|
begin
|
||||||
// Swap channels of RGB/ARGB images. Binary RGB image files use BGR order.
|
// Swap channels of RGB/ARGB images. Binary RGB image files use BGR order.
|
||||||
SwapChannels(Images[0], ChannelBlue, ChannelRed);
|
SwapChannels(Images[0], ChannelBlue, ChannelRed);
|
||||||
end;
|
end;
|
||||||
if FMapInfo.BitCount = 16 then
|
|
||||||
begin
|
// Swap byte order if needed
|
||||||
Dest := Bits;
|
if (MapInfo.BitCount = 16) and MapInfo.IsBigEndian then
|
||||||
for I := 0 to Width * Height * Info.BytesPerPixel div SizeOf(Word) - 1 do
|
SwapEndianWord(Bits, Width * Height * Info.BytesPerPixel div SizeOf(Word));
|
||||||
begin
|
|
||||||
PWord(Dest)^ := SwapEndianWord(PWord(Dest)^);
|
|
||||||
Inc(Dest, SizeOf(Word));
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
|
@ -520,19 +544,19 @@ begin
|
||||||
|
|
||||||
FixInputPos;
|
FixInputPos;
|
||||||
|
|
||||||
if (FMapInfo.MaxVal <> Pow2Int(FMapInfo.BitCount) - 1) and
|
if (MapInfo.MaxVal <> Pow2Int(MapInfo.BitCount) - 1) and
|
||||||
(FMapInfo.TupleType in [ttGrayScale, ttGrayScaleAlpha, ttRGB, ttRGBAlpha]) then
|
(MapInfo.TupleType in [ttGrayScale, ttGrayScaleAlpha, ttRGB, ttRGBAlpha]) then
|
||||||
begin
|
begin
|
||||||
Dest := Bits;
|
Dest := Bits;
|
||||||
// Scale color values according to MaxVal we got from header
|
// Scale color values according to MaxVal we got from header
|
||||||
// if necessary.
|
// if necessary.
|
||||||
for I := 0 to Width * Height * Info.BytesPerPixel div (FMapInfo.BitCount shr 3) - 1 do
|
for I := 0 to Width * Height * Info.BytesPerPixel div (MapInfo.BitCount shr 3) - 1 do
|
||||||
begin
|
begin
|
||||||
if FMapInfo.BitCount = 8 then
|
if MapInfo.BitCount = 8 then
|
||||||
Dest^ := Dest^ * 255 div FMapInfo.MaxVal
|
Dest^ := Dest^ * 255 div MapInfo.MaxVal
|
||||||
else
|
else
|
||||||
PWord(Dest)^ := PWord(Dest)^ * 65535 div FMapInfo.MaxVal;
|
PWord(Dest)^ := PWord(Dest)^ * 65535 div MapInfo.MaxVal;
|
||||||
Inc(Dest, FMapInfo.BitCount shr 3);
|
Inc(Dest, MapInfo.BitCount shr 3);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -540,9 +564,12 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TPortableMapFileFormat.SaveData(Handle: TImagingHandle;
|
function TPortableMapFileFormat.SaveDataInternal(Handle: TImagingHandle;
|
||||||
const Images: TDynImageDataArray; Index: Integer): Boolean;
|
const Images: TDynImageDataArray; Index: Integer; var MapInfo: TPortableMapInfo): Boolean;
|
||||||
const
|
const
|
||||||
|
// Use Unix linebreak, for many viewers/editors it means that
|
||||||
|
// 16bit samples are stored as big endian - so we need to swap byte order
|
||||||
|
// before saving
|
||||||
LineDelimiter = #10;
|
LineDelimiter = #10;
|
||||||
PixelDelimiter = #32;
|
PixelDelimiter = #32;
|
||||||
var
|
var
|
||||||
|
@ -567,14 +594,14 @@ var
|
||||||
var
|
var
|
||||||
OldSeparator: Char;
|
OldSeparator: Char;
|
||||||
begin
|
begin
|
||||||
WriteString('P' + FMapInfo.FormatId);
|
WriteString('P' + MapInfo.FormatId);
|
||||||
if not FMapInfo.HasPAMHeader then
|
if not MapInfo.HasPAMHeader then
|
||||||
begin
|
begin
|
||||||
// Write header of PGM, PPM, and PFM files
|
// Write header of PGM, PPM, and PFM files
|
||||||
WriteString(IntToStr(ImageToSave.Width));
|
WriteString(IntToStr(ImageToSave.Width));
|
||||||
WriteString(IntToStr(ImageToSave.Height));
|
WriteString(IntToStr(ImageToSave.Height));
|
||||||
case FMapInfo.TupleType of
|
case MapInfo.TupleType of
|
||||||
ttGrayScale, ttRGB: WriteString(IntToStr(Pow2Int(FMapInfo.BitCount) - 1));
|
ttGrayScale, ttRGB: WriteString(IntToStr(Pow2Int(MapInfo.BitCount) - 1));
|
||||||
ttGrayScaleFP, ttRGBFP:
|
ttGrayScaleFP, ttRGBFP:
|
||||||
begin
|
begin
|
||||||
OldSeparator := DecimalSeparator;
|
OldSeparator := DecimalSeparator;
|
||||||
|
@ -590,9 +617,9 @@ var
|
||||||
// Write PAM file header
|
// Write PAM file header
|
||||||
WriteString(Format('%s %d', [SPAMWidth, ImageToSave.Width]));
|
WriteString(Format('%s %d', [SPAMWidth, ImageToSave.Width]));
|
||||||
WriteString(Format('%s %d', [SPAMHeight, ImageToSave.Height]));
|
WriteString(Format('%s %d', [SPAMHeight, ImageToSave.Height]));
|
||||||
WriteString(Format('%s %d', [SPAMDepth, FMapInfo.Depth]));
|
WriteString(Format('%s %d', [SPAMDepth, MapInfo.Depth]));
|
||||||
WriteString(Format('%s %d', [SPAMMaxVal, Pow2Int(FMapInfo.BitCount) - 1]));
|
WriteString(Format('%s %d', [SPAMMaxVal, Pow2Int(MapInfo.BitCount) - 1]));
|
||||||
WriteString(Format('%s %s', [SPAMTupleType, TupleTypeNames[FMapInfo.TupleType]]));
|
WriteString(Format('%s %s', [SPAMTupleType, TupleTypeNames[MapInfo.TupleType]]));
|
||||||
WriteString(SPAMEndHdr);
|
WriteString(SPAMEndHdr);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
@ -605,29 +632,29 @@ begin
|
||||||
Info := GetFormatInfo(Format);
|
Info := GetFormatInfo(Format);
|
||||||
// Fill values of MapInfo record that were not filled by
|
// Fill values of MapInfo record that were not filled by
|
||||||
// descendants in their SaveData methods
|
// descendants in their SaveData methods
|
||||||
FMapInfo.BitCount := (Info.BytesPerPixel div Info.ChannelCount) * 8;
|
MapInfo.BitCount := (Info.BytesPerPixel div Info.ChannelCount) * 8;
|
||||||
FMapInfo.Depth := Info.ChannelCount;
|
MapInfo.Depth := Info.ChannelCount;
|
||||||
if FMapInfo.TupleType = ttInvalid then
|
if MapInfo.TupleType = ttInvalid then
|
||||||
begin
|
begin
|
||||||
if Info.HasGrayChannel then
|
if Info.HasGrayChannel then
|
||||||
begin
|
begin
|
||||||
if Info.HasAlphaChannel then
|
if Info.HasAlphaChannel then
|
||||||
FMapInfo.TupleType := ttGrayScaleAlpha
|
MapInfo.TupleType := ttGrayScaleAlpha
|
||||||
else
|
else
|
||||||
FMapInfo.TupleType := ttGrayScale;
|
MapInfo.TupleType := ttGrayScale;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
if Info.HasAlphaChannel then
|
if Info.HasAlphaChannel then
|
||||||
FMapInfo.TupleType := ttRGBAlpha
|
MapInfo.TupleType := ttRGBAlpha
|
||||||
else
|
else
|
||||||
FMapInfo.TupleType := ttRGB;
|
MapInfo.TupleType := ttRGB;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
// Write file header
|
// Write file header
|
||||||
WriteHeader;
|
WriteHeader;
|
||||||
|
|
||||||
if not FMapInfo.Binary then
|
if not MapInfo.Binary then
|
||||||
begin
|
begin
|
||||||
Src := Bits;
|
Src := Bits;
|
||||||
LineLength := 0;
|
LineLength := 0;
|
||||||
|
@ -656,12 +683,12 @@ begin
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
// Write binary images
|
// Write binary images
|
||||||
if not (FMapInfo.TupleType in [ttGrayScaleFP, ttRGBFP]) then
|
if not (MapInfo.TupleType in [ttGrayScaleFP, ttRGBFP]) then
|
||||||
begin
|
begin
|
||||||
// Save integer binary images
|
// Save integer binary images
|
||||||
if FMapInfo.BitCount = 8 then
|
if MapInfo.BitCount = 8 then
|
||||||
begin
|
begin
|
||||||
if FMapInfo.TupleType in [ttGrayScale, ttGrayScaleAlpha] then
|
if MapInfo.TupleType in [ttGrayScale, ttGrayScaleAlpha] then
|
||||||
begin
|
begin
|
||||||
// 8bit grayscale images can be written in one Write call
|
// 8bit grayscale images can be written in one Write call
|
||||||
Write(Handle, Bits, Size);
|
Write(Handle, Bits, Size);
|
||||||
|
@ -674,7 +701,7 @@ begin
|
||||||
for I := 0 to Width * Height - 1 do
|
for I := 0 to Width * Height - 1 do
|
||||||
with PColor32Rec(Src)^ do
|
with PColor32Rec(Src)^ do
|
||||||
begin
|
begin
|
||||||
if FMapInfo.TupleType = ttRGBAlpha then
|
if MapInfo.TupleType = ttRGBAlpha then
|
||||||
Pixel32.A := A;
|
Pixel32.A := A;
|
||||||
Pixel32.R := B;
|
Pixel32.R := B;
|
||||||
Pixel32.G := G;
|
Pixel32.G := G;
|
||||||
|
@ -688,7 +715,7 @@ begin
|
||||||
begin
|
begin
|
||||||
// Images with 16bit channels: make sure that channel values are saved in big endian
|
// Images with 16bit channels: make sure that channel values are saved in big endian
|
||||||
Src := Bits;
|
Src := Bits;
|
||||||
if FMapInfo.TupleType in [ttGrayScale, ttGrayScaleAlpha] then
|
if MapInfo.TupleType in [ttGrayScale, ttGrayScaleAlpha] then
|
||||||
begin
|
begin
|
||||||
// 16bit grayscale image
|
// 16bit grayscale image
|
||||||
for I := 0 to Width * Height * Info.BytesPerPixel div SizeOf(Word) - 1 do
|
for I := 0 to Width * Height * Info.BytesPerPixel div SizeOf(Word) - 1 do
|
||||||
|
@ -704,7 +731,7 @@ begin
|
||||||
for I := 0 to Width * Height - 1 do
|
for I := 0 to Width * Height - 1 do
|
||||||
with PColor64Rec(Src)^ do
|
with PColor64Rec(Src)^ do
|
||||||
begin
|
begin
|
||||||
if FMapInfo.TupleType = ttRGBAlpha then
|
if MapInfo.TupleType = ttRGBAlpha then
|
||||||
Pixel64.A := SwapEndianWord(A);
|
Pixel64.A := SwapEndianWord(A);
|
||||||
Pixel64.R := SwapEndianWord(B);
|
Pixel64.R := SwapEndianWord(B);
|
||||||
Pixel64.G := SwapEndianWord(G);
|
Pixel64.G := SwapEndianWord(G);
|
||||||
|
@ -719,7 +746,7 @@ begin
|
||||||
begin
|
begin
|
||||||
// Floating point images (no need to swap endian here - little
|
// Floating point images (no need to swap endian here - little
|
||||||
// endian is specified in file header)
|
// endian is specified in file header)
|
||||||
if FMapInfo.TupleType = ttGrayScaleFP then
|
if MapInfo.TupleType = ttGrayScaleFP then
|
||||||
begin
|
begin
|
||||||
// Grayscale images can be written in one Write call
|
// Grayscale images can be written in one Write call
|
||||||
Write(Handle, Bits, Size);
|
Write(Handle, Bits, Size);
|
||||||
|
@ -787,11 +814,13 @@ end;
|
||||||
|
|
||||||
function TPGMFileFormat.SaveData(Handle: TImagingHandle;
|
function TPGMFileFormat.SaveData(Handle: TImagingHandle;
|
||||||
const Images: TDynImageDataArray; Index: Integer): Boolean;
|
const Images: TDynImageDataArray; Index: Integer): Boolean;
|
||||||
|
var
|
||||||
|
MapInfo: TPortableMapInfo;
|
||||||
begin
|
begin
|
||||||
FillChar(FMapInfo, SizeOf(FMapInfo), 0);
|
FillChar(MapInfo, SizeOf(MapInfo), 0);
|
||||||
FMapInfo.FormatId := Iff(FSaveBinary, FIdNumbers[1], FIdNumbers[0]);
|
MapInfo.FormatId := Iff(FSaveBinary, FIdNumbers[1], FIdNumbers[0]);
|
||||||
FMapInfo.Binary := FSaveBinary;
|
MapInfo.Binary := FSaveBinary;
|
||||||
Result := inherited SaveData(Handle, Images, Index);
|
Result := SaveDataInternal(Handle, Images, Index, MapInfo);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TPGMFileFormat.ConvertToSupported(var Image: TImageData;
|
procedure TPGMFileFormat.ConvertToSupported(var Image: TImageData;
|
||||||
|
@ -831,11 +860,13 @@ end;
|
||||||
|
|
||||||
function TPPMFileFormat.SaveData(Handle: TImagingHandle;
|
function TPPMFileFormat.SaveData(Handle: TImagingHandle;
|
||||||
const Images: TDynImageDataArray; Index: Integer): Boolean;
|
const Images: TDynImageDataArray; Index: Integer): Boolean;
|
||||||
|
var
|
||||||
|
MapInfo: TPortableMapInfo;
|
||||||
begin
|
begin
|
||||||
FillChar(FMapInfo, SizeOf(FMapInfo), 0);
|
FillChar(MapInfo, SizeOf(MapInfo), 0);
|
||||||
FMapInfo.FormatId := Iff(FSaveBinary, FIdNumbers[1], FIdNumbers[0]);
|
MapInfo.FormatId := Iff(FSaveBinary, FIdNumbers[1], FIdNumbers[0]);
|
||||||
FMapInfo.Binary := FSaveBinary;
|
MapInfo.Binary := FSaveBinary;
|
||||||
Result := inherited SaveData(Handle, Images, Index);
|
Result := SaveDataInternal(Handle, Images, Index, MapInfo);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TPPMFileFormat.ConvertToSupported(var Image: TImageData;
|
procedure TPPMFileFormat.ConvertToSupported(var Image: TImageData;
|
||||||
|
@ -873,12 +904,14 @@ end;
|
||||||
|
|
||||||
function TPAMFileFormat.SaveData(Handle: TImagingHandle;
|
function TPAMFileFormat.SaveData(Handle: TImagingHandle;
|
||||||
const Images: TDynImageDataArray; Index: Integer): Boolean;
|
const Images: TDynImageDataArray; Index: Integer): Boolean;
|
||||||
|
var
|
||||||
|
MapInfo: TPortableMapInfo;
|
||||||
begin
|
begin
|
||||||
FillChar(FMapInfo, SizeOf(FMapInfo), 0);
|
FillChar(MapInfo, SizeOf(MapInfo), 0);
|
||||||
FMapInfo.FormatId := FIdNumbers[0];
|
MapInfo.FormatId := FIdNumbers[0];
|
||||||
FMapInfo.Binary := True;
|
MapInfo.Binary := True;
|
||||||
FMapInfo.HasPAMHeader := True;
|
MapInfo.HasPAMHeader := True;
|
||||||
Result := inherited SaveData(Handle, Images, Index);
|
Result := SaveDataInternal(Handle, Images, Index, MapInfo);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TPAMFileFormat.ConvertToSupported(var Image: TImageData;
|
procedure TPAMFileFormat.ConvertToSupported(var Image: TImageData;
|
||||||
|
@ -915,16 +948,17 @@ function TPFMFileFormat.SaveData(Handle: TImagingHandle;
|
||||||
const Images: TDynImageDataArray; Index: Integer): Boolean;
|
const Images: TDynImageDataArray; Index: Integer): Boolean;
|
||||||
var
|
var
|
||||||
Info: TImageFormatInfo;
|
Info: TImageFormatInfo;
|
||||||
|
MapInfo: TPortableMapInfo;
|
||||||
begin
|
begin
|
||||||
FillChar(FMapInfo, SizeOf(FMapInfo), 0);
|
FillChar(MapInfo, SizeOf(MapInfo), 0);
|
||||||
Info := GetFormatInfo(Images[Index].Format);
|
Info := GetFormatInfo(Images[Index].Format);
|
||||||
if (Info.ChannelCount > 1) or Info.IsIndexed then
|
if (Info.ChannelCount > 1) or Info.IsIndexed then
|
||||||
FMapInfo.TupleType := ttRGBFP
|
MapInfo.TupleType := ttRGBFP
|
||||||
else
|
else
|
||||||
FMapInfo.TupleType := ttGrayScaleFP;
|
MapInfo.TupleType := ttGrayScaleFP;
|
||||||
FMapInfo.FormatId := Iff(FMapInfo.TupleType = ttGrayScaleFP, FIdNumbers[1], FIdNumbers[0]);
|
MapInfo.FormatId := Iff(MapInfo.TupleType = ttGrayScaleFP, FIdNumbers[1], FIdNumbers[0]);
|
||||||
FMapInfo.Binary := True;
|
MapInfo.Binary := True;
|
||||||
Result := inherited SaveData(Handle, Images, Index);
|
Result := SaveDataInternal(Handle, Images, Index, MapInfo);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TPFMFileFormat.ConvertToSupported(var Image: TImageData;
|
procedure TPFMFileFormat.ConvertToSupported(var Image: TImageData;
|
||||||
|
@ -949,6 +983,10 @@ initialization
|
||||||
-- TODOS ----------------------------------------------------
|
-- TODOS ----------------------------------------------------
|
||||||
- nothing now
|
- nothing now
|
||||||
|
|
||||||
|
-- 0.24.3 Changes/Bug Fixes -----------------------------------
|
||||||
|
- Improved compatibility of 16bit/component image loading.
|
||||||
|
- Changes for better thread safety.
|
||||||
|
|
||||||
-- 0.21 Changes/Bug Fixes -----------------------------------
|
-- 0.21 Changes/Bug Fixes -----------------------------------
|
||||||
- Made modifications to ASCII PNM loading to be more "stream-safe".
|
- Made modifications to ASCII PNM loading to be more "stream-safe".
|
||||||
- Fixed bug: indexed images saved as grayscale in PFM.
|
- Fixed bug: indexed images saved as grayscale in PFM.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
$Id: ImagingTypes.pas 112 2007-12-11 19:43:15Z galfar $
|
$Id: ImagingTypes.pas 132 2008-08-27 20:37:38Z galfar $
|
||||||
Vampyre Imaging Library
|
Vampyre Imaging Library
|
||||||
by Marek Mauder
|
by Marek Mauder
|
||||||
http://imaginglib.sourceforge.net
|
http://imaginglib.sourceforge.net
|
||||||
|
@ -37,9 +37,9 @@ const
|
||||||
{ Current Major version of Imaging.}
|
{ Current Major version of Imaging.}
|
||||||
ImagingVersionMajor = 0;
|
ImagingVersionMajor = 0;
|
||||||
{ Current Minor version of Imaging.}
|
{ Current Minor version of Imaging.}
|
||||||
ImagingVersionMinor = 24;
|
ImagingVersionMinor = 26;
|
||||||
{ Current patch of Imaging.}
|
{ Current patch of Imaging.}
|
||||||
ImagingVersionPatch = 2;
|
ImagingVersionPatch = 0;
|
||||||
|
|
||||||
{ Imaging Option Ids whose values can be set/get by SetOption/
|
{ Imaging Option Ids whose values can be set/get by SetOption/
|
||||||
GetOption functions.}
|
GetOption functions.}
|
||||||
|
@ -137,6 +137,11 @@ const
|
||||||
Allowed values are 0 (store as text - very! large files) and 1 (save binary).
|
Allowed values are 0 (store as text - very! large files) and 1 (save binary).
|
||||||
Default value is 1.}
|
Default value is 1.}
|
||||||
ImagingPPMSaveBinary = 51;
|
ImagingPPMSaveBinary = 51;
|
||||||
|
{ Boolean option that specifies whether GIF images with more frames
|
||||||
|
are animated by Imaging (according to frame disposal methods) or just
|
||||||
|
raw frames are loaded and sent to user (if you want to animate GIF yourself).
|
||||||
|
Default value is 1.}
|
||||||
|
ImagingGIFLoadAnimated = 56;
|
||||||
|
|
||||||
|
|
||||||
{ This option is used when reducing number of colors used in
|
{ This option is used when reducing number of colors used in
|
||||||
|
@ -225,7 +230,9 @@ type
|
||||||
ifDXT1 = 220,
|
ifDXT1 = 220,
|
||||||
ifDXT3 = 221,
|
ifDXT3 = 221,
|
||||||
ifDXT5 = 222,
|
ifDXT5 = 222,
|
||||||
ifBTC = 223);
|
ifBTC = 223,
|
||||||
|
ifATI1N = 224,
|
||||||
|
ifATI2N = 225);
|
||||||
|
|
||||||
{ Color value for 32 bit images.}
|
{ Color value for 32 bit images.}
|
||||||
TColor32 = LongWord;
|
TColor32 = LongWord;
|
||||||
|
@ -439,11 +446,9 @@ implementation
|
||||||
|
|
||||||
-- TODOS ----------------------------------------------------
|
-- TODOS ----------------------------------------------------
|
||||||
- add lookup tables to pixel formats for fast conversions
|
- add lookup tables to pixel formats for fast conversions
|
||||||
- change TImageFormatInfo - add new fields that shoudl replace old chaos
|
|
||||||
like not knowing whether it is RGB without checking all other fields for False
|
-- 0.24.3 Changes/Bug Fixes ---------------------------------
|
||||||
(add something like FormatType = (ftIndexed, ftRGB, ftIntensity, ftCompressed,
|
- Added ifATI1N and ifATI2N image data formats.
|
||||||
ftFloatingPoint, ftRGBBitFields) and additional infos like HasAlphaChannel,
|
|
||||||
ChannelSize, ChannelCount, ...)
|
|
||||||
|
|
||||||
-- 0.23 Changes/Bug Fixes -----------------------------------
|
-- 0.23 Changes/Bug Fixes -----------------------------------
|
||||||
- Added ifBTC image format and SpecialNearestFormat field
|
- Added ifBTC image format and SpecialNearestFormat field
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
$Id: ImagingUtility.pas 86 2007-06-12 22:39:08Z galfar $
|
$Id: ImagingUtility.pas 128 2008-07-23 11:57:36Z galfar $
|
||||||
Vampyre Imaging Library
|
Vampyre Imaging Library
|
||||||
by Marek Mauder
|
by Marek Mauder
|
||||||
http://imaginglib.sourceforge.net
|
http://imaginglib.sourceforge.net
|
||||||
|
@ -56,6 +56,9 @@ type
|
||||||
TBooleanArray = array[0..MaxInt - 1] of Boolean;
|
TBooleanArray = array[0..MaxInt - 1] of Boolean;
|
||||||
PBooleanArray = ^TBooleanArray;
|
PBooleanArray = ^TBooleanArray;
|
||||||
|
|
||||||
|
TDynIntegerArray = array of Integer;
|
||||||
|
TDynBooleanArray = array of Boolean;
|
||||||
|
|
||||||
TWordRec = packed record
|
TWordRec = packed record
|
||||||
case Integer of
|
case Integer of
|
||||||
0: (WordValue: Word);
|
0: (WordValue: Word);
|
||||||
|
@ -119,8 +122,10 @@ procedure FreeMemNil(var P); {$IFDEF USE_INLINE}inline;{$ENDIF}
|
||||||
procedure FreeMem(P: Pointer); {$IFDEF USE_INLINE}inline;{$ENDIF}
|
procedure FreeMem(P: Pointer); {$IFDEF USE_INLINE}inline;{$ENDIF}
|
||||||
{ Returns current exception object. Do not call outside exception handler.}
|
{ Returns current exception object. Do not call outside exception handler.}
|
||||||
function GetExceptObject: Exception; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
function GetExceptObject: Exception; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
||||||
{ Returns time value with microsecond resolution. Use for some time counters.}
|
{ Returns time value with microsecond resolution.}
|
||||||
function GetTimeMicroseconds: Int64;
|
function GetTimeMicroseconds: Int64;
|
||||||
|
{ Returns time value with milisecond resolution.}
|
||||||
|
function GetTimeMilliseconds: Int64;
|
||||||
|
|
||||||
{ Returns file extension (without "." dot)}
|
{ Returns file extension (without "." dot)}
|
||||||
function GetFileExt(const FileName: string): string;
|
function GetFileExt(const FileName: string): string;
|
||||||
|
@ -128,7 +133,7 @@ function GetFileExt(const FileName: string): string;
|
||||||
function GetAppExe: string;
|
function GetAppExe: string;
|
||||||
{ Returns directory where application's exceutable is located without
|
{ Returns directory where application's exceutable is located without
|
||||||
path delimiter at the end.}
|
path delimiter at the end.}
|
||||||
function GetAppDir:string;
|
function GetAppDir: string;
|
||||||
{ Returns True if FileName matches given Mask with optional case sensitivity.
|
{ Returns True if FileName matches given Mask with optional case sensitivity.
|
||||||
Mask can contain ? and * special characters: ? matches
|
Mask can contain ? and * special characters: ? matches
|
||||||
one character, * matches zero or more characters.}
|
one character, * matches zero or more characters.}
|
||||||
|
@ -151,6 +156,10 @@ function PosNoCase(const SubStr, S: string; Offset: LongInt = 1): LongInt; {$IFD
|
||||||
function StrToken(var S: string; Sep: Char): string;
|
function StrToken(var S: string; Sep: Char): string;
|
||||||
{ Same as StrToken but searches from the end of S string.}
|
{ Same as StrToken but searches from the end of S string.}
|
||||||
function StrTokenEnd(var S: string; Sep: Char): string;
|
function StrTokenEnd(var S: string; Sep: Char): string;
|
||||||
|
{ Returns string representation of integer number (with digit grouping).}
|
||||||
|
function IntToStrFmt(const I: Int64): string;
|
||||||
|
{ Returns string representation of float number (with digit grouping).}
|
||||||
|
function FloatToStrFmt(const F: Double; Precision: Integer = 2): string;
|
||||||
|
|
||||||
{ Clamps integer value to range <Min, Max>}
|
{ Clamps integer value to range <Min, Max>}
|
||||||
function ClampInt(Number: LongInt; Min, Max: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
function ClampInt(Number: LongInt; Min, Max: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
||||||
|
@ -235,6 +244,7 @@ procedure SwapEndianWord(P: PWordArray; Count: LongInt); overload;
|
||||||
function SwapEndianLongWord(Value: LongWord): LongWord; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
function SwapEndianLongWord(Value: LongWord): LongWord; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
||||||
{ Swaps byte order of multiple LongWord values.}
|
{ Swaps byte order of multiple LongWord values.}
|
||||||
procedure SwapEndianLongWord(P: PLongWord; Count: LongInt); overload;
|
procedure SwapEndianLongWord(P: PLongWord; Count: LongInt); overload;
|
||||||
|
|
||||||
{ Calculates CRC32 for the given data.}
|
{ Calculates CRC32 for the given data.}
|
||||||
procedure CalcCrc32(var Crc: LongWord; Data: Pointer; Size: LongInt);
|
procedure CalcCrc32(var Crc: LongWord; Data: Pointer; Size: LongInt);
|
||||||
{ Fills given memory with given Byte value. Size is size of buffer in bytes.}
|
{ Fills given memory with given Byte value. Size is size of buffer in bytes.}
|
||||||
|
@ -385,6 +395,11 @@ asm
|
||||||
end;
|
end;
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
|
|
||||||
|
function GetTimeMilliseconds: Int64;
|
||||||
|
begin
|
||||||
|
Result := GetTimeMicroseconds div 1000;
|
||||||
|
end;
|
||||||
|
|
||||||
function GetFileExt(const FileName: string): string;
|
function GetFileExt(const FileName: string): string;
|
||||||
begin
|
begin
|
||||||
Result := ExtractFileExt(FileName);
|
Result := ExtractFileExt(FileName);
|
||||||
|
@ -418,7 +433,7 @@ begin
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function GetAppDir:string;
|
function GetAppDir: string;
|
||||||
begin
|
begin
|
||||||
Result := ExtractFileDir(GetAppExe);
|
Result := ExtractFileDir(GetAppExe);
|
||||||
end;
|
end;
|
||||||
|
@ -760,6 +775,16 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function IntToStrFmt(const I: Int64): string;
|
||||||
|
begin
|
||||||
|
Result := Format('%.0n', [I * 1.0]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function FloatToStrFmt(const F: Double; Precision: Integer): string;
|
||||||
|
begin
|
||||||
|
Result := Format('%.' + IntToStr(Precision) + 'n', [F]);
|
||||||
|
end;
|
||||||
|
|
||||||
function ClampInt(Number: LongInt; Min, Max: LongInt): LongInt;
|
function ClampInt(Number: LongInt; Min, Max: LongInt): LongInt;
|
||||||
begin
|
begin
|
||||||
Result := Number;
|
Result := Number;
|
||||||
|
@ -1371,7 +1396,6 @@ procedure ClipCopyBounds(var SrcX, SrcY, Width, Height, DstX, DstY: LongInt; Src
|
||||||
begin
|
begin
|
||||||
Diff := DstClipMin - DstPos;
|
Diff := DstClipMin - DstPos;
|
||||||
Size := Size - Diff;
|
Size := Size - Diff;
|
||||||
if DstPos < SrcPos then
|
|
||||||
SrcPos := SrcPos + Diff;
|
SrcPos := SrcPos + Diff;
|
||||||
DstPos := DstClipMin;
|
DstPos := DstClipMin;
|
||||||
end;
|
end;
|
||||||
|
@ -1528,6 +1552,13 @@ initialization
|
||||||
-- TODOS ----------------------------------------------------
|
-- TODOS ----------------------------------------------------
|
||||||
- nothing now
|
- nothing now
|
||||||
|
|
||||||
|
-- 0.25.0 Changes/Bug Fixes -----------------------------------
|
||||||
|
- Fixed error in ClipCopyBounds which was causing ... bad clipping!
|
||||||
|
|
||||||
|
-- 0.24.3 Changes/Bug Fixes -----------------------------------
|
||||||
|
- Added GetTimeMilliseconds function.
|
||||||
|
- Added IntToStrFmt and FloatToStrFmt helper functions.
|
||||||
|
|
||||||
-- 0.23 Changes/Bug Fixes -----------------------------------
|
-- 0.23 Changes/Bug Fixes -----------------------------------
|
||||||
- Added RectInRect and RectIntersects functions
|
- Added RectInRect and RectIntersects functions
|
||||||
- Added some string utils: StrToken, StrTokenEnd, PosEx, PosNoCase.
|
- Added some string utils: StrToken, StrTokenEnd, PosEx, PosNoCase.
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<CONFIG>
|
||||||
|
<ProjectOptions>
|
||||||
|
<PathDelim Value="/"/>
|
||||||
|
<Version Value="6"/>
|
||||||
|
<General>
|
||||||
|
<MainUnit Value="0"/>
|
||||||
|
<TargetFileExt Value=""/>
|
||||||
|
<ActiveEditorIndexAtStart Value="0"/>
|
||||||
|
</General>
|
||||||
|
<VersionInfo>
|
||||||
|
<ProjectVersion Value=""/>
|
||||||
|
<Language Value=""/>
|
||||||
|
<CharSet Value=""/>
|
||||||
|
</VersionInfo>
|
||||||
|
<PublishOptions>
|
||||||
|
<Version Value="2"/>
|
||||||
|
<IgnoreBinaries Value="False"/>
|
||||||
|
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
|
||||||
|
<ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
|
||||||
|
</PublishOptions>
|
||||||
|
<RunParams>
|
||||||
|
<local>
|
||||||
|
<FormatVersion Value="1"/>
|
||||||
|
<LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
|
||||||
|
</local>
|
||||||
|
</RunParams>
|
||||||
|
<Units Count="1">
|
||||||
|
<Unit0>
|
||||||
|
<Filename Value="cedserver_config_2_3.lpr"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
<UnitName Value="cedserver_config_2_3"/>
|
||||||
|
<CursorPos X="31" Y="72"/>
|
||||||
|
<TopLine Value="56"/>
|
||||||
|
<EditorIndex Value="0"/>
|
||||||
|
<UsageCount Value="20"/>
|
||||||
|
<Loaded Value="True"/>
|
||||||
|
</Unit0>
|
||||||
|
</Units>
|
||||||
|
<JumpHistory Count="3" HistoryIndex="2">
|
||||||
|
<Position1>
|
||||||
|
<Filename Value="cedserver_config_2_3.lpr"/>
|
||||||
|
<Caret Line="106" Column="3" TopLine="30"/>
|
||||||
|
</Position1>
|
||||||
|
<Position2>
|
||||||
|
<Filename Value="cedserver_config_2_3.lpr"/>
|
||||||
|
<Caret Line="51" Column="66" TopLine="21"/>
|
||||||
|
</Position2>
|
||||||
|
<Position3>
|
||||||
|
<Filename Value="cedserver_config_2_3.lpr"/>
|
||||||
|
<Caret Line="44" Column="39" TopLine="27"/>
|
||||||
|
</Position3>
|
||||||
|
</JumpHistory>
|
||||||
|
</ProjectOptions>
|
||||||
|
<CompilerOptions>
|
||||||
|
<Version Value="8"/>
|
||||||
|
<Parsing>
|
||||||
|
<SyntaxOptions>
|
||||||
|
<CStyleOperator Value="False"/>
|
||||||
|
</SyntaxOptions>
|
||||||
|
</Parsing>
|
||||||
|
<CodeGeneration>
|
||||||
|
<SmartLinkUnit Value="True"/>
|
||||||
|
</CodeGeneration>
|
||||||
|
<Linking>
|
||||||
|
<Debugging>
|
||||||
|
<UseLineInfoUnit Value="False"/>
|
||||||
|
<StripSymbols Value="True"/>
|
||||||
|
</Debugging>
|
||||||
|
<LinkSmart Value="True"/>
|
||||||
|
</Linking>
|
||||||
|
<Other>
|
||||||
|
<CompilerPath Value="$(CompPath)"/>
|
||||||
|
</Other>
|
||||||
|
</CompilerOptions>
|
||||||
|
</CONFIG>
|
Loading…
Reference in New Issue