OPBitmap 1.0

Zur Vorstellung von Komponenten und Units für Lazarus
schnullerbacke
Beiträge: 1187
Registriert: Mi 13. Dez 2006, 10:58
OS, Lazarus, FPC: Winux (L 1.2.xy FPC 2.6.z)
CPU-Target: AMD A4-6400 APU
Wohnort: Hamburg

Beitrag von schnullerbacke »

@theo

Das sollte möglichst schon so laufen, das man beim Image laden das auch direkt ans TImage bindet in dem es angezeigt werden soll. Das läuft doch normaler weise über TPicture.LoadFromFile. Da muß das dann je nach Typ als TGiFImage, TMNGImage, TJpegImage usw. initialisiert werden. Wenn's also AniGIF oder MNG (ist auch ani) ist muß das Objekt entsprechend die Mimik für die Animation beinhalten.

Im Proggi mußt man dann nur bei LoadFromFile dafür sorgen, daß das richtige Format verwendet wird in dem man das als TGIFImage oder TMNGImage produziert und auf TPicture zuweist. Dann sollte das auch ohne die LCL-Abhängigkeiten gehen.
Humor ist der Knopf, der verhindert, daß uns der Kragen platzt.

(Ringelnatz)

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Beitrag von theo »

schnullerbacke hat geschrieben:@theo
Das sollte möglichst schon so laufen, das man beim Image laden das auch direkt ans TImage bindet in dem es angezeigt werden soll.


Naja, kommt drauf an. Wenn du's an TImage bindest flackert's halt ziemlich (mindestens unter GTK).
In der jetztigen Demo paintet's direkt auf TForm.Canvas und das sieht viel sanfter aus.

schnullerbacke
Beiträge: 1187
Registriert: Mi 13. Dez 2006, 10:58
OS, Lazarus, FPC: Winux (L 1.2.xy FPC 2.6.z)
CPU-Target: AMD A4-6400 APU
Wohnort: Hamburg

Beitrag von schnullerbacke »

Das sollte sich aber optimieren lassen. Direkt auf der Form schränkt die Einsatzmöglichkeiten kräftig ein, das sollte man sich nicht antun.
Humor ist der Knopf, der verhindert, daß uns der Kragen platzt.

(Ringelnatz)

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Beitrag von theo »

schnullerbacke hat geschrieben:Das sollte sich aber optimieren lassen. Direkt auf der Form schränkt die Einsatzmöglichkeiten kräftig ein, das sollte man sich nicht antun.


Nö, wieso? Kannst ja auch ein TPanel oder einen TGraphicControl-Abkömmling nehmen.

schnullerbacke
Beiträge: 1187
Registriert: Mi 13. Dez 2006, 10:58
OS, Lazarus, FPC: Winux (L 1.2.xy FPC 2.6.z)
CPU-Target: AMD A4-6400 APU
Wohnort: Hamburg

Beitrag von schnullerbacke »

Na ja, aber Stretchen und ähnliches entfällt damit wenn ich das richtig im Hinterkopf hab. Mal abgesehen davon, das man über Panel oder ähnlich ne Menge mehr Arbeit hat, ne Oberfläche zu bauen. Das wäre über TImage deutlich einfacher.

Geht ja nur darum, TPicture.Graphic das entsprechende Objekt zu übergeben. Das geht aber eben nur, wenn man das von TGraphic ableitet und dort die Mimik einbaut. Dann sollte sich das auch als neues Format registrieren lassen.

Muß ich mir das halt doch mal ansehen.
Humor ist der Knopf, der verhindert, daß uns der Kragen platzt.

(Ringelnatz)

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Beitrag von theo »

schnullerbacke hat geschrieben: Mal abgesehen davon, das man über Panel oder ähnlich ne Menge mehr Arbeit hat, ne Oberfläche zu bauen. Das wäre über TImage deutlich einfacher.

Wieso das denn?

schnullerbacke hat geschrieben:Geht ja nur darum, TPicture.Graphic das entsprechende Objekt zu übergeben. Das geht aber eben nur, wenn man das von TGraphic ableitet und dort die Mimik einbaut. Dann sollte sich das auch als neues Format registrieren lassen.


Die Formaterkennung läuft i.a. über TOPPicture, via Extension, Stream oder Mime-Typ.

Ich seh dein Problem irgendwie nicht.

schnullerbacke
Beiträge: 1187
Registriert: Mi 13. Dez 2006, 10:58
OS, Lazarus, FPC: Winux (L 1.2.xy FPC 2.6.z)
CPU-Target: AMD A4-6400 APU
Wohnort: Hamburg

Beitrag von schnullerbacke »

Zumindest man das hier bei jedem Bildwechsel (also andere Image-Datei) machen:

Code: Alles auswählen

begin
  OrigBmp.LoadFromFile(ExtractFilePath(Paramstr(0)) + filename);
  ViewBmp.Assign(OrigBmp);
  ViewBmp.Canvas.Resample(Image1.width, Image1.height);
  AssignOpBitmapToBitmap(ViewBmp, Image1.Picture.Bitmap);
end;
 
anstatt:
 
function GetNewImage(filename: string): TGraphic;
var
  Img: TGIFImage;
begin
  Img:= TGIFImage.Create;
  Img.LoadFromFile(filename);
  Result:= Img;
  // und dann beim Aufrufer
  // Image1.Picture.Graphic:= GetNewImage(filename);
end;


Das untere Beispiel irgendwo in einer Unit ausgelagert;
Humor ist der Knopf, der verhindert, daß uns der Kragen platzt.

(Ringelnatz)

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Beitrag von theo »

schnullerbacke hat geschrieben:Zumindest man das hier bei jedem Bildwechsel (also andere Image-Datei) machen:

Code: Alles auswählen

begin
  OrigBmp.LoadFromFile(ExtractFilePath(Paramstr(0)) + filename);
  ViewBmp.Assign(OrigBmp);
  ViewBmp.Canvas.Resample(Image1.width, Image1.height);
  AssignOpBitmapToBitmap(ViewBmp, Image1.Picture.Bitmap);
end;



Joh, aber das tut dann auch schon stretchen (resamplen) und das Original-Bild speichern, damit beim wiederholten stretchen keine Informationen verloren gehen.

Ausserdem sind das vier Zeilen. Also wenn du sonst keine Probleme hast... ;-)

Ausserdem erhältst du dadurch den Vorteil, dass alles bis auf die letzte Zeile auch mit FPC-Commandline ohne X-Server funzt. (auch Kylix, Delphi).
Du kannst das Bild also einfach z.B. in einem anderen Format wieder speichern oder über den Webserver rausstreamen.

Und noch mehr "auserdem" hält dich ja keiner davon ab, die ganze Geschichte für Lazarus noch weiter zu kapseln.
Da die Vererbung von TGraphic ja optional vorgesehen ist, kannst du dort die Draw Methode in einer Ableitung überschreiben und auf einen eingehängten Canvas direkt malen.
Allerdings muss man dann bei jeder internen Änderung noch die Changed procedure aufrufen, damit neu gezeichnet wird.
Das hat mir dann allerdings nicht so gefallen (Aufwand und Performance mässig), und deshalb hab ich's nicht gemacht.

schnullerbacke
Beiträge: 1187
Registriert: Mi 13. Dez 2006, 10:58
OS, Lazarus, FPC: Winux (L 1.2.xy FPC 2.6.z)
CPU-Target: AMD A4-6400 APU
Wohnort: Hamburg

Beitrag von schnullerbacke »

Axo.

An deinem GifThread müssen wir aber arbeiten. Die Methode sleep zu benutzen ist nicht so elegant. Das sollten wir vielleicht mal über die abgelaufen Zeit machen, weil sonst alles schlafen gelegt wird.

Also eher nach dem Muster:

Code: Alles auswählen

// delaytime setzen wenn das erste Bild kommt oder zum nächsten gewechselt wird
  systime:= Date(now);
  if ((systime - delaytime) >= delay) then begin
     // hier neues bild
  end;


Evenuell mit CriticalSection absichern, das der Thread nicht unterbrochen wird, bis das Bild vollständig aufgebaut ist.
Humor ist der Knopf, der verhindert, daß uns der Kragen platzt.

(Ringelnatz)

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Beitrag von theo »

schnullerbacke hat geschrieben:Axo.

An deinem GifThread müssen wir aber arbeiten. Die Methode sleep zu benutzen ist nicht so elegant. Das sollten wir vielleicht mal über die abgelaufen Zeit machen, weil sonst alles schlafen gelegt wird.

Evenuell mit CriticalSection absichern, das der Thread nicht unterbrochen wird, bis das Bild vollständig aufgebaut ist.


??? Bahnhof.
Wieso soll der Thread denn nicht sleepen? Bzw. was heisst "alles schlafen gelegt".
Ausserdem wird doch Synchronized. Also weshalb Critical Section?
Das kann man bestimmt alles auch ganz anders machen, z.B. mit Timer, aber das AniGIF ist im Moment wirklich nicht die Hauptsache für mich.
Wieso interessiert dich das Ding eigentlich so? Was möchtest du denn damit anstellen?

schnullerbacke
Beiträge: 1187
Registriert: Mi 13. Dez 2006, 10:58
OS, Lazarus, FPC: Winux (L 1.2.xy FPC 2.6.z)
CPU-Target: AMD A4-6400 APU
Wohnort: Hamburg

Beitrag von schnullerbacke »

Immer von Delphi ausgegangen, sleep legt die ganze Anwendung schlafen also auch den Mainthread. Mag ja sein, das FPC das anders macht, aber glauben kann ich das nicht recht.
Humor ist der Knopf, der verhindert, daß uns der Kragen platzt.

(Ringelnatz)

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Beitrag von theo »

schnullerbacke hat geschrieben:Immer von Delphi ausgegangen, sleep legt die ganze Anwendung schlafen also auch den Mainthread. Mag ja sein, das FPC das anders macht, aber glauben kann ich das nicht recht.


Ach was, das läuft doch im Thread-Context. Dort pausiert Sleep nur den Thread.
Auch in Delphi.

Ausserdem weiss ich nicht, wieso ihr immer Stundenlang über so einen Schmarren sinniert.
Das ist doch in 3 Minuten getestet:

Code: Alles auswählen

interface
 
uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, Buttons;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
  { MyThrd }
 
  TMyThrd=class(TThread)
  protected
  Procedure Execute; override;
 
  end;
 
var
  Form1: TForm1;
 
implementation
 
{ MyThrd }
 
procedure TMyThrd.Execute;
begin
  writeln('Running');
  Sleep(10000);
  writeln('Finished');
end;
 
{ TForm1 }
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  TMyThrd.Create(false);
end;
 
initialization
  {$I unit1.lrs}
 
end.


Und? Kannst du den Button jetzt nicht mehr drücken während der Thread schläft?

schnullerbacke
Beiträge: 1187
Registriert: Mi 13. Dez 2006, 10:58
OS, Lazarus, FPC: Winux (L 1.2.xy FPC 2.6.z)
CPU-Target: AMD A4-6400 APU
Wohnort: Hamburg

Beitrag von schnullerbacke »

Ich guck das gerne nochmal nach. Sowas hatte ich aber auch mal versucht, nach mehreren Threads mit sleep war faktisch keine Bedienung der Anwendung mehr möglich.

Aus der Delphi-Hilfe:

Code: Alles auswählen

Die Prozedur verzögert die Programmausführung für eine bestimmte Anzahl von Mikrosekunden.
 
Unit
 
SysUtils
 
Kategorie
 
Ablaufsteuerung
 
Delphi-Syntax:
 
procedure Sleep(milliseconds: Cardinal);{$IFDEF MSWINDOWS} stdcall; {$ENDIF}
 
C++ Syntax:
 
void Sleep(unsigned milliseconds);
 
Beschreibung
 
Sleep pausiert Programmausführungen gemäß dem Parameter Millseconds. Unter Windows ist Sleep lediglich eine Verknüpfung mit der Sleep-Funktion in der System-API. Unter Linux ruft Sleep die usleep-Bibliotheksroutine auf.
Humor ist der Knopf, der verhindert, daß uns der Kragen platzt.

(Ringelnatz)

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Beitrag von theo »

schnullerbacke hat geschrieben:Ich guck das gerne nochmal nach. Sowas hatte ich aber auch mal versucht, nach mehreren Threads mit sleep war faktisch keine Bedienung der Anwendung mehr möglich.


Da war aber was anderes falsch. Im Gegenteil, wenn der Thread schläft, braucht er keine CPU Time. Mit tausenden Threads hast du natürlich ein Ressourcen-Problem, das hängt aber nicht mit Sleep zusammen. Sleep im Nicht-Main-Thread ist super-elegant. Klar, wenn's richtig lange geht, sollte man Loopen für Terminated Checks

schnullerbacke
Beiträge: 1187
Registriert: Mi 13. Dez 2006, 10:58
OS, Lazarus, FPC: Winux (L 1.2.xy FPC 2.6.z)
CPU-Target: AMD A4-6400 APU
Wohnort: Hamburg

Beitrag von schnullerbacke »

Bei Delphi ging das schon bei 6-7 Threads los. Das dürfte wohl mit dem Aufruf der Windows-API zusammenhängen. Deswegen hab ich mir bei Delphi sleep grundsätzlich verkniffen und bin stattdessen über die Zeit gegangen. Ausführen halt nur wenn das Zeitkriterium erfüllt ist. Ist ja auch nicht ganz unelegant... :wink:

Was mich an den AniGIF's so interessiert? Na ganz einfach, ich hab ne Anwendung fast fertig, die kann zumindest bei Delphi auch AniGIF's übers Internet empfangen und senden. Aber auch Sounds. Der einzige Nachteil ist, das ich das nur schwer nach LINUX übertragen bekomme. Da wären dann reichlich Änderungen am Quell-Code nötig.

Sowas möchte man sich natürlich gerne verkneifen.
Humor ist der Knopf, der verhindert, daß uns der Kragen platzt.

(Ringelnatz)

Antworten