const HIMETRIC_INCH = 2540; { THTMLPicture } procedure THTMLPicture.Assign(Source: TPersistent); begin FIsEmpty := true; gpPicture := nil; FFrameCount := -1; FNextCount := -1; FTimerCount := -1; Frame := 1; if Source = nil then FDataStream.Clear else begin if (Source is THTMLPicture) then begin FStretched := (Source as THTMLPicture).Stretch; FFrame := (Source as THTMLPicture).Frame; FID := (Source as THTMLPicture).ID; FDataStream.LoadFromStream(THTMLPicture(Source).fDataStream); FIsEmpty := False; LoadPicture; if Assigned(OnChange) then OnChange(self); end; end; end; constructor THTMLPicture.Create; begin inherited; FDataStream := TMemoryStream.Create; FIsEmpty := True; gpPicture := nil; FLogPixX := 96; FLogPixY := 96; FThreadBusy := False; FAsynch := True; FFrameCount := -1; FNextCount := -1; FTimerCount := -1; FFrame := 1; FIsDB := False; end; destructor THTMLPicture.Destroy; begin FDataStream.Free; inherited; end; procedure THTMLPicture.LoadPicture; {$IFNDEF TMSDOTNET} const IID_IPicture: TGUID = ( D1:$7BF80980;D2:$BF32;D3:$101A;D4:($8B,$BB,$00,$AA,$00,$30,$0C,$AB)); {$ENDIF} var hGlobal: THandle; {$IFNDEF TMSDOTNET} pvData: Pointer; {$ENDIF} {$IFDEF TMSDOTNET} pvData: IntPtr; {$ENDIF} pstm: IStream; hr: hResult; GifStream: TMemoryStream; i: Integer; b,c,d,e: Byte; skipimg: Boolean; imgidx: Integer; begin {$IFNDEF TMSDOTNET} hGlobal := GlobalAlloc(GMEM_MOVEABLE, FDataStream.Size); if hGlobal = 0 then raise Exception.Create('Could not allocate memory for image'); try pvData := GlobalLock(hGlobal); FDataStream.Position := 0; FFrameXPos := 0; FFrameYPos := 0; FAnimMaxX := 0; FAnimMaxY := 0; {skip first image ctrl} if IsGIF and (FrameCount > 0) then begin //manipulate the stream here for animated GIF ? Gifstream := TMemoryStream.Create; ImgIdx := 1; SkipImg := False; FDataStream.Position := 6; FDataStream.Read(FAnimMaxX,2); FDataStream.Read(FAnimMaxY,2); for i := 1 to FDataStream.Size do begin FDataStream.Position := i - 1; FDataStream.Read(b,1); if (b = $21) and (i + 8 < FDataStream.Size) then begin FDataStream.Read(c,1); FDataStream.Read(d,1); FDataStream.Position := FDataStream.Position + 5; FDataStream.Read(e,1); if (c = $F9) and (d = $4) and (e = $2C) then begin if imgidx = FFrame then begin FDataStream.Read(FFrameXPos,2); FDataStream.Read(FFrameYPos,2); FDataStream.Read(FFrameXSize,2); FDataStream.Read(FFrameYSize,2); end; Inc(ImgIdx); if ImgIdx <= FFrame then SkipImg := True else SkipImg := False; end; end; if not SkipImg then GifStream.Write(b,1); end; GifStream.Position := 0; GifStream.ReadBuffer(pvData^,GifStream.Size); GifStream.Free; end else begin FDataStream.ReadBuffer(pvData^,fDataStream.Size); end; GlobalUnlock(hGlobal); pstm := nil; // Create IStream* from global memory hr := CreateStreamOnHGlobal(hGlobal, TRUE, pstm); if (not hr=S_OK) then raise Exception.Create('Could not create image stream') else if (pstm = nil) then raise Exception.Create('Empty image stream created'); // Create IPicture from image file hr := OleLoadPicture(pstm, FDataStream.Size,FALSE,IID_IPicture,gpPicture); if not (hr = S_OK) then raise Exception.Create('Could not load image. Invalid format') else if gpPicture = nil then raise Exception.Create('Could not load image'); finally GlobalFree(hGlobal); end; {$ENDIF} end; procedure THTMLPicture.Draw(ACanvas: TCanvas; const Rect: TRect); var hmWidth:integer; hmHeight:integer; nPixX,nPixY:integer; pnWidth,pnHeight:integer; begin if Empty then Exit; if gpPicture = nil then Exit; hmWidth := 0; hmHeight := 0; gpPicture.get_Width(hmWidth); gpPicture.get_Height(hmHeight); if Stretch then begin gpPicture.Render(ACanvas.Handle,Rect.Left,Rect.Bottom,Rect.Right - Rect.Left,-(Rect.Bottom - Rect.Top),0,0, hmWidth,hmHeight, Rect); end else begin nPixX := GetDeviceCaps(ACanvas.Handle,LOGPIXELSX); nPixY := GetDeviceCaps(ACanvas.Handle,LOGPIXELSY); //Convert to device units pnWidth := MulDiv(hmWidth, nPixX, HIMETRIC_INCH); pnHeight := MulDiv(hmHeight, nPixY, HIMETRIC_INCH); //gpPicture.Render(ACanvas.Handle,Rect.Left,Rect.Top + pnHeight,pnWidth,-pnHeight,0,0, // hmWidth,hmHeight, Rect); gpPicture.Render(ACanvas.Handle,Rect.Left,Rect.Top, pnWidth,pnHeight,0,hmHeight, hmWidth,-hmHeight, Rect); end; end; function THTMLPicture.GetEmpty: Boolean; begin Result := FIsEmpty; end; function THTMLPicture.GetHeight: integer; var hmHeight:integer; begin if gpPicture = nil then Result := 0 else begin gpPicture.get_Height(hmHeight); Result := MulDiv(hmHeight, FLogPixY, HIMETRIC_INCH); end; end; function THTMLPicture.GetWidth: Integer; var hmWidth: Integer; begin if gpPicture = nil then Result := 0 else begin gpPicture.get_Width(hmWidth); Result := MulDiv(hmWidth, FLogPixX, HIMETRIC_INCH); end; end; procedure THTMLPicture.LoadFromFile(const FileName: string); begin try FDataStream.LoadFromFile(Filename); FIsEmpty:=false; LoadPicture; if Assigned(OnChange) then OnChange(self); except FIsEmpty:=true; end; end; procedure THTMLPicture.LoadFromStream(Stream: TStream); begin if Assigned(Stream) then begin FDataStream.LoadFromStream(Stream); FIsEmpty := False; LoadPicture; if Assigned(OnChange) then OnChange(self); end; end; procedure THTMLPicture.ReadData(Stream: TStream); begin if assigned(Stream) then begin fDataStream.LoadFromStream(stream); fIsEmpty:=false; LoadPicture; end; end; procedure THTMLPicture.SaveToStream(Stream: TStream); begin if Assigned(Stream) then fDataStream.SaveToStream(Stream); end; procedure THTMLPicture.LoadFromResourceName(Instance: THandle; const ResName: string); var Stream: TCustomMemoryStream; begin {$IFNDEF TMSDOTNET} if FindResource(Instance,pchar(ResName),RT_RCDATA)<>0 then {$ENDIF} {$IFDEF TMSDOTNET} if FindResource(Instance,ResName,RT_RCDATA)<>0 then {$ENDIF} begin Stream := TResourceStream.Create(Instance, ResName, RT_RCDATA); try LoadFromStream(Stream); finally Stream.Free; end; end; end; procedure THTMLPicture.LoadFromResourceID(Instance: THandle; ResID: Integer); var Stream: TCustomMemoryStream; begin Stream := TResourceStream.CreateFromID(Instance, ResID, RT_RCDATA); try LoadFromStream(Stream); finally Stream.Free; end; end; procedure THTMLPicture.SetHeight(Value: integer); begin end; procedure THTMLPicture.SetWidth(Value: integer); begin end; procedure THTMLPicture.WriteData(Stream: TStream); begin if Assigned(Stream) then begin FDataStream.savetostream(stream); end; end; procedure THTMLPicture.LoadFromURL(url: string); var UUrl: string; begin UUrl := UpperCase(url); if Pos('RES://',UUrl) = 1 then begin ID := url; Delete(url,1,6); if url <> '' then LoadFromResourceName(hinstance,url); Exit; end; if Pos('FILE://',Uurl) = 1 then begin ID := url; Delete(url,1,7); if url <> '' then LoadFromFile(url); Exit; end; if FAsynch then begin if FThreadBusy then Exit; FURL := url; FThreadBusy := True; TDownLoadThread.Create(self); end else begin FURL := url; ID := url; {$IFDEF USEWININET} DownLoad; {$ENDIF} end; end; {$IFDEF USEWININET} procedure THTMLPicture.DownLoad; var RBSIZE:dword; httpstatus,httpsize,err:integer; dwIdx:dword; dwBufSize:dword; ms:TMemoryStream; len:dword; cbuf:array[0..255] of char; rb:array[0..4095] of byte; FISession:hinternet; FIHttp:hinternet; Cancel:boolean; begin fISession:=InternetOpen('HTMLImage',INTERNET_OPEN_TYPE_PRECONFIG,nil,nil,0); if (fISession=nil) then begin DownLoadError('Cannot open internet session'); fThreadBusy:=false; Exit; end; fIHttp:=InternetOpenURL(fISession,pchar(furl),nil,0, INTERNET_FLAG_PRAGMA_NOCACHE or INTERNET_FLAG_NO_CACHE_WRITE or INTERNET_FLAG_RELOAD,0); if (fIHttp=nil) then begin InternetCloseHandle(fISession); DownLoadError('Cannot open http connection'); fThreadBusy:=false; Exit; end; dwBufSize := SizeOf(cbuf); dwidx := 0; HttpQueryInfo(fIHttp,HTTP_QUERY_STATUS_CODE,@cbuf,dwBufSize,dwIdx); val(cbuf,httpstatus,err); if (httpstatus <> 200) or (err <> 0) then begin InternetCloseHandle(fISession); InternetCloseHandle(fIHttp); DownLoadError('Cannot open URL '+furl); FThreadBusy:=false; Exit; end; dwBufSize := SizeOf(cbuf); dwidx := 0; HttpQueryInfo(fIHttp,HTTP_QUERY_CONTENT_TYPE,@cbuf,dwBufSize,dwIdx); if Pos('IMAGE',UpperCase(StrPas(cbuf))) = 0 then begin InternetCloseHandle(fISession); InternetCloseHandle(fIHttp); DownLoadError('Resource is not of image type : ' + FUrl); fThreadBusy := false; Exit; end; dwBufSize := SizeOf(cbuf); dwidx := 0; HttpQueryInfo(fIHttp,HTTP_QUERY_CONTENT_LENGTH,@cbuf,dwBufSize,dwIdx); val(cbuf,httpsize,err); if (httpsize = 0) or (err <> 0) then begin InternetCloseHandle(fISession); InternetCloseHandle(fIHttp); DownLoadError('Image size is 0'); fThreadBusy:=false; Exit; end; DownLoadProgress(0,httpsize); len := 4096; RBSIZE := 4096; ms := TMemoryStream.Create; cancel:=false; while (len=RBSIZE) and not Cancel do begin InternetReadFile(fIHttp,@rb,RBSIZE,len); if len>0 then ms.WriteBuffer(rb,len); DownLoadProgress(ms.Size,httpsize); DownLoadCancel(cancel); end; if not cancel then begin ms.Position := 0; LoadFromStream(ms); end; ms.Free; InternetCloseHandle(fIHttp); InternetCloseHandle(fISession); FThreadBusy:=false; end; {$ENDIF} procedure THTMLPicture.DownLoadCancel(var cancel: boolean); begin if assigned(FOnDownLoadCancel) then FOnDownLoadCancel(self,cancel); end; procedure THTMLPicture.DownLoadComplete; begin if Assigned(FOnDownLoadComplete) then FOnDownLoadComplete(self); end; procedure THTMLPicture.DownLoadError(err: string); begin if Assigned(fOnDownloadError) then FOnDownLoadError(self,err); end; procedure THTMLPicture.DownLoadProgress(dwSize, dwTotSize: dword); begin if Assigned(FOnDownLoadProgress) then FOnDownLoadProgress(self,dwSize,dwTotSize); end; procedure THTMLPicture.LoadFromClipboardFormat(AFormat: Word; AData: THandle; APalette: HPALETTE); begin end; procedure THTMLPicture.SaveToClipboardFormat(var AFormat: Word; var AData: THandle; var APalette: HPALETTE); begin end; function THTMLPicture.GetFrameCount: Integer; var i: Integer; b,c,d,e: Byte; Res: Integer; begin Result := -1; if FFrameCount <> -1 then Result := FFrameCount else if IsGIFFile then begin Res := 0; for i := 1 to FDataStream.Size do begin FDataStream.Position := i - 1; FDataStream.Read(b,1); if (b = $21) and (i + 8 < FDataStream.Size) then begin FDataStream.Read(c,1); FDataStream.Read(d,1); FDataStream.Position := FDataStream.Position+5; FDataStream.Read(e,1); if (c = $F9) and (d = $4) and (e = $2C) then Inc(res); end; end; FFrameCount := Res; Result := Res; FDataStream.Position := 0; end; end; function THTMLPicture.IsGIFFile: Boolean; var buf: array[0..4] of char; begin Result := False; if FDataStream.Size>4 then begin FDataStream.Position := 0; {$IFNDEF TMSDOTNET} FDataStream.Read(buf,4); buf[4] := #0; Result := Strpas(buf) = 'GIF8'; {$ENDIF} FDataStream.Position := 0; end; end; function THTMLPicture.GetFrameTime(i: Integer): Integer; var j: Integer; b,c,d,e: Byte; res: Integer; ft: Word; begin Result := -1; if IsGIFFile then begin Res := 0; for j := 1 to FDataStream.Size do begin FDataStream.Position := j-1; FDataStream.Read(b,1); if (b = $21) and (i + 8 < FDataStream.Size) then begin FDataStream.Read(c,1); FDataStream.Read(d,1); FDataStream.Read(b,1); {transp. flag here} FDataStream.Read(ft,2); FDataStream.Position := FDataStream.Position + 2; FDataStream.Read(e,1); if (c = $F9) and (d = $4) and (e = $2C) then begin Inc(res); if res = i then begin Result := ft; FFrameTransp := b and $01=$01; FFrameDisposal := (b shr 3) and $7; end; end; end; end; end; FDataStream.Position := 0; end; function THTMLPicture.GetMaxHeight: Integer; var hmHeight: Integer; begin {$IFNDEF TMSDOTNET} if gpPicture = nil then Result := 0 else begin if FAnimMaxY>0 then Result:=FAnimMaxY else begin gpPicture.get_Height(hmHeight); Result := MulDiv(hmHeight, fLogPixY, HIMETRIC_INCH); end; end; {$ENDIF} end; function THTMLPicture.GetMaxWidth: Integer; var hmWidth: Integer; begin if gpPicture = nil then Result := 0 else begin if FAnimMaxX > 0 then Result := FAnimMaxX else begin gpPicture.get_Width(hmWidth); Result := MulDiv(hmWidth, fLogPixX, HIMETRIC_INCH); end; end; end; procedure THTMLPicture.SetFrame(const Value: Integer); begin FFrame := Value; if FDataStream.Size > 0 then begin LoadPicture; if Assigned(OnFrameChange) then OnFrameChange(self); end; end; procedure THTMLPicture.FrameNext; begin if FFrame < FFrameCount then Inc(FFrame) else FFrame := 1; end; function THTMLPicture.Step: Boolean; begin Result := False; if (FFrameCount <= 1) or FIsEmpty then Exit; if FNextCount = -1 then FrameTime[FFrame]; if FTimerCount*10 >= FNextCount then begin FrameNext; LoadPicture; FNextCount := FNextCount + FrameTime[FFrame]; Result := True; end; Inc(FTimerCount); end; procedure THTMLPicture.FramePrev; begin if FFrame > 1 then Dec(FFrame) else FFrame := FFrameCount; end; function THTMLPicture.GetStretched: boolean; begin Result := FStretched; end; procedure THTMLPicture.SetStretched(const Value: boolean); begin FStretched := Value; end; { THTMLImage } constructor THTMLImage.Create(aOwner: TComponent); begin inherited; fHTMLPicture:=THTMLPicture.Create; fHTMLPicture.OnChange:=PictureChanged; Width:=100; Height:=100; fHTMLPicture.OnDownLoadError:=DownLoadError; fHTMLPicture.OnDownLoadCancel:=DownLoadCancel; fHTMLPicture.OnDownLoadProgress:=DownLoadProgress; fHTMLPicture.OnDownLoadComplete:=DownLoadComplete; end; destructor THTMLImage.Destroy; begin fHTMLPicture.Free; inherited; end; procedure THTMLImage.Loaded; begin inherited; fHTMLPicture.fLogPixX := GetDeviceCaps(canvas.handle,LOGPIXELSX); fHTMLPicture.fLogPixY := GetDeviceCaps(canvas.handle,LOGPIXELSY); end; procedure THTMLImage.Paint; var xo,yo:integer; function Max(a,b:integer):integer; begin if (a>b) then result:=a else result:=b; end; begin inherited; if assigned(fHTMLPicture) then begin if not fHTMLPicture.Empty then case fPicturePosition of bpTopLeft:Canvas.Draw(0,0,fHTMLPicture); bpTopRight:Canvas.Draw(Max(0,width-fHTMLPicture.Width),0,fHTMLPicture); bpBottomLeft:Canvas.Draw(0,Max(0,height-fHTMLPicture.Height),fHTMLPicture); bpBottomRight:Canvas.Draw(Max(0,width-fHTMLPicture.Width),Max(0,height-fHTMLPicture.Height),fHTMLPicture); bpCenter:Canvas.Draw(Max(0,width-fHTMLPicture.Width) shr 1,Max(0,height-fHTMLPicture.Height) shr 1,fHTMLPicture); bpTiled:begin yo:=0; while (yo Value) then begin fPicturePosition := Value; Invalidate; end; end; procedure THTMLImage.DownLoadCancel(Sender: TObject; var cancel: boolean); begin if assigned(fOnDownLoadCancel) then fOnDownLoadCancel(self,cancel); end; procedure THTMLImage.DownLoadComplete(Sender: TObject); begin if assigned(fOnDownLoadComplete) then fOnDownLoadComplete(self); end; procedure THTMLImage.DownLoadError(Sender: TObject; err: string); begin if Assigned(FOnDownloadError) then FOnDownLoadError(self,err); end; procedure THTMLImage.DownLoadProgress(Sender: TObject; dwSize, dwTotSize: dword); begin if Assigned(FOnDownLoadProgress) then FOnDownLoadProgress(self,dwSize,dwTotSize); end; { TDownLoadThread } constructor TDownLoadThread.Create(aHTMLPicture: THTMLPicture); begin inherited Create(false); HTMLPicture := aHTMLPicture; FreeOnTerminate := True; end; procedure TDownLoadThread.Execute; begin {$IFDEF USEWININET} HTMLPicture.DownLoad; {$ENDIF} end; { THTMLPictureCache } destructor THTMLPictureCache.Destroy; begin ClearPictures; inherited; end; function THTMLPictureCache.AddPicture: THTMLPicture; begin Result := THTMLPicture.Create; {$IFNDEF TMSDOTNET} Add(pointer(result)); {$ENDIF} {$IFDEF TMSDOTNET} Add(TObject(Result)); {$ENDIF} end; procedure THTMLPictureCache.ClearPictures; var i: Integer; begin for i := 1 to Count do Items[i - 1].Free; Clear; //inherited; end; function THTMLPictureCache.FindPicture(ID: string): THTMLPicture; var i: Integer; begin Result := nil; for i := 1 to Count do begin if (Items[i - 1].ID = ID) then begin Result := Items[i - 1]; Break; end; end; end; function THTMLPictureCache.GetPicture(Index: Integer): THTMLPicture; begin Result := THTMLPicture(inherited Items[Index]); end; procedure THTMLPictureCache.SetPicture(Index: Integer; Value: THTMLPicture); begin {$IFNDEF TMSDOTNET} inherited Items[index] := Pointer(Value); {$ENDIF} {$IFDEF TMSDOTNET} inherited Items[index] := Value; {$ENDIF} end; function THTMLPictureCache.Animate: Boolean; var i: Integer; begin Result := False; for i := 1 to Count do begin if Items[i - 1].Step then Result := True; end; end;