| @@ -1411,7 +1411,7 @@ type | |||||
| end; | end; | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| TBitfieldFormat = class(TFormatDescriptor) | |||||
| TbmpBitfieldFormat = class(TFormatDescriptor) | |||||
| private | private | ||||
| procedure SetRedMask (const aValue: UInt64); | procedure SetRedMask (const aValue: UInt64); | ||||
| procedure SetGreenMask(const aValue: UInt64); | procedure SetGreenMask(const aValue: UInt64); | ||||
| @@ -1432,17 +1432,21 @@ type | |||||
| end; | end; | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| TColorTableEnty = packed record | |||||
| TbmpColorTableEnty = packed record | |||||
| b, g, r, a: Byte; | b, g, r, a: Byte; | ||||
| end; | end; | ||||
| TColorTable = array of TColorTableEnty; | |||||
| TColorTableFormat = class(TFormatDescriptor) | |||||
| TbmpColorTable = array of TbmpColorTableEnty; | |||||
| TbmpColorTableFormat = class(TFormatDescriptor) | |||||
| private | private | ||||
| fColorTable: TColorTable; | |||||
| fColorTable: TbmpColorTable; | |||||
| public | public | ||||
| property PixelSize: Single read fPixelSize write fPixelSize; | 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 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 Map(const aPixel: TglBitmapPixelData; var aData: PByte; var aMapData: Pointer); override; | ||||
| procedure Unmap(var aData: PByte; var aPixel: TglBitmapPixelData; var aMapData: Pointer); override; | procedure Unmap(var aData: PByte; var aPixel: TglBitmapPixelData; var aMapData: Pointer); override; | ||||
| @@ -1549,11 +1553,41 @@ begin | |||||
| result.a := a; | result.a := a; | ||||
| end; | 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; | function FormatGetSupportedFiles(const aFormat: TglBitmapFormat): TglBitmapFileTypes; | ||||
| begin | 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! | //TODO Supported File Formats! | ||||
| result := [ftDDS, ftTGA, ftBMP]; | |||||
| (* | (* | ||||
| {$IFDEF GLB_SUPPORT_PNG_WRITE} | {$IFDEF GLB_SUPPORT_PNG_WRITE} | ||||
| if aFormat in [ | if aFormat in [ | ||||
| @@ -3363,31 +3397,31 @@ end; | |||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| //TBitfieldFormat///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //TBitfieldFormat///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TBitfieldFormat.SetRedMask(const aValue: UInt64); | |||||
| procedure TbmpBitfieldFormat.SetRedMask(const aValue: UInt64); | |||||
| begin | begin | ||||
| Update(aValue, fRange.r, fShift.r); | Update(aValue, fRange.r, fShift.r); | ||||
| end; | end; | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TBitfieldFormat.SetGreenMask(const aValue: UInt64); | |||||
| procedure TbmpBitfieldFormat.SetGreenMask(const aValue: UInt64); | |||||
| begin | begin | ||||
| Update(aValue, fRange.g, fShift.g); | Update(aValue, fRange.g, fShift.g); | ||||
| end; | end; | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TBitfieldFormat.SetBlueMask(const aValue: UInt64); | |||||
| procedure TbmpBitfieldFormat.SetBlueMask(const aValue: UInt64); | |||||
| begin | begin | ||||
| Update(aValue, fRange.b, fShift.b); | Update(aValue, fRange.b, fShift.b); | ||||
| end; | end; | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TBitfieldFormat.SetAlphaMask(const aValue: UInt64); | |||||
| procedure TbmpBitfieldFormat.SetAlphaMask(const aValue: UInt64); | |||||
| begin | begin | ||||
| Update(aValue, fRange.a, fShift.a); | Update(aValue, fRange.a, fShift.a); | ||||
| end; | end; | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TBitfieldFormat.Update(aMask: UInt64; out aRange: Cardinal; out | |||||
| procedure TbmpBitfieldFormat.Update(aMask: UInt64; out aRange: Cardinal; out | |||||
| aShift: Byte); | aShift: Byte); | ||||
| begin | begin | ||||
| aShift := 0; | aShift := 0; | ||||
| @@ -3409,7 +3443,7 @@ begin | |||||
| end; | 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 | var | ||||
| data: UInt64; | data: UInt64; | ||||
| s: Integer; | s: Integer; | ||||
| @@ -3434,7 +3468,7 @@ begin | |||||
| end; | 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 | var | ||||
| data: UInt64; | data: UInt64; | ||||
| s, i: Integer; | s, i: Integer; | ||||
| @@ -3458,12 +3492,90 @@ end; | |||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| //TColorTableFormat/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //TColorTableFormat/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TColorTableFormat.Map(const aPixel: TglBitmapPixelData; var aData: PByte; var aMapData: Pointer); | |||||
| procedure TbmpColorTableFormat.CreateColorTable; | |||||
| var | |||||
| bits: Byte; | |||||
| len: Integer; | |||||
| i: Integer; | |||||
| begin | 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; | 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 | type | ||||
| PUInt64 = ^UInt64; | PUInt64 = ^UInt64; | ||||
| var | var | ||||
| @@ -3500,7 +3612,7 @@ begin | |||||
| inc(aData, s); | inc(aData, s); | ||||
| end; | end; | ||||
| destructor TColorTableFormat.Destroy; | |||||
| destructor TbmpColorTableFormat.Destroy; | |||||
| begin | begin | ||||
| SetLength(fColorTable, 0); | SetLength(fColorTable, 0); | ||||
| inherited Destroy; | inherited Destroy; | ||||
| @@ -5906,16 +6018,6 @@ type | |||||
| biClrImportant: Cardinal; | biClrImportant: Cardinal; | ||||
| end; | end; | ||||
| (* TODO: delete? | |||||
| TBMPInfoOS = packed record | |||||
| biSize: Cardinal; | |||||
| biWidth: Longint; | |||||
| biHeight: Longint; | |||||
| biPlanes: Word; | |||||
| biBitCount: Word; | |||||
| end; | |||||
| *) | |||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| function TglBitmap.LoadBMP(const aStream: TStream): Boolean; | function TglBitmap.LoadBMP(const aStream: TStream): Boolean; | ||||
| @@ -5952,10 +6054,10 @@ function TglBitmap.LoadBMP(const aStream: TStream): Boolean; | |||||
| end; | end; | ||||
| end; | end; | ||||
| function ReadColorTable(var aFormat: TglBitmapFormat; const aInfo: TBMPInfo): TColorTableFormat; | |||||
| function ReadColorTable(var aFormat: TglBitmapFormat; const aInfo: TBMPInfo): TbmpColorTableFormat; | |||||
| var | var | ||||
| i, c: Integer; | i, c: Integer; | ||||
| ColorTable: TColorTable; | |||||
| ColorTable: TbmpColorTable; | |||||
| begin | begin | ||||
| result := nil; | result := nil; | ||||
| if (aInfo.biBitCount >= 16) then | if (aInfo.biBitCount >= 16) then | ||||
| @@ -5966,20 +6068,20 @@ function TglBitmap.LoadBMP(const aStream: TStream): Boolean; | |||||
| c := 1 shl aInfo.biBitCount; | c := 1 shl aInfo.biBitCount; | ||||
| SetLength(ColorTable, c); | SetLength(ColorTable, c); | ||||
| for i := 0 to c-1 do begin | 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 | if (ColorTable[i].r <> ColorTable[i].g) or (ColorTable[i].g <> ColorTable[i].b) then | ||||
| aFormat := tfRGB8; | aFormat := tfRGB8; | ||||
| end; | end; | ||||
| result := TColorTableFormat.Create; | |||||
| result := TbmpColorTableFormat.Create; | |||||
| result.PixelSize := aInfo.biBitCount / 8; | result.PixelSize := aInfo.biBitCount / 8; | ||||
| result.ColorTable := ColorTable; | result.ColorTable := ColorTable; | ||||
| result.Range := glBitmapColorRec($FF, $FF, $FF, $00); | |||||
| result.Range := glBitmapColorRec($FF, $FF, $FF, $00); | |||||
| end; | end; | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| function CheckBitfields(var aFormat: TglBitmapFormat; const aMask: TglBitmapColorRec; | function CheckBitfields(var aFormat: TglBitmapFormat; const aMask: TglBitmapColorRec; | ||||
| const aInfo: TBMPInfo): TBitfieldFormat; | |||||
| const aInfo: TBMPInfo): TbmpBitfieldFormat; | |||||
| var | var | ||||
| TmpFormat: TglBitmapFormat; | TmpFormat: TglBitmapFormat; | ||||
| FormatDesc: TFormatDescriptor; | FormatDesc: TFormatDescriptor; | ||||
| @@ -5999,7 +6101,7 @@ function TglBitmap.LoadBMP(const aStream: TStream): Boolean; | |||||
| if (aMask.a <> 0) and not TFormatDescriptor.Get(aFormat).HasAlpha then | if (aMask.a <> 0) and not TFormatDescriptor.Get(aFormat).HasAlpha then | ||||
| aFormat := TFormatDescriptor.Get(aFormat).WithAlpha; | aFormat := TFormatDescriptor.Get(aFormat).WithAlpha; | ||||
| result := TBitfieldFormat.Create; | |||||
| result := TbmpBitfieldFormat.Create; | |||||
| result.PixelSize := aInfo.biBitCount / 8; | result.PixelSize := aInfo.biBitCount / 8; | ||||
| result.RedMask := aMask.r; | result.RedMask := aMask.r; | ||||
| result.GreenMask := aMask.g; | result.GreenMask := aMask.g; | ||||
| @@ -6016,7 +6118,7 @@ var | |||||
| LineBuf, ImageData, TmpData: PByte; | LineBuf, ImageData, TmpData: PByte; | ||||
| SourceMD, DestMD: Pointer; | SourceMD, DestMD: Pointer; | ||||
| BmpFormat: TglBitmapFormat; | BmpFormat: TglBitmapFormat; | ||||
| ColorTable: TColorTable; | |||||
| ColorTable: TbmpColorTable; | |||||
| //records | //records | ||||
| Mask: TglBitmapColorRec; | Mask: TglBitmapColorRec; | ||||
| @@ -6134,12 +6236,15 @@ procedure TglBitmap.SaveBMP(const aStream: TStream); | |||||
| var | var | ||||
| Header: TBMPHeader; | Header: TBMPHeader; | ||||
| Info: TBMPInfo; | Info: TBMPInfo; | ||||
| pData, pTemp: pByte; | |||||
| Converter: TbmpColorTableFormat; | |||||
| FormatDesc: TFormatDescriptor; | |||||
| SourceFD, DestFD: Pointer; | |||||
| pData, srcData, dstData, ConvertBuffer: pByte; | |||||
| Pixel: TglBitmapPixelData; | |||||
| PixelFormat: 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; | PaddingBuff: Cardinal; | ||||
| @@ -6152,8 +6257,11 @@ begin | |||||
| if not (ftBMP in FormatGetSupportedFiles(Format)) then | if not (ftBMP in FormatGetSupportedFiles(Format)) then | ||||
| raise EglBitmapUnsupportedFormatFormat.Create('SaveBMP - ' + UNSUPPORTED_FORMAT); | 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.bfType := BMP_MAGIC; | ||||
| Header.bfSize := SizeOf(Header) + SizeOf(Info) + ImageSize; | Header.bfSize := SizeOf(Header) + SizeOf(Info) + ImageSize; | ||||
| Header.bfReserved1 := 0; | Header.bfReserved1 := 0; | ||||
| @@ -6167,100 +6275,142 @@ begin | |||||
| Info.biPlanes := 1; | Info.biPlanes := 1; | ||||
| Info.biCompression := BMP_COMP_RGB; | Info.biCompression := BMP_COMP_RGB; | ||||
| Info.biSizeImage := ImageSize; | 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; | ||||
| 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; | end; | ||||
| finally | finally | ||||
| // destroy row buffer | |||||
| if Format = tfRGB8 then | |||||
| FreeMem(pTemp); | |||||
| if Assigned(Converter) then | |||||
| Converter.Free; | |||||
| end; | end; | ||||
| end; | end; | ||||
| @@ -7702,3 +7852,4 @@ finalization | |||||
| TFormatDescriptor.Finalize; | TFormatDescriptor.Finalize; | ||||
| end. | end. | ||||