¿Está inmigrando desde otro proveedor? Check out our migration guide
El formato del resultado Delta PNG puede ahorrar latencia y ancho de banda y es especialmente útil en situaciones en las cuales la latencia y el ancho de banda son sumamente importantes, como en aplicaciones móviles.
Requiere que los píxeles de la imagen original se carguen en el cliente, y luego, se aplica el formato Delta PNG a la imagen original para producir la imagen.
Un ejemplo:
Hasta en este ejemplo centrado en el cabello (que es el peor de los casos para el formato Delta PNG), los ahorros son considerables: 73%
Un Delta PNG es solo un archivo PNG normal y lo puede leer cualquier biblioteca de software capaz de leer los PNG. La única diferencia en comparación con el PNG regular es los valores de los píxeles. El fondo está codificado como negro transparente 0x00000000
y el primer plano como blanco transparente 0x00FFFFFF
. Los píxeles parcialmente transparentes tienen sus valores de color reales.
Tipo de píxeles | Original | PNG regular | Delta PNG | Fuente del resultado |
---|---|---|---|---|
Primer plano |
0xFFrrggbb
|
0xFFrrggbb
|
0x00FFFFFF
|
Original |
Fondo |
0xFFrrggbb
|
0x00000000
|
0x00000000
|
Delta PNG |
Borde |
0xFFrrggbb
|
0x80rrggbb
|
0x80rrggbb
|
Delta PNG |
Esto significa que cuando está descodificando los valores de los píxeles de Delta PNG, necesita obtener el valor real de los píxeles del Original cuando encuentra blanco transparente 0x00FFFFFF
. Los otros píxeles tienen los mismos valores que tiene el formato PNG regular.
Este es un ejemplo del código de TypeScript para descodificar el formato 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; }
Para obtener más información sobre cómo manejar sobre una imagen y los datos de los píxeles en JavaScript, consulte el excelente tutorial Manipulación de píxeles con canvas en la red de desarrolladores de Mozilla.
La biblioteca de carga de imágenes debe poder preservar los valores de los píxeles hasta para los píxeles completamente transparentes, que es como normalmente funciona.
Sin embargo, si está usando, p. ej. Python y la conocida biblioteca OpenCV, entonces necesitará usar la etiqueta cv2.IMREAD_UNCHANGED
y cargar la imagen the esta manera: cv2.imread(path, cv2.IMREAD_UNCHANGED)
De lo contrario, OpenCV destruirá los valores reales de los píxeles completamente transparentes.
Desafortunadamente, OpenCV no aplica ninguna información de rotación almacenada en la imagen cuando se usa esa etiqueta. Es por eso que devolvemos el encabezado X-Input-Orientation
para que el usuario pueda aplicar la orientación correcta a la imagen en esta situación.
Este es un ejemplo del código de Python+OpenCV para aplicar la orientación:
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