Sie migrieren von einem anderen Anbieter? Check out our migration guide
Das Delta-PNG-Ausgabeformat kann sehr viel Latenz und Bandbreite einsparen und ist besonders in latenz- und bandbreitenkritischen Anwendungsbereichen wie mobilen Apps nützlich.
Dabei müssen die Pixel im Originalbild zum Client hochgeladen werden. Anschließend wird das Delta-PNG auf das Originalbild angewendet, um das Ergebnisbild zu erzeugen.
Beispiel:
Selbst in diesem haarzentrischen Beispiel (was für das Delta-PNG-Format den ungünstigsten Fall darstellt) sind die Einsparungen erheblich: 73%
Eine Delta-PNG ist lediglich eine normale PNG-Datei und kann von einer beliebigen Softwarebibliothek gelesen werden, die PNGs lesen kann. Der einzige Unterschied im Vergleich zu einem normalen PNG-Ergebnis besteht in den eigentlichen Pixelwerten. Der Hintergrund wird als transparentes Schwarz 0x00000000
und der Vordergrund als transparentes Weiß 0x00FFFFFF
codiert. Teilweise transparente Pixel besitzen ihre tatsächlichen Farbwerte.
Pixeltyp | Original | Normale PNG | Delta-PNG | Ausgabequelle |
---|---|---|---|---|
Vordergrund |
0xFFrrggbb
|
0xFFrrggbb
|
0x00FFFFFF
|
Original |
Hintergrund |
0xFFrrggbb
|
0x00000000
|
0x00000000
|
Delta-PNG |
Kante |
0xFFrrggbb
|
0x80rrggbb
|
0x80rrggbb
|
Delta-PNG |
Das bedeutet, dass Sie bei der Decodierung der Delta-PNG-Pixelwerte den eigentlichen Pixelwert aus dem Original verwenden müssen, wenn transparentes Weiß 0x00FFFFFF
vorkommt. Die anderen Pixel haben dieselben Werte wie im normalen PNG-Format.
Hier ist ein Beispiel in TypeScript-Code zur Decodierung des Delta-PNG-Formats:
export function decodeDeltaPngInPlace(originalPixels: Uint8Array, deltaPngPixels: Uint8Array): Uint8Array { const N = originalPixels.length / 4; // Array of RGBA values, div 4 to get number of pixels for (let i = 0; i < N; i++) { const i4 = i * 4; const alpha = deltaPngPixels[i4 + 3]; // JavaScript is RGBA, +3 to get alpha if (alpha == 0) { const r = deltaPngPixels[i4]; // JavaScript is RGBA, +0 to get red if (r == 0xFF) { // Transparent white => foreground => take values from original deltaPngPixels[i4] = originalPixels[i4]; deltaPngPixels[i4 + 1] = originalPixels[i4 + 1]; deltaPngPixels[i4 + 2] = originalPixels[i4 + 2]; deltaPngPixels[i4 + 3] = originalPixels[i4 + 3]; } // else transparent black => background => keep values } // else partially transparent => keep values } return deltaPngPixels; }
Weitere Informationen über die Ausführung von Vorgängen an Bild- und Pixeldaten in JavaScript finden Sie diesem ausgezeichneten Tutorial zur Manipulation von Pixeln mit Canvas im Mozilla Developer Network.
Ihre Bildbibliothek muss in der Lage sein, die Pixelwerte selbst bei vollständig transparenten Pixel beizubehalten (normale Funktionsweise).
Wenn Sie jedoch z. B. Python und die bekannte OpenCV-Bibliothek verwenden, müssen Sie das Flag cv2.IMREAD_UNCHANGED
verwenden und das Bild wie folgt laden: cv2.imread(path, cv2.IMREAD_UNCHANGED)
. Ansonsten zerstört OpenCV die tatsächlichen Pixelwerte der vollständig transparenten Pixel.
Leider wendet OpenCV keine im Bild gespeicherten Informationen an, wenn Sie dieses Flag benutzen. Deshalb geben wir die Kopfzeile X-Input-Orientation
zurück, damit Sie unter diesen Umständen die korrekte Ausrichtung auf das Bild anwenden können.
Hier ist ein Beispiel für einen Python+OpenCV-Code zur Anwendung der Ausrichtung:
def apply_exif_rotation(im: np.ndarray, orientation: int) -> np.ndarray: # https://note.nkmk.me/en/python-opencv-numpy-rotate-flip/ if 1 < orientation <= 8: if 2 == orientation: # TOP-RIGHT, flip left-right, [1, 1] -> [-1, 1] im = cv2.flip(im, 1) elif 3 == orientation: # BOTTOM-RIGHT, rotate 180 im = cv2.rotate(im, cv2.ROTATE_180) elif 4 == orientation: # BOTTOM-LEFT, flip up-down, [1, 1] -> [1, -1] im = cv2.flip(im, 0) elif 5 == orientation: # LEFT-TOP, Rotate 90 and flip left-right im = cv2.rotate(im, cv2.ROTATE_90_CLOCKWISE) im = cv2.flip(im, 1) elif 6 == orientation: # RIGHT-TOP, Rotate 90 im = cv2.rotate(im, cv2.ROTATE_90_CLOCKWISE) elif 7 == orientation: # RIGHT-BOTTOM, im = cv2.rotate(im, cv2.ROTATE_90_CLOCKWISE) im = cv2.flip(im, 0) else: # 8 == orientation: # LEFT-BOTTOM, Rotate 270 im = cv2.rotate(im, cv2.ROTATE_90_COUNTERCLOCKWISE) return im