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 bajty

Delta PNG

110 904 bajty
Oszczędności 73%.

Nawet w tym przykładzie skoncentrowanym na włosach (co jest najgorszym scenariuszem dla formatu Delta PNG) oszczędności są znaczne: 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. Tło jest zakodowane jako przezroczysty czarny 0x00000000, a pierwszy plan jako przezroczysty biały 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

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.

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.

Jeśli jednak używasz np. Pythona i dobrze znanej biblioteki OpenCV, musisz użyć flagi cv2.IMREAD_UNCHANGED i załadować obraz w następujący sposób: 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. 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
Uzyskaj klucz interfejsu API