Format docelowy Delta PNG

Uzyskaj klucz interfejsu API

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:

Oryginał

778 × 639 px

Zwykły PNG

409 048 bytes

Delta PNG

110 904 bytes
73% savings.

Even in this hair-centric example (which is a worst-case scenario for the Delta PNG format), the savings are significant: 73%

Dekodowanie Delta PNG

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.

Zastrzeżenia

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
Uzyskaj klucz interfejsu API