2012-06-08 14:14:58 +00:00
|
|
|
{ Graphic functions for pyramidtiff.
|
|
|
|
|
|
|
|
Copyright (C) 2008 Mattias Gaertner mattias@freepascal.org
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify it
|
|
|
|
under the terms of the GNU Library General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or (at your
|
|
|
|
option) any later version with the following modification:
|
|
|
|
|
|
|
|
As a special exception, the copyright holders of this library give you
|
|
|
|
permission to link this library with independent modules to produce an
|
|
|
|
executable, regardless of the license terms of these independent modules,and
|
|
|
|
to copy and distribute the resulting executable under terms of your choice,
|
|
|
|
provided that you also meet, for each linked independent module, the terms
|
|
|
|
and conditions of the license of that module. An independent module is a
|
|
|
|
module which is not derived from or based on this library. If you modify
|
|
|
|
this library, you may extend this exception to your version of the library,
|
|
|
|
but you are not obligated to do so. If you do not wish to do so, delete this
|
|
|
|
exception statement from your version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
|
|
|
for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; if not, write to the Free Software Foundation,
|
|
|
|
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
}
|
|
|
|
unit PyTiGraphics;
|
|
|
|
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
|
|
|
|
{$inline on}
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
uses
|
2012-06-10 15:05:31 +00:00
|
|
|
Math, sysutils, Classes, FPimage,
|
2012-06-08 14:14:58 +00:00
|
|
|
LazLogger, FPCanvas, FPWriteTiff, FPTiffCmn;
|
|
|
|
|
|
|
|
type
|
|
|
|
TPTMemImgDesc = record
|
2012-06-10 15:05:31 +00:00
|
|
|
Gray: boolean; // true = red=green=blue, false: a RGB image
|
|
|
|
Depth: word; // 8 or 16 bit
|
2012-06-08 14:14:58 +00:00
|
|
|
HasAlpha: boolean;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ TPTMemImgBase }
|
|
|
|
|
|
|
|
TPTMemImgBase = class(TFPCustomImage)
|
|
|
|
private
|
|
|
|
FDesc: TPTMemImgDesc;
|
|
|
|
public
|
|
|
|
property Desc: TPTMemImgDesc read FDesc;
|
|
|
|
end;
|
|
|
|
TPTMemImgBaseClass = class of TPTMemImgBase;
|
|
|
|
|
|
|
|
{ TPTMemImgGray16Bit }
|
|
|
|
|
|
|
|
TPTMemImgGray16Bit = class(TPTMemImgBase)
|
|
|
|
protected
|
|
|
|
FData: PWord;
|
|
|
|
function GetInternalColor(x, y: integer): TFPColor; override;
|
|
|
|
function GetInternalPixel({%H-}x, {%H-}y: integer): integer; override;
|
|
|
|
procedure SetInternalColor (x, y: integer; const Value: TFPColor); override;
|
|
|
|
procedure SetInternalPixel({%H-}x, {%H-}y: integer; {%H-}Value: integer); override;
|
|
|
|
public
|
|
|
|
constructor Create(AWidth, AHeight: integer); override;
|
|
|
|
destructor Destroy; override;
|
|
|
|
procedure SetSize(AWidth, AHeight: integer); override;
|
|
|
|
end;
|
|
|
|
|
|
|
|
TPTMemImgGrayAlpha16BitValue = packed record
|
|
|
|
g,a: word;
|
|
|
|
end;
|
|
|
|
PPTMemImgGrayAlpha16BitValue = ^TPTMemImgGrayAlpha16BitValue;
|
|
|
|
|
|
|
|
{ TPTMemImgGrayAlpha16Bit }
|
|
|
|
|
|
|
|
TPTMemImgGrayAlpha16Bit = class(TPTMemImgBase)
|
|
|
|
protected
|
|
|
|
FData: PPTMemImgGrayAlpha16BitValue;
|
|
|
|
function GetInternalColor(x, y: integer): TFPColor; override;
|
|
|
|
function GetInternalPixel({%H-}x, {%H-}y: integer): integer; override;
|
|
|
|
procedure SetInternalColor (x, y: integer; const Value: TFPColor); override;
|
|
|
|
procedure SetInternalPixel({%H-}x, {%H-}y: integer; {%H-}Value: integer); override;
|
|
|
|
public
|
|
|
|
constructor Create(AWidth, AHeight: integer); override;
|
|
|
|
destructor Destroy; override;
|
|
|
|
procedure SetSize(AWidth, AHeight: integer); override;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ TPTMemImgGray8Bit }
|
|
|
|
|
|
|
|
TPTMemImgGray8Bit = class(TPTMemImgBase)
|
|
|
|
protected
|
|
|
|
FData: PByte;
|
|
|
|
function GetInternalColor(x, y: integer): TFPColor; override;
|
|
|
|
function GetInternalPixel({%H-}x, {%H-}y: integer): integer; override;
|
|
|
|
procedure SetInternalColor (x, y: integer; const Value: TFPColor); override;
|
|
|
|
procedure SetInternalPixel({%H-}x, {%H-}y: integer; {%H-}Value: integer); override;
|
|
|
|
public
|
|
|
|
constructor Create(AWidth, AHeight: integer); override;
|
|
|
|
destructor Destroy; override;
|
|
|
|
procedure SetSize(AWidth, AHeight: integer); override;
|
|
|
|
end;
|
|
|
|
|
|
|
|
TPTMemImgGrayAlpha8BitValue = packed record
|
|
|
|
g,a: byte;
|
|
|
|
end;
|
|
|
|
PPTMemImgGrayAlpha8BitValue = ^TPTMemImgGrayAlpha8BitValue;
|
|
|
|
|
|
|
|
{ TPTMemImgGrayAlpha8Bit }
|
|
|
|
|
|
|
|
TPTMemImgGrayAlpha8Bit = class(TPTMemImgBase)
|
|
|
|
protected
|
|
|
|
FData: PPTMemImgGrayAlpha8BitValue;
|
|
|
|
function GetInternalColor(x, y: integer): TFPColor; override;
|
|
|
|
function GetInternalPixel({%H-}x, {%H-}y: integer): integer; override;
|
|
|
|
procedure SetInternalColor (x, y: integer; const Value: TFPColor); override;
|
|
|
|
procedure SetInternalPixel({%H-}x, {%H-}y: integer; {%H-}Value: integer); override;
|
|
|
|
public
|
|
|
|
constructor Create(AWidth, AHeight: integer); override;
|
|
|
|
destructor Destroy; override;
|
|
|
|
procedure SetSize(AWidth, AHeight: integer); override;
|
|
|
|
end;
|
|
|
|
|
|
|
|
TPTMemImgRGBA8BitValue = packed record
|
|
|
|
r,g,b,a: byte;
|
|
|
|
end;
|
|
|
|
PPTMemImgRGBA8BitValue = ^TPTMemImgRGBA8BitValue;
|
|
|
|
|
|
|
|
{ TPTMemImgRGBA8Bit }
|
|
|
|
|
|
|
|
TPTMemImgRGBA8Bit = class(TPTMemImgBase)
|
|
|
|
protected
|
|
|
|
FData: PPTMemImgRGBA8BitValue;
|
|
|
|
function GetInternalColor(x, y: integer): TFPColor; override;
|
|
|
|
function GetInternalPixel({%H-}x, {%H-}y: integer): integer; override;
|
|
|
|
procedure SetInternalColor (x, y: integer; const Value: TFPColor); override;
|
|
|
|
procedure SetInternalPixel({%H-}x, {%H-}y: integer; {%H-}Value: integer); override;
|
|
|
|
public
|
|
|
|
constructor Create(AWidth, AHeight: integer); override;
|
|
|
|
destructor Destroy; override;
|
|
|
|
procedure SetSize(AWidth, AHeight: integer); override;
|
|
|
|
end;
|
|
|
|
|
|
|
|
TPTMemImgRGB8BitValue = packed record
|
|
|
|
r,g,b: byte;
|
|
|
|
end;
|
|
|
|
PPTMemImgRGB8BitValue = ^TPTMemImgRGB8BitValue;
|
|
|
|
|
|
|
|
{ TPTMemImgRGB8Bit }
|
|
|
|
|
|
|
|
TPTMemImgRGB8Bit = class(TPTMemImgBase)
|
|
|
|
protected
|
|
|
|
FData: PPTMemImgRGB8BitValue;
|
|
|
|
function GetInternalColor(x, y: integer): TFPColor; override;
|
|
|
|
function GetInternalPixel({%H-}x, {%H-}y: integer): integer; override;
|
|
|
|
procedure SetInternalColor (x, y: integer; const Value: TFPColor); override;
|
|
|
|
procedure SetInternalPixel({%H-}x, {%H-}y: integer; {%H-}Value: integer); override;
|
|
|
|
public
|
|
|
|
constructor Create(AWidth, AHeight: integer); override;
|
|
|
|
destructor Destroy; override;
|
|
|
|
procedure SetSize(AWidth, AHeight: integer); override;
|
|
|
|
end;
|
|
|
|
|
|
|
|
TPTMemImgRGB16BitValue = packed record
|
|
|
|
r,g,b: word;
|
|
|
|
end;
|
|
|
|
PPTMemImgRGB16BitValue = ^TPTMemImgRGB16BitValue;
|
|
|
|
|
|
|
|
{ TPTMemImgRGB16Bit }
|
|
|
|
|
|
|
|
TPTMemImgRGB16Bit = class(TPTMemImgBase)
|
|
|
|
protected
|
|
|
|
FData: PPTMemImgRGB16BitValue;
|
|
|
|
function GetInternalColor(x, y: integer): TFPColor; override;
|
|
|
|
function GetInternalPixel({%H-}x, {%H-}y: integer): integer; override;
|
|
|
|
procedure SetInternalColor (x, y: integer; const Value: TFPColor); override;
|
|
|
|
procedure SetInternalPixel({%H-}x, {%H-}y: integer; {%H-}Value: integer); override;
|
|
|
|
public
|
|
|
|
constructor Create(AWidth, AHeight: integer); override;
|
|
|
|
destructor Destroy; override;
|
|
|
|
procedure SetSize(AWidth, AHeight: integer); override;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ TPTMemImgRGBA16Bit }
|
|
|
|
|
|
|
|
TPTMemImgRGBA16Bit = class(TPTMemImgBase)
|
|
|
|
protected
|
|
|
|
FData: PFPColor;
|
|
|
|
function GetInternalColor(x, y: integer): TFPColor; override;
|
|
|
|
function GetInternalPixel({%H-}x, {%H-}y: integer): integer; override;
|
|
|
|
procedure SetInternalColor (x, y: integer; const Value: TFPColor); override;
|
|
|
|
procedure SetInternalPixel({%H-}x, {%H-}y: integer; {%H-}Value: integer); override;
|
|
|
|
public
|
|
|
|
constructor Create(AWidth, AHeight: integer); override;
|
|
|
|
destructor Destroy; override;
|
|
|
|
procedure SetSize(AWidth, AHeight: integer); override;
|
|
|
|
end;
|
|
|
|
|
|
|
|
TCreateCompatibleMemImgEvent = procedure(Sender: TObject; Img: TFPCustomImage;
|
|
|
|
NewWidth, NewHeight: integer; out NewImage: TFPCustomImage) of object;
|
|
|
|
|
|
|
|
{ TLinearInterpolation }
|
|
|
|
|
|
|
|
TLinearInterpolation = class(TFPCustomInterpolation)
|
|
|
|
private
|
|
|
|
procedure CreatePixelWeights(OldSize, NewSize: integer;
|
|
|
|
out Entries: Pointer; out EntrySize: integer; out Support: integer);
|
|
|
|
protected
|
|
|
|
procedure Execute(x,y,w,h: integer); override;
|
|
|
|
function Filter(x: double): double; virtual;
|
|
|
|
function MaxSupport: double; virtual;
|
|
|
|
end;
|
|
|
|
|
2012-06-10 15:51:32 +00:00
|
|
|
{ Create a descriptor to select a memimg class }
|
2012-06-10 14:03:58 +00:00
|
|
|
function GetPTMemImgDesc(Gray: boolean; Depth: word; HasAlpha: boolean): TPTMemImgDesc;
|
2012-06-10 15:51:32 +00:00
|
|
|
|
|
|
|
{ Returns a memimg class that fits the descriptor }
|
2012-06-10 14:03:58 +00:00
|
|
|
function GetPTMemImgClass(const Desc: TPTMemImgDesc): TPTMemImgBaseClass;
|
2012-06-10 15:51:32 +00:00
|
|
|
|
|
|
|
{ Create a memimg with the descriptor }
|
2012-06-10 14:03:58 +00:00
|
|
|
function CreatePTMemImg(const Desc: TPTMemImgDesc; Width, Height: integer): TFPCustomImage;
|
2012-06-10 15:51:32 +00:00
|
|
|
|
|
|
|
{ Create a memimg with the same features as Img.
|
|
|
|
If Img is a TPTMemImgBaseClass it will create that.
|
|
|
|
Otherwise it returns a memimg that fits the Img using GetMinimumPTDesc. }
|
2012-06-10 14:03:58 +00:00
|
|
|
function CreateCompatiblePTMemImg(Img: TFPCustomImage; Width, Height: integer
|
2012-06-08 14:14:58 +00:00
|
|
|
): TFPCustomImage;
|
2012-06-10 15:51:32 +00:00
|
|
|
|
|
|
|
{ As CreateCompatiblePTMemImg, but the image has always an alpha channel. }
|
2012-06-10 14:03:58 +00:00
|
|
|
function CreateCompatiblePTMemImgWithAlpha(Img: TFPCustomImage;
|
2012-06-08 14:14:58 +00:00
|
|
|
Width, Height: integer): TFPCustomImage;
|
2012-06-10 15:51:32 +00:00
|
|
|
|
|
|
|
{ Returns the smallest descriptor that allows to store the Img.
|
|
|
|
It returns HasAlpha=false if all pixel are opaque.
|
|
|
|
It returns Gray=true if all red=green=blue.
|
|
|
|
It returns Depth=8 if all lo byte equals the hi byte or all lo bytes are 0.
|
|
|
|
To ignore rounding errors you can pass a FuzzyDepth. For example a FuzzyDepth
|
|
|
|
of 3 ignores the lower 3 bits when comparing. }
|
|
|
|
function GetMinimumPTDesc(Img: TFPCustomImage; FuzzyDepth: word = 4): TPTMemImgDesc;
|
|
|
|
|
|
|
|
{ Create a smaller memimg with the same information as Img.
|
|
|
|
Pass FreeImg=true to call Img.Free }
|
|
|
|
function GetMinimumPTMemImg(Img: TFPCustomImage; FreeImg: boolean;
|
|
|
|
FuzzyDepth: word = 4): TFPCustomImage;
|
2012-06-08 14:14:58 +00:00
|
|
|
|
|
|
|
procedure SetFPImgExtraTiff(const Desc: TPTMemImgDesc; Img: TFPCustomImage;
|
|
|
|
ClearTiffExtras: boolean);
|
|
|
|
|
|
|
|
function dbgs(const Desc: TPTMemImgDesc): string; overload;
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
|
|
procedure SetFPImgExtraTiff(const Desc: TPTMemImgDesc; Img: TFPCustomImage;
|
|
|
|
ClearTiffExtras: boolean);
|
|
|
|
begin
|
|
|
|
if ClearTiffExtras then
|
|
|
|
FPTiffCmn.ClearTiffExtras(Img);
|
|
|
|
if Desc.Gray then begin
|
|
|
|
Img.Extra[TiffPhotoMetric]:='1';
|
|
|
|
Img.Extra[TiffGrayBits]:=IntToStr(Desc.Depth);
|
|
|
|
end else begin
|
|
|
|
Img.Extra[TiffPhotoMetric]:='2';
|
|
|
|
Img.Extra[TiffRedBits]:=IntToStr(Desc.Depth);
|
|
|
|
Img.Extra[TiffGreenBits]:=IntToStr(Desc.Depth);
|
|
|
|
Img.Extra[TiffBlueBits]:=IntToStr(Desc.Depth);
|
|
|
|
end;
|
|
|
|
if Desc.HasAlpha then
|
|
|
|
Img.Extra[TiffAlphaBits]:=IntToStr(Desc.Depth)
|
|
|
|
else
|
|
|
|
Img.Extra[TiffAlphaBits]:='0';
|
|
|
|
end;
|
|
|
|
|
|
|
|
function dbgs(const Desc: TPTMemImgDesc): string;
|
|
|
|
begin
|
|
|
|
Result:='Depth='+dbgs(Desc.Depth)
|
|
|
|
+',Gray='+dbgs(Desc.Gray)
|
|
|
|
+',HasAlpha='+dbgs(Desc.HasAlpha);
|
|
|
|
end;
|
|
|
|
|
2012-06-10 14:03:58 +00:00
|
|
|
function GetPTMemImgDesc(Gray: boolean; Depth: word; HasAlpha: boolean
|
2012-06-08 14:14:58 +00:00
|
|
|
): TPTMemImgDesc;
|
|
|
|
begin
|
|
|
|
Result.Gray:=Gray;
|
|
|
|
Result.Depth:=Depth;
|
|
|
|
Result.HasAlpha:=HasAlpha;
|
|
|
|
end;
|
|
|
|
|
2012-06-10 14:03:58 +00:00
|
|
|
function GetPTMemImgClass(const Desc: TPTMemImgDesc): TPTMemImgBaseClass;
|
2012-06-08 14:14:58 +00:00
|
|
|
begin
|
|
|
|
if Desc.Gray then begin
|
|
|
|
if Desc.HasAlpha then begin
|
|
|
|
// gray, alpha
|
|
|
|
if Desc.Depth<=8 then
|
|
|
|
Result:=TPTMemImgGrayAlpha8Bit
|
|
|
|
else
|
|
|
|
Result:=TPTMemImgGrayAlpha16Bit;
|
|
|
|
end else begin
|
|
|
|
// gray, no alpha
|
|
|
|
if Desc.Depth<=8 then
|
|
|
|
Result:=TPTMemImgGray8Bit
|
|
|
|
else
|
|
|
|
Result:=TPTMemImgGray16Bit;
|
|
|
|
end;
|
|
|
|
end else begin
|
|
|
|
// RGB
|
|
|
|
if Desc.HasAlpha then begin
|
|
|
|
// RGB, alpha
|
|
|
|
if Desc.Depth<=8 then
|
|
|
|
Result:=TPTMemImgRGBA8Bit
|
|
|
|
else
|
|
|
|
Result:=TPTMemImgRGBA16Bit;
|
|
|
|
end else begin
|
|
|
|
// RGB, no alpha
|
|
|
|
if Desc.Depth<=8 then
|
|
|
|
Result:=TPTMemImgRGB8Bit
|
|
|
|
else
|
|
|
|
Result:=TPTMemImgRGB16Bit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2012-06-10 14:03:58 +00:00
|
|
|
function CreatePTMemImg(const Desc: TPTMemImgDesc; Width, Height: integer
|
2012-06-08 14:14:58 +00:00
|
|
|
): TFPCustomImage;
|
|
|
|
var
|
|
|
|
ImgClass: TPTMemImgBaseClass;
|
|
|
|
begin
|
2012-06-10 14:03:58 +00:00
|
|
|
ImgClass:=GetPTMemImgClass(Desc);
|
2012-06-08 14:14:58 +00:00
|
|
|
Result:=ImgClass.Create(Width,Height);
|
|
|
|
end;
|
|
|
|
|
2012-06-10 14:03:58 +00:00
|
|
|
function CreateCompatiblePTMemImg(Img: TFPCustomImage; Width, Height: integer
|
2012-06-08 14:14:58 +00:00
|
|
|
): TFPCustomImage;
|
|
|
|
begin
|
|
|
|
if Img is TPTMemImgBase then
|
2012-06-10 14:03:58 +00:00
|
|
|
Result:=CreatePTMemImg(TPTMemImgBase(Img).Desc,Width,Height)
|
2012-06-08 14:14:58 +00:00
|
|
|
else
|
2012-06-10 15:51:32 +00:00
|
|
|
Result:=CreatePTMemImg(GetMinimumPTDesc(Img),Width,Height);
|
2012-06-08 14:14:58 +00:00
|
|
|
//DebugLn(['CreateCompatibleQVMemImg '+Img.ClassName+' '+Result.ClassName]);
|
|
|
|
end;
|
|
|
|
|
2012-06-10 14:03:58 +00:00
|
|
|
function CreateCompatiblePTMemImgWithAlpha(Img: TFPCustomImage; Width,
|
2012-06-08 14:14:58 +00:00
|
|
|
Height: integer): TFPCustomImage;
|
|
|
|
var
|
|
|
|
Desc: TPTMemImgDesc;
|
|
|
|
begin
|
2012-06-10 15:51:32 +00:00
|
|
|
if Img is TPTMemImgBase then
|
|
|
|
Desc:=TPTMemImgBase(Img).Desc
|
|
|
|
else
|
|
|
|
Desc:=GetMinimumPTDesc(Img);
|
|
|
|
Desc.HasAlpha:=true;
|
|
|
|
Result:=CreatePTMemImg(Desc,Width,Height);
|
2012-06-08 14:14:58 +00:00
|
|
|
end;
|
|
|
|
|
2012-06-10 15:51:32 +00:00
|
|
|
function GetMinimumPTDesc(Img: TFPCustomImage; FuzzyDepth: word = 4): TPTMemImgDesc;
|
|
|
|
var
|
|
|
|
AllLoEqualsHi, AllLoAre0: Boolean;
|
|
|
|
FuzzyMaskLoHi: Word;
|
2012-06-08 14:14:58 +00:00
|
|
|
|
2012-06-10 15:51:32 +00:00
|
|
|
procedure Need16Bit(c: word); inline;
|
2012-06-08 14:14:58 +00:00
|
|
|
var
|
|
|
|
l: Byte;
|
|
|
|
begin
|
2012-06-10 15:51:32 +00:00
|
|
|
c:=c and FuzzyMaskLoHi;
|
2012-06-08 14:14:58 +00:00
|
|
|
l:=Lo(c);
|
2012-06-10 15:51:32 +00:00
|
|
|
AllLoAre0:=AllLoAre0 and (l=0);
|
|
|
|
AllLoEqualsHi:=AllLoEqualsHi and (l=Hi(c));
|
2012-06-08 14:14:58 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
var
|
|
|
|
TestGray: Boolean;
|
|
|
|
TestAlpha: Boolean;
|
|
|
|
Test16Bit: Boolean;
|
|
|
|
BaseImg: TPTMemImgBase;
|
|
|
|
ImgDesc: TPTMemImgDesc;
|
|
|
|
y: Integer;
|
|
|
|
x: Integer;
|
|
|
|
col: TFPColor;
|
2012-06-10 15:51:32 +00:00
|
|
|
FuzzyMaskWord: Word;
|
|
|
|
FuzzyOpaque: Word;
|
2012-06-08 14:14:58 +00:00
|
|
|
begin
|
|
|
|
TestGray:=true;
|
|
|
|
TestAlpha:=true;
|
2012-06-10 15:51:32 +00:00
|
|
|
Test16Bit:=FuzzyDepth<8;
|
2012-06-08 14:14:58 +00:00
|
|
|
Result.HasAlpha:=false;
|
|
|
|
Result.Gray:=true;
|
|
|
|
Result.Depth:=8;
|
|
|
|
if Img is TPTMemImgBase then begin
|
|
|
|
BaseImg:=TPTMemImgBase(Img);
|
|
|
|
ImgDesc:=BaseImg.Desc;
|
|
|
|
if ImgDesc.Depth<=8 then Test16Bit:=false;
|
|
|
|
if ImgDesc.Gray then TestGray:=false;
|
|
|
|
if not ImgDesc.HasAlpha then TestAlpha:=false;
|
|
|
|
end;
|
2012-06-10 15:51:32 +00:00
|
|
|
|
|
|
|
if (not TestGray) and (not TestAlpha) and (not Test16Bit) then exit;
|
|
|
|
|
|
|
|
FuzzyMaskWord:=Word($ffff) shl FuzzyDepth;
|
|
|
|
FuzzyOpaque:=alphaOpaque and FuzzyMaskWord;
|
|
|
|
FuzzyMaskLoHi:=Word(lo(FuzzyMaskWord))+(Word(lo(FuzzyMaskWord)) shl 8);
|
|
|
|
AllLoAre0:=true;
|
|
|
|
AllLoEqualsHi:=true;
|
2012-06-08 14:14:58 +00:00
|
|
|
for y:=0 to Img.Height-1 do begin
|
|
|
|
for x:=0 to Img.Width-1 do begin
|
|
|
|
col:=Img.Colors[x,y];
|
2012-06-10 15:51:32 +00:00
|
|
|
if TestAlpha and ((col.alpha and FuzzyMaskWord)<>FuzzyOpaque) then begin
|
2012-06-08 14:14:58 +00:00
|
|
|
TestAlpha:=false;
|
|
|
|
Result.HasAlpha:=true;
|
|
|
|
if (not TestGray) and (not Test16Bit) then break;
|
|
|
|
end;
|
|
|
|
if TestGray
|
2012-06-10 15:51:32 +00:00
|
|
|
and ((col.red and FuzzyMaskWord)<>(col.green and FuzzyMaskWord))
|
|
|
|
or ((col.red and FuzzyMaskWord)<>(col.blue and FuzzyMaskWord)) then begin
|
2012-06-08 14:14:58 +00:00
|
|
|
TestGray:=false;
|
|
|
|
Result.Gray:=false;
|
|
|
|
if (not TestAlpha) and (not Test16Bit) then break;
|
|
|
|
end;
|
|
|
|
if Test16Bit then begin
|
2012-06-10 15:51:32 +00:00
|
|
|
Need16Bit(col.red);
|
|
|
|
Need16Bit(col.green);
|
|
|
|
Need16Bit(col.blue);
|
|
|
|
Need16Bit(col.alpha);
|
|
|
|
if (not AllLoAre0) and (not AllLoEqualsHi) then begin
|
2012-06-08 14:14:58 +00:00
|
|
|
Test16Bit:=false;
|
|
|
|
Result.Depth:=16;
|
|
|
|
if (not TestAlpha) and (not TestGray) then break;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2012-06-10 15:51:32 +00:00
|
|
|
function GetMinimumPTMemImg(Img: TFPCustomImage; FreeImg: boolean;
|
|
|
|
FuzzyDepth: word = 4): TFPCustomImage;
|
2012-06-08 14:14:58 +00:00
|
|
|
var
|
|
|
|
Desc: TPTMemImgDesc;
|
|
|
|
ImgClass: TPTMemImgBaseClass;
|
|
|
|
y: Integer;
|
|
|
|
x: Integer;
|
|
|
|
begin
|
2012-06-10 15:51:32 +00:00
|
|
|
Desc:=GetMinimumPTDesc(Img,FuzzyDepth);
|
2012-06-08 14:14:58 +00:00
|
|
|
//debugln(['GetMinimumQVMemImg Depth=',Desc.Depth,' Gray=',Desc.Gray,' HasAlpha=',Desc.HasAlpha]);
|
2012-06-10 14:03:58 +00:00
|
|
|
ImgClass:=GetPTMemImgClass(Desc);
|
2012-06-08 14:14:58 +00:00
|
|
|
if Img.ClassType=ImgClass then
|
|
|
|
exit(Img);
|
2012-06-10 14:03:58 +00:00
|
|
|
Result:=CreatePTMemImg(Desc,Img.Width,Img.Height);
|
2012-06-08 14:14:58 +00:00
|
|
|
for y:=0 to Img.Height-1 do
|
|
|
|
for x:=0 to Img.Width-1 do
|
|
|
|
Result.Colors[x,y]:=Img.Colors[x,y];
|
|
|
|
if FreeImg then
|
|
|
|
Img.Free;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function ColorRound (c : double) : word;
|
|
|
|
begin
|
|
|
|
if c > $FFFF then
|
|
|
|
result := $FFFF
|
|
|
|
else if c < 0.0 then
|
|
|
|
result := 0
|
|
|
|
else
|
|
|
|
result := round(c);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ TPTMemImgGrayAlpha16Bit }
|
|
|
|
|
|
|
|
function TPTMemImgGrayAlpha16Bit.GetInternalColor(x, y: integer): TFPColor;
|
|
|
|
var
|
|
|
|
v: TPTMemImgGrayAlpha16BitValue;
|
|
|
|
begin
|
|
|
|
v:=FData[x+y*Width];
|
|
|
|
Result.red:=v.g;
|
|
|
|
Result.green:=Result.red;
|
|
|
|
Result.blue:=Result.red;
|
|
|
|
Result.alpha:=v.a;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TPTMemImgGrayAlpha16Bit.GetInternalPixel(x, y: integer): integer;
|
|
|
|
begin
|
|
|
|
Result:=0;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgGrayAlpha16Bit.SetInternalColor(x, y: integer;
|
|
|
|
const Value: TFPColor);
|
|
|
|
var
|
|
|
|
v: TPTMemImgGrayAlpha16BitValue;
|
|
|
|
begin
|
|
|
|
v.g:=Value.red;
|
|
|
|
v.a:=Value.alpha;
|
|
|
|
FData[x+y*Width]:=v;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgGrayAlpha16Bit.SetInternalPixel(x, y: integer; Value: integer
|
|
|
|
);
|
|
|
|
begin
|
|
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
constructor TPTMemImgGrayAlpha16Bit.Create(AWidth, AHeight: integer);
|
|
|
|
begin
|
2012-06-10 14:03:58 +00:00
|
|
|
FDesc:=GetPTMemImgDesc(true,16,true);
|
2012-06-08 14:14:58 +00:00
|
|
|
inherited Create(AWidth, AHeight);
|
|
|
|
end;
|
|
|
|
|
|
|
|
destructor TPTMemImgGrayAlpha16Bit.Destroy;
|
|
|
|
begin
|
|
|
|
ReAllocMem(FData,0);
|
|
|
|
inherited Destroy;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgGrayAlpha16Bit.SetSize(AWidth, AHeight: integer);
|
|
|
|
begin
|
|
|
|
if (AWidth=Width) and (AHeight=Height) then exit;
|
|
|
|
ReAllocMem(FData,SizeOf(TPTMemImgGrayAlpha16BitValue)*AWidth*AHeight);
|
|
|
|
inherited SetSize(AWidth, AHeight);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ TPTMemImgGrayAlpha8Bit }
|
|
|
|
|
|
|
|
function TPTMemImgGrayAlpha8Bit.GetInternalColor(x, y: integer): TFPColor;
|
|
|
|
var
|
|
|
|
v: TPTMemImgGrayAlpha8BitValue;
|
|
|
|
begin
|
|
|
|
v:=FData[x+y*Width];
|
|
|
|
Result.red:=(v.g shl 8)+v.g;
|
|
|
|
Result.green:=Result.red;
|
|
|
|
Result.blue:=Result.red;
|
|
|
|
Result.alpha:=(v.a shl 8)+v.a;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TPTMemImgGrayAlpha8Bit.GetInternalPixel(x, y: integer): integer;
|
|
|
|
begin
|
|
|
|
Result:=0;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgGrayAlpha8Bit.SetInternalColor(x, y: integer;
|
|
|
|
const Value: TFPColor);
|
|
|
|
var
|
|
|
|
v: TPTMemImgGrayAlpha8BitValue;
|
|
|
|
begin
|
|
|
|
v.g:=Value.red shr 8;
|
|
|
|
v.a:=Value.alpha shr 8;
|
|
|
|
FData[x+y*Width]:=v;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgGrayAlpha8Bit.SetInternalPixel(x, y: integer; Value: integer
|
|
|
|
);
|
|
|
|
begin
|
|
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
constructor TPTMemImgGrayAlpha8Bit.Create(AWidth, AHeight: integer);
|
|
|
|
begin
|
2012-06-10 14:03:58 +00:00
|
|
|
FDesc:=GetPTMemImgDesc(true,8,true);
|
2012-06-08 14:14:58 +00:00
|
|
|
inherited Create(AWidth, AHeight);
|
|
|
|
end;
|
|
|
|
|
|
|
|
destructor TPTMemImgGrayAlpha8Bit.Destroy;
|
|
|
|
begin
|
|
|
|
ReAllocMem(FData,0);
|
|
|
|
inherited Destroy;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgGrayAlpha8Bit.SetSize(AWidth, AHeight: integer);
|
|
|
|
begin
|
|
|
|
if (AWidth=Width) and (AHeight=Height) then exit;
|
|
|
|
ReAllocMem(FData,SizeOf(TPTMemImgGrayAlpha8BitValue)*AWidth*AHeight);
|
|
|
|
inherited SetSize(AWidth, AHeight);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ TPTMemImgGray16Bit }
|
|
|
|
|
|
|
|
function TPTMemImgGray16Bit.GetInternalColor(x, y: integer): TFPColor;
|
|
|
|
begin
|
|
|
|
Result.red:=FData[x+y*Width];
|
|
|
|
Result.green:=Result.red;
|
|
|
|
Result.blue:=Result.red;
|
|
|
|
Result.alpha:=alphaOpaque;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TPTMemImgGray16Bit.GetInternalPixel(x, y: integer): integer;
|
|
|
|
begin
|
|
|
|
Result:=0;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgGray16Bit.SetInternalColor(x, y: integer;
|
|
|
|
const Value: TFPColor);
|
|
|
|
begin
|
|
|
|
FData[x+y*Width]:=Value.red;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgGray16Bit.SetInternalPixel(x, y: integer; Value: integer);
|
|
|
|
begin
|
|
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
constructor TPTMemImgGray16Bit.Create(AWidth, AHeight: integer);
|
|
|
|
begin
|
2012-06-10 14:03:58 +00:00
|
|
|
FDesc:=GetPTMemImgDesc(true,16,false);
|
2012-06-08 14:14:58 +00:00
|
|
|
inherited Create(AWidth, AHeight);
|
|
|
|
end;
|
|
|
|
|
|
|
|
destructor TPTMemImgGray16Bit.Destroy;
|
|
|
|
begin
|
|
|
|
ReAllocMem(FData,0);
|
|
|
|
inherited Destroy;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgGray16Bit.SetSize(AWidth, AHeight: integer);
|
|
|
|
begin
|
|
|
|
if (AWidth=Width) and (AHeight=Height) then exit;
|
|
|
|
ReAllocMem(FData,SizeOf(Word)*AWidth*AHeight);
|
|
|
|
inherited SetSize(AWidth,AHeight);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ TPTMemImgGray8Bit }
|
|
|
|
|
|
|
|
function TPTMemImgGray8Bit.GetInternalColor(x, y: integer): TFPColor;
|
|
|
|
begin
|
|
|
|
Result.red:=FData[x+y*Width];
|
|
|
|
Result.red:=(Word(Result.red) shl 8)+Result.red;
|
|
|
|
Result.green:=Result.red;
|
|
|
|
Result.blue:=Result.red;
|
|
|
|
Result.alpha:=alphaOpaque;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TPTMemImgGray8Bit.GetInternalPixel(x, y: integer): integer;
|
|
|
|
begin
|
|
|
|
Result:=0;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgGray8Bit.SetInternalColor(x, y: integer;
|
|
|
|
const Value: TFPColor);
|
|
|
|
begin
|
|
|
|
FData[x+y*Width]:=Value.red shr 8;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgGray8Bit.SetInternalPixel(x, y: integer; Value: integer);
|
|
|
|
begin
|
|
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
constructor TPTMemImgGray8Bit.Create(AWidth, AHeight: integer);
|
|
|
|
begin
|
2012-06-10 14:03:58 +00:00
|
|
|
FDesc:=GetPTMemImgDesc(true,8,false);
|
2012-06-08 14:14:58 +00:00
|
|
|
inherited Create(AWidth, AHeight);
|
|
|
|
end;
|
|
|
|
|
|
|
|
destructor TPTMemImgGray8Bit.Destroy;
|
|
|
|
begin
|
|
|
|
ReAllocMem(FData,0);
|
|
|
|
inherited Destroy;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgGray8Bit.SetSize(AWidth, AHeight: integer);
|
|
|
|
begin
|
|
|
|
if (AWidth=Width) and (AHeight=Height) then exit;
|
|
|
|
ReAllocMem(FData,SizeOf(Byte)*AWidth*AHeight);
|
|
|
|
inherited SetSize(AWidth,AHeight);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ TPTMemImgRGBA8Bit }
|
|
|
|
|
|
|
|
function TPTMemImgRGBA8Bit.GetInternalColor(x, y: integer): TFPColor;
|
|
|
|
var
|
|
|
|
v: TPTMemImgRGBA8BitValue;
|
|
|
|
begin
|
|
|
|
v:=FData[x+y*Width];
|
|
|
|
Result.red:=(v.r shl 8)+v.r;
|
|
|
|
Result.green:=(v.g shl 8)+v.g;
|
|
|
|
Result.blue:=(v.b shl 8)+v.b;
|
|
|
|
Result.alpha:=(v.a shl 8)+v.a;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TPTMemImgRGBA8Bit.GetInternalPixel(x, y: integer): integer;
|
|
|
|
begin
|
|
|
|
Result:=0;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgRGBA8Bit.SetInternalColor(x, y: integer;
|
|
|
|
const Value: TFPColor);
|
|
|
|
var
|
|
|
|
v: TPTMemImgRGBA8BitValue;
|
|
|
|
begin
|
|
|
|
v.r:=Value.red shr 8;
|
|
|
|
v.g:=Value.green shr 8;
|
|
|
|
v.b:=Value.blue shr 8;
|
|
|
|
v.a:=Value.alpha shr 8;
|
|
|
|
FData[x+y*Width]:=v;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgRGBA8Bit.SetInternalPixel(x, y: integer; Value: integer);
|
|
|
|
begin
|
|
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
constructor TPTMemImgRGBA8Bit.Create(AWidth, AHeight: integer);
|
|
|
|
begin
|
2012-06-10 14:03:58 +00:00
|
|
|
FDesc:=GetPTMemImgDesc(false,8,true);
|
2012-06-08 14:14:58 +00:00
|
|
|
inherited Create(AWidth, AHeight);
|
|
|
|
end;
|
|
|
|
|
|
|
|
destructor TPTMemImgRGBA8Bit.Destroy;
|
|
|
|
begin
|
|
|
|
ReAllocMem(FData,0);
|
|
|
|
inherited Destroy;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgRGBA8Bit.SetSize(AWidth, AHeight: integer);
|
|
|
|
begin
|
|
|
|
if (AWidth=Width) and (AHeight=Height) then exit;
|
|
|
|
ReAllocMem(FData,SizeOf(TPTMemImgRGBA8BitValue)*AWidth*AHeight);
|
|
|
|
inherited SetSize(AWidth,AHeight);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ TPTMemImgRGB8Bit }
|
|
|
|
|
|
|
|
function TPTMemImgRGB8Bit.GetInternalColor(x, y: integer): TFPColor;
|
|
|
|
var
|
|
|
|
v: TPTMemImgRGB8BitValue;
|
|
|
|
begin
|
|
|
|
v:=FData[x+y*Width];
|
|
|
|
Result.red:=(v.r shl 8)+v.r;
|
|
|
|
Result.green:=(v.g shl 8)+v.g;
|
|
|
|
Result.blue:=(v.b shl 8)+v.b;
|
|
|
|
Result.alpha:=alphaOpaque;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TPTMemImgRGB8Bit.GetInternalPixel(x, y: integer): integer;
|
|
|
|
begin
|
|
|
|
Result:=0;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgRGB8Bit.SetInternalColor(x, y: integer; const Value: TFPColor
|
|
|
|
);
|
|
|
|
var
|
|
|
|
v: TPTMemImgRGB8BitValue;
|
|
|
|
begin
|
|
|
|
v.r:=Value.red shr 8;
|
|
|
|
v.g:=Value.green shr 8;
|
|
|
|
v.b:=Value.blue shr 8;
|
|
|
|
FData[x+y*Width]:=v;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgRGB8Bit.SetInternalPixel(x, y: integer; Value: integer);
|
|
|
|
begin
|
|
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
constructor TPTMemImgRGB8Bit.Create(AWidth, AHeight: integer);
|
|
|
|
begin
|
2012-06-10 14:03:58 +00:00
|
|
|
FDesc:=GetPTMemImgDesc(false,8,false);
|
2012-06-08 14:14:58 +00:00
|
|
|
inherited Create(AWidth, AHeight);
|
|
|
|
end;
|
|
|
|
|
|
|
|
destructor TPTMemImgRGB8Bit.Destroy;
|
|
|
|
begin
|
|
|
|
ReAllocMem(FData,0);
|
|
|
|
inherited Destroy;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgRGB8Bit.SetSize(AWidth, AHeight: integer);
|
|
|
|
begin
|
|
|
|
if (AWidth=Width) and (AHeight=Height) then exit;
|
|
|
|
ReAllocMem(FData,SizeOf(TPTMemImgRGB8BitValue)*AWidth*AHeight);
|
|
|
|
inherited SetSize(AWidth,AHeight);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ TPTMemImgRGB16Bit }
|
|
|
|
|
|
|
|
function TPTMemImgRGB16Bit.GetInternalColor(x, y: integer): TFPColor;
|
|
|
|
var
|
|
|
|
v: TPTMemImgRGB16BitValue;
|
|
|
|
begin
|
|
|
|
v:=FData[x+y*Width];
|
|
|
|
Result.red:=v.r;
|
|
|
|
Result.green:=v.g;
|
|
|
|
Result.blue:=v.b;
|
|
|
|
Result.alpha:=alphaOpaque;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TPTMemImgRGB16Bit.GetInternalPixel(x, y: integer): integer;
|
|
|
|
begin
|
|
|
|
Result:=0;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgRGB16Bit.SetInternalColor(x, y: integer;
|
|
|
|
const Value: TFPColor);
|
|
|
|
var
|
|
|
|
v: TPTMemImgRGB16BitValue;
|
|
|
|
begin
|
|
|
|
v.r:=Value.red;
|
|
|
|
v.g:=Value.green;
|
|
|
|
v.b:=Value.blue;
|
|
|
|
FData[x+y*Width]:=v;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgRGB16Bit.SetInternalPixel(x, y: integer; Value: integer);
|
|
|
|
begin
|
|
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
constructor TPTMemImgRGB16Bit.Create(AWidth, AHeight: integer);
|
|
|
|
begin
|
2012-06-10 14:03:58 +00:00
|
|
|
FDesc:=GetPTMemImgDesc(false,16,false);
|
2012-06-08 14:14:58 +00:00
|
|
|
inherited Create(AWidth, AHeight);
|
|
|
|
end;
|
|
|
|
|
|
|
|
destructor TPTMemImgRGB16Bit.Destroy;
|
|
|
|
begin
|
|
|
|
ReAllocMem(FData,0);
|
|
|
|
inherited Destroy;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgRGB16Bit.SetSize(AWidth, AHeight: integer);
|
|
|
|
begin
|
|
|
|
if (AWidth=Width) and (AHeight=Height) then exit;
|
|
|
|
ReAllocMem(FData,SizeOf(TPTMemImgRGB16BitValue)*AWidth*AHeight);
|
|
|
|
inherited SetSize(AWidth,AHeight);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ TPTMemImgRGBA16Bit }
|
|
|
|
|
|
|
|
function TPTMemImgRGBA16Bit.GetInternalColor(x, y: integer): TFPColor;
|
|
|
|
begin
|
|
|
|
Result:=FData[x+y*Width];
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TPTMemImgRGBA16Bit.GetInternalPixel(x, y: integer): integer;
|
|
|
|
begin
|
|
|
|
Result:=0;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgRGBA16Bit.SetInternalColor(x, y: integer;
|
|
|
|
const Value: TFPColor);
|
|
|
|
begin
|
|
|
|
FData[x+y*Width]:=Value;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgRGBA16Bit.SetInternalPixel(x, y: integer; Value: integer);
|
|
|
|
begin
|
|
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
constructor TPTMemImgRGBA16Bit.Create(AWidth, AHeight: integer);
|
|
|
|
begin
|
2012-06-10 14:03:58 +00:00
|
|
|
FDesc:=GetPTMemImgDesc(false,16,true);
|
2012-06-08 14:14:58 +00:00
|
|
|
inherited Create(AWidth, AHeight);
|
|
|
|
end;
|
|
|
|
|
|
|
|
destructor TPTMemImgRGBA16Bit.Destroy;
|
|
|
|
begin
|
|
|
|
ReAllocMem(FData,0);
|
|
|
|
inherited Destroy;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPTMemImgRGBA16Bit.SetSize(AWidth, AHeight: integer);
|
|
|
|
begin
|
|
|
|
if (AWidth=Width) and (AHeight=Height) then exit;
|
|
|
|
ReAllocMem(FData,SizeOf(TFPColor)*AWidth*AHeight);
|
|
|
|
inherited SetSize(AWidth,AHeight);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ TLinearInterpolation }
|
|
|
|
|
|
|
|
procedure TLinearInterpolation.CreatePixelWeights(OldSize, NewSize: integer;
|
|
|
|
out Entries: Pointer; out EntrySize: integer; out Support: integer);
|
|
|
|
// create an array of #NewSize entries. Each entry starts with an integer
|
|
|
|
// for the StartIndex, followed by #Support singles for the pixel weights.
|
|
|
|
// The sum of weights for each entry is 1.
|
|
|
|
var
|
|
|
|
Entry: Pointer;
|
|
|
|
|
|
|
|
procedure SetSupport(NewSupport: integer);
|
|
|
|
begin
|
|
|
|
Support:=NewSupport;
|
|
|
|
EntrySize:=SizeOf(integer)+SizeOf(Single)*Support;
|
|
|
|
Getmem(Entries,EntrySize*NewSize);
|
|
|
|
Entry:=Entries;
|
|
|
|
end;
|
|
|
|
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
Factor: double;
|
|
|
|
StartPos: Double;
|
|
|
|
StartIndex: Integer;
|
|
|
|
j: Integer;
|
|
|
|
FirstValue: Double;
|
|
|
|
//Sum: double;
|
|
|
|
begin
|
|
|
|
if NewSize=OldSize then begin
|
|
|
|
SetSupport(1);
|
|
|
|
for i:=0 to NewSize-1 do begin
|
|
|
|
// 1:1
|
|
|
|
PInteger(Entry)^:=i;
|
|
|
|
inc(Entry,SizeOf(Integer));
|
|
|
|
PSingle(Entry)^:=1.0;
|
|
|
|
inc(Entry,SizeOf(Single));
|
|
|
|
end;
|
|
|
|
end else if NewSize<OldSize then begin
|
|
|
|
// shrink
|
|
|
|
SetSupport(Max(2,(OldSize+NewSize-1) div NewSize));
|
|
|
|
Factor:=double(OldSize)/double(NewSize);
|
|
|
|
for i:=0 to NewSize-1 do begin
|
|
|
|
StartPos:=Factor*i;
|
|
|
|
StartIndex:=Floor(StartPos);
|
|
|
|
PInteger(Entry)^:=StartIndex;
|
|
|
|
inc(Entry,SizeOf(Integer));
|
|
|
|
// first pixel
|
|
|
|
FirstValue:=(1.0-(StartPos-double(StartIndex)));
|
|
|
|
PSingle(Entry)^:=FirstValue/Factor;
|
|
|
|
inc(Entry,SizeOf(Single));
|
|
|
|
// middle pixel
|
|
|
|
for j:=1 to Support-2 do begin
|
|
|
|
PSingle(Entry)^:=1.0/Factor;
|
|
|
|
inc(Entry,SizeOf(Single));
|
|
|
|
end;
|
|
|
|
// last pixel
|
|
|
|
PSingle(Entry)^:=(Factor-FirstValue-(Support-2))/Factor;
|
|
|
|
inc(Entry,SizeOf(Single));
|
|
|
|
end;
|
|
|
|
end else begin
|
|
|
|
// enlarge
|
|
|
|
if OldSize=1 then begin
|
|
|
|
SetSupport(1);
|
|
|
|
for i:=0 to NewSize-1 do begin
|
|
|
|
// nothing to interpolate
|
|
|
|
PInteger(Entry)^:=0;
|
|
|
|
inc(Entry,SizeOf(Integer));
|
|
|
|
PSingle(Entry)^:=1.0;
|
|
|
|
inc(Entry,SizeOf(Single));
|
|
|
|
end;
|
|
|
|
end else begin
|
|
|
|
SetSupport(2);
|
|
|
|
Factor:=double(OldSize-1)/double(NewSize);
|
|
|
|
for i:=0 to NewSize-1 do begin
|
|
|
|
StartPos:=Factor*i+Factor/2;
|
|
|
|
StartIndex:=Floor(StartPos);
|
|
|
|
PInteger(Entry)^:=StartIndex;
|
|
|
|
inc(Entry,SizeOf(Integer));
|
|
|
|
// first pixel
|
|
|
|
FirstValue:=(1.0-(StartPos-double(StartIndex)));
|
|
|
|
// convert linear distribution
|
|
|
|
FirstValue:=Min(1.0,Max(0.0,Filter(FirstValue/MaxSupport)));
|
|
|
|
PSingle(Entry)^:=FirstValue;
|
|
|
|
inc(Entry,SizeOf(Single));
|
|
|
|
// last pixel
|
|
|
|
PSingle(Entry)^:=1.0-FirstValue;
|
|
|
|
inc(Entry,SizeOf(Single));
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
if Entry<>Entries+EntrySize*NewSize then
|
|
|
|
raise Exception.Create('TSimpleInterpolation.Execute inconsistency');
|
|
|
|
|
|
|
|
{WriteLn('CreatePixelWeights Old=',OldSize,' New=',NewSize,' Support=',Support,' EntrySize=',EntrySize,' Factor=',FloatToStr(Factor));
|
|
|
|
Entry:=Entries;
|
|
|
|
for i:=0 to NewSize-1 do begin
|
|
|
|
StartIndex:=PInteger(Entry)^;
|
|
|
|
inc(Entry,SizeOf(Integer));
|
|
|
|
write(i,' Start=',StartIndex);
|
|
|
|
Sum:=0;
|
|
|
|
for j:=0 to Support-1 do begin
|
|
|
|
FirstValue:=PSingle(Entry)^;
|
|
|
|
inc(Entry,SizeOf(Single));
|
|
|
|
write(' ',FloatToStr(FirstValue));
|
|
|
|
Sum:=Sum+FirstValue;
|
|
|
|
end;
|
|
|
|
writeln(' Sum=',FloatToStr(Sum));
|
|
|
|
end;}
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TLinearInterpolation.Execute(x, y, w, h: integer);
|
|
|
|
// paint Image on Canvas at x,y,w*h
|
|
|
|
var
|
|
|
|
dy: Integer;
|
|
|
|
dx: Integer;
|
|
|
|
HorzResized: PFPColor;
|
|
|
|
xEntries: Pointer; // size:integer,weight1:single,weight2:single,...
|
|
|
|
xEntrySize: integer;
|
|
|
|
xSupport: integer;// how many horizontal pixel are needed to created one new pixel
|
|
|
|
yEntries: Pointer; // size:integer,weight1:single,weight2:single,...
|
|
|
|
yEntrySize: integer;
|
|
|
|
ySupport: integer;// how many vertizontal pixel are needed to created one new pixel
|
|
|
|
NewSupportLines: LongInt;
|
|
|
|
yEntry: Pointer;
|
|
|
|
SrcStartY: LongInt;
|
|
|
|
LastSrcStartY: LongInt;
|
|
|
|
sy: Integer;
|
|
|
|
xEntry: Pointer;
|
|
|
|
sx: LongInt;
|
|
|
|
cx: Integer;
|
|
|
|
f: Single;
|
|
|
|
NewCol: TFPColor;
|
|
|
|
Col: TFPColor;
|
|
|
|
CurEntry: Pointer;
|
|
|
|
NewRed, NewGreen, NewBlue, NewAlpha: Single;
|
|
|
|
begin
|
|
|
|
//WriteLn('TSimpleInterpolation.Execute Src=',image.width,'x',image.Height,' Dest=',x,',',y,',',w,'x',h);
|
|
|
|
if (w<=0) or (h<=0) or (image.Width=0) or (image.Height=0) then exit;
|
|
|
|
|
|
|
|
xEntries:=nil;
|
|
|
|
yEntries:=nil;
|
|
|
|
HorzResized:=nil;
|
|
|
|
try
|
|
|
|
CreatePixelWeights(image.Width,w,xEntries,xEntrySize,xSupport);
|
|
|
|
CreatePixelWeights(image.Height,h,yEntries,yEntrySize,ySupport);
|
|
|
|
//WriteLn('TSimpleInterpolation.Execute xSupport=',xSupport,' ySupport=',ySupport);
|
|
|
|
// create temporary buffer for the horizontally resized pixel for the current
|
|
|
|
// y line
|
|
|
|
GetMem(HorzResized,w*ySupport*SizeOf(TFPColor));
|
|
|
|
|
|
|
|
SrcStartY:=0;
|
|
|
|
for dy:=0 to h-1 do begin
|
|
|
|
if dy=0 then begin
|
|
|
|
yEntry:=yEntries;
|
|
|
|
SrcStartY:=PInteger(yEntry)^;
|
|
|
|
NewSupportLines:=ySupport;
|
|
|
|
end else begin
|
|
|
|
LastSrcStartY:=SrcStartY;
|
|
|
|
inc(yEntry,yEntrySize);
|
|
|
|
SrcStartY:=PInteger(yEntry)^;
|
|
|
|
NewSupportLines:=SrcStartY-LastSrcStartY;
|
|
|
|
//WriteLn('TSimpleInterpolation.Execute dy=',dy,' SrcStartY=',SrcStartY,' LastSrcStartY=',LastSrcStartY,' NewSupportLines=',NewSupportLines);
|
|
|
|
// move lines up
|
|
|
|
if (NewSupportLines>0) and (ySupport>NewSupportLines) then
|
|
|
|
System.Move(HorzResized[NewSupportLines*w],
|
|
|
|
HorzResized[0],
|
|
|
|
(ySupport-NewSupportLines)*w*SizeOf(TFPColor));
|
|
|
|
end;
|
|
|
|
|
|
|
|
// compute new horizontally resized line(s)
|
|
|
|
for sy:=ySupport-NewSupportLines to ySupport-1 do begin
|
|
|
|
xEntry:=xEntries;
|
|
|
|
for dx:=0 to w-1 do begin
|
|
|
|
sx:=PInteger(xEntry)^;
|
|
|
|
inc(xEntry,SizeOf(integer));
|
|
|
|
NewRed:=0.0;
|
|
|
|
NewGreen:=0.0;
|
|
|
|
NewBlue:=0.0;
|
|
|
|
NewAlpha:=0.0;
|
|
|
|
for cx:=sx to sx+xSupport-1 do begin
|
|
|
|
f:=PSingle(xEntry)^;
|
|
|
|
inc(xEntry,SizeOf(Single));
|
|
|
|
Col:=image.Colors[cx,SrcStartY+sy];
|
|
|
|
NewRed:=NewRed+Col.red*f;
|
|
|
|
NewGreen:=NewGreen+Col.green*f;
|
|
|
|
NewBlue:=NewBlue+Col.blue*f;
|
|
|
|
NewAlpha:=NewAlpha+Col.alpha*f;
|
|
|
|
end;
|
|
|
|
NewCol.red:=Min(round(NewRed),$ffff);
|
|
|
|
NewCol.green:=Min(round(NewGreen),$ffff);
|
|
|
|
NewCol.blue:=Min(round(NewBlue),$ffff);
|
|
|
|
NewCol.alpha:=Min(round(NewAlpha),$ffff);
|
|
|
|
HorzResized[dx+sy*w]:=NewCol;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// compute new vertically resized line
|
|
|
|
for dx:=0 to w-1 do begin
|
|
|
|
CurEntry:=yEntry+SizeOf(integer);
|
|
|
|
NewRed:=0.0;
|
|
|
|
NewGreen:=0.0;
|
|
|
|
NewBlue:=0.0;
|
|
|
|
NewAlpha:=0.0;
|
|
|
|
for sy:=0 to ySupport-1 do begin
|
|
|
|
f:=PSingle(CurEntry)^;
|
|
|
|
inc(CurEntry,SizeOf(Single));
|
|
|
|
Col:=HorzResized[dx+sy*w];
|
|
|
|
NewRed:=NewRed+Col.red*f;
|
|
|
|
NewGreen:=NewGreen+Col.green*f;
|
|
|
|
NewBlue:=NewBlue+Col.blue*f;
|
|
|
|
NewAlpha:=NewAlpha+Col.alpha*f;
|
|
|
|
end;
|
|
|
|
NewCol.red:=Min(round(NewRed),$ffff);
|
|
|
|
NewCol.green:=Min(round(NewGreen),$ffff);
|
|
|
|
NewCol.blue:=Min(round(NewBlue),$ffff);
|
|
|
|
NewCol.alpha:=Min(round(NewAlpha),$ffff);
|
|
|
|
Canvas.Colors[x+dx,y+dy]:=NewCol;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
finally
|
|
|
|
if xEntries<>nil then FreeMem(xEntries);
|
|
|
|
if yEntries<>nil then FreeMem(yEntries);
|
|
|
|
if HorzResized<>nil then FreeMem(HorzResized);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TLinearInterpolation.Filter(x: double): double;
|
|
|
|
begin
|
|
|
|
Result:=x;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TLinearInterpolation.MaxSupport: double;
|
|
|
|
begin
|
|
|
|
Result:=1.0;
|
|
|
|
end;
|
|
|
|
|
|
|
|
end.
|
|
|
|
|