Delta PNG 출력 포맷

API 키 가져오기

다른 제공업체에서 이전 중 이십니까? Check out our migration guide

Delta PNG 출력 형식은 대기 시간과 대역폭을 많이 절약할 수 있으며, 모바일 앱과 같이 대기 시간 및 대역폭이 중요한 시나리오에 특히 유용합니다.

원본 이미지의 픽셀을 클라이언트에 로드한 다음, 델타 PNG를 원본 이미지에 적용하여 결과 이미지를 생성해야 합니다.

예:

원본

778 × 639 px

일반 PNG

409,048 바이트

Delta PNG

110,904 바이트
73% 절약.

머리카락 중심의 예(델타 PNG 형식에 대한 최악의 시나리오)에서도 절감 효과는 상당합니다: 73%

델타 PNG 디코딩

Delta PNG는 일반 PNG 파일이며, PNG를 읽을 수 있는 모든 소프트웨어 라이브러리에서 읽을 수 있습니다. 일반 PNG 결과와 비교할 때 유일한 차이점은 픽셀 값 자체에 있습니다. 배경은 투명한 검정색 0x00000000으로 인코딩되고 전경은 투명한 흰색 0x00FFFFFF으로 인코딩됩니다. 부분적으로 투명한 픽셀에는 실제 색상 값이 있습니다.

픽셀 형식 원본 일반 PNG Delta PNG 출력 소스
전경 0xFFrrggbb 0xFFrrggbb 0x00FFFFFF 원본
배경 0xFFrrggbb 0x00000000 0x00000000 Delta PNG
가장자리 0xFFrrggbb 0x80rrggbb 0x80rrggbb Delta PNG

즉, 델타 PNG 픽셀 값을 디코딩할 때 투명한 흰색 0x00FFFFFF이 나타나면 원본에서 실제 픽셀 값을 가져와야 합니다. 다른 픽셀은 일반 PNG 형식과 동일한 값을 갖습니다.

다음은 Delta PNG 형식을 디코딩하기 위한 TypeScript 코드 예제입니다.

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;
}

JavaScript에서 이미지 및 픽셀 데이터 작업에 대해 자세히 알아보려면, Mozilla 개발자 네트워크에서 뛰어난 캔버스를 사용한 픽셀 조작 튜토리얼 을 참조하십시오.

주의사항

이미지 로딩 라이브러리는 완전히 투명한 픽셀의 경우에도 픽셀 값을 보존할 수 있어야 하며, 이는 일반적으로 작동하는 방식입니다.

하지만, 예를 들어 Python 및 잘 알려진 OpenCV 라이브러리를 사용하는 경우 cv2.IMREAD_UNCHANGED 플래그를 사용하고 cv2.imread(path, cv2.IMREAD_UNCHANGED)처럼 이미지를 로드해야 합니다. 그렇지 않으면, OpenCV는 완전히 투명한 픽셀의 실제 픽셀 값을 방해합니다.

불행히도 OpenCV는 해당 플래그를 사용할 때 이미지에 저장된 회전 정보를 적용하지 않습니다. 이러한 이유로, 이 시나리오에서 이미지에 올바른 방향을 적용할 수 있도록 X-Input-Orientation 헤더를 반환하는 이유입니다.

다음은 방향을 적용하기 위한 Python+OpenCV 코드 예제입니다:

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
API 키 가져오기