|
|
@@ -1411,7 +1411,7 @@ type |
|
|
|
end; |
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
TBitfieldFormat = class(TFormatDescriptor) |
|
|
|
TbmpBitfieldFormat = class(TFormatDescriptor) |
|
|
|
private |
|
|
|
procedure SetRedMask (const aValue: UInt64); |
|
|
|
procedure SetGreenMask(const aValue: UInt64); |
|
|
@@ -1432,17 +1432,21 @@ type |
|
|
|
end; |
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
TColorTableEnty = packed record |
|
|
|
TbmpColorTableEnty = packed record |
|
|
|
b, g, r, a: Byte; |
|
|
|
end; |
|
|
|
TColorTable = array of TColorTableEnty; |
|
|
|
TColorTableFormat = class(TFormatDescriptor) |
|
|
|
TbmpColorTable = array of TbmpColorTableEnty; |
|
|
|
TbmpColorTableFormat = class(TFormatDescriptor) |
|
|
|
private |
|
|
|
fColorTable: TColorTable; |
|
|
|
fColorTable: TbmpColorTable; |
|
|
|
public |
|
|
|
property PixelSize: Single read fPixelSize write fPixelSize; |
|
|
|
property ColorTable: TColorTable read fColorTable write fColorTable; |
|
|
|
property ColorTable: TbmpColorTable read fColorTable write fColorTable; |
|
|
|
property Range: TglBitmapColorRec read fRange write fRange; |
|
|
|
property Shift: TShiftRec read fShift write fShift; |
|
|
|
property Format: TglBitmapFormat read fFormat write fFormat; |
|
|
|
|
|
|
|
procedure CreateColorTable; |
|
|
|
|
|
|
|
procedure Map(const aPixel: TglBitmapPixelData; var aData: PByte; var aMapData: Pointer); override; |
|
|
|
procedure Unmap(var aData: PByte; var aPixel: TglBitmapPixelData; var aMapData: Pointer); override; |
|
|
@@ -1549,11 +1553,41 @@ begin |
|
|
|
result.a := a; |
|
|
|
end; |
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
function glBitmapShiftRec(const r, g, b, a: Byte): TShiftRec; |
|
|
|
begin |
|
|
|
result.r := r; |
|
|
|
result.g := g; |
|
|
|
result.b := b; |
|
|
|
result.a := a; |
|
|
|
end; |
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
function FormatGetSupportedFiles(const aFormat: TglBitmapFormat): TglBitmapFileTypes; |
|
|
|
begin |
|
|
|
result := [ftDDS, ftTGA]; |
|
|
|
|
|
|
|
if (aFormat in [ |
|
|
|
//4 bbp |
|
|
|
tfLuminance4, |
|
|
|
|
|
|
|
//8bpp |
|
|
|
tfR3G3B2, tfLuminance8, |
|
|
|
|
|
|
|
//16bpp |
|
|
|
tfRGB4, tfRGB5, tfR5G6B5, tfRGB5A1, tfRGBA4, |
|
|
|
tfBGR4, tfBGR5, tfB5G6R5, tfBGR5A1, tfBGRA4, |
|
|
|
|
|
|
|
//24bpp |
|
|
|
tfBGR8, tfRGB8, |
|
|
|
|
|
|
|
//32bpp |
|
|
|
tfRGB10, tfRGB10A2, tfRGBA8, |
|
|
|
tfBGR10, tfBGR10A2, tfBGRA8]) then |
|
|
|
result := result + [ftBMP]; |
|
|
|
|
|
|
|
//TODO Supported File Formats! |
|
|
|
result := [ftDDS, ftTGA, ftBMP]; |
|
|
|
|
|
|
|
(* |
|
|
|
{$IFDEF GLB_SUPPORT_PNG_WRITE} |
|
|
|
if aFormat in [ |
|
|
@@ -3363,31 +3397,31 @@ end; |
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
//TBitfieldFormat///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
procedure TBitfieldFormat.SetRedMask(const aValue: UInt64); |
|
|
|
procedure TbmpBitfieldFormat.SetRedMask(const aValue: UInt64); |
|
|
|
begin |
|
|
|
Update(aValue, fRange.r, fShift.r); |
|
|
|
end; |
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
procedure TBitfieldFormat.SetGreenMask(const aValue: UInt64); |
|
|
|
procedure TbmpBitfieldFormat.SetGreenMask(const aValue: UInt64); |
|
|
|
begin |
|
|
|
Update(aValue, fRange.g, fShift.g); |
|
|
|
end; |
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
procedure TBitfieldFormat.SetBlueMask(const aValue: UInt64); |
|
|
|
procedure TbmpBitfieldFormat.SetBlueMask(const aValue: UInt64); |
|
|
|
begin |
|
|
|
Update(aValue, fRange.b, fShift.b); |
|
|
|
end; |
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
procedure TBitfieldFormat.SetAlphaMask(const aValue: UInt64); |
|
|
|
procedure TbmpBitfieldFormat.SetAlphaMask(const aValue: UInt64); |
|
|
|
begin |
|
|
|
Update(aValue, fRange.a, fShift.a); |
|
|
|
end; |
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
procedure TBitfieldFormat.Update(aMask: UInt64; out aRange: Cardinal; out |
|
|
|
procedure TbmpBitfieldFormat.Update(aMask: UInt64; out aRange: Cardinal; out |
|
|
|
aShift: Byte); |
|
|
|
begin |
|
|
|
aShift := 0; |
|
|
@@ -3409,7 +3443,7 @@ begin |
|
|
|
end; |
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
procedure TBitfieldFormat.Map(const aPixel: TglBitmapPixelData; var aData: PByte; var aMapData: Pointer); |
|
|
|
procedure TbmpBitfieldFormat.Map(const aPixel: TglBitmapPixelData; var aData: PByte; var aMapData: Pointer); |
|
|
|
var |
|
|
|
data: UInt64; |
|
|
|
s: Integer; |
|
|
@@ -3434,7 +3468,7 @@ begin |
|
|
|
end; |
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
procedure TBitfieldFormat.Unmap(var aData: PByte; var aPixel: TglBitmapPixelData; var aMapData: Pointer); |
|
|
|
procedure TbmpBitfieldFormat.Unmap(var aData: PByte; var aPixel: TglBitmapPixelData; var aMapData: Pointer); |
|
|
|
var |
|
|
|
data: UInt64; |
|
|
|
s, i: Integer; |
|
|
@@ -3458,12 +3492,90 @@ end; |
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
//TColorTableFormat/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
procedure TColorTableFormat.Map(const aPixel: TglBitmapPixelData; var aData: PByte; var aMapData: Pointer); |
|
|
|
procedure TbmpColorTableFormat.CreateColorTable; |
|
|
|
var |
|
|
|
bits: Byte; |
|
|
|
len: Integer; |
|
|
|
i: Integer; |
|
|
|
begin |
|
|
|
raise EglBitmapException.Create('mapping of color table formats is not supported'); |
|
|
|
if not (Format in [tfLuminance4, tfLuminance8, tfR3G3B2]) then |
|
|
|
raise EglBitmapException.Create(UNSUPPORTED_FORMAT); |
|
|
|
|
|
|
|
if (Format = tfLuminance4) then |
|
|
|
SetLength(fColorTable, 16) |
|
|
|
else |
|
|
|
SetLength(fColorTable, 256); |
|
|
|
|
|
|
|
case Format of |
|
|
|
tfLuminance4: begin |
|
|
|
for i := 0 to High(fColorTable) do begin |
|
|
|
fColorTable[i].r := 16 * i; |
|
|
|
fColorTable[i].g := 16 * i; |
|
|
|
fColorTable[i].b := 16 * i; |
|
|
|
fColorTable[i].a := 0; |
|
|
|
end; |
|
|
|
end; |
|
|
|
|
|
|
|
tfLuminance8: begin |
|
|
|
for i := 0 to High(fColorTable) do begin |
|
|
|
fColorTable[i].r := i; |
|
|
|
fColorTable[i].g := i; |
|
|
|
fColorTable[i].b := i; |
|
|
|
fColorTable[i].a := 0; |
|
|
|
end; |
|
|
|
end; |
|
|
|
|
|
|
|
tfR3G3B2: begin |
|
|
|
for i := 0 to High(fColorTable) do begin |
|
|
|
fColorTable[i].r := Round(((i shr Shift.r) and Range.r) / Range.r * 255); |
|
|
|
fColorTable[i].g := Round(((i shr Shift.g) and Range.g) / Range.g * 255); |
|
|
|
fColorTable[i].b := Round(((i shr Shift.b) and Range.b) / Range.b * 255); |
|
|
|
fColorTable[i].a := 0; |
|
|
|
|
|
|
|
s := SysUtils.Format('%.2X%.2X%.2X' + sLineBreak, [fColorTable[i].r, fColorTable[i].g, fColorTable[i].b]); |
|
|
|
fs.Write(s[1], Length(s)); |
|
|
|
end; |
|
|
|
end; |
|
|
|
end; |
|
|
|
end; |
|
|
|
|
|
|
|
procedure TColorTableFormat.Unmap(var aData: PByte; var aPixel: TglBitmapPixelData; var aMapData: Pointer); |
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
procedure TbmpColorTableFormat.Map(const aPixel: TglBitmapPixelData; var aData: PByte; var aMapData: Pointer); |
|
|
|
var |
|
|
|
d: Byte; |
|
|
|
begin |
|
|
|
if not (Format in [tfLuminance4, tfLuminance8, tfR3G3B2]) then |
|
|
|
raise EglBitmapException.Create(UNSUPPORTED_FORMAT); |
|
|
|
|
|
|
|
case Format of |
|
|
|
tfLuminance4: begin |
|
|
|
if (aMapData = nil) then |
|
|
|
aData^ := 0; |
|
|
|
d := LuminanceWeight(aPixel) and Range.r; |
|
|
|
aData^ := aData^ or (d shl (4 - PtrInt(aMapData))); |
|
|
|
inc(aMapData, 4); |
|
|
|
if (PtrInt(aMapData) >= 8) then begin |
|
|
|
inc(aData); |
|
|
|
aMapData := nil; |
|
|
|
end; |
|
|
|
end; |
|
|
|
|
|
|
|
tfLuminance8: begin |
|
|
|
aData^ := LuminanceWeight(aPixel) and Range.r; |
|
|
|
inc(aData); |
|
|
|
end; |
|
|
|
|
|
|
|
tfR3G3B2: begin |
|
|
|
aData^ := Round( |
|
|
|
((aPixel.Data.r and Range.r) shl Shift.r) or |
|
|
|
((aPixel.Data.g and Range.g) shl Shift.g) or |
|
|
|
((aPixel.Data.b and Range.b) shl Shift.b)); |
|
|
|
inc(aData); |
|
|
|
end; |
|
|
|
end; |
|
|
|
end; |
|
|
|
|
|
|
|
procedure TbmpColorTableFormat.Unmap(var aData: PByte; var aPixel: TglBitmapPixelData; var aMapData: Pointer); |
|
|
|
type |
|
|
|
PUInt64 = ^UInt64; |
|
|
|
var |
|
|
@@ -3500,7 +3612,7 @@ begin |
|
|
|
inc(aData, s); |
|
|
|
end; |
|
|
|
|
|
|
|
destructor TColorTableFormat.Destroy; |
|
|
|
destructor TbmpColorTableFormat.Destroy; |
|
|
|
begin |
|
|
|
SetLength(fColorTable, 0); |
|
|
|
inherited Destroy; |
|
|
@@ -5906,16 +6018,6 @@ type |
|
|
|
biClrImportant: Cardinal; |
|
|
|
end; |
|
|
|
|
|
|
|
(* TODO: delete? |
|
|
|
TBMPInfoOS = packed record |
|
|
|
biSize: Cardinal; |
|
|
|
biWidth: Longint; |
|
|
|
biHeight: Longint; |
|
|
|
biPlanes: Word; |
|
|
|
biBitCount: Word; |
|
|
|
end; |
|
|
|
*) |
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
function TglBitmap.LoadBMP(const aStream: TStream): Boolean; |
|
|
|
|
|
|
@@ -5952,10 +6054,10 @@ function TglBitmap.LoadBMP(const aStream: TStream): Boolean; |
|
|
|
end; |
|
|
|
end; |
|
|
|
|
|
|
|
function ReadColorTable(var aFormat: TglBitmapFormat; const aInfo: TBMPInfo): TColorTableFormat; |
|
|
|
function ReadColorTable(var aFormat: TglBitmapFormat; const aInfo: TBMPInfo): TbmpColorTableFormat; |
|
|
|
var |
|
|
|
i, c: Integer; |
|
|
|
ColorTable: TColorTable; |
|
|
|
ColorTable: TbmpColorTable; |
|
|
|
begin |
|
|
|
result := nil; |
|
|
|
if (aInfo.biBitCount >= 16) then |
|
|
@@ -5966,20 +6068,20 @@ function TglBitmap.LoadBMP(const aStream: TStream): Boolean; |
|
|
|
c := 1 shl aInfo.biBitCount; |
|
|
|
SetLength(ColorTable, c); |
|
|
|
for i := 0 to c-1 do begin |
|
|
|
aStream.Read(ColorTable[i], SizeOf(TColorTableEnty)); |
|
|
|
aStream.Read(ColorTable[i], SizeOf(TbmpColorTableEnty)); |
|
|
|
if (ColorTable[i].r <> ColorTable[i].g) or (ColorTable[i].g <> ColorTable[i].b) then |
|
|
|
aFormat := tfRGB8; |
|
|
|
end; |
|
|
|
|
|
|
|
result := TColorTableFormat.Create; |
|
|
|
result := TbmpColorTableFormat.Create; |
|
|
|
result.PixelSize := aInfo.biBitCount / 8; |
|
|
|
result.ColorTable := ColorTable; |
|
|
|
result.Range := glBitmapColorRec($FF, $FF, $FF, $00); |
|
|
|
result.Range := glBitmapColorRec($FF, $FF, $FF, $00); |
|
|
|
end; |
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
function CheckBitfields(var aFormat: TglBitmapFormat; const aMask: TglBitmapColorRec; |
|
|
|
const aInfo: TBMPInfo): TBitfieldFormat; |
|
|
|
const aInfo: TBMPInfo): TbmpBitfieldFormat; |
|
|
|
var |
|
|
|
TmpFormat: TglBitmapFormat; |
|
|
|
FormatDesc: TFormatDescriptor; |
|
|
@@ -5999,7 +6101,7 @@ function TglBitmap.LoadBMP(const aStream: TStream): Boolean; |
|
|
|
if (aMask.a <> 0) and not TFormatDescriptor.Get(aFormat).HasAlpha then |
|
|
|
aFormat := TFormatDescriptor.Get(aFormat).WithAlpha; |
|
|
|
|
|
|
|
result := TBitfieldFormat.Create; |
|
|
|
result := TbmpBitfieldFormat.Create; |
|
|
|
result.PixelSize := aInfo.biBitCount / 8; |
|
|
|
result.RedMask := aMask.r; |
|
|
|
result.GreenMask := aMask.g; |
|
|
@@ -6016,7 +6118,7 @@ var |
|
|
|
LineBuf, ImageData, TmpData: PByte; |
|
|
|
SourceMD, DestMD: Pointer; |
|
|
|
BmpFormat: TglBitmapFormat; |
|
|
|
ColorTable: TColorTable; |
|
|
|
ColorTable: TbmpColorTable; |
|
|
|
|
|
|
|
//records |
|
|
|
Mask: TglBitmapColorRec; |
|
|
@@ -6134,12 +6236,15 @@ procedure TglBitmap.SaveBMP(const aStream: TStream); |
|
|
|
var |
|
|
|
Header: TBMPHeader; |
|
|
|
Info: TBMPInfo; |
|
|
|
pData, pTemp: pByte; |
|
|
|
Converter: TbmpColorTableFormat; |
|
|
|
FormatDesc: TFormatDescriptor; |
|
|
|
SourceFD, DestFD: Pointer; |
|
|
|
pData, srcData, dstData, ConvertBuffer: pByte; |
|
|
|
|
|
|
|
Pixel: TglBitmapPixelData; |
|
|
|
PixelFormat: TglBitmapPixelData; |
|
|
|
FormatDesc: TFormatDescriptor; |
|
|
|
ImageSize, LineSize, Padding, LineIdx, ColorIdx: Integer; |
|
|
|
Temp, RedMask, GreenMask, BlueMask, AlphaMask: Cardinal; |
|
|
|
ImageSize, wbLineSize, rbLineSize, Padding, LineIdx, PixelIdx, i: Integer; |
|
|
|
RedMask, GreenMask, BlueMask, AlphaMask: Cardinal; |
|
|
|
|
|
|
|
PaddingBuff: Cardinal; |
|
|
|
|
|
|
@@ -6152,8 +6257,11 @@ begin |
|
|
|
if not (ftBMP in FormatGetSupportedFiles(Format)) then |
|
|
|
raise EglBitmapUnsupportedFormatFormat.Create('SaveBMP - ' + UNSUPPORTED_FORMAT); |
|
|
|
|
|
|
|
ImageSize := TFormatDescriptor.Get(Format).GetSize(Dimension); |
|
|
|
Converter := nil; |
|
|
|
FormatDesc := TFormatDescriptor.Get(Format); |
|
|
|
ImageSize := FormatDesc.GetSize(Dimension); |
|
|
|
|
|
|
|
FillChar(Header, SizeOf(Header), 0); |
|
|
|
Header.bfType := BMP_MAGIC; |
|
|
|
Header.bfSize := SizeOf(Header) + SizeOf(Info) + ImageSize; |
|
|
|
Header.bfReserved1 := 0; |
|
|
@@ -6167,100 +6275,142 @@ begin |
|
|
|
Info.biPlanes := 1; |
|
|
|
Info.biCompression := BMP_COMP_RGB; |
|
|
|
Info.biSizeImage := ImageSize; |
|
|
|
case Format of |
|
|
|
tfR3G3B2, tfLuminance8: begin |
|
|
|
Info.biBitCount := 8; |
|
|
|
Header.bfOffBits := Header.bfOffBits + 256 * SizeOf(Cardinal); |
|
|
|
end; |
|
|
|
|
|
|
|
tfRGB5, tfRGB5A1, tfR5G6B5, tfRGB4, tfRGBA4, |
|
|
|
tfBGR5, tfBGR5A1, tfB5G6R5, tfBGR4, tfBGRA4: begin |
|
|
|
Info.biBitCount := 16; |
|
|
|
Info.biCompression := BMP_COMP_BITFIELDS; |
|
|
|
end; |
|
|
|
|
|
|
|
tfBGR8, tfRGB8: begin |
|
|
|
Info.biBitCount := 24; |
|
|
|
end; |
|
|
|
try |
|
|
|
case Format of |
|
|
|
tfLuminance4: begin |
|
|
|
Info.biBitCount := 4; |
|
|
|
Header.bfSize := Header.bfSize + 16 * SizeOf(Cardinal); |
|
|
|
Header.bfOffBits := Header.bfOffBits + 16 * SizeOf(Cardinal); //16 ColorTable entries |
|
|
|
Converter := TbmpColorTableFormat.Create; |
|
|
|
Converter.PixelSize := 0.5; |
|
|
|
Converter.Format := Format; |
|
|
|
Converter.Range := glBitmapColorRec($F, $F, $F, $0); |
|
|
|
Converter.CreateColorTable; |
|
|
|
end; |
|
|
|
|
|
|
|
tfRGB10, tfRGB10A2, tfRGBA8, |
|
|
|
tfBGR10, tfBGR10A2, tfBGRA8: begin |
|
|
|
Info.biBitCount := 32; |
|
|
|
Info.biCompression := BMP_COMP_BITFIELDS; |
|
|
|
end; |
|
|
|
else |
|
|
|
raise EglBitmapUnsupportedFormatFormat.Create('SaveBMP - ' + UNSUPPORTED_FORMAT); |
|
|
|
end; |
|
|
|
Info.biXPelsPerMeter := 2835; |
|
|
|
Info.biYPelsPerMeter := 2835; |
|
|
|
tfR3G3B2, tfLuminance8: begin |
|
|
|
Info.biBitCount := 8; |
|
|
|
Header.bfSize := Header.bfSize + 256 * SizeOf(Cardinal); |
|
|
|
Header.bfOffBits := Header.bfOffBits + 256 * SizeOf(Cardinal); //256 ColorTable entries |
|
|
|
Converter := TbmpColorTableFormat.Create; |
|
|
|
Converter.PixelSize := 1; |
|
|
|
Converter.Format := Format; |
|
|
|
if (Format = tfR3G3B2) then begin |
|
|
|
Converter.Range := glBitmapColorRec($7, $7, $3, $0); |
|
|
|
Converter.Shift := glBitmapShiftRec(0, 3, 6, 0); |
|
|
|
end else |
|
|
|
Converter.Range := glBitmapColorRec($FF, $FF, $FF, $0); |
|
|
|
Converter.CreateColorTable; |
|
|
|
end; |
|
|
|
|
|
|
|
// prepare bitmasks |
|
|
|
if Info.biCompression = BMP_COMP_BITFIELDS then begin |
|
|
|
Info.biSize := Info.biSize + 4 * SizeOf(Cardinal); |
|
|
|
Header.bfSize := Header.bfSize + 4 * SizeOf(Cardinal); |
|
|
|
Header.bfOffBits := Header.bfOffBits + 4 * SizeOf(Cardinal); |
|
|
|
tfRGB4, tfRGB5, tfR5G6B5, tfRGB5A1, tfRGBA4, |
|
|
|
tfBGR4, tfBGR5, tfB5G6R5, tfBGR5A1, tfBGRA4: begin |
|
|
|
Info.biBitCount := 16; |
|
|
|
Info.biCompression := BMP_COMP_BITFIELDS; |
|
|
|
end; |
|
|
|
|
|
|
|
FormatDesc := TFormatDescriptor.Get(Format); |
|
|
|
RedMask := FormatDesc.RedMask; |
|
|
|
GreenMask := FormatDesc.GreenMask; |
|
|
|
BlueMask := FormatDesc.BlueMask; |
|
|
|
AlphaMask := FormatDesc.AlphaMask; |
|
|
|
end; |
|
|
|
tfBGR8, tfRGB8: begin |
|
|
|
Info.biBitCount := 24; |
|
|
|
end; |
|
|
|
|
|
|
|
// headers |
|
|
|
aStream.Write(Header, SizeOf(Header)); |
|
|
|
aStream.Write(Info, SizeOf(Info)); |
|
|
|
|
|
|
|
// colortable |
|
|
|
if Info.biBitCount = 8 then begin |
|
|
|
Temp := 0; |
|
|
|
for ColorIdx := Low(Byte) to High(Byte) do begin |
|
|
|
aStream.Write(Temp, 4); |
|
|
|
Temp := Temp + $00010101; |
|
|
|
tfRGB10, tfRGB10A2, tfRGBA8, |
|
|
|
tfBGR10, tfBGR10A2, tfBGRA8: begin |
|
|
|
Info.biBitCount := 32; |
|
|
|
Info.biCompression := BMP_COMP_BITFIELDS; |
|
|
|
end; |
|
|
|
else |
|
|
|
raise EglBitmapUnsupportedFormatFormat.Create('SaveBMP - ' + UNSUPPORTED_FORMAT); |
|
|
|
end; |
|
|
|
Info.biXPelsPerMeter := 2835; |
|
|
|
Info.biYPelsPerMeter := 2835; |
|
|
|
|
|
|
|
// prepare bitmasks |
|
|
|
if Info.biCompression = BMP_COMP_BITFIELDS then begin |
|
|
|
Header.bfSize := Header.bfSize + 4 * SizeOf(Cardinal); |
|
|
|
Header.bfOffBits := Header.bfOffBits + 4 * SizeOf(Cardinal); |
|
|
|
|
|
|
|
RedMask := FormatDesc.RedMask; |
|
|
|
GreenMask := FormatDesc.GreenMask; |
|
|
|
BlueMask := FormatDesc.BlueMask; |
|
|
|
AlphaMask := FormatDesc.AlphaMask; |
|
|
|
end; |
|
|
|
end; |
|
|
|
|
|
|
|
// bitmasks |
|
|
|
if Info.biCompression = BMP_COMP_BITFIELDS then begin |
|
|
|
aStream.Write(RedMask, SizeOf(Cardinal)); |
|
|
|
aStream.Write(GreenMask, SizeOf(Cardinal)); |
|
|
|
aStream.Write(BlueMask, SizeOf(Cardinal)); |
|
|
|
aStream.Write(AlphaMask, SizeOf(Cardinal)); |
|
|
|
end; |
|
|
|
|
|
|
|
// image data |
|
|
|
LineSize := Trunc(Width * TFormatDescriptor.Get(Format).PixelSize); |
|
|
|
Padding := GetLineWidth - LineSize; |
|
|
|
PaddingBuff := 0; |
|
|
|
|
|
|
|
pData := Data; |
|
|
|
Inc(pData, (Height -1) * LineSize); |
|
|
|
// headers |
|
|
|
aStream.Write(Header, SizeOf(Header)); |
|
|
|
aStream.Write(Info, SizeOf(Info)); |
|
|
|
|
|
|
|
// colortable |
|
|
|
if Assigned(Converter) then |
|
|
|
aStream.Write(Converter.ColorTable[0].b, |
|
|
|
SizeOf(TbmpColorTableEnty) * Length(Converter.ColorTable)); |
|
|
|
|
|
|
|
// bitmasks |
|
|
|
if Info.biCompression = BMP_COMP_BITFIELDS then begin |
|
|
|
aStream.Write(RedMask, SizeOf(Cardinal)); |
|
|
|
aStream.Write(GreenMask, SizeOf(Cardinal)); |
|
|
|
aStream.Write(BlueMask, SizeOf(Cardinal)); |
|
|
|
aStream.Write(AlphaMask, SizeOf(Cardinal)); |
|
|
|
end; |
|
|
|
|
|
|
|
// prepare row buffer. But only for RGB because RGBA supports color masks |
|
|
|
// so it's possible to change color within the image. |
|
|
|
if (Format = tfRGB8) then |
|
|
|
GetMem(pTemp, fRowSize) |
|
|
|
else |
|
|
|
pTemp := nil; |
|
|
|
// image data |
|
|
|
rbLineSize := Round(Info.biWidth * FormatDesc.PixelSize); |
|
|
|
wbLineSize := Round(Info.biWidth * Info.biBitCount / 8); |
|
|
|
Padding := GetLineWidth - wbLineSize; |
|
|
|
PaddingBuff := 0; |
|
|
|
|
|
|
|
pData := Data; |
|
|
|
inc(pData, (Height-1) * rbLineSize); |
|
|
|
|
|
|
|
// prepare row buffer. But only for RGB because RGBA supports color masks |
|
|
|
// so it's possible to change color within the image. |
|
|
|
if Assigned(Converter) then begin |
|
|
|
FormatDesc.PreparePixel(Pixel); |
|
|
|
GetMem(ConvertBuffer, wbLineSize); |
|
|
|
SourceFD := FormatDesc.CreateMappingData; |
|
|
|
DestFD := Converter.CreateMappingData; |
|
|
|
end else |
|
|
|
ConvertBuffer := nil; |
|
|
|
|
|
|
|
try |
|
|
|
// write image data |
|
|
|
for LineIdx := 0 to Height - 1 do begin |
|
|
|
// preparing row |
|
|
|
if Format = tfRGB8 then begin |
|
|
|
Move(pData^, pTemp^, fRowSize); |
|
|
|
SwapRGB(pTemp, Width, false); |
|
|
|
end else |
|
|
|
pTemp := pData; |
|
|
|
aStream.Write(pTemp^, LineSize); |
|
|
|
Dec(pData, LineSize); |
|
|
|
if Padding > 0 then |
|
|
|
aStream.Write(PaddingBuff, Padding); |
|
|
|
try |
|
|
|
for LineIdx := 0 to Height - 1 do begin |
|
|
|
// preparing row |
|
|
|
if Assigned(Converter) then begin |
|
|
|
srcData := pData; |
|
|
|
dstData := ConvertBuffer; |
|
|
|
for PixelIdx := 0 to Info.biWidth-1 do begin |
|
|
|
FormatDesc.Unmap(srcData, Pixel, SourceFD); |
|
|
|
with FormatDesc do begin |
|
|
|
//TODO use convert function |
|
|
|
for i := 0 to 3 do |
|
|
|
if (Converter.Range.arr[i] <> Range.arr[i]) then begin |
|
|
|
if (Range.arr[i] > 0) then |
|
|
|
Pixel.Data.arr[i] := Round(Pixel.Data.arr[i] / Range.arr[i] * Converter.Range.arr[i]) |
|
|
|
else |
|
|
|
Pixel.Data.arr[i] := 0; |
|
|
|
end; |
|
|
|
end; |
|
|
|
Converter.Map(Pixel, dstData, DestFD); |
|
|
|
end; |
|
|
|
aStream.Write(ConvertBuffer^, wbLineSize); |
|
|
|
end else begin |
|
|
|
aStream.Write(pData^, rbLineSize); |
|
|
|
end; |
|
|
|
dec(pData, rbLineSize); |
|
|
|
if (Padding > 0) then |
|
|
|
aStream.Write(PaddingBuff, Padding); |
|
|
|
end; |
|
|
|
finally |
|
|
|
// destroy row buffer |
|
|
|
if Assigned(ConvertBuffer) then begin |
|
|
|
FormatDesc.FreeMappingData(SourceFD); |
|
|
|
Converter.FreeMappingData(DestFD); |
|
|
|
FreeMem(ConvertBuffer); |
|
|
|
end; |
|
|
|
end; |
|
|
|
finally |
|
|
|
// destroy row buffer |
|
|
|
if Format = tfRGB8 then |
|
|
|
FreeMem(pTemp); |
|
|
|
if Assigned(Converter) then |
|
|
|
Converter.Free; |
|
|
|
end; |
|
|
|
end; |
|
|
|
|
|
|
@@ -7702,3 +7852,4 @@ finalization |
|
|
|
TFormatDescriptor.Finalize; |
|
|
|
|
|
|
|
end. |
|
|
|
|