1{%MainUnit ../graphics.pp} 2 3{ TPicture and help classes TPictureFileFormatList 4 5 ***************************************************************************** 6 This file is part of the Lazarus Component Library (LCL) 7 8 See the file COPYING.modifiedLGPL.txt, included in this distribution, 9 for details about the license. 10 ***************************************************************************** 11} 12 13type 14 { TPicFileFormatsList } 15 16 PPicFileFormat = ^TPicFileFormat; 17 TPicFileFormat = record 18 GraphicClass: TGraphicClass; 19 Extension: string; // ; low case separated list, first is default 20 Description: string; 21 end; 22 23 TPicFileFormatsList = class(TList) 24 // list of TPicFileFormat 25 public 26 constructor Create; 27 procedure Clear; override; 28 procedure Delete(Index: Integer); 29 procedure Add(const Ext, Desc: String; AClass: TGraphicClass); 30 function GetFormats(Index: integer): PPicFileFormat; 31 function GetFormatExt(Index: integer): String; 32 function GetFormatFilter(Index: integer): String; 33 function FindExt(const Ext: string): TGraphicClass; 34 function FindClassName(const AClassname: string): TGraphicClass; 35 function FindByStreamFormat(Stream: TStream): TGraphicClass; 36 procedure Remove(AClass: TGraphicClass); 37 procedure BuildFilterStrings(GraphicClass: TGraphicClass; 38 var Descriptions, Filters: string); 39 property Formats[Index: integer]: PPicFileFormat read GetFormats; default; 40 end; 41 42constructor TPicFileFormatsList.Create; 43begin 44 inherited Create; 45 // add by priority of use in LCL/IDE 46 Add(TPortableNetworkGraphic.GetFileExtensions, rsPortableNetworkGraphic, TPortableNetworkGraphic); 47 Add(TPixmap.GetFileExtensions, rsPixmap, TPixmap); 48 Add(TBitmap.GetFileExtensions, rsBitmaps, TBitmap); 49 Add(TCursorImage.GetFileExtensions, rsCursor, TCursorImage); 50 Add(TIcon.GetFileExtensions, rsIcon, TIcon); 51 Add(TIcnsIcon.GetFileExtensions, rsIcns, TIcnsIcon); 52 {$IFNDEF DisableLCLJPEG} 53 Add(TJpegImage.GetFileExtensions, rsJpeg, TJpegImage); 54 {$ENDIF} 55 {$IFNDEF DisableLCLTIFF} 56 Add(TTiffImage.GetFileExtensions, rsTiff, TTiffImage); 57 {$ENDIF} 58 {$IFNDEF DisableLCLGIF} 59 Add(TGIFImage.GetFileExtensions, rsGIF, TGIFImage); 60 {$ENDIF} 61 {$IFNDEF DisableLCLPNM} 62 Add(TPortableAnyMapGraphic.GetFileExtensions, rsPortablePixmap, TPortableAnyMapGraphic); 63 {$ENDIF} 64end; 65 66procedure TPicFileFormatsList.Clear; 67var 68 i: integer; 69 P: PPicFileFormat; 70begin 71 for i:=0 to Count - 1 do 72 begin 73 P := GetFormats(i); 74 Dispose(P); 75 end; 76 inherited Clear; 77end; 78 79procedure TPicFileFormatsList.Delete(Index: Integer); 80var 81 P: PPicFileFormat; 82begin 83 P:=GetFormats(Index); 84 Dispose(P); 85 inherited Delete(Index); 86end; 87 88procedure TPicFileFormatsList.Add(const Ext, Desc: String; 89 AClass: TGraphicClass); 90var 91 NewFormat: PPicFileFormat; 92begin 93 New(NewFormat); 94 with NewFormat^ do 95 begin 96 Extension := AnsiLowerCase(Ext); 97 GraphicClass := AClass; 98 Description := Desc; 99 end; 100 inherited Add(NewFormat); 101end; 102 103function TPicFileFormatsList.GetFormats(Index: integer): PPicFileFormat; 104begin 105 Result:=PPicFileFormat(Items[Index]); 106end; 107 108function TPicFileFormatsList.GetFormatExt(Index: integer): String; 109begin 110 Result := PPicFileFormat(Items[Index])^.Extension; 111 if Pos(';', Result) > 0 then 112 System.Delete(Result, Pos(';', Result), MaxInt); 113end; 114 115function TPicFileFormatsList.GetFormatFilter(Index: integer): String; 116begin 117 Result := StringReplace('*.' + PPicFileFormat(Items[Index])^.Extension, ';', ';*.', [rfReplaceAll]); 118end; 119 120function TPicFileFormatsList.FindExt(const Ext: string): TGraphicClass; 121var 122 I, P: Integer; 123 E, ExtList: String; 124begin 125 if Ext<>'' then 126 begin 127 E := AnsiLowerCase(Ext); 128 if E[1] = '.' then System.Delete(E, 1, 1); 129 130 for I := Count - 1 downto 0 do 131 with Formats[I]^ do 132 if Pos(E, Extension) > 0 then 133 begin 134 ExtList := Extension; 135 repeat 136 P := Pos(';', ExtList); 137 if (P = 0) and (ExtList = E) or (Pos(E + ';', ExtList) = 1) then 138 begin 139 Result := GraphicClass; 140 Exit; 141 end; 142 System.Delete(ExtList, 1, P); 143 until P = 0; 144 end; 145 end; 146 Result := nil; 147end; 148 149function TPicFileFormatsList.FindClassName(const AClassName: string): TGraphicClass; 150var 151 I: Integer; 152begin 153 // search backwards so that new formats will be found first 154 for I := Count-1 downto 0 do begin 155 Result := GetFormats(I)^.GraphicClass; 156 if AnsiCompareText(Result.ClassName,AClassname)=0 then 157 Exit; 158 end; 159 Result := nil; 160end; 161 162function TPicFileFormatsList.FindByStreamFormat(Stream: TStream): TGraphicClass; 163var 164 I: Integer; 165begin 166 for I := 0 to Count - 1 do 167 begin 168 Result := GetFormats(I)^.GraphicClass; 169 if Result.IsStreamFormatSupported(Stream) then 170 Exit; 171 end; 172 Result := nil; 173end; 174 175procedure TPicFileFormatsList.Remove(AClass: TGraphicClass); 176// remove all file formats which inherits from AClass 177var 178 I: Integer; 179 P: PPicFileFormat; 180begin 181 for I := Count - 1 downto 0 do 182 begin 183 P := GetFormats(I); 184 if P^.GraphicClass.InheritsFrom(AClass) then 185 Delete(I); 186 end; 187end; 188 189procedure TPicFileFormatsList.BuildFilterStrings(GraphicClass: TGraphicClass; 190 var Descriptions, Filters: string); 191var 192 C, I: Integer; 193 P: PPicFileFormat; 194 Filter: String; 195begin 196 Descriptions := ''; 197 Filters := ''; 198 C := 0; 199 for I := 0 to Count - 1 do 200 begin 201 P := GetFormats(I); 202 if P^.GraphicClass.InheritsFrom(GraphicClass) and (P^.Extension <> '') then 203 with P^ do begin 204 if C <> 0 then begin 205 Descriptions := Descriptions + '|'; 206 Filters := Filters + ';'; 207 end; 208 Filter := GetFormatFilter(I); 209 FmtStr(Descriptions, '%s%s (%s)|%s', 210 [Descriptions, Description, Filter, Filter]); 211 FmtStr(Filters, '%s%s', [Filters, Filter]); 212 Inc(C); 213 end; 214 end; 215 if C > 1 then 216 FmtStr(Descriptions, '%s (%s)|%1:s|%s', 217 [rsGraphic, Filters, Descriptions]); 218end; 219 220//------------------------------------------------------------------------------ 221 222type 223 PPicClipboardFormat = ^TPicClipboardFormat; 224 TPicClipboardFormat = record 225 GraphicClass: TGraphicClass; 226 FormatID: TClipboardFormat; 227 end; 228 229 TPicClipboardFormats = class(TList) 230 // list of TPicClipboardFormat 231 private 232 function GetFormats(Index: integer): PPicClipboardFormat; 233 public 234 constructor Create; 235 procedure Clear; override; 236 procedure Delete(Index: Integer); 237 procedure Add(AFormatID: TClipboardFormat; AClass: TGraphicClass); 238 function FindFormat(FormatID: TClipboardFormat): TGraphicClass; 239 procedure Remove(AClass: TGraphicClass); 240 property Formats[Index: integer]: PPicClipboardFormat read GetFormats; default; 241 end; 242 243function TPicClipboardFormats.GetFormats(Index: integer): PPicClipboardFormat; 244begin 245 Result:=PPicClipboardFormat(Items[Index]); 246end; 247 248constructor TPicClipboardFormats.Create; 249const 250 sMimeTypePng = 'image/png'; 251 sMimeTypeJpg = 'image/jpeg'; 252begin 253 inherited Create; 254 Add(PredefinedClipboardFormat(pcfBitmap), TBitmap); 255 Add(PredefinedClipboardFormat(pcfPixmap), TPixmap); 256 //Add(PredefinedClipboardFormat(pcfIcon), TCustomIcon); 257 Add(ClipboardRegisterFormat(sMimeTypePng), TPortableNetworkGraphic); 258 {$IFNDEF DisableLCLJPEG} 259 Add(ClipboardRegisterFormat(sMimeTypeJpg), TJPegImage); 260 {$ENDIF} 261end; 262 263procedure TPicClipboardFormats.Clear; 264var 265 i: integer; 266 P: PPicClipboardFormat; 267begin 268 for i := 0 to Count - 1 do 269 begin 270 P := GetFormats(i); 271 Dispose(P); 272 end; 273 inherited Clear; 274end; 275 276procedure TPicClipboardFormats.Delete(Index: Integer); 277var 278 P: PPicClipboardFormat; 279begin 280 P := GetFormats(Index); 281 Dispose(P); 282 inherited Delete(Index); 283end; 284 285procedure TPicClipboardFormats.Add(AFormatID: TClipboardFormat; 286 AClass: TGraphicClass); 287var NewFormat: PPicClipboardFormat; 288begin 289 if AFormatID=0 then exit; 290 New(NewFormat); 291 with NewFormat^ do begin 292 GraphicClass:=AClass; 293 FormatID:=AFormatID; 294 end; 295 inherited Add(NewFormat); 296end; 297 298function TPicClipboardFormats.FindFormat( 299 FormatID: TClipboardFormat): TGraphicClass; 300var 301 I: Integer; 302 P: PPicClipboardFormat; 303begin 304 for I := Count-1 downto 0 do begin 305 P:=GetFormats(i); 306 if P^.FormatID=FormatID then begin 307 Result:=P^.GraphicClass; 308 Exit; 309 end; 310 end; 311 Result := nil; 312end; 313 314procedure TPicClipboardFormats.Remove(AClass: TGraphicClass); 315var 316 I: Integer; 317begin 318 for I := Count-1 downto 0 do 319 if GetFormats(i)^.GraphicClass.InheritsFrom(AClass) then 320 Delete(i); 321end; 322 323//------------------------------------------------------------------------------ 324 325var 326 PicClipboardFormats: TPicClipboardFormats=nil; 327 PicFileFormats: TPicFileFormatsList=nil; 328 329function GetPicFileFormats: TPicFileFormatsList; 330begin 331 if not Assigned(PicFileFormats) and not GraphicsFinalized then 332 PicFileFormats := TPicFileFormatsList.Create; 333 Result := PicFileFormats; 334end; 335 336function GetPicClipboardFormats: TPicClipboardFormats; 337begin 338 if (PicClipboardFormats = nil) and (not GraphicsFinalized) then 339 PicClipboardFormats := TPicClipboardFormats.Create; 340 Result := PicClipboardFormats; 341end; 342 343function GraphicFilter(GraphicClass: TGraphicClass): string; 344var 345 Filters: string; 346begin 347 Result := ''; 348 GetPicFileFormats.BuildFilterStrings(GraphicClass,Result,Filters); 349end; 350 351function GraphicExtension(GraphicClass: TGraphicClass): string; 352var 353 I: Integer; 354 PicFormats: TPicFileFormatsList; 355begin 356 PicFormats := GetPicFileFormats; 357 for I := PicFormats.Count-1 downto 0 do 358 if PicFormats[I]^.GraphicClass.ClassName = GraphicClass.ClassName then 359 begin 360 Result := PicFormats.GetFormatExt(I); 361 Exit; 362 end; 363 Result := ''; 364end; 365 366function GraphicFileMask(GraphicClass: TGraphicClass): string; 367var 368 Descriptions: string; 369begin 370 Result := ''; 371 GetPicFileFormats.BuildFilterStrings(GraphicClass,Descriptions,Result); 372end; 373 374function GetGraphicClassForFileExtension(const FileExt: string): TGraphicClass; 375begin 376 Result:=GetPicFileFormats.FindExt(FileExt); 377end; 378 379//--TPicture-------------------------------------------------------------------- 380 381 382constructor TPicture.Create; 383begin 384 inherited Create; 385 GetPicFileFormats; 386 GetPicClipboardFormats; 387end; 388 389destructor TPicture.Destroy; 390begin 391 FGraphic.Free; 392 inherited Destroy; 393end; 394 395procedure TPicture.AssignTo(Dest: TPersistent); 396begin 397 if Graphic is Dest.ClassType then 398 Dest.Assign(Graphic) 399 else 400 inherited AssignTo(Dest); 401end; 402 403procedure TPicture.ForceType(GraphicType: TGraphicClass); 404var 405 NewGraphic: TGraphic; 406begin 407 if not (FGraphic is GraphicType) then 408 begin 409 NewGraphic := GraphicType.Create; 410 NewGraphic.Assign(FGraphic); 411 FGraphic.Free; 412 FGraphic := NewGraphic; 413 FGraphic.OnChange := @Changed; 414 FGraphic.OnProgress := @Progress; 415 Changed(Self); 416 end; 417end; 418 419function TPicture.GetBitmap: TBitmap; 420begin 421 ForceType(TBitmap); 422 Result := TBitmap(Graphic); 423end; 424 425function TPicture.GetPNG: TPortableNetworkGraphic; 426begin 427 ForceType(TPortableNetworkGraphic); 428 Result := TPortableNetworkGraphic(Graphic); 429end; 430 431{$IFNDEF DisableLCLPNM} 432function TPicture.GetPNM: TPortableAnyMapGraphic; 433begin 434 ForceType(TPortableAnyMapGraphic); 435 Result := TPortableAnyMapGraphic(Graphic); 436end; 437{$ENDIF} 438 439function TPicture.GetPixmap: TPixmap; 440begin 441 ForceType(TPixmap); 442 Result := TPixmap(Graphic); 443end; 444 445function TPicture.GetIcon: TIcon; 446begin 447 ForceType(TIcon); 448 Result := TIcon(Graphic); 449end; 450 451{$IFNDEF DisableLCLJPEG} 452function TPicture.GetJpeg: TJpegImage; 453begin 454 ForceType(TJpegImage); 455 Result := TJpegImage(Graphic); 456end; 457{$ENDIF} 458 459procedure TPicture.SetBitmap(Value: TBitmap); 460begin 461 SetGraphic(Value); 462end; 463 464procedure TPicture.SetPNG(const AValue: TPortableNetworkGraphic); 465begin 466 SetGraphic(AValue); 467end; 468 469{$IFNDEF DisableLCLPNM} 470procedure TPicture.SetPNM(const AValue: TPortableAnyMapGraphic); 471begin 472 SetGraphic(AValue); 473end; 474{$ENDIF} 475 476procedure TPicture.SetPixmap(Value: TPixmap); 477begin 478 SetGraphic(Value); 479end; 480 481procedure TPicture.SetIcon(Value: TIcon); 482begin 483 SetGraphic(Value); 484end; 485 486{$IFNDEF DisableLCLJPEG} 487procedure TPicture.SetJpeg(Value: TJpegImage); 488begin 489 SetGraphic(Value); 490end; 491{$ENDIF} 492 493procedure TPicture.SetGraphic(Value: TGraphic); 494var 495 NewGraphic: TGraphic; 496 ok: boolean; 497begin 498 if (Value=FGraphic) then exit; 499 NewGraphic := nil; 500 ok := False; 501 try 502 if Value <> nil then 503 begin 504 NewGraphic := TGraphicClass(Value.ClassType).Create; 505 NewGraphic.Assign(Value); 506 NewGraphic.OnChange := @Changed; 507 NewGraphic.OnProgress := @Progress; 508 end; 509 FGraphic.Free; 510 FGraphic := NewGraphic; 511 Changed(Self); 512 ok := True; 513 finally 514 // this try..finally construction will in case of an exception 515 // not alter the error backtrace output 516 if not ok then 517 NewGraphic.Free; 518 end; 519end; 520 521{ Based on the extension of Filename, create the corresponding TGraphic class 522 and call its LoadFromFile method. } 523 524procedure TPicture.LoadFromFile(const Filename: string); 525var 526 Ext: string; 527 Stream: TStream; 528begin 529 Ext := ExtractFileExt(Filename); 530 System.Delete(Ext, 1, 1); // delete '.' 531 532 Stream := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite); 533 try 534 if Ext <> '' then 535 LoadFromStreamWithFileExt(Stream, Ext) 536 else 537 LoadFromStream(Stream); 538 finally 539 Stream.Free; 540 end; 541end; 542 543procedure TPicture.LoadFromResourceName(Instance: THandle; const ResName: String); 544var 545 NewGraphic: TGraphic; 546begin 547 NewGraphic := CreateGraphicFromResourceName(Instance, ResName); 548 FGraphic.Free; 549 FGraphic := NewGraphic; 550 FGraphic.OnChange := @Changed; 551 Changed(Self); 552end; 553 554procedure TPicture.LoadFromResourceName(Instance: THandle; 555 const ResName: String; AClass: TGraphicClass); 556var 557 NewGraphic: TGraphic; 558 ok: Boolean; 559begin 560 NewGraphic := AClass.Create; 561 ok:=false; 562 try 563 NewGraphic.OnProgress := @Progress; 564 NewGraphic.LoadFromResourceName(Instance, ResName); 565 ok:=true; 566 finally 567 // this try..finally construction will in case of an exception 568 // not alter the error backtrace output 569 if not ok then NewGraphic.Free; 570 end; 571 FGraphic.Free; 572 FGraphic := NewGraphic; 573 FGraphic.OnChange := @Changed; 574 Changed(Self); 575end; 576 577procedure TPicture.LoadFromLazarusResource(const AName: string); 578var 579 Stream: TLazarusResourceStream; 580begin 581 Stream := TLazarusResourceStream.Create(AName, nil); 582 try 583 LoadFromStreamWithFileExt(Stream, Stream.Res.ValueType); 584 finally 585 Stream.Free; 586 end; 587end; 588 589procedure TPicture.LoadFromStream(Stream: TStream); 590var 591 GraphicClass: TGraphicClass; 592begin 593 GraphicClass := GetPicFileFormats.FindByStreamFormat(Stream); 594 if GraphicClass = nil then 595 raise EInvalidGraphic.Create(rsUnknownPictureFormat); 596 LoadFromStreamWithClass(Stream, GraphicClass); 597end; 598 599procedure TPicture.SaveToFile(const Filename: string; const FileExt: string = ''); 600var 601 Ext: string; 602 Stream: TStream; 603begin 604 if FileExt <> '' then 605 Ext := AnsiLowerCase(FileExt) 606 else 607 Ext := AnsiLowerCase(ExtractFileExt(Filename)); 608 609 if (Ext <> '') and (Ext[1] = '.') then System.Delete(Ext, 1, 1); // delete '.' 610 611 Stream := TFileStream.Create(Filename, fmCreate); 612 try 613 SaveToStreamWithFileExt(Stream, Ext); 614 finally 615 Stream.Free; 616 end; 617end; 618 619procedure TPicture.SaveToStream(Stream: TStream); 620begin 621 if Assigned(Graphic) then 622 Graphic.SaveToStream(Stream); 623end; 624 625procedure TPicture.SaveToStreamWithFileExt(Stream: TStream; const FileExt: string); 626var 627 GraphicClass: TGraphicClass; 628 IntfImg: TLazIntfImage; 629 ImgWriter: TFPCustomImageWriter; 630 fpBmp: TFPImageBitmap; 631begin 632 if Graphic = nil then Exit; 633 if FileExt <> '' then 634 GraphicClass := FindGraphicClassWithFileExt(FileExt); 635 636 if (FileExt = '') 637 or (Graphic is GraphicClass) 638 then begin 639 Graphic.SaveToStream(Stream); 640 Exit; 641 end; 642 643 // save in different format 644 if (Graphic is TFPImageBitmap) and GraphicClass.InheritsFrom(TFPImageBitmap) 645 then begin 646 fpBmp := TFPImageBitmap(Graphic); 647 ImgWriter := nil; 648 IntfImg := TLazIntfImage.Create(0,0,[]); 649 try 650 ImgWriter := TFPImageBitmapClass(GraphicClass).GetWriterClass.Create; 651 IntfImg.SetRawImage(fpBmp.GetRawImagePtr^, False); 652 fpBmp.InitializeWriter(IntfImg, ImgWriter); 653 IntfImg.SaveToStream(Stream, ImgWriter); 654 fpBmp.FinalizeWriter(ImgWriter); 655 finally 656 IntfImg.Free; 657 ImgWriter.Free; 658 end; 659 Exit; 660 end; 661 662 // no conversion available yet 663 raise Exception.CreateFmt('TODO: Conversion for vector or icon images of format "%s" to "%s"!', [Graphic.GetFileExtensions, FileExt]); 664end; 665 666procedure TPicture.LoadFromStreamWithFileExt(Stream: TStream; 667 const FileExt: string); 668begin 669 LoadFromStreamWithClass(Stream, FindGraphicClassWithFileExt(FileExt)); 670end; 671 672procedure TPicture.LoadFromClipboardFormat(FormatID: TClipboardFormat); 673begin 674 LoadFromClipboardFormatID(ctClipboard,FormatID); 675end; 676 677procedure TPicture.LoadFromClipboardFormatID(ClipboardType: TClipboardType; 678 FormatID: TClipboardFormat); 679var 680 NewGraphic: TGraphic; 681 GraphicClass: TGraphicClass; 682 ok: boolean; 683begin 684 GraphicClass := PicClipboardFormats.FindFormat(FormatID); 685 if GraphicClass = nil then 686 raise EInvalidGraphic.CreateFmt(rsUnsupportedClipboardFormat, 687 [ClipboardFormatToMimeType(FormatID)]); 688 689 NewGraphic := GraphicClass.Create; 690 ok:=false; 691 try 692 NewGraphic.OnProgress := @Progress; 693 NewGraphic.LoadFromClipboardFormatID(ClipboardType,FormatID); 694 ok:=true; 695 finally 696 if not ok then NewGraphic.Free; 697 end; 698 FGraphic.Free; 699 FGraphic := NewGraphic; 700 FGraphic.OnChange := @Changed; 701 Changed(Self); 702end; 703 704procedure TPicture.SaveToClipboardFormat(FormatID: TClipboardFormat); 705begin 706 if FGraphic <> nil then 707 FGraphic.SaveToClipboardFormat(FormatID); 708end; 709 710class function TPicture.SupportsClipboardFormat(FormatID: TClipboardFormat): Boolean; 711begin 712 Result := GetPicClipboardFormats.FindFormat(FormatID) <> nil; 713end; 714 715procedure TPicture.Assign(Source: TPersistent); 716begin 717 if Source = nil then 718 SetGraphic(nil) 719 else if Source is TPicture then 720 SetGraphic(TPicture(Source).Graphic) 721 else if Source is TGraphic then 722 SetGraphic(TGraphic(Source)) 723 else if Source is TFPCustomImage then 724 Bitmap.Assign(Source) 725 else 726 inherited Assign(Source); 727end; 728 729class procedure TPicture.RegisterFileFormat(const AnExtension, 730 ADescription: string; AGraphicClass: TGraphicClass); 731begin 732 GetPicFileFormats.Add(AnExtension, ADescription, AGraphicClass); 733end; 734 735class procedure TPicture.RegisterClipboardFormat(FormatID: TClipboardFormat; 736 AGraphicClass: TGraphicClass); 737begin 738 GetPicClipboardFormats.Add(FormatID, AGraphicClass); 739end; 740 741class procedure TPicture.UnregisterGraphicClass(AClass: TGraphicClass); 742begin 743 if PicFileFormats <> nil then PicFileFormats.Remove(AClass); 744 if PicClipboardFormats <> nil then PicClipboardFormats.Remove(AClass); 745end; 746 747procedure TPicture.Clear; 748begin 749 SetGraphic(nil); 750end; 751 752class function TPicture.FindGraphicClassWithFileExt(const Ext: string; 753 ExceptionOnNotFound: boolean): TGraphicClass; 754var 755 FileExt: String; 756begin 757 FileExt := Ext; 758 if (FileExt <> '') and (FileExt[1] = '.') then 759 FileExt := Copy(FileExt, 2, length(FileExt)); 760 Result := GetPicFileFormats.FindExt(FileExt); 761 if (Result = nil) and ExceptionOnNotFound then 762 raise EInvalidGraphic.CreateFmt(rsUnknownPictureExtension, [Ext]); 763end; 764 765procedure TPicture.Changed(Sender: TObject); 766begin 767 if Assigned(FOnChange) then FOnChange(Self); 768end; 769 770procedure TPicture.Progress(Sender: TObject; Stage: TProgressStage; 771 PercentDone: Byte; RedrawNow: Boolean; const R: TRect; const Msg: string; 772 var DoContinue: boolean); 773begin 774 DoContinue:=true; 775 if Assigned(FOnProgress) then 776 FOnProgress(Sender, Stage, PercentDone, RedrawNow, R, Msg, DoContinue); 777end; 778 779procedure TPicture.LoadFromStreamWithClass(Stream: TStream; AClass: TGraphicClass); 780var 781 NewGraphic: TGraphic; 782 ok: Boolean; 783begin 784 NewGraphic := AClass.Create; 785 ok:=false; 786 try 787 NewGraphic.OnProgress := @Progress; 788 NewGraphic.LoadFromStream(Stream); 789 ok:=true; 790 finally 791 // this try..finally construction will in case of an exception 792 // not alter the error backtrace output 793 if not ok then NewGraphic.Free; 794 end; 795 FGraphic.Free; 796 FGraphic := NewGraphic; 797 FGraphic.OnChange := @Changed; 798 Changed(Self); 799end; 800 801procedure TPicture.ReadData(Stream: TStream); 802var 803 GraphicClassName: Shortstring; 804 NewGraphic: TGraphic; 805 GraphicClass: TGraphicClass; 806 ok: boolean; 807begin 808 Stream.Read(GraphicClassName[0], 1); 809 Stream.Read(GraphicClassName[1], length(GraphicClassName)); 810 GraphicClass := GetPicFileFormats.FindClassName(GraphicClassName); 811 NewGraphic := nil; 812 if GraphicClass <> nil then begin 813 NewGraphic := GraphicClass.Create; 814 ok:=false; 815 try 816 NewGraphic.ReadData(Stream); 817 ok:=true; 818 finally 819 if not ok then NewGraphic.Free; 820 end; 821 end; 822 FGraphic.Free; 823 FGraphic := NewGraphic; 824 if NewGraphic <> nil then begin 825 NewGraphic.OnChange := @Changed; 826 NewGraphic.OnProgress := @Progress; 827 end; 828 Changed(Self); 829end; 830 831procedure TPicture.WriteData(Stream: TStream); 832var 833 GraphicClassName: ShortString; 834begin 835 with Stream do 836 begin 837 if Graphic <> nil then 838 GraphicClassName := Graphic.ClassName 839 else 840 GraphicClassName := ''; 841 Write(GraphicClassName, Length(GraphicClassName) + 1); 842 if Graphic <> nil then 843 Graphic.WriteData(Stream); 844 end; 845end; 846 847procedure TPicture.DefineProperties(Filer: TFiler); 848 849 function DoWrite: Boolean; 850 var 851 Ancestor: TPicture; 852 begin 853 if Filer.Ancestor is TPicture then 854 begin 855 Ancestor := TPicture(Filer.Ancestor); 856 if not Assigned(Graphic) then 857 Exit(Assigned(Ancestor.Graphic)); 858 Result := not Graphic.Equals(Ancestor.Graphic); 859 end 860 else 861 Result := Assigned(Graphic); 862 end; 863 864begin 865 Filer.DefineBinaryProperty('Data', @ReadData, @WriteData, DoWrite); 866end; 867 868function TPicture.GetWidth: Integer; 869begin 870 if FGraphic <> nil then 871 Result := FGraphic.Width 872 else 873 Result := 0; 874end; 875 876function TPicture.GetHeight: Integer; 877begin 878 Result := 0; 879 if FGraphic <> nil then 880 Result := FGraphic.Height 881 else 882 Result := 0; 883end; 884 885// included by graphics.pp 886