diff --git a/lcl/graphics.pp b/lcl/graphics.pp index e754eb1d50..a9125bdbef 100644 --- a/lcl/graphics.pp +++ b/lcl/graphics.pp @@ -12,7 +12,7 @@ * * * This file is part of the Lazarus Component Library (LCL) * * * - * See the file COPYING.modifiedLGPL.txt, included in this distribution, * + * See the file COPYING.modifiedLGPL.txt, included in this distribution, * * for details about the copyright. * * * * This program is distributed in the hope that it will be useful, * @@ -1892,6 +1892,76 @@ begin CB.Free; end; +//TODO: publish ?? (as RawImage_CreateCompatibleBitmaps) +function CreateCompatibleBitmaps(const ARawImage: TRawImage; out ABitmap, AMask: HBitmap; ASkipMask: Boolean = False): Boolean; +var + Desc: TRawImageDescription absolute ARawimage.Description; + + ImgHandle, ImgMaskHandle: HBitmap; + ImagePtr: PRawImage; + DevImage: TRawImage; + DevDesc: TRawImageDescription; + SrcImage, DstImage: TLazIntfImage; + QueryFlags: TRawImageQueryFlags; + W, H: Integer; +begin + ImgMaskHandle := 0; + + W := Desc.Width; + if W < 1 then W := 1; + H := Desc.Height; + if H < 1 then H := 1; + + if Desc.Depth = 1 + then QueryFlags := [riqfMono] + else QueryFlags := [riqfRGB]; + if Desc.AlphaPrec <> 0 + then Include(QueryFlags, riqfAlpha); + if Desc.MaskBitsPerPixel <> 0 + then Include(QueryFlags, riqfMask); + QueryDescription(DevDesc, QueryFlags, W, H); + + if DevDesc.IsEqual(Desc) + then begin + // image is compatible, so use it + DstImage := nil; + ImagePtr := @ARawImage; + end + else begin + // create compatible copy + SrcImage := TLazIntfImage.Create(ARawImage, False); + DstImage := TLazIntfImage.Create(0, 0); + // create mask for alphachannel when device has no alpha support + if (DevDesc.AlphaPrec = 0) and (riqfAlpha in QueryFlags) + then begin + //add mask if not already queried + if not (riqfMask in QueryFlags) + then QueryDescription(DevDesc, [riqfMask, riqfUpdate]); + DstImage.DataDescription := DevDesc; + DstImage.CopyPixels(SrcImage, 0, 0, True, $8000); + end + else begin + DstImage.DataDescription := DevDesc; + DstImage.CopyPixels(SrcImage); + end; + SrcImage.Free; + DstImage.GetRawImage(DevImage); + ImagePtr := @DevImage; + end; + + try + Result := RawImage_CreateBitmaps(ImagePtr^, ImgHandle, ImgMaskHandle, ASkipMask); + if not Result then Exit; + + ABitmap := ImgHandle; + if not ASkipMask + then AMask := ImgMaskHandle; + finally + DstImage.Free; + end; +end; + + procedure Register; begin RegisterClasses([TBitmap,TPixmap,TPortableNetworkGraphic, diff --git a/lcl/graphtype.pp b/lcl/graphtype.pp index 82c9159949..7a0e2b26c3 100644 --- a/lcl/graphtype.pp +++ b/lcl/graphtype.pp @@ -1572,7 +1572,7 @@ var BitOffset: Cardinal; begin if FLineOrder = riloBottomToTop then - y := FHeight - y; + y := FHeight - y - 1; Result := Positions[y]; BitOffset := x * FBitsPerPixel + Result.Bit; Result.Bit := BitOffset and 7; @@ -1622,210 +1622,6 @@ begin end; end; - - -{$ifdef OldRawImageProcs} -function RawImageMaskIsEmpty(RawImage: PRawImage; TestPixels: boolean): boolean; -begin - Result := not RawImage^.IsMasked(TestPixels); -end; -{$endif} - -{$ifdef OldRawImageProcs} -function RawImageDescriptionAsString(Desc: PRawImageDescription): string; -begin - Result := Desc^.AsString; -end; -{$endif} - -{$ifdef OldRawImageProcs} -procedure FreeRawImageData(RawImage: PRawImage); -begin - RawImage^.FreeData; -end; -{$endif} - -{$ifdef OldRawImageProcs} -procedure ReleaseRawImageData(RawImage: PRawImage); -begin - RawImage^.ReleaseData; -end; -{$endif} - -{------------------------------------------------------------------------------- - Beware: Data is used in ReallocMem - --------------------------------------------------------------------------------} -{$ifdef OldRawImageProcs} -procedure CreateRawImageData(Width, Height, BitsPerPixel: cardinal; - LineEnd: TRawImageLineEnd; var Data: Pointer; var DataSize: PtrUInt); -var - PixelCount: PtrUInt; - BitsPerLine: PtrUInt; - DataBits: QWord; -begin - // get current size - PixelCount:=Width*Height; - if PixelCount=0 then exit; - - // calculate BitsPerLine - BitsPerLine:=GetBitsPerLine(Width,BitsPerPixel,LineEnd); - - // create pixels - DataBits:=QWord(BitsPerLine)*Height; - DataSize:=cardinal((DataBits+7) shr 3); - ReAllocMem(Data,DataSize); - FillChar(Data^,DataSize,0); -end; -{$endif} - -{$ifdef OldRawImageProcs} -procedure CreateRawImageDescFromMask(SrcRawImageDesc, - DestRawImageDesc: PRawImageDescription); -begin - // original code raises an exception, imo it is perfectly valid - // to create a black image (MWE) - if (SrcRawImageDesc^.MaskBitsPerPixel = 0) then - RaiseGDBException('CreateRawImageFromMask Alpha not separate'); - - DestRawImageDesc^ := SrcRawImageDesc^.GetDescriptionFromMask; -end; -{$endif} - -{$ifdef OldRawImageProcs} -procedure GetRawImageXYPosition(RawImageDesc: PRawImageDescription; - LineStarts: PRawImagePosition; x, y: cardinal; - var Position: TRawImagePosition); -var - BitOffset: cardinal; -begin - if RawImageDesc^.LineOrder=riloBottomToTop then - y:=RawImageDesc^.Height-y; - Position:=LineStarts[y]; - BitOffset:=RawImageDesc^.BitsPerPixel*cardinal(x)+Position.Bit; - Position.Bit:=(BitOffset and 7); - inc(Position.Byte,BitOffset shr 3); -end; -{$endif} - -{$ifdef OldRawImageProcs} -procedure ExtractRawImageRect(SrcRawImage: PRawImage; const SrcRect: TRect; - DestRawImage: PRawImage); -begin - SrcRawImage^.ExtractRect(SrcRect, DestRawImage^); -end; -{$endif} - -{$ifdef OldRawImageProcs} -procedure CreateRawImageLineStarts(Width, Height, BitsPerPixel: cardinal; - LineEnd: TRawImageLineEnd; var LineStarts: PRawImagePosition); -// LineStarts is recreated, so make sure it is nil or a valid mem -var - PixelCount: cardinal; - BitsPerLine: cardinal; - CurLine: cardinal; - BytesPerLine: cardinal; - ExtraBitsPerLine: cardinal; - CurBitOffset: cardinal; -begin - // get current size - PixelCount:=Width*Height; - if PixelCount=0 then exit; - - // calculate BitsPerLine, BytesPerLine and ExtraBitsPerLine - BitsPerLine:=GetBitsPerLine(Width,BitsPerPixel,LineEnd); - BytesPerLine:=BitsPerLine shr 3; - ExtraBitsPerLine:=BitsPerLine and 7; - - // create line start array - ReAllocMem(LineStarts,Height*SizeOf(TRawImagePosition)); - LineStarts[0].Byte:=0; - LineStarts[0].Bit:=0; - for CurLine:=1 to Height-1 do begin - CurBitOffset:=LineStarts[CurLine-1].Bit+ExtraBitsPerLine; - LineStarts[CurLine].Byte:=LineStarts[CurLine-1].Byte+BytesPerLine - +(CurBitOffset shr 3); - LineStarts[CurLine].Bit:=CurBitOffset and 7; - end; -end; -{$endif} - -{$ifdef OldRawImageProcs} -procedure ReadRawImageBits(TheData: PByte; - const Position: TRawImagePosition; - BitsPerPixel, Prec, Shift: cardinal; BitOrder: TRawImageBitOrder; - var Bits: word); -begin - RawImage_ReadBits(TheData, Position, BitsPerPixel, Prec, Shift, BitOrder, Bits); -end; -{$endif} - -{$ifdef OldRawImageProcs} -procedure WriteRawImageBits(TheData: PByte; - const Position: TRawImagePosition; - BitsPerPixel, Prec, Shift: cardinal; BitOrder: TRawImageBitOrder; Bits: word); -begin - RawImage_WriteBits(TheData, Position, BitsPerPixel, Prec, Shift, BitOrder, Bits); -end; -{$endif} - -{$ifdef OldRawImageProcs} -procedure ReAlignRawImageLines(var Data: Pointer; var Size: PtrUInt; - Width, Height, BitsPerPixel: cardinal; - var OldLineEnd: TRawImageLineEnd; NewLineEnd: TRawImageLineEnd); -var - OldBytesPerLine: PtrUInt; - OldSize: PtrUInt; - NewBytesPerLine: PtrUInt; - NewSize: PtrUInt; - y: Integer; - OldPos: Pointer; - NewPos: Pointer; -begin - if OldLineEnd=NewLineEnd then exit; - if (Width=0) or (Height=0) then exit; - OldBytesPerLine:=GetBytesPerLine(Width,BitsPerPixel,OldLineEnd); - OldSize:=OldBytesPerLine*PtrUInt(Height); - if OldSize<>Size then - RaiseGDBException('ReAlignRawImageLines OldSize<>Size'); - NewBytesPerLine:=GetBytesPerLine(Width,BitsPerPixel,NewLineEnd); - NewSize:=NewBytesPerLine*PtrUInt(Height); - //DebugLn(['ReAlignRawImageLines OldBytesPerLine=',OldBytesPerLine,' NewBytesPerLine=',NewBytesPerLine]); - - // enlarge before - if OldSizeNewBytesPerLine then begin - // compress - for y:=0 to Height-1 do begin - System.Move(OldPos^,NewPos^,NewBytesPerLine); - inc(OldPos,OldBytesPerLine); - inc(NewPos,NewBytesPerLine); - end; - end else begin - // expand - inc(OldPos,OldSize); - inc(NewPos,NewSize); - for y:=Height-1 downto 0 do begin - dec(OldPos,OldBytesPerLine); - dec(NewPos,NewBytesPerLine); - System.Move(OldPos^,NewPos^,OldBytesPerLine); - end; - end; - - // shrink after - if OldSize>NewSize then - ReAllocMem(Data,NewSize); - - Size:=NewSize; - OldLineEnd:=NewLineEnd; -end; -{$endif} - //------------------------------------------------------------------------------ procedure InternalInit; var diff --git a/lcl/include/icon.inc b/lcl/include/icon.inc index 39098bbebb..7c146d53eb 100644 --- a/lcl/include/icon.inc +++ b/lcl/include/icon.inc @@ -534,9 +534,24 @@ begin end; procedure TCustomIcon.MaskHandleNeeded; +var + ImgHandle, dummy: HBITMAP; begin // Created by bitmaphandle - BitmapHandleNeeded; +//!!! BitmapHandleNeeded; + + if FCurrent = -1 then Exit; + if MaskHandleAllocated then exit; + + if not CreateCompatibleBitmaps(GetRawImagePtr^, Dummy, ImgHandle) + then begin + DebugLn('TCustomIcon.MaskHandleNeeded: Unable to create makshandle'); + Exit; + end; + + if BitmapHandleAllocated + then UpdateHandles(BitmapHandle, ImgHandle) + else UpdateHandles(0, ImgHandle); end; function TCustomIcon.PaletteAllocated: boolean; diff --git a/lcl/include/rasterimage.inc b/lcl/include/rasterimage.inc index 00809feb44..a671905c20 100644 --- a/lcl/include/rasterimage.inc +++ b/lcl/include/rasterimage.inc @@ -170,9 +170,7 @@ procedure TRasterImage.BitmapHandleNeeded; var ImgHandle, ImgMaskHandle: HBitmap; ImagePtr: PRawImage; - DevImage: TRawImage; DevDesc: TRawImageDescription; - SrcImage, DstImage: TLazIntfImage; QueryFlags: TRawImageQueryFlags; W, H: Integer; SkipMask: Boolean; @@ -180,77 +178,41 @@ begin if BitmapHandleAllocated then exit; ImagePtr := GetRawImagePtr; + if ImagePtr = nil then Exit; + ImgMaskHandle := 0; - // create a device compatible image - W := Width; - if W < 1 then W := 1; - H := Height; - if H < 1 then H := 1; + // we must skip mask creation if + // a) we already have mask + // b) mask needs to be created another way - using TransparentColor + SkipMask := MaskHandleAllocated + or (TransparentMode = tmFixed) + or (ImagePtr^.Description.MaskBitsPerPixel = 0); - if ImagePtr^.Description.Depth = 1 - then QueryFlags := [riqfMono] - else QueryFlags := [riqfRGB]; - if ImagePtr^.Description.AlphaPrec <> 0 - then Include(QueryFlags, riqfAlpha); - if ImagePtr^.Description.MaskBitsPerPixel <> 0 - then Include(QueryFlags, riqfMask); - QueryDescription(DevDesc, QueryFlags, W, H); - - if DevDesc.IsEqual(ImagePtr^.Description) + if not CreateCompatibleBitmaps(ImagePtr^, ImgHandle, ImgMaskHandle, SkipMask) then begin - // image is compatible, so use it - DstImage := nil; - end - else begin - // create compatible copy - SrcImage := TLazIntfImage.Create(ImagePtr^, False); - DstImage := TLazIntfImage.Create(0, 0); - // create mask for alphachannel when device has no alpha support - if (DevDesc.AlphaPrec = 0) and (riqfAlpha in QueryFlags) - then begin - //add mask if not already queried - if not (riqfMask in QueryFlags) - then QueryDescription(DevDesc, [riqfMask, riqfUpdate]); - DstImage.DataDescription := DevDesc; - DstImage.CopyPixels(SrcImage, 0, 0, True, $8000); - end - else begin - DstImage.DataDescription := DevDesc; - DstImage.CopyPixels(SrcImage); - end; - SrcImage.Free; - DstImage.GetRawImage(DevImage); - ImagePtr := @DevImage; + DebugLn('TRasterImage.BitmapHandleNeeded: Unable to create handles, using default'); + // create a default handle + W := Width; + if W < 1 then W := 1; + H := Height; + if H < 1 then H := 1; + + if ImagePtr^.Description.Depth = 1 + then QueryFlags := [riqfMono] + else QueryFlags := [riqfRGB]; + if ImagePtr^.Description.AlphaPrec <> 0 + then Include(QueryFlags, riqfAlpha); + if ImagePtr^.Description.MaskBitsPerPixel <> 0 + then Include(QueryFlags, riqfMask); + QueryDescription(DevDesc, QueryFlags, W, H); + ImgHandle := CreateDefaultBitmapHandle(DevDesc); end; - try - // we must skip mask creation if - // a) we already have mask - // b) mask needs to be created another way - using TransparentColor - // c) we dont have mask in the description - SkipMask := MaskHandleAllocated or - (TransparentMode = tmFixed) or - (DevDesc.MaskBitsPerPixel = 0); - if not RawImage_CreateBitmaps(ImagePtr^, ImgHandle, ImgMaskHandle, SkipMask) - then begin - DebugLn('TRasterImage.BitmapHandleNeeded: Unable to create handles, using default'); - // create a default handle - ImgHandle := CreateDefaultBitmapHandle(DevDesc); - end; - - if SkipMask - then begin - // if we dont have new mask then either use old one or use none - if MaskHandleAllocated - then UpdateHandles(ImgHandle, MaskHandle) - else UpdateHandles(ImgHandle, 0); - end - else UpdateHandles(ImgHandle, ImgMaskHandle); - - finally - DstImage.Free; - end; + // if we dont have new mask then either use old one or use none + if SkipMask and MaskHandleAllocated + then UpdateHandles(ImgHandle, MaskHandle) + else UpdateHandles(ImgHandle, ImgMaskHandle); end; function TRasterImage.CanShareImage(AClass: TSharedRasterImageClass): Boolean;