1{%MainUnit ../graphics.pp} 2 3{****************************************************************************** 4 TRasterImage 5 ****************************************************************************** 6 7 ***************************************************************************** 8 This file is part of the Lazarus Component Library (LCL) 9 10 See the file COPYING.modifiedLGPL.txt, included in this distribution, 11 for details about the license. 12 ***************************************************************************** 13} 14 15procedure TRasterImage.Assign(Source: TPersistent); 16 procedure CopyMask(AMask: HBITMAP); 17 var 18 RI: TRawImage; 19 msk, dummy: HBITMAP; 20 Res: Boolean; 21 begin 22 // we need a winapi.CopyImage here (would make things easier) 23 // in theory, it should not matter if a HBITMAP was created as bitmap or as mask 24 // since there is a description problem in gtk, create both (we cannot create mask only) 25 // todo: fix gtk 26 if not RawImage_FromBitmap(RI, AMask, AMask) then Exit; 27 msk := 0; 28 dummy := 0; 29 RawImage_CreateBitmaps(RI, dummy, msk {, True}); 30 RI.FreeData; 31 DeleteObject(dummy); 32 33 if BitmapHandleAllocated 34 then Res := UpdateHandles(BitmapHandle, msk) 35 else Res := UpdateHandles(0, msk); 36 if not Res then DeleteObject(msk); 37 end; 38 39 40var 41 SrcImage: TRasterImage absolute Source; 42 SrcFPImage: TFPCustomImage absolute Source; 43 SrcRawImage, DstRawImage: PRawImage; 44 IntfImage: TLazIntfImage; 45 ImgHandle,ImgMaskHandle: HBitmap; 46begin 47 if Source = Self then exit; 48 49 if Source is TRasterImage 50 then begin 51 if MaskHandleAllocated 52 then begin 53 // Clear mask first mask 54 if BitmapHandleAllocated 55 then UpdateHandles(BitmapHandle, 0) 56 else UpdateHandles(0, 0); 57 end; 58 59 FTransparentMode := SrcImage.FTransparentMode; 60 FTransparentColor := SrcImage.FTransparentColor; 61 FMasked := SrcImage.FMasked; 62 63 // -> check if already shared 64 if SrcImage.FSharedImage <> FSharedImage 65 then begin 66 // image is not shared => new image data 67 // -> free canvas (interface handles) 68 FreeCanvasContext; 69 // release old FImage 70 FSharedImage.Release; 71 72 // We only can share images of the same type ... 73 if CanShareImage(SrcImage.GetSharedImageClass) 74 then begin 75 // share FImage with assigned graphic 76 FSharedImage := SrcImage.FSharedImage; 77 FSharedImage.Reference; 78 79 // when updating, unshare 80 // Since we "share" it first, the unshare code will create a copy 81 if (FUpdateCount > 0) 82 or (SrcImage.FUpdateCount > 0) 83 then begin 84 UnshareImage(True); 85 FreeSaveStream; 86 end; 87 end 88 else begin 89 // not sharable, create rawimage copy 90 FSharedImage := GetSharedImageClass.Create; 91 FSharedImage.Reference; 92 93 // copy raw image 94 SrcRawImage := SrcImage.GetRawImagePtr; 95 DstRawImage := GetRawImagePtr; 96 if (SrcRawImage <> nil) and (DstRawImage <> nil) 97 then with SrcRawImage^ do 98 ExtractRect(Rect(0, 0, Description.Width, Description.Height), DstRawImage^); 99 end; 100 end; 101 102 if SrcImage.MaskHandleAllocated 103 then CopyMask(SrcImage.MaskHandle); 104 105 106 if FUpdateCount = 0 107 then Changed(Self); 108 109 Exit; 110 end; 111 112 if Source is TFPCustomImage 113 then begin 114 // todo: base on rawimage 115 116 IntfImage := TLazIntfImage.Create(0,0,[]); 117 try 118 if BitmapHandleAllocated 119 then IntfImage.DataDescription := GetDescriptionFromBitmap(BitmapHandle, 0, 0) 120 else IntfImage.DataDescription := GetDescriptionFromDevice(0, 0, 0); 121 IntfImage.Assign(SrcFPImage); 122 IntfImage.CreateBitmaps(ImgHandle, ImgMaskHandle); 123 SetHandles(ImgHandle, ImgMaskHandle); 124 finally 125 IntfImage.Free; 126 end; 127 if FUpdateCount = 0 128 then Changed(Self); 129 130 Exit; 131 end; 132 133 // fall back to default 134 inherited Assign(Source); 135end; 136 137procedure TRasterImage.BeginUpdate(ACanvasOnly: Boolean); 138begin 139 if FUpdateCount = 0 140 then begin 141 UnshareImage(True); 142 FUpdateCanvasOnly := ACanvasOnly; 143 end 144 else begin 145 // if we are updating all, then requesting a canvas only won't change it 146 // if we are updating canvas only, then requesting all is an error 147 if FUpdateCanvasOnly and not ACanvasOnly 148 then raise EInvalidGraphicOperation.Create(rsRasterImageUpdateAll); 149 end; 150 151 Inc(FUpdateCount); 152end; 153 154procedure TRasterImage.Clear; 155begin 156 if Empty then Exit; 157 158 FreeSaveStream; 159 SetSize(0, 0); 160 if FUpdateCount = 0 161 then Changed(Self); 162end; 163 164procedure TRasterImage.BitmapHandleNeeded; 165var 166 ImgHandle, ImgMaskHandle: HBitmap; 167 ImagePtr: PRawImage; 168 DevDesc: TRawImageDescription; 169 QueryFlags: TRawImageQueryFlags; 170 W, H: Integer; 171 SkipMask: Boolean; 172begin 173 if BitmapHandleAllocated then exit; 174 175 ImagePtr := GetRawImagePtr; 176 if ImagePtr = nil then Exit; 177 178 ImgMaskHandle := 0; 179 180 // we must skip mask creation if 181 // a) we already have mask 182 // b) mask needs to be created another way - using TransparentColor 183 // c) there's no mask data 184 SkipMask := MaskHandleAllocated 185 or (TransparentMode = tmFixed) 186 or not ImagePtr^.IsMasked(False); 187 188 if not CreateCompatibleBitmaps(ImagePtr^, ImgHandle, ImgMaskHandle, SkipMask) 189 then begin 190 {$IFNDEF DisableChecks} 191 DebugLn('TRasterImage.BitmapHandleNeeded: Unable to create handles, using default'); 192 {$ENDIF} 193 // create a default handle 194 W := Width; 195 if W < 1 then W := 1; 196 H := Height; 197 if H < 1 then H := 1; 198 199 if ImagePtr^.Description.Depth = 1 200 then QueryFlags := [riqfMono] 201 else QueryFlags := [riqfRGB]; 202 if ImagePtr^.Description.AlphaPrec <> 0 203 then Include(QueryFlags, riqfAlpha); 204 if ImagePtr^.Description.MaskBitsPerPixel <> 0 205 then Include(QueryFlags, riqfMask); 206 QueryDescription(DevDesc, QueryFlags, W, H); 207 ImgHandle := CreateDefaultBitmapHandle(DevDesc); 208 end; 209 210 // if we do not have new mask then either use old one or use none 211 if SkipMask and MaskHandleAllocated 212 then UpdateHandles(ImgHandle, MaskHandle) 213 else UpdateHandles(ImgHandle, ImgMaskHandle); 214end; 215 216function TRasterImage.CanShareImage(AClass: TSharedRasterImageClass): Boolean; 217begin 218 // We only can share images of the same type. 219 // And if we are some "end" graphic type 220 Result := (AClass <> TSharedCustomBitmap) 221 and (AClass = GetSharedImageClass); 222end; 223 224 225procedure TRasterImage.Draw(DestCanvas: TCanvas; const DestRect: TRect); 226var 227 UseMaskHandle: HBitmap; 228 SrcDC: hDC; 229 DestDC: hDC; 230begin 231 if (Width=0) or (Height=0) 232 then Exit; 233 234 BitmapHandleNeeded; 235 if not BitmapHandleAllocated then Exit; 236 237 if Masked then 238 UseMaskHandle:=MaskHandle 239 else 240 UseMaskHandle:=0; 241 242 SrcDC := Canvas.GetUpdatedHandle([csHandleValid]); 243 DestCanvas.Changing; 244 DestDC := DestCanvas.GetUpdatedHandle([csHandleValid]); 245 StretchMaskBlt(DestDC, 246 DestRect.Left,DestRect.Top, 247 DestRect.Right-DestRect.Left,DestRect.Bottom-DestRect.Top, 248 SrcDC,0,0,Width,Height, UseMaskHandle,0,0,DestCanvas.CopyMode); 249 DestCanvas.Changed; 250end; 251 252procedure TRasterImage.EndUpdate(AStreamIsValid: Boolean = False); 253begin 254 if FUpdatecount = 0 255 then raise EInvalidGraphicOperation.Create(rsRasterImageEndUpdate); 256 257 Dec(FUpdatecount); 258 if FUpdatecount > 0 then Exit; 259 260 if not FUpdateCanvasOnly 261 then begin 262 FreeCanvasContext; 263 // delete bitmaphandle too 264 if BitmapHandleAllocated 265 then DeleteObject(InternalReleaseBitmapHandle) 266 267 end; 268 269 if not AStreamIsValid 270 then FreeSaveStream; 271 Changed(Self); 272end; 273 274constructor TRasterImage.Create; 275begin 276 inherited Create; 277 FSharedImage := GetSharedImageClass.Create; 278 FSharedImage.Reference; 279 FTransparentColor := clDefault; // for Delphi compatibility. clDefault means: 280 // use Left,Bottom pixel as transparent pixel 281end; 282 283destructor TRasterImage.Destroy; 284begin 285 FreeCanvasContext; 286 FSharedImage.Release; 287 FSharedImage := nil; 288 FreeAndNil(FCanvas); 289 inherited Destroy; 290end; 291 292procedure TRasterImage.FreeCanvasContext; 293begin 294 if (FCanvas <> nil) then TBitmapCanvas(FCanvas).FreeDC; 295end; 296 297function TRasterImage.GetCanvas: TCanvas; 298begin 299 if FCanvas = nil then 300 CreateCanvas; 301 Result := FCanvas; 302end; 303 304procedure TRasterImage.CreateCanvas; 305begin 306 if FCanvas <> nil then Exit; 307 308 FCanvas := TBitmapCanvas.Create(Self); 309 FCanvas.OnChanging := @CanvasChanging; 310 FCanvas.OnChange := @Changed; 311end; 312 313procedure TRasterImage.FreeImage; 314begin 315 SetHandle(0); 316end; 317 318procedure TRasterImage.LoadFromBitmapHandles(ABitmap, AMask: HBitmap; ARect: PRect); 319var 320 RawImg: TRawImage; 321 ImgHandle, ImgMaskHandle: HBitmap; 322begin 323 //DebugLn('TRasterImage.CreateFromBitmapHandles A SrcRect=',dbgs(SrcRect)); 324 if not RawImage_FromBitmap(RawImg, ABitmap, AMask, ARect) then 325 raise EInvalidGraphicOperation.Create('TRasterImage.LoadFromBitmapHandles Get RawImage'); 326 ImgHandle:=0; 327 ImgMaskHandle:=0; 328 try 329 //DebugLn('TRasterImage.CreateFromBitmapHandles B SrRect=',dbgs(SrcRect)); 330 if not RawImage_CreateBitmaps(RawImg, ImgHandle, ImgMaskHandle) then 331 raise EInvalidGraphicOperation.Create('TRasterImage.LoadFromBitmapHandles Create bitmaps'); 332 SetHandles(ImgHandle, ImgMaskHandle); 333 ImgHandle:=0; 334 ImgMaskHandle:=0; 335 finally 336 RawImg.FreeData; 337 if ImgHandle<>0 then DeleteObject(ImgHandle); 338 if ImgMaskHandle<>0 then DeleteObject(ImgMaskHandle); 339 end; 340end; 341 342procedure TRasterImage.LoadFromDevice(DC: HDC); 343var 344 IntfImg: TLazIntfImage; 345 ImgHandle, ImgMaskHandle: HBitmap; 346begin 347 ImgHandle:=0; 348 ImgMaskHandle:=0; 349 IntfImg:=nil; 350 try 351 // create the interface image 352 IntfImg:=TLazIntfImage.Create(0,0,[]); 353 // get a snapshot 354 IntfImg.LoadFromDevice(DC); 355 // create HBitmap 356 IntfImg.CreateBitmaps(ImgHandle, ImgMaskHandle); 357 // feed HBitmap into a TRasterImage 358 SetHandles(ImgHandle, ImgMaskHandle); 359 ImgHandle:=0; 360 ImgMaskHandle:=0; 361 finally 362 IntfImg.Free; 363 if ImgHandle<>0 then DeleteObject(ImgHandle); 364 if ImgMaskHandle<>0 then DeleteObject(ImgMaskHandle); 365 end; 366end; 367 368procedure TRasterImage.Mask(ATransparentColor: TColor); 369begin 370 CreateMask(ATransparentColor); 371end; 372 373procedure TRasterImage.SetTransparentColor(AValue: TColor); 374begin 375 if FTransparentColor = AValue then exit; 376 FTransparentColor := AValue; 377 378 if AValue = clDefault 379 then FTransparentMode := tmAuto 380 else FTransparentMode := tmFixed; 381 382 if MaskHandleAllocated 383 then MaskHandle := 0 384 else Changed(Self); 385end; 386 387procedure TRasterImage.Changed(Sender: TObject); 388begin 389 if FUpdateCount > 0 then Exit; 390 391 //FMaskBitsValid := False; 392 if Sender = FCanvas 393 then FreeSaveStream; 394 395 inherited Changed(Sender); 396end; 397 398function TRasterImage.CreateDefaultBitmapHandle( 399 const ADesc: TRawImageDescription): HBITMAP; 400begin 401 Result := 0; 402end; 403 404procedure TRasterImage.CanvasChanging(Sender: TObject); 405begin 406 if FUpdateCount > 0 then Exit; 407 408 // called before the canvas is modified 409 // -> make sure the handle is unshared (otherwise the modifications will also 410 // modify all copies) 411 // -> Savestream will be freed when changed (so it can be loaded by canvas) 412 UnshareImage(True); 413end; 414 415procedure TRasterImage.LoadFromStream(AStream: TStream); 416begin 417 LoadFromStream(AStream, AStream.Size - AStream.Position); 418end; 419 420procedure TRasterImage.LoadFromStream(AStream: TStream; ASize: Cardinal); 421var 422 WorkStream: TMemoryStream; 423 OldPos, NewSize: Int64; 424begin 425 BeginUpdate; 426 UnshareImage(False); 427 Clear; // clear old saved stream, allocated handles, etc 428 if ASize = 0 429 then begin 430 EndUpdate(False); 431 Exit; 432 end; 433 434 WorkStream := nil; 435 try 436 WorkStream := TMemoryStream.Create; 437 WorkStream.SetSize(ASize); 438 OldPos := AStream.Position; 439 WorkStream.CopyFrom(AStream, ASize); 440 WorkStream.Position := 0; 441 ReadStream(WorkStream, ASize); 442 NewSize := WorkStream.Position; 443 if NewSize < ASize 444 then begin 445 // the size given was different than the image loaded 446 // MWE: original code adjusted the streampos, do we stil need this ? 447 AStream.Position := OldPos + NewSize; 448 WorkStream.SetSize(NewSize); 449 end; 450 // Store our worstream as savestream 451 FSharedImage.SaveStream := WorkStream; 452 WorkStream := nil; 453 finally 454 // if something went wrong, free the workstream 455 WorkStream.Free; 456 end; 457 EndUpdate(True); 458end; 459 460function TRasterImage.GetRawImage: TRawImage; 461var 462 p: PRawImage; 463begin 464 p := GetRawImagePtr; 465 if p = nil 466 then Result{%H-}.Init 467 else Result := p^; 468end; 469 470function TRasterImage.GetScanline(ARow: Integer): Pointer; 471var 472 RI: TRawImage; 473begin 474 RI := GetRawImage; 475 Result := RI.GetLineStart(ARow); 476end; 477 478function TRasterImage.GetTransparentColor: TColor; 479begin 480 if FTransparentColor = clDefault 481 then Result := RequestTransparentColor 482 else Result := FTransparentColor; 483end; 484 485procedure TRasterImage.GetSupportedSourceMimeTypes(List: TStrings); 486begin 487 if (ClassType=TBitmap) or (ClassType=TPixmap) or (ClassType=TCustomIcon) then 488 begin 489 List.Clear; 490 List.Add(PredefinedClipboardMimeTypes[pcfBitmap]); 491 List.Add(PredefinedClipboardMimeTypes[pcfPixmap]); 492 end else 493 inherited GetSupportedSourceMimeTypes(List); 494end; 495 496function TRasterImage.GetTransparent: Boolean; 497var 498 Desc: PRawImageDescription; 499begin 500 if Masked 501 then begin 502 // postpone description generation since we know we are transparent here 503 Result := True 504 end 505 else begin 506 Desc := GetRawImageDescriptionPtr; 507 Result := (Desc <> nil) 508 and (Desc^.Format <> ricfNone) 509 and (Desc^.AlphaPrec > 0); 510 //TODO: check for transparency through palette etc. 511 end; 512end; 513 514function TRasterImage.GetWidth: Integer; 515var 516 Desc: PRawImageDescription; 517begin 518 Desc := GetRawImageDescriptionPtr; 519 if (Desc = nil) or (Desc^.Format = ricfNone) 520 then Result := 0 521 else Result := Desc^.Width; 522end; 523 524function TRasterImage.HandleAllocated: boolean; 525begin 526 Result := FSharedImage.FHandle <> 0; 527end; 528 529function TRasterImage.GetMimeType: string; 530begin 531 {$IFDEF VerboseLCLTodos}{$note: implement}{$ENDIF} 532 533 (* 534 if (ClassType=TBitmap) or (ClassType=TPixmap) or (ClassType=TCustomIcon) then begin 535 if FSharedImage.SaveStream<>nil then begin 536 case FSharedImage.SaveStreamType of 537 bnXPixmap: Result:=PredefinedClipboardMimeTypes[pcfPixmap]; 538 else 539 Result:=PredefinedClipboardMimeTypes[pcfBitmap]; 540 end; 541 end else 542 Result:=PredefinedClipboardMimeTypes[pcfBitmap]; 543 end else 544 *) 545 546 Result:=inherited GetMimeType; 547end; 548 549procedure TRasterImage.LoadFromIntfImage(IntfImage: TLazIntfImage); 550var 551 ImgHandle, ImgMaskHandle: HBitmap; 552begin 553 IntfImage.CreateBitmaps(ImgHandle, ImgMaskHandle, not IntfImage.HasMask); 554 SetHandles(ImgHandle, ImgMaskHandle); 555end; 556 557procedure TRasterImage.FreeSaveStream; 558begin 559 if FSharedImage.FSaveStream = nil then exit; 560 //DebugLn(['TRasterImage.FreeSaveStream A ',ClassName,' ',FImage.FSaveStream.Size]); 561 UnshareImage(false); 562 FreeAndNil(FSharedImage.FSaveStream); 563end; 564 565procedure TRasterImage.LoadFromMimeStream(AStream: TStream; const AMimeType: string); 566begin 567 {$IFDEF VerboseLCLTodos}{$note Make oo}{$ENDIF} 568 if (ClassType=TBitmap) or (ClassType=TPixmap) or (ClassType=TCustomIcon) then begin 569 if (AnsiCompareText(AMimeType,PredefinedClipboardMimeTypes[pcfBitmap])=0) 570 or (AnsiCompareText(AMimeType,PredefinedClipboardMimeTypes[pcfPixmap])=0) then 571 begin 572 LoadFromStream(AStream); 573 exit; 574 end; 575 end; 576 inherited LoadFromMimeStream(AStream, AMimeType); 577end; 578 579procedure TRasterImage.LoadFromRawImage(const AImage: TRawImage; ADataOwner: Boolean); 580var 581 img: PRawImage; 582begin 583 BeginUpdate; 584 try 585 Clear; 586 if AImage.Description.Format = ricfNone then Exit; // empty image 587 588 img := GetRawImagePtr; 589 590 // Make sure, we do not free AImage.Data or Mask 591 if img^.Data = AImage.Data then begin 592 img^.Data := nil; 593 img^.DataSize := 0; 594 end; 595 if img^.Mask = AImage.Mask then begin 596 img^.Mask := nil; 597 img^.MaskSize := 0; 598 end; 599 if img^.Palette = AImage.Palette then begin 600 img^.Palette := nil; 601 img^.PaletteSize := 0; 602 end; 603 img^.FreeData; 604 605 img^.Description := AImage.Description; 606 if ADataOwner 607 then begin 608 img^.DataSize := AImage.DataSize; 609 img^.Data := AImage.Data; 610 img^.MaskSize := AImage.MaskSize; 611 img^.Mask := AImage.Mask; 612 img^.PaletteSize := AImage.PaletteSize; 613 img^.Palette := AImage.Palette; 614 end 615 else begin 616 // copy needed 617 img^.DataSize := AImage.DataSize; 618 if img^.DataSize > 0 619 then begin 620 GetMem(img^.Data, img^.DataSize); 621 Move(AImage.Data^, img^.Data^, img^.DataSize); 622 end 623 else img^.Data := nil; 624 625 img^.MaskSize := AImage.MaskSize; 626 if img^.MaskSize > 0 627 then begin 628 GetMem(img^.Mask, img^.MaskSize); 629 Move(AImage.Mask^, img^.Mask^, img^.MaskSize); 630 end 631 else img^.Mask := nil; 632 633 img^.PaletteSize := AImage.PaletteSize; 634 if img^.PaletteSize > 0 635 then begin 636 GetMem(img^.Palette, img^.PaletteSize); 637 Move(AImage.Palette^, img^.Palette^, img^.PaletteSize); 638 end 639 else img^.Palette := nil; 640 end; 641 finally 642 EndUpdate; 643 end; 644end; 645 646procedure TRasterImage.SaveToStream(AStream: TStream); 647 procedure Error; 648 begin 649 raise FPImageException.Create(rsErrorWhileSavingBitmap); 650 end; 651var 652 Size, BytesWritten: Int64; 653begin 654 SaveStreamNeeded; 655 if FSharedImage.SaveStream = nil 656 then Error; 657 658 FSharedImage.SaveStream.Position := 0; 659 Size := FSharedImage.SaveStream.Size; 660 if AStream is TMemoryStream 661 then TMemoryStream(AStream).SetSize(AStream.Position + Size); 662 663 BytesWritten := AStream.CopyFrom(FSharedImage.SaveStream, Size); 664 if BytesWritten <> Size 665 then Error; 666end; 667 668procedure TRasterImage.SetBitmapHandle(AValue: HBITMAP); 669begin 670 if MaskHandleAllocated 671 then SetHandles(AValue, MaskHandle) 672 else SetHandles(AValue, 0); 673end; 674 675procedure TRasterImage.SetHandle(AValue: THandle); 676begin 677 if FSharedImage.FHandle = AValue then Exit; 678 FreeCanvasContext; 679 UnshareImage(False); 680 FSharedImage.FHandle := AValue; 681 if FUpdateCount = 0 682 then Changed(Self); 683end; 684 685procedure TRasterImage.SetMaskHandle(AValue: HBITMAP); 686begin 687 if BitmapHandleAllocated 688 then SetHandles(BitmapHandle, AValue) 689 else SetHandles(0, AValue); 690end; 691 692procedure TRasterImage.SetMasked(AValue: Boolean); 693begin 694 if AValue = Masked then Exit; 695 696 FMasked := AValue; 697 Changed(Self); 698end; 699 700procedure TRasterImage.SetTransparentMode(AValue: TTransparentMode); 701begin 702 if AValue = TransparentMode then exit; 703 FTransparentMode := AValue; 704 705 if AValue = tmAuto 706 then TransparentColor := clDefault 707 else TransparentColor := RequestTransparentColor; 708end; 709 710procedure TRasterImage.SetTransparent(AValue: Boolean); 711var 712 lTransparent: Boolean; 713begin 714 lTransparent := GetTransparent(); 715 if AValue = lTransparent then Exit; 716 717 // some delphi compatibility, we can only change transparency through the mask. 718 Masked := AValue; 719end; 720 721// release handles without freeing them 722// useful for creating a HBitmap 723function TRasterImage.ReleaseBitmapHandle: HBITMAP; 724begin 725 BitmapHandleNeeded; 726 FreeCanvasContext; 727 Result := InternalReleaseBitmapHandle; 728end; 729 730function TRasterImage.ReleaseMaskHandle: HBITMAP; 731begin 732 MaskHandleNeeded; 733 FreeCanvasContext; 734 Result := InternalReleaseMaskHandle; 735end; 736 737function TRasterImage.ReleasePalette: HPALETTE; 738begin 739 PaletteNeeded; 740 FreeCanvasContext; 741 Result := InternalReleasePalette; 742end; 743 744procedure TRasterImage.SaveStreamNeeded; 745var 746 WorkStream: TMemoryStream; 747begin 748 if FUpdateCount > 0 749 then raise EInvalidGraphicOperation.Create(rsRasterImageSaveInUpdate); 750 751 if FSharedImage.SaveStream <> nil then Exit; 752 753 WorkStream := TMemoryStream.Create; 754 try 755 WriteStream(WorkStream); 756 // Store our workstream as savestream 757 FSharedImage.SaveStream := WorkStream; 758 WorkStream := nil; 759 finally 760 // if something went wrong, free the workstream 761 WorkStream.Free; 762 end; 763end; 764 765function TRasterImage.CreateIntfImage: TLazIntfImage; 766begin 767 {$IFDEF VerboseLCLTodos}{$note todo: create based on rawimage}{$ENDIF} 768 Result := TLazIntfImage.Create(0,0,[]); 769 Result.LoadFromBitmap(BitmapHandle, MaskHandle); 770end; 771 772procedure TRasterImage.CreateMask(AColor: TColor); 773var 774 IntfImage: TLazIntfImage; 775 ImgHandle, MskHandle: HBitmap; 776 TransColor: TFPColor; 777begin 778 //DebugLn(['TRasterImage.CreateMask ',Width,'x',Height,' ',Transparent,' ',dbgs(ord(TransparentMode)),' ',dbgs(TransparentColor)]); 779 if (Width = 0) 780 or (Height = 0) 781 or (AColor = clNone) 782 or ( (FTransparentMode = tmFixed) 783 and (FTransparentColor = clNone) 784 and (AColor = clDefault) 785 ) 786 then begin 787 MaskHandle := 0; 788 Exit; 789 end; 790 791 {$IFDEF VerboseLCLTodos}{$note todo: move to IntfImage}{$ENDIF} 792 IntfImage := TLazIntfImage.Create(0,0,[]); 793 try 794 // force handle creation here, since at next step we will check for mask handle 795 ImgHandle := BitmapHandle; 796 // load from bitmap needs a mask handle otherwise no mask description is 797 // created. 798 if MaskHandleAllocated 799 then MskHandle := MaskHandle 800 else MskHandle := CreateBitmap(Width, Height, 1, 1, nil); 801 IntfImage.LoadFromBitmap(ImgHandle, MskHandle); 802 if not MaskHandleAllocated 803 then DeleteObject(MskHandle); 804 ImgHandle := 0; 805 806 if AColor = clDefault 807 then begin 808 if (FTransparentMode = tmFixed) and (FTransparentColor <> clDefault) 809 then TransColor := TColorToFPColor(ColorToRGB(FTransparentColor)) 810 else TransColor := IntfImage.Colors[0, IntfImage.Height - 1]; 811 end 812 else TransColor := TColorToFPColor(ColorToRGB(AColor)); 813 814 IntfImage.Mask(TransColor); 815 816 IntfImage.CreateBitmaps(ImgHandle, MskHandle); 817 MaskHandle := MskHandle; 818 DeleteObject(ImgHandle); 819 finally 820 IntfImage.Free; 821 end; 822end; 823 824function TRasterImage.GetEmpty: boolean; 825begin 826 Result := FSharedImage.IsEmpty; 827end; 828 829function TRasterImage.GetHandle: THandle; 830begin 831 HandleNeeded; 832 Result := FSharedImage.FHandle; 833end; 834 835function TRasterImage.GetHeight: Integer; 836var 837 Desc: PRawImageDescription; 838begin 839 Desc := GetRawImageDescriptionPtr; 840 if (Desc = nil) or (Desc^.Format = ricfNone) 841 then Result := 0 842 else Result := Desc^.Height; 843end; 844 845function TRasterImage.GetMasked: Boolean; 846begin 847 Result := FMasked; 848end; 849 850class function TRasterImage.GetSharedImageClass: TSharedRasterImageClass; 851begin 852 Result := TSharedRasterImage; 853end; 854 855procedure TRasterImage.GetSize(out AWidth, AHeight: Integer); 856var 857 Desc: PRawImageDescription; 858begin 859 Desc := GetRawImageDescriptionPtr; 860 if (Desc = nil) or (Desc^.Format = ricfNone) 861 then begin 862 AWidth := 0; 863 AHeight := 0; 864 end 865 else begin 866 AWidth := Desc^.Width; 867 AHeight := Desc^.Height; 868 end; 869end; 870 871 872 873procedure TRasterImage.ReadData(Stream: TStream); 874 function GetImageClass: TRasterImageClass; 875 const 876 // need to repeat here since they aren't defined yet 877 IconSignature: array [0..3] of char = #0#0#1#0; 878 CursorSignature: array [0..3] of char = #0#0#2#0; 879 var 880 Sig: array[0..7] of Char; 881 Position: Int64; 882 begin 883 Position := Stream.Position; 884 Stream.Read(Sig[0], SizeOf(Sig)); 885 Stream.Position := Position; 886 887 if (Sig[0] = 'B') and (Sig[1] = 'M') then Exit(TBitmap); 888 if CompareMem(@Sig[0], @PNGcomn.Signature[0], 8) then Exit(TPortableNetworkGraphic); 889 if CompareMem(@Sig[0], @IconSignature[0], 4) then Exit(TIcon); 890 if CompareMem(@Sig[0], @CursorSignature[0], 4) then Exit(TCursorImage); 891 if TestStreamIsXPM(Stream) then Exit(TPixmap); 892 893 Result := nil; 894 end; 895 896var 897 Size: Longint; 898 ImageClass: TRasterImageClass; 899 Image: TRasterImage; 900begin 901 Stream.Read(Size, SizeOf(Size)); 902 Size := LEtoN(Size); 903 904 // pre laz 0.9.26 there was no strict relation between graphic format and 905 // classtype, so we need to check if we need some conversion 906 if Size >= 8 907 then ImageClass := GetImageClass 908 else ImageClass := nil; 909 910 if (ImageClass = nil) or ClassType.InheritsFrom(ImageClass) 911 then begin 912 // no conversion needed, or it wasn't a known "old" format 913 LoadFromStream(Stream, Size); 914 Exit; 915 end; 916 917 Image := ImageClass.Create; 918 Image.LoadFromStream(Stream, Size); 919 try 920 Assign(Image); 921 finally 922 Image.Free; 923 end; 924end; 925 926procedure TRasterImage.WriteData(Stream: TStream); 927 procedure Error; 928 begin 929 raise FPImageException.Create(rsErrorWhileSavingBitmap); 930 end; 931var 932 Size: Longint; 933begin 934 SaveStreamNeeded; 935 if FSharedImage.SaveStream = nil 936 then Error; 937 938 Size := NtoLE(Longint(FSharedImage.SaveStream.Size)); 939 Stream.Write(Size, SizeOf(Size)); 940 SaveToStream(Stream); 941end; 942 943function TRasterImage.RequestTransparentColor: TColor; 944var 945 RawImagePtr: PRawImage; 946 IntfImage: TLazIntfImage; 947begin 948 // if RawImage exits then use it to get pixel overwise get it from the canvas 949 if Empty then 950 begin 951 Result := clNone; 952 Exit; 953 end; 954 955 RawImagePtr := GetRawImagePtr; 956 if RawImagePtr <> nil then 957 begin 958 IntfImage := TLazIntfImage.Create(RawImagePtr^, False); 959 try 960 Result := FPColorToTColor(IntfImage.Colors[0, Height - 1]); 961 finally 962 IntfImage.Free; 963 end; 964 end 965 else 966 Result := Canvas.GetPixel(0, Height - 1); 967end; 968 969procedure TRasterImage.SetWidth(AWidth: Integer); 970begin 971 SetSize(AWidth, Height); 972end; 973 974procedure TRasterImage.SetHeight(AHeight: Integer); 975begin 976 SetSize(Width, AHeight); 977end; 978 979// included by graphics.pp 980 981 982