다른 제공업체에서 이전 중 이십니까? Check out our migration guide
Delta PNG 출력 형식은 대기 시간과 대역폭을 많이 절약할 수 있으며, 모바일 앱과 같이 대기 시간 및 대역폭이 중요한 시나리오에 특히 유용합니다.
원본 이미지의 픽셀을 클라이언트에 로드한 다음, 델타 PNG를 원본 이미지에 적용하여 결과 이미지를 생성해야 합니다.
예:
머리카락 중심의 예(델타 PNG 형식에 대한 최악의 시나리오)에서도 절감 효과는 상당합니다: 73%
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