Entwickler-Ecke

Multimedia / Grafik - pinch zoom


Symbroson - Mi 31.01.18 23:24
Titel: pinch zoom
Moin EE,

Es geht um eine Bildvorschau, in der man ein Bild beliebig hinein und hinauszoomen und bis zur Canvasgrenze bewgeen können soll.

Meine bisherigen Versuche haven zwar im prinzip immer funktioniert, aber nicht zu 100%
In meinem jetzigen Versuch in Delphi gab es 2 Probleme:

1. Die Bewegungsgrenze war wegen Rundungsfehlern leicht fehlerhaft, da die Korrektur von vorher gerundeten Werten abhing, die ein Zittern um einen Pixel verursachten.

2. Man sollte in die Bildmitte zoomen können - nur erwies sich das mit dem bisherigen Ansatz als nicht so einfach.

Frage wäre jetzt also ob jemand vielleicht schonmal eine funktionierendes Pinch-Zoom umgesetzt hat, oder eine Seite kennt, die in etwa den gleichen Ansatz wie ich hatten.
Vielleicht ist der Ansatz selbst schon das Problem - ich glaube, ich mache mir es irgendwo zu schwer.

Den Quellcode kann ich jetzt leider nicht nochmal schicken, geschweigedenn das Projekt.

LG,
Symbroson


Christian S. - Do 01.02.18 08:27

user profile iconSymbroson hat folgendes geschrieben Zum zitierten Posting springen:
[gelöscht] (Lösung gefunden)
Schön für Dich. Und warum schreibst Du sie dann nicht hier hin, damit jeder etwas davon hat?

Und unsere Richtlinien besagen auch:
Zitat:
4.6 Nachträgliches Bearbeiten eines Beitrags
Wenn du zu einem deiner Beiträge etwas nachtragen möchtest, dann verwende ebenfalls die Editier-Funktion und trage direkt in deinem letzten Beitrag nach. Jeder hat schonmal was vergessen oder kurz nach dem Absenden bemerkt, dass der Beitrag so nicht ganz korrekt ist. Es ist unerwünscht Nachträge in weiteren Postings direkt nach deinem letzten Beitrag zu erstellen (und damit die Schiebungs-Regel 3.8 zu unterlaufen).
Es ist ausdrücklich untersagt eigene Beiträge durch die Editier-Funktion zu entfernen, da somit das gesamte Thema sinnentleert wird (abgesehen davon haben wir Backups)! Hat sich dein Problem erledigt oder hast du bereits selbst eine Lösung gefunden, dann ist es sehr viel besser, wenn du kurz beschreibst, wie du das Problem gelöst hast. So können auch spätere Leser mit dem gleichen Problem eine Lösung finden.

https://www.entwickler-ecke.de/sites.php?id=9


Symbroson - Do 01.02.18 09:43

Ok - entschuldige bitte. Wärst du so nett und stellst die Frage wieder her wenn ihr backups habt :)


Symbroson - Do 01.02.18 10:06

Also mein Fehler war allgemein, dass ich das Bild von der oberen linken Ecke aus verschiebe. Es wird alles viel einfacher, wenn ich es von Anfang an von der Bildmitte heraus betrachte.
Die positionen mussten wegen dem Zoom zu floats werden, damit die Verschiebung weiterhin über genau einen Pixel hinweg erfolgt

Manchmal kommt es noch vor, dass beim Hineinzoomen in ein weit hinaus gezoomtes Bild (sodass das Bild kleiner als die Canvas ist) das Bild kurz an den Rand 'buggt' - vielleicht findet ja jemand die Ursache dafür :)

Die Redraw-Methode sieht nun in etwa so aus: (komplettes Projekt wieder im Anhang)


Delphi-Quelltext
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:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
var img: TImage;
  bmp: TBitmap;
  Form1: TForm1;
  touching: boolean;
  px, py, tx, ty, scale: double;

{...}

procedure TForm1.Redraw;
var mx, my, nx1, ny1, nx2, ny2, m, s: integer;
begin
  //Bildmitte berechnen
  mx := round(scale * px) + bmp.Width  div 2;
  my := round(scale * py) + bmp.Height div 2;

  //Rechteck von Bildmitte aus auf bmp berechnen
  nx1 := round(mx  - scale * img.Width  / 2);
  ny1 := round(my  - scale * img.Height / 2);
  nx2 := round(nx1 + scale * img.Width);
  ny2 := round(ny1 + scale * img.Height);

  //Scrollbegrenzung
  if ny2 < PBox.Height then begin
    inc(ny1, PBox.Height - ny2);
    py := py + (PBox.Height - ny2) / scale;
    ny2 := PBox.Height;
  end;

  if nx2 < PBox.Width then begin
    inc(nx1, PBox.Width - nx2);
    px := px + (PBox.Width - nx2) / scale;
    nx2 := PBox.Width;
  end;

  //Bild Zentrieren wenn img*scale < bmp
  if nx1 > 0 then begin
    if nx2 = PBox.Width then begin
      px := px - nx1 / 2;
      dec(nx2, nx1 div 2);
      dec(nx1, nx1 div 2);
    end else begin
      dec(nx2, nx1);
      px := px - nx1 / scale;
      nx1 := 0;
    end;
  end;

  if ny1 > 0 then begin
    if ny2 = PBox.Height then begin
      py := py - ny1 / 2;
      dec(ny2, ny1 div 2);
      dec(ny1, ny1 div 2);
    end else begin
      dec(ny2, ny1);
      py := py - ny1 / scale;
      ny1 := 0;
    end;
  end;

  //Zeichnen
  bmp.Canvas.Rectangle(-1, -1, bmp.Width, bmp.Height);
  bmp.Canvas.StretchDraw(Rect(nx1, ny1, nx2, ny2), img.Picture.Bitmap);

  //Scrollbalken
  s := round((bmp.Width * bmp.Width) / (2 * scale * img.Width));
  m := round(bmp.Width * (0.5 - px / img.Width));
  bmp.Canvas.Rectangle(m - s, bmp.Height - 7, m + s, bmp.Height - 2);

  s := round((bmp.Height * bmp.Height) / (2 * scale * img.Height));
  m := round(bmp.Height * (0.5 - py / img.Height));
  bmp.Canvas.Rectangle(bmp.Width - 7, m - s, bmp.Width - 2, m + s);

  if scale >= 1 then bmp.Canvas.TextOut(00, FormatFloat('scale: 0.0', scale))
  else bmp.Canvas.TextOut(00, FormatFloat('scale: 1/0.0'1/scale));

  //Rendern
  PBox.Canvas.Draw(00, bmp);
end;




bitte Entschuldigt den EE-Verstoß :( - ich werde mir euer Regelwerk nochmal zu gemüte führen müssen. :les:

trotzdem beste Grüße,
Symbroson


Christian S. - Do 01.02.18 10:50

user profile iconSymbroson hat folgendes geschrieben Zum zitierten Posting springen:
Ok - entschuldige bitte. Wärst du so nett und stellst die Frage wieder her wenn ihr backups habt :)
Auf dem neuen Server liegen die Backups beim Hoster. Versuche bitte, die Frage so einigermaßen wiederherzustellen. Danke! :)