Migracja z innego dostawcy? Check out our migration guide
Format wyjściowy Delta PNG może zaoszczędzić wiele opóźnień i przepustowości i jest szczególnie przydatny w scenariuszach krytycznych dla opóźnień i przepustowości, takich jak aplikacje mobilne.
Wymaga to załadowania pikseli w oryginalnym obrazie na kliencie, a następnie do oryginalnego obrazu zastosowano plik PNG Delta w celu uzyskania obrazu wynikowego.
Przykład:
778 × 639 px
409 048 bytes
110 904 bytes
Even in this hair-centric example (which is a worst-case scenario for the Delta PNG format), the savings are significant: 73%
Delta PNG to zwykły plik PNG i może być odczytany przez dowolną bibliotekę oprogramowania zdolną do odczytu PNG. Jedyną różnicą w porównaniu ze zwykłym wynikiem PNG są same wartości pikseli. The background is encoded as transparent black 0x00000000 and the foreground as transparent white 0x00FFFFFF. Częściowo przezroczyste piksele mają swoje rzeczywiste wartości kolorów.
| Typ pikseli | Oryginał | Zwykły PNG | Delta PNG | Źródło wyjściowe |
|---|---|---|---|---|
| Pierwszy plan |
0xFFrrggbb
|
0xFFrrggbb
|
0x00FFFFFF
|
Oryginał |
| Tło |
0xFFrrggbb
|
0x00000000
|
0x00000000
|
Delta PNG |
| Krawędź |
0xFFrrggbb
|
0x80rrggbb
|
0x80rrggbb
|
Delta PNG |
This means that when you're decoding the Delta PNG pixel values, you need to pull the actual pixel value from the Original when you encounter transparent white 0x00FFFFFF. Pozostałe piksele mają takie same wartości jak w zwykłym formacie PNG.
Oto przykład kodu TypeScript do dekodowania formatu Delta PNG:
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;
}
Aby dowiedzieć się więcej o obsłudze danych obrazów i pikseli w JavaScript, zobacz doskonały samouczek dotyczący manipulacji pikselami z płót nem w sieci Mozilla Developer Network.
Biblioteka ładowania obrazów musi być w stanie zachować wartości pikseli nawet dla w pełni przezroczystych pikseli, tak to normalnie działa.
However, if you're using e.g. Python and the well known OpenCV library, then you need to use the cv2.IMREAD_UNCHANGED flag and load the image like so: cv2.imread(path, cv2.IMREAD_UNCHANGED). W przeciwnym razie OpenCV zamyka rzeczywiste wartości pikseli w pełni przezroczystych pikseli.
Niestety OpenCV nie stosuje żadnych informacji o rotacji przechowywanych na obrazie, gdy używasz tej flagi. This is why we return the X-Input-Orientation header so that you can apply the correct orientation to the image in this scenario.
Oto przykład kodu Python+OpenCV do zastosowania orientacji:
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