Bildausschnitt justieren

Die Aufgabe ist, den Ausschnitt eines Bildes, basierend auf den Originalmaßen, in einem Viewport zu justieren, so dass er bildfüllend dargestellt wird. Dazu ist zunächst der Zoomfaktor (Breite des dargestellten Images, wi) zu berechnen und dann noch die Offsets in x und y.

Variablen

xo1,yo1,xo2,yo2Ecken des Ausschnitts im Original
xi1,yi1,xi2,yi2Ecken des Ausschnitts im Image
dix, diyAusdehnung des Ausschnitts im dargestellten Image
wvpBreite des ViewportshvpHöhe des Viewports
woBreite des Image (original)hoHöhe des Image (original)
arSeitenverhältnis x/y
wiBreite des Image (dargestellt)hiHöhe des Image (dargestellt)
offsxOffset des linken Randes (Image → Viewport)offsyOffset des oberen Randes (Image → Viewport)
foiFaktor zur Umrechnung Originalkoordinate ⇒ Imagekordinate

Berechnung

Anteil des Ausschnitts an der Ausdehnung des Originals:

(1) zx = (xo2 - xo1) / wo
    zy = (yo2 - yo1) / ho

Es gilt weiterhin für die Darstellung (zx und zy entsprechen den eben berechneten Werten):

(2) zx = dix / wi
    zy = diy / hi

Da der Ausschnitt in den Viewport passen soll, gilt weiterhin:

(3) dix = wvp
    diy = hvp

Gemäß der Berechnung (1) sind zx und zy bekannt und (3) kann nach wi umgestellt und die Werte des Originals eingesetzt werdenwerden:

(4) wi{1} = wvp / zx
    hi = hvp / zy
    oder
    wi{2} = hvp / zy * ar = hvp / zy * wo / ho
    
    nach Einsetzung:
    wi{1} = wvp * wo / (xo2 - xo1)
    wi{2} = hvp * wo / ho * ho / (yo2 - yo1) = hvp * wo / (yo2 - yo1)

Damit der Ausschnitt in beiden Richtungen in den Viewport passt, muss der kleinere der beiden Werte für die weiteren Berechnungen angesetzt werden und damit ergeben sich die Darstellungsmaße für den Ausschnitt des Images im Viewport gemäß (2):

(5) wi = min(wi{1}, wi{2})
    hi = wi / ar
    dix = zx * wi = (xo2 - xo1) / wo * wi
    diy = zy * hi oder
    diy = zy * wi / ar = (yo2 - yo1) / ho * wi / wo * ho = (yo2 - yo1) * wi / wo

Die Ecken des Ausschnitts im Image (und damit die Offsets des Images im Viewport, xi2 und yi2 werden nicht benötigt) ergeben sich zu:

(6) foi = wi / wo
    xi1 = xo1 * foi = xo1 * wi / wo
    yi1 = yo1 * foi = yo1 * wi / wo
    xi2 = xo2 * foi = xo2 * wi / wo
    yi2 = yo2 * foi = yo2 * wi / wo

Um die Offsets zu berechnen, bewegt man sich vom Rand des Viewports zu dessen Mitte und von dort zum Rand des Images, also für den X-Offset:

(7) offsx = wvp / 2 - dix / 2 - xi1
    nach Einsetzung der Werte des Originals
    offsx = wvp / 2 - (xo2 - xo1) * wi / wo / 2 - xo1 * wi / wo
    offsx = wvp / 2 - (xo2 - xo1 + 2 * xo1) * wi / wo / 2
    offsx = wvp / 2 - (xo1 + xo2) * wi / wo / 2 

Zusammenfassung

Zusammengefasst ergeben sich folgende Berechnungen:

wi = wo * min(wvp / (xo2 - xo1), hvp / (yo2 - yo1))
offsx = wvp / 2 - (xo1 + xo2) * wi / wo / 2
offsx = hvp / 2 - (yo1 + yo2) * wi / wo / 2