Autor |
Beitrag |
Gausi
Beiträge: 8541
Erhaltene Danke: 475
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Di 23.07.19 10:10
Ich hab da eine Frage, die hauptsächlich theoretischer Natur ist, aber auch so ein klein wenig eine Grundsatzfrage ist.
Ausgangspunkt ist das Problem, ein (großes) Bild "schön" zu skalieren, d.h. in ein kleineres TImage zu laden. Mit der Eigenschaft Stretch des TImage wird das Ergebnis sehr pixelig und sieht nicht gut aus.
Über StretchBlt sieht das ganze deutlich besser aus, allerdings kommt diese Methode nicht mit Transparenzen klar - stattdessen gibt es dann einen schwarzen Hintergrund. Die Eigenschaft Transparent des TImage scheidet dabei auch aus, Stichwort Alphakanal und so. Das gibt ganz, ganz hässliche Ränder.
Durch etwas Recherche bin ich dann auf Windows Imaging Component (WIC) gestoßen, z.B. hier www.delphipraxis.net/1291613-post31.html
Das funktioniert sehr gut, läuft aber erst ab XP SP3. Nun ist das sicherlich keine relevante Hürde mehr, und tatsächlich möchte ich XP nicht weiter komplett unterstützen. Aber das hier ist eine Kleinigkeit, die aber sehr oft durchgeführt werden muss. Da hätte ich gerne einen Fallback auf die "unschöne" Methode.
Kann ich da einfach mit Try..except arbeiten, oder muss ich da anders ansetzen? Da komme ich dann zur Grundsatzfrage: Wie kann ich testen, ob das System ein bestimmtes Feature bereitstellt oder nicht?
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| try WPic := TWICImage.Create; try WPic.LoadFromFile(aFilename); ResizeImage(WPic, SomeNewWidth); TargetBitmap.Assign(WPic); finally WPic.Free end; except end; |
Oder kommt ohnehin direkt beim Start der Anwendung ne Fehlermeldung, wenn der Code im Binary steckt?
In meiner alten XP-VM habe ich "leider" auch schon SP3, kann das also nicht unmittelbar testen.
_________________ We are, we were and will not be.
|
|
Steku
Beiträge: 23
Erhaltene Danke: 5
|
Verfasst: Di 23.07.19 12:11
Nur so eine Idee zum Testen, vielleicht kannst du dein Programm
unter Windows in einem Kompatibilätsmodus ausführen.
Hier auf meinem Win7 PC kann ich Modi runter bis Win95 wählen
(auch WinXP SP2).
Grüße
Steku
Einloggen, um Attachments anzusehen!
|
|
Sinspin
Beiträge: 1334
Erhaltene Danke: 118
Win 10
RIO, CE, Lazarus
|
Verfasst: Di 23.07.19 17:57
Hallo Daniel,
Für das Transparenzproblem würde ich mir im Bild als erstes eine Farbe suchen die nicht verwendet wird. Möglichst was reines (R G B) und volle Sättigung. Dann alle Pixel im Bild die Transparent sein sollen in der Farbe zeichnen und nach BitBlt / StretchBlt die Transparenzinfo mit Hilfe der Farbe wieder herstellen.
Durch das Glätten den Bildes werden die Farbwerte verändert / verwischt und du brauchst eine Strategie zum entscheiden wie stark die Transparenz für einen Pixel werden soll in dem nur ein Teil deiner Farbe enthalten ist. Das ist zugegeben nicht ganz einfach wenn es wirklich schön werden soll. Aber recht gut mit Nachbarschaftsbeziehungen zu lösen.
try except, so pauschal blind, ohne Einschränkung auf eine bestimmte Exception Klasse würde ich es nicht machen. Du solltest einen Test schreiben der die passende Exception auslöst, falls Du sie nirgendwo in der Doku finden kannst und einen deiner alt alt alt XP Nutzer fragen ob er den test mal laufen lassen kann um rauszubekommen ob es passt.
Aber, ganz eigentlich, würde ich alles vor XP SP3 nicht mehr unterstützen. Nennt man Nutzererziehung, wenn man sie zwingt sich zu verbessern und auf Win1.0 umzusteigen.
_________________ Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
|
|
Gausi
Beiträge: 8541
Erhaltene Danke: 475
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Di 23.07.19 19:54
Das hilft mir nicht so direkt weiter.
Der Kompatibilitätsmodus ist ja dafür nicht gedacht. Das funktioniert dann auch nicht - bzw. es funktioniert, was es unter XP SP2 nicht tun sollte.
@Stefan: Das reicht auch nicht so ganz. Quelle der Bilder, um die es geht, sind PNGs mit alpha-Kanal. Also nicht nur Transparenz ja/nein pro Pixel, sondern auch halbtransparente Bereiche. Die sind auch nötig, wenn die Grafiken sowohl auf dunklem, als auch auf hellem Grund schön dargestellt werden sollen. Selber was bauen ginge natürlich, aber das wäre für diese Stelle Overkill. 99% der Bilder brauchen keine Transparenz und sind rechteckig. Aber ab und zu, bzw. als Fallback, wenn das "eigentliche" Bild nicht gefunden werden kann, möchte ich da ein Symbol-Bild anzeigen lassen, das nicht unbedingt rechteckig ist - und für glatte Kanten braucht man dann Transparenz.
Generell wird auch XP SP3 nicht mehr voll unterstützt von mir, alleine schon wegen des HttpClients und den "neueren"
aHttpClient.SecureProtocols (TLS 1.1, 1.2). Da knallt es eh schon, wenn der Player ins Internet will.
Ist auch eher eine Frage aus Neugier, bzw. zur Weiterbildung. Ich weiß halt nicht, wie man auf eine bestimmte API-Funktion testen kann ... Vielleicht mach ich das am Ende auch einfach über eine Option in der settings.ini, die der User zur Not umstellen kann. Oder ich liefere nur das "kleine" Bild mit, und wenn der User größer skaliert, wird das nur zentriert in dieser Größe ausgegeben ...
Ist halt auch kein Key-Feature, was unbedingt sein muss.
_________________ We are, we were and will not be.
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Di 23.07.19 20:07
Vielleicht hilft dir das weiter: www.delphipraxis.net/1095307-post20.html
Oder:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63:
| procedure ScaleImage(const SourceImage, DestImage: TImage; DestWidth, DestHeight: Integer; aColor: TColor); var W, H: Double; L, T: Integer; aRect: TRect; aImage: TImage; begin aImage := TImage.Create(nil);
try aImage.Canvas.Brush.Color := aColor; aImage.Canvas.FloodFill(0, 0, aColor, fsBorder);
W := SourceImage.Picture.Width; H := SourceImage.Picture.Height;
if (H < DestHeight) and (W > DestWidth) then exit; if (H > DestHeight) and (W < DestWidth) then exit;
if (H > DestHeight) and (W > DestWidth) then while (W > DestWidth) or (H > DestHeight) do begin W := W / 1.01; H := H / 1.01; end else while (W < DestWidth) or (H < DestHeight) do begin W := W * 1.01; H := H * 1.01; end;
if (SourceImage.Picture.Width > DestWidth) and (SourceImage.Picture.Height > DestHeight) then begin L := DestWidth+1; T := DestHeight+1;
L := L mod Trunc(W) div 2; T := T mod Trunc(H) div 2; end else begin L := 0; T := 0; end;
aRect := Rect(L, T, Trunc(W)+L, Trunc(H)+T);
aImage.Picture.Graphic.Width := DestWidth; aImage.Picture.Graphic.Height := DestHeight; aImage.Canvas.CopyMode := cmSrcCopy; aImage.Canvas.StretchDraw(aRect, SourceImage.Picture.Graphic);
DestImage.Picture.Assign(aImage.Picture); DestImage.Width := aRect.Right; DestImage.Height := aRect.Bottom;
finally aImage.Free; end; end; |
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Gausi
Beiträge: 8541
Erhaltene Danke: 475
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Mi 24.07.19 07:18
Leider auch nicht. In der DP ist wieder die StretchBlt-Methode (Problem mit Transparenzen), und bei deinem Code wird StretchDraw von TImage verwendet, und das erzeugt pixelige Ergebnisse.
btw.: Die Skalierung in deinem Code kann man eleganter machen, hier mal ein Auszug aus meinem Code, der Source so anpasst, dass es in Bounds hineinpasst. Eine alternative Methode dafür sieht man im DP-Code. Die Größenänderung um je 1% in der Schleife ist nicht nötig.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| xFactor:= Bounds.Width / Source.Width; yFactor:= Bounds.Height / Source.Height; if xFactor > yFactor then begin Bounds.Width := round(Source.Width * yFactor); Bounds.Height := round(Source.Height * yFactor); Factor := yFactor; end else begin Bounds.Width := round(Source.Width * xFactor); Bounds.Height := round(Source.Height * xFactor); Factor := xFactor; end; |
Im Anhang mal ein Beispiel, was ich meine. Links jeweils die automatische Skalierung durch TImage, in der Mitte das Transparenzproblem mit StretchBlt, rechts das Ergebnis mit WIC. Letzteres funktioniert super, nur da würde ich irgendwie gerne den optionalen Fallback einbauen, falls das nicht verfügbar ist.
Einloggen, um Attachments anzusehen!
_________________ We are, we were and will not be.
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mi 24.07.19 07:31
Gausi hat folgendes geschrieben : | Leider auch nicht. In der DP ist wieder die StretchBlt-Methode (Problem mit Transparenzen), und bei deinem Code wird StretchDraw von TImage verwendet, und das erzeugt pixelige Ergebnisse. |
Und wenn du AntiAliasing verwendest, verbesserst du - rein optisch - die Pixeligkeit, aber es wird unscharf...
Ich verwende den Code, um Fotos verzerrungsfrei zu skalieren, so als eine Art Thumbnail. Auf 100%-ige Qualität kommt es mir dabei nicht an.
Ich werde mir deine Verbesserung ansehen und ggf. einbauen, danke!
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Narses
Beiträge: 10182
Erhaltene Danke: 1255
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Mi 24.07.19 09:17
Moin!
Ich werfe mal zwei Gedanken in den Raum (für mehr hab ich leider grade keine Zeit ):
GRAPHICS32 für das Scaling-Problem
und
im wesentlichen das hier (als Ansatz): www.delphipraxis.net...-ob-dll-geladen.html für das Kompatibilitätsproblem (Kerngedanke: rausfinden, welche API-Calls in Windows erfolgen, die DLL ermitteln, prüfen ob die im System verfügbar ist, wenn ja, prüfen, ob die gewünschte Methode verfügbar ist; bei statischer Bindung von Methoden aus den Delphi-System-Bibliotheken wird das aber sowieso egal sein, weil dann die Exe beim Start direkt mit einem Fehler rausfliegt, weil die statische Bindung an den Prozess nicht geklappt hat).
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
Gausi
Beiträge: 8541
Erhaltene Danke: 475
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Mi 24.07.19 11:53
Narses hat folgendes geschrieben : | bei statischer Bindung von Methoden aus den Delphi-System-Bibliotheken wird das aber sowieso egal sein, weil dann die Exe beim Start direkt mit einem Fehler rausfliegt, weil die statische Bindung an den Prozess nicht geklappt hat). |
Dann hat sich das an der Stelle ohnehin erledigt, und ich kann weder mit Try..Except noch mit einer Einstellung was retten.
Aber die Graphics32 werde ich mir mal näher anschauen - das sieht recht vielversprechend aus. Nur für diese Kleinigkeit werde ich das vermutlich nicht machen. Aber wie es aussieht, ist TBitmap32 daraus threadsafe, kann also auch außerhalb des VCL-Threads verwendet werden. Und das macht das Ding für mich sehr interessant ...
(Auch wenn das vermutlich einen Haufen Arbeit bedeutet.)
_________________ We are, we were and will not be.
|
|
|