1{ 2 This file is part of the Free Pascal run time library. 3 Copyright (c) 2003 by the Free Pascal development team 4 5 TFPCustomImage implementation. 6 7 See the file COPYING.FPC, included in this distribution, 8 for details about the copyright. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 14 **********************************************************************} 15{ TFPCustomImage } 16 17constructor TFPCustomImage.create (AWidth,AHeight:integer); 18begin 19 inherited create; 20 FExtra := TStringList.Create; 21 FWidth := 0; 22 FHeight := 0; 23 FPalette := nil; 24 SetSize (AWidth,AHeight); 25end; 26 27destructor TFPCustomImage.destroy; 28begin 29 FExtra.Free; 30 if assigned (FPalette) then 31 FPalette.Free; 32 inherited; 33end; 34 35procedure TFPCustomImage.LoadFromStream (Str:TStream; Handler:TFPCustomImagereader); 36begin 37 Handler.ImageRead (Str, self); 38end; 39 40procedure TFPCustomImage.LoadFromFile (const filename:String; Handler:TFPCustomImageReader); 41var 42 fs : TStream; 43begin 44 if FileExists (filename) then 45 begin 46 fs := TFileStream.Create (filename, fmOpenRead); 47 try 48 LoadFromStream (fs, handler); 49 finally 50 fs.Free; 51 end; 52 end 53 else 54 FPImgError (StrNoFile, [filename]); 55end; 56 57procedure TFPCustomImage.SaveToStream (Str:TStream; Handler:TFPCustomImageWriter); 58begin 59 Handler.ImageWrite (Str, Self); 60end; 61 62procedure TFPCustomImage.SaveToFile (const filename:String; Handler:TFPCustomImageWriter); 63var 64 fs : TStream; 65begin 66 fs := TFileStream.Create (filename, fmCreate); 67 try 68 SaveToStream (fs, handler); 69 finally 70 fs.Free; 71 end 72end; 73 74function TFPCustomImage.SaveToFile (const filename:String):boolean; 75 76var h : TFPCustomImageWriterClass; 77 Writer : TFPCustomImageWriter; 78 Msg : string; 79 80begin 81 Msg := ''; 82 try 83 h := FindWriterFromFileName(filename); 84 Result := assigned (h); 85 if Result then 86 begin 87 Writer := h.Create; 88 try 89 SaveTofile (filename, Writer); 90 finally 91 Writer.Free; 92 end; 93 end; 94 except 95 on e : exception do 96 Msg := e.message; 97 end; 98 if (Msg<>'') then 99 FPImgError (StrWriteWithError, [Msg]); 100end; 101 102 103procedure TFPCustomImage.LoadFromStream (Str:TStream); 104var r : integer; 105 h : TFPCustomImageReaderClass; 106 reader : TFPCustomImageReader; 107 msg : string; 108 d : TIHData; 109 startPos: Int64; 110begin 111 msg := ''; 112 startPos := str.Position; 113 with ImageHandlers do 114 try 115 r := count-1; 116 while (r >= 0) do 117 begin 118 d := GetData(r); 119 if assigned (d) then 120 h := d.FReader 121 else 122 h := nil; 123 if assigned (h) then 124 begin 125 reader := h.Create; 126 with reader do 127 try 128 if CheckContents (str) then 129 try 130 FStream := str; 131 FImage := self; 132 InternalRead (str, self); 133 msg := ''; 134 break; 135 except 136 on e : exception do 137 msg := e.message; 138 end; 139 finally 140 Free; 141 str.Position := startPos; 142 end; 143 end; 144 dec (r); 145 end; 146 except 147 on e : exception do 148 FPImgError (StrCantDetermineType, [e.message]); 149 end; 150 if r < 0 then 151 if msg = '' then 152 FPImgError (StrNoCorrectReaderFound) 153 else 154 FPImgError (StrReadWithError, [Msg]); 155end; 156 157function TFPCustomImage.LoadFromFile (const filename:String):boolean; 158var f : TFileStream; 159 h : TFPCustomImageReaderClass; 160 reader : TFPCustomImageReader; 161 Msg : string; 162begin 163 Msg := ''; 164 try 165 h := FindReaderFromFileName(filename); 166 Result := assigned (h); 167 if Result then 168 begin 169 reader := h.Create; 170 try 171 loadfromfile (filename, reader); 172 finally 173 Reader.Free; 174 end; 175 end; 176 except 177 on e : exception do 178 Msg := e.message; 179 end; 180 if Msg = '' then 181 begin 182 if h = nil then 183 begin 184 f := TFileStream.Create (filename, fmOpenRead); 185 try 186 LoadFromStream (f); 187 finally 188 f.Free; 189 end; 190 end; 191 end 192 else 193 FPImgError (StrReadWithError, [Msg]); 194end; 195 196procedure TFPCustomImage.SetHeight (Value : integer); 197begin 198 if Value <> FHeight then 199 SetSize (FWidth, Value); 200end; 201 202procedure TFPCustomImage.SetWidth (Value : integer); 203begin 204 if Value <> FWidth then 205 SetSize (Value, FHeight); 206end; 207 208procedure TFPCustomImage.SetSize (AWidth, AHeight : integer); 209begin 210 FWidth := AWidth; 211 FHeight := AHeight; 212end; 213 214procedure TFPCustomImage.SetExtraValue (index:integer; const AValue:string); 215var s : string; 216 p : integer; 217begin 218 s := FExtra[index]; 219 p := pos ('=', s); 220 if p > 0 then 221 FExtra[index] := copy(s, 1, p) + AValue 222 else 223 FPImgError (StrInvalidIndex,[ErrorText[StrImageExtra],index]); 224end; 225 226function TFPCustomImage.GetExtraValue (index:integer) : string; 227var s : string; 228 p : integer; 229begin 230 s := FExtra[index]; 231 p := pos ('=', s); 232 if p > 0 then 233 result := copy(s, p+1, maxint) 234 else 235 result := ''; 236end; 237 238procedure TFPCustomImage.SetExtraKey (index:integer; const AValue:string); 239var s : string; 240 p : integer; 241begin 242 s := FExtra[index]; 243 p := pos('=',s); 244 if p > 0 then 245 s := AValue + copy(s,p,maxint) 246 else 247 s := AValue; 248 FExtra[index] := s; 249end; 250 251function TFPCustomImage.GetExtraKey (index:integer) : string; 252begin 253 result := FExtra.Names[index]; 254end; 255 256procedure TFPCustomImage.SetExtra (const key:String; const AValue:string); 257begin 258 FExtra.values[key] := AValue; 259end; 260 261function TFPCustomImage.GetExtra (const key:String) : string; 262begin 263 result := FExtra.values[key]; 264end; 265 266function TFPCustomImage.ExtraCount : integer; 267begin 268 result := FExtra.count; 269end; 270 271const dumchar = ';'; 272class function TFPCustomImage.FindHandlerFromExtension(extension: String 273 ): TIHData; 274var s : string; 275 r : integer; 276begin 277 if extension='' then 278 Exit(nil); 279 extension := lowercase (extension); 280 if (extension <> '') and (extension[1] = '.') then 281 delete (extension,1,1); 282 with ImageHandlers do 283 begin 284 r := count-1; 285 s := dumchar + extension + dumchar; 286 while (r >= 0) do 287 begin 288 Result := GetData(r); 289 if (pos(s, dumchar+Result.Fextension+dumchar) <> 0) then 290 Exit; 291 dec (r); 292 end; 293 end; 294 Result := nil; 295end; 296 297class function TFPCustomImage.FindHandlerFromStream(Str: TStream): TIHData; 298var r : integer; 299 p: Int64; 300 reader: TFPCustomImageReader; 301begin 302 r := ImageHandlers.Count-1; 303 p := Str.Position; 304 while (r >= 0) do 305 begin 306 Result := ImageHandlers.GetData(r); 307 if Result.Reader<>nil then 308 begin 309 reader := Result.Reader.Create; 310 try 311 if reader.CheckContents(Str) then 312 Exit; 313 finally 314 reader.free; 315 Str.Position := p; 316 end; 317 end; 318 dec (r); 319 end; 320 Result := nil; 321end; 322 323class function TFPCustomImage.FindReaderFromExtension(const extension: String 324 ): TFPCustomImageReaderClass; 325var d : TIHData; 326begin 327 d := FindHandlerFromExtension(extension); 328 if d<>nil then 329 Result := d.FReader 330 else 331 Result := nil; 332end; 333 334class function TFPCustomImage.FindReaderFromFileName(const filename: String 335 ): TFPCustomImageReaderClass; 336begin 337 Result := FindReaderFromExtension(ExtractFileExt(filename)); 338end; 339 340class function TFPCustomImage.FindReaderFromStream( 341 Str: TStream): TFPCustomImageReaderClass; 342var d : TIHData; 343begin 344 d := FindHandlerFromStream(Str); 345 if d<>nil then 346 Result := d.FReader 347 else 348 Result := nil; 349end; 350 351class function TFPCustomImage.FindWriterFromExtension(const extension: String 352 ): TFPCustomImageWriterClass; 353var d : TIHData; 354begin 355 d := FindHandlerFromExtension(extension); 356 if d<>nil then 357 Result := d.FWriter 358 else 359 Result := nil; 360end; 361 362class function TFPCustomImage.FindWriterFromFileName(const filename: String 363 ): TFPCustomImageWriterClass; 364begin 365 Result := FindWriterFromExtension(ExtractFileExt(filename)); 366end; 367 368procedure TFPCustomImage.RemoveExtra (const key:string); 369var p : integer; 370begin 371 p := FExtra.IndexOfName(key); 372 if p >= 0 then 373 FExtra.Delete (p); 374end; 375 376procedure TFPCustomImage.SetPixel (x,y:integer; Value:integer); 377begin 378 CheckPaletteIndex (Value); 379 CheckIndex (x,y); 380 SetInternalPixel (x,y,Value); 381end; 382 383function TFPCustomImage.GetPixel (x,y:integer) : integer; 384begin 385 CheckIndex (x,y); 386 result := GetInternalPixel(x,y); 387end; 388 389procedure TFPCustomImage.SetColor (x,y:integer; const Value:TFPColor); 390begin 391 CheckIndex (x,y); 392 SetInternalColor (x,y,Value); 393end; 394 395function TFPCustomImage.GetColor (x,y:integer) : TFPColor; 396begin 397 CheckIndex (x,y); 398 result := GetInternalColor(x,y); 399end; 400 401procedure TFPCustomImage.SetInternalColor (x,y:integer; const Value:TFPColor); 402var i : integer; 403begin 404 i := FPalette.IndexOf (Value); 405 SetInternalPixel (x,y,i); 406end; 407 408function TFPCustomImage.GetInternalColor (x,y:integer) : TFPColor; 409begin 410 result := FPalette.Color[GetInternalPixel(x,y)]; 411end; 412 413function TFPCustomImage.GetUsePalette : boolean; 414begin 415 result := assigned(FPalette); 416end; 417 418procedure TFPCustomImage.SetUsePalette(Value:boolean); 419begin 420 if Value <> assigned(FPalette) 421 then 422 if Value 423 then 424 begin 425 FPalette := TFPPalette.Create (0); 426 // FPalette.Add (colTransparent); 427 end 428 else 429 begin 430 FPalette.Free; 431 FPalette := nil; 432 end; 433end; 434 435procedure TFPCustomImage.CheckPaletteIndex (PalIndex:integer); 436begin 437 if UsePalette then 438 begin 439 if (PalIndex < -1) or (PalIndex >= FPalette.Count) then 440 FPImgError (StrInvalidIndex,[ErrorText[StrPalette],PalIndex]); 441 end 442 else 443 FPImgError (StrNoPaletteAvailable); 444end; 445 446procedure TFPCustomImage.CheckIndex (x,y:integer); 447begin 448 if (x < 0) or (x >= FWidth) then 449 FPImgError (StrInvalidIndex,[ErrorText[StrImageX],x]); 450 if (y < 0) or (y >= FHeight) then 451 FPImgError (StrInvalidIndex,[ErrorText[StrImageY],y]); 452end; 453 454Procedure TFPCustomImage.Progress(Sender: TObject; Stage: TProgressStage; 455 PercentDone: Byte; RedrawNow: Boolean; const R: TRect; 456 const Msg: AnsiString; var Continue: Boolean); 457begin 458 If Assigned(FOnProgress) then 459 FonProgress(Sender,Stage,PercentDone,RedrawNow,R,Msg,Continue); 460end; 461 462Procedure TFPCustomImage.Assign(Source: TPersistent); 463 464Var 465 Src : TFPCustomImage; 466 X,Y : Integer; 467 468begin 469 If Source is TFPCustomImage then 470 begin 471 Src:=TFPCustomImage(Source); 472 // Copy extra info 473 FExtra.Assign(Src.Fextra); 474 // Copy palette if needed. 475 SetSize(0,0); { avoid side-effects in descendant classes } 476 UsePalette:=Src.UsePalette; 477 If UsePalette then 478 begin 479 Palette.Count:=0; 480 Palette.Merge(Src.Palette); 481 end; 482 // Copy image. 483 SetSize(Src.Width,Src.height); 484 If UsePalette then 485 For x:=0 to Src.Width-1 do 486 For y:=0 to src.Height-1 do 487 pixels[X,Y]:=src.pixels[X,Y] 488 else 489 For x:=0 to Src.Width-1 do 490 For y:=0 to src.Height-1 do 491 self[X,Y]:=src[X,Y]; 492 end 493 else 494 Inherited Assign(Source); 495end; 496 497{ TFPMemoryImage } 498 499constructor TFPMemoryImage.Create (AWidth,AHeight:integer); 500begin 501 Fdata := nil; 502 inherited create (AWidth,AHeight); 503 SetUsePalette(False); 504end; 505 506destructor TFPMemoryImage.Destroy; 507begin 508 // MG: missing if 509 if FData<>nil then 510 FreeMem (FData); 511 inherited Destroy; 512end; 513 514function TFPMemoryImage.GetInternalColor(x,y:integer):TFPColor; 515 begin 516 if Assigned(FPalette) 517 then 518 Result:=inherited GetInternalColor(x,y) 519 else 520 Result:=PFPColorArray(FData)^[y*FWidth+x]; 521 end; 522 523function TFPMemoryImage.GetInternalPixel (x,y:integer) : integer; 524begin 525 result := FData^[y*FWidth+x]; 526end; 527 528procedure TFPMemoryImage.SetInternalColor (x,y:integer; const Value:TFPColor); 529 begin 530 if Assigned(FPalette) 531 then 532 inherited SetInternalColor(x,y,Value) 533 else 534 PFPColorArray(FData)^[y*FWidth+x]:=Value; 535 end; 536 537procedure TFPMemoryImage.SetInternalPixel (x,y:integer; Value:integer); 538begin 539 FData^[y*FWidth+x] := Value; 540end; 541 542function Lowest (a,b : integer) : integer; 543begin 544 if a <= b then 545 result := a 546 else 547 result := b; 548end; 549 550procedure TFPMemoryImage.SetSize (AWidth, AHeight : integer); 551var w, h, r, old : integer; 552 NewData : PFPIntegerArray; 553begin 554 if (AWidth <> Width) or (AHeight <> Height) then 555 begin 556 old := Height * Width; 557 r:=AWidth*AHeight; 558 if Assigned(FPalette) 559 then 560 r:=SizeOf(integer)*r 561 else 562 r:=SizeOf(TFPColor)*r; 563 if r = 0 then 564 NewData := nil 565 else 566 begin 567 GetMem (NewData, r); 568 FillWord (Newdata^[0], r div sizeof(word), 0); 569 end; 570 // MG: missing "and (NewData<>nil)" 571 if (old <> 0) and assigned(FData) and (NewData<>nil) then 572 begin 573 if r <> 0 then 574 begin 575 w := Lowest(Width, AWidth); 576 h := Lowest(Height, AHeight); 577 for r := 0 to h-1 do 578 move (FData^[r*Width], NewData^[r*AWidth], w); 579 end; 580 end; 581 if Assigned(FData) then FreeMem(FData); 582 FData := NewData; 583 inherited; 584 end; 585end; 586 587procedure TFPMemoryImage.SetUsePalette(Value:boolean); 588var 589 OldColors:PFPColorArray; 590 OldPixels:PFPIntegerArray; 591 r,c:Integer; 592begin 593 if Value<>assigned(FPalette) 594 then 595 if Value 596 then 597 begin 598 FPalette:=TFPPalette.Create(0); 599 //FPalette.Add(colTransparent); 600 if assigned(FData) then 601 begin 602 OldColors:=PFPColorArray(FData); 603 GetMem(FData,FWidth*FHeight*SizeOf(Integer)); 604 for r:=0 to FHeight-1 do 605 for c:=0 to FWidth-1 do 606 Colors[c,r]:=OldColors^[r*FWidth+c]; 607 FreeMem(OldColors); 608 end; 609 end 610 else 611 begin 612 if Assigned(FData) then 613 begin 614 OldPixels:=PFPIntegerArray(FData); 615 GetMem(FData,FWidth*FHeight*SizeOf(TFPColor)); 616 for r:=0 to FHeight-1 do 617 for c:=0 to FWidth-1 do 618 Colors[c,r]:=FPalette.Color[OldPixels^[r*FWidth+c]]; 619 FreeMem(OldPixels); 620 end; 621 FPalette.Free; 622 FPalette:=nil; 623 end; 624end; 625