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 bajty
110 904 bajty
Nawet w tym przykładzie skoncentrowanym na włosach (co jest najgorszym scenariuszem dla formatu Delta PNG) oszczędności są znaczne: 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. Tło jest zakodowane jako przezroczysty czarny Częściowo przezroczyste piksele mają swoje rzeczywiste wartości kolorów.
0x00000000, a pierwszy plan jako przezroczysty biały 0x00FFFFFF.
| 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 |
Oznacza to, że podczas dekodowania wartości pikseli Delta PNG należy wyciągnąć rzeczywistą wartość piksela z oryginału, gdy napotkasz przezroczystą biel 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.
Jeśli jednak używasz np. Pythona i dobrze znanej biblioteki OpenCV, musisz użyć flagi W przeciwnym razie OpenCV zamyka rzeczywiste wartości pikseli w pełni przezroczystych pikseli.
cv2.IMREAD_UNCHANGED i załadować obraz w następujący sposób: cv2.imread(path, cv2.IMREAD_UNCHANGED).
Niestety OpenCV nie stosuje żadnych informacji o rotacji przechowywanych na obrazie, gdy używasz tej flagi. Dlatego zwracamy nagłówek X-Input-Orientation, abyś mógł zastosować prawidłową orientację obrazu w tym scenariuszu.
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