Maße eines Vorschaubildes berechnen

Unsere Fotoapparate und Smartfone produzieren Bilder mit mehreren Millionen Bildpunkten. Viele Details einzufangen und mit anderen zu teilen ist häufig beabsichtigt. Oft ist allerdings auch ratsam, mit kleineren Versionen der Bilder zu arbeiten, denn mit vielen Pixeln geht ein großes Datenvolumen einher. Dieses sowie die Übertragungskapazität pro Zeiteinheit ist insbesondere bei mobilen Zugängen zum weltweiten Netz beschränkt. Ein kleines Vorschaubild spart Zeit, Geld, Strom.

in Schwarz-Weiß ein auf dem Bauch liegender Labärdor von vorn
Abbildung 1: Vorschaubild, 796 × 597 Pixel, 51'035 Bytes.
Das Original misst 3456 × 2592 Pixel und 1'541'386 Bytes.

Um sich als Autor diese Ersparnisse nicht durch neue Arbeit erkaufen zu müssen, ist wünschenswert, dass Vorschaubilder automatisch erstellt werden. Für den Aneamal-Konverter habe ich nun eine solche Funktion implementiert. Auf dieser Seite geht es darum, wie man aus Größenvorgaben fürs Vorschaubild die tatsächlichen Maße der automatisch zu erstellenden Bilder berechnen kann. Diese Berechnungen übernimmt das Programm im Hintergrund; weder Autor noch Leser werden damit behelligt.

Definitionen

$b_o$
Breite des Orignialbildes in Pixeln, $b_o>0$
$b_a$
Breite des Ausschnitts, der aus dem Originalbald fürs neue Bild verwendet wird, in Pixeln
$b_v$
Vorgabe für die Breite des Vorschaubildes
$b_n$
tatsächliche Breite des Vorschaubildes in Pixeln
$h_o$
Höhe des Originalbildes in Pixeln, $h_o>0$
$h_a$
Höhe des Ausschnitts, der aus dem Originalbald fürs neue Bild verwendet wird, in Pixeln
$h_v$
Vorgabe für die Höhe des Vorschaubildes
$h_n$
tatsächliche Höhe des Vorschaubildes in Pixeln
$\min\left\{\ldots,\ldots\right\}$
das dem Wert nach kleinste der durch Kommas getrennten Elemente der Menge[1]
$\lfloor\ldots\rceil$
steht fürs Runden des Ausdrucks auf die naheste ganze Zahl
$\lfloor\ldots\rceil_+$
steht fürs Runden des Ausdrucks auf die naheste positive ganze Zahl[2]

Ausschnitt

Der Ausschnitt des Originalbildes, der fürs Erstellen des Vorschaubildes verwendet wird, entspricht normalerweise dem gesamten Originalbild, das heißt $b_a=b_o$ und $h_a=h_o$. Je nach Vorgaben kann es aber dazu kommen, dass die Seitenverhältnisse von Original und neuem Bild nicht übereinstimmen. In jenem Fall wird ein passender zentraler Ausschnitt aus dem Original verwendet.

Wenn das Originalbild bei den Koordinaten $x_o=0, y_o=0$ beginnt und sich in positive Richtung aufspannt, liegt der Beginn eines mittigen Ausschnitts bei den Koordinaten

$$\begin{aligned} x_a &=\left\lfloor\frac{b_o-b_a}{2}\right\rceil\\ y_a &=\left\lfloor\frac{h_o-h_a}{2}\right\rceil \end{aligned}$$

Vorgaben

Um ein Vorschaubild automatisch zu erstellen, braucht es eine Vorgabe zu seiner Größe. Eine Möglichkeit wäre, die Fläche festzulegen, sodass die Vorschaubilder unabhängig von ihrer Form möglichst immer die gleiche Zahl an Pixeln einnehmen.[3] Das klingt fair, wirkt in der Praxis manchmal aber ungeschickt, wenn Bilder mit mehreren verschiedenen Seitenverhältnissen zusammenkommen. Bilder lassen sich hingegen leicht arrangieren, wenn sie dieselbe Breite oder Höhe aufweisen.

Um eine gewisse Flexibilität zu ermöglichen, entschied ich mich dazu, zwei einfache Vorgaben fürs Vorschaubild auszuwerten: Breite $b_v$ und Höhe $h_v$. Dabei gibt es für jedes der beiden Maße drei Möglichkeiten:

Drei Möglichkeiten für die Breite und drei Möglichkeiten für die Höhe ergeben neun verschiedene Fälle:

$h_v<0$$h_v=0$$h_v>0$
$b_v<0$Fall 4Fall 3Fall 9
$b_v=0$Fall 8Fall 1Fall 7
$b_v>0$Fall 6Fall 2Fall 5

Formeln

Weder Breite noch Höhe vorgegeben ($b_v=0, h_v=0$)

Ohne eine Vorgabe zur Breite oder Höhe erhält das neue Bild dieselben Abmaße wie das Original.

$$\begin{aligned} b_n &=b_o\\ h_n &=h_o \end{aligned}$$

Ist es überhaupt sinnvoll, ein Vorschaubild zu erstellen, wenn sich die Maße gegenüber dem Original nicht ändern? Ja, denn das Vorschaubild kann auch dann ein geringeres Datenvolumen umfassen, wenn es stärker komprimiert wird.

Breite genau vorgegeben, Höhe nicht vorgegeben ($b_v>0, h_v=0$)

Ist die Breite genau vorgegeben, wird sie fürs neue Bild verwendet.

$$b_n=b_v$$

Mithilfe eines Skalierungsfaktors $s$ lässt sich der Zusammenhang von Original- und neuer Breite $b_n=b_o\cdot s$ herstellen. Umgestellt ist der Skalierungsfaktor $s=\frac{b_n}{b_o}$. Den gleichen Skalierungsfaktor nutzen wir fürs Ausrechnen der neuen Höhe $h_n=\left\lfloor h_o\cdot s\right\rceil_+$, sodass das Seitenverhältnis des Originalbildes beim neuen Bild beibehalten wird. Wir runden, da wir es immer mit ganzen Pixeln zu tun haben. Zusammengefasst ergibt das für die neue Höhe

$$h_n=\left\lfloor h_o\cdot\frac{b_n}{b_o}\right\rceil_+$$

Maximalbreite vorgegeben, Höhe nicht vorgegeben ($b_v<0, h_v=0$)

Wenn nur eine Maximalbreite vorgegeben ist, erhält das neue Bild die Breite des Originals, wenn diese den Maximalwert nicht überschreitet. Ansonsten wird der Maximalwert angenommen. Die neue Breite wird also durch den kleineren Wert, dem Minimum aus Originalbreite und vorgegebenem Maximalwert bestimmt.

$$b_n=\min\left\{b_o,-b_v\right\}$$

Da $b_v$ in diesem Fall negativ ist, sorgt das vorgesetzte Minuszeichen für einen positiven Betrag, denn minus mal minus ergibt plus. Wie in wird dann für die Höhe der Skalierungsfaktor von der Breite übernommen.

$$h_n=\left\lfloor h_o\cdot\frac{b_n}{b_o}\right\rceil_+$$

Maximalbreite und Maximalhöhe vorgegeben ($b_v<0, h_v<0$)

Wenn Originalbreite und -höhe kleiner als die jeweils vorgegebenen Maximalwerte sind, behält das neue Bild die Maße des Originals: Der Skalierungsfaktor ist dann 1. Anderenfalls wird das Bild und damit der Skalierungsfaktor so weit geschrumpft, bis weder Breite noch Höhe den jeweils vorgegebenen Maximalwert überschreiten.

Abbildung 2: Weißt gepunktet ist ein durch Maximalbreite und -höhe vorgegebenes Fenster eingezeichnet. Das Original (grau) wird fürs neue Bild so lang geschrumpft, bis es in das Fenster passt (schwarz).

Je nachdem, ob beim Schrumpfen zuletzt die Maximalbreite oder -höhe eingestellt wird, beträgt der Skalierungsfaktor in jenem Moment $\frac{-b_v}{b_o}$ oder $\frac{-h_v}{h_o}$. Zusammenfassen lässt sich der Skalierungsfaktor als Minimum der drei möglichen Werte

$$s=\min\left\{1,-\frac{b_v}{b_o},-\frac{h_v}{h_o}\right\}$$

und die neuen Abmaße sind

$$\begin{aligned} b_n &=\left\lfloor b_o\cdot s\right\rceil_+\\ h_n &=\left\lfloor h_o\cdot s\right\rceil_+ \end{aligned}$$

Breite und Höhe genau vorgegeben ($b_v>0, h_v>0$)

Bei genau vorgegebener Breite und Höhe ist das Ermitteln der neuen Abmaße kein Hexenwerk.

$$\begin{aligned} b_n &=b_v\\ h_n &=h_v \end{aligned}$$

Wenn das Seitenverhältnis des neuen Bildes nicht dem Original entspricht, kann ohne Verzerrung allerdings nur ein Ausschnitt des Originalbildes ins Vorschaubild übernommen werden.

Abbildung 3: Die Maße des neuen Bildes sind genau vorgegeben (schwarz). Da die Seitenverhältnisse von neuem Bild und Original (grau) sich unterscheiden, wird nur ein passender Ausschnitt (gestrichelt) des Originals aufs neue Bild abgebildet.

Die Abmaße des Ausschnitts erhalten wir durchs Skalieren des neuen Bildes

$$\begin{aligned} b_a &=\left\lfloor b_n\cdot z\right\rceil_+\\ h_a &=\left\lfloor h_n\cdot z\right\rceil_+ \end{aligned}$$

auf die Größe des Originals. Der Skalierungsfaktor $z$ ist dabei

$$z=\min\left\{\frac{b_o}{b_n},\frac{h_o}{h_n}\right\}$$

Durch Einsetzen von $z$ sieht man, dass der Ausschnitt entweder die Breite oder die Höhe des Originals annimmt und die andere Seite des Ausschnitts kürzer als am Original ausfällt – eben so, wie es dem Seitenverhältnis des Vorschaubildes entspricht.

Breite genau vorgegeben, Maximalhöhe vorgegeben ($b_v>0, h_v<0$)

Die genau vorgegebene Breite wird beim neuen Bild berücksichtigt.

$$b_n=b_v$$

Die Höhe des neuen Bildes wird dann genau wie in berechnet, solange sie den hier gegebenen Maximalwert nicht überschreitet, der ansonsten verwendet wird.

$$h_n=\min\left\{\left\lfloor h_o\cdot\frac{b_n}{b_o}\right\rceil_+,-h_v\right\}$$

Damit sind die Abmaße des neuen Bildes ermittelt und der abzubildende Ausschnitt des Originals berechnet sich genau wie bei .

$$\begin{aligned} z &= \min\left\{\frac{b_o}{b_n},\frac{h_o}{h_n}\right\}\\ b_a &=\left\lfloor b_n\cdot z\right\rceil_+\\ h_a &=\left\lfloor h_n\cdot z\right\rceil_+ \end{aligned}$$

Breite nicht vorgegeben, Höhe genau vorgegeben ($b_v=0, h_v>0$)

Wenn man Höhe und Breite vertauscht, gleicht dieser Fall und es gilt

$$\begin{aligned} h_n &=h_v\\ b_n &=\left\lfloor b_o\cdot\frac{h_n}{h_o}\right\rceil_+ \end{aligned}$$

Breite nicht vorgegeben, Maximalhöhe vorgegeben ($b_v=0, h_v<0$)

Wenn man Höhe und Breite vertauscht, gleicht dieser Fall und es gilt

$$\begin{aligned} h_n &=\min\left\{h_o,-h_v\right\}\\ b_n &=\left\lfloor b_o\cdot \frac{h_n}{h_o}\right\rceil_+ \end{aligned}$$

Maximalbreite vorgegeben, Höhe genau vorgegeben ($b_v<0, h_v>0$)

Wenn man Breite und Höhe vertauscht, gleicht dieser Fall und es gilt

$$\begin{aligned} h_n &=h_v\\ b_n &=\min\left\{\left\lfloor b_o\cdot\frac{h_n}{h_o}\right\rceil_+,-b_v\right\}\\ z &=\min\left\{\frac{b_o}{b_n},\frac{h_o}{h_n}\right\}\\ b_a &=\left\lfloor b_n\cdot z\right\rceil_+\\ h_a &=\left\lfloor h_n\cdot z\right\rceil_+ \end{aligned}$$

Und nun?

Mit den berechneten Maßen kann man ein Programm füttern, welches das Vorschaubild erzeugt. In PHP etwa steht dafür die Funktion „imagecopyresampled“ zur Verfügung.[4] Es gibt viele verschiedene Algorithmen zur Größenänderung von Bildern. Wer sich dafür interessiert, wie diese arbeiten, findet eine Reihe von ihnen im Wikipedia-Artikel „Skalierung (Computergrafik)“ in Ansätzen vorgestellt.


[1]
Beispielsweise ist $\min\left\{x,y\right\}=x$ falls $x\leq y$, und $\min\left\{x,y\right\}=y$ falls $x\geq y$.
[2]
Mithilfe des Maximums einer Menge ausgedrückt ist $\lfloor\ldots\rceil_+=\max\left\{\lfloor\ldots\rceil,1\right\}$. Typischerweise macht es beim Erstellen von Vorschaubildern keinen Unterschied, ob $\lfloor\ldots\rceil$ oder $\lfloor\ldots\rceil_+$ verwendet wird. $\lfloor\ldots\rceil_+$ verhindert Divisionen durch null und null Pixel hohe/breite Bilder bei atypischen Vorgaben beziehungsweise Originalen.
[3]
Bei Vorgabe einer Fläche $F_v$ ergäben sich die Maße des Vorschaubildes als $b_n=\left\lfloor b_o\cdot s\right\rceil_+$ und $h_n =\left\lfloor h_o\cdot s\right\rceil_+$ mit dem Skalierungsfaktor $s=\sqrt{\frac{F_v}{b_o\cdot h_o}}$.
[4]
In PHP sähe der Befehl zum Beispiel wie folgt aus:
imagecopyresampled ($vorschau, $original, 0, 0, $x_a, $y_a, $b_n, $h_n, $b_a, $h_a);