Stai effettuando la migrazione da un altro provider? Check out our migration guide
Il formato di output Delta PNG può far risparmiare molta latenza e larghezza di banda, cosa particolarmente utile quando la latenza e la larghezza di banda sono un fattore da considerare, come le app mobili.
Richiede il caricamento sul client dei pixel nell'immagine originale, e l'applicazione di Delta PNG all'immagine originale per la produzione dell'immagine risultato.
Un esempio:
Anche in questo esempio centrato sui capelli (peggior caso per il formato Delta PNG), i risparmi sono notevoli: 73%
Un file Delta PNG è un file PNG regolare e può essere letto da qualsiasi libreria software in grado di leggere file PNG. L'unica differenza rispetto a un risultato PNG regolare consiste nei valori di pixel. Lo sfondo è codificato come nero trasparente 0x00000000
e il primo piano come bianco trasparente 0x00FFFFFF
. I pixel parzialmente trasparenti hanno i propri valori effettivi di colore.
Tipo di pixel | Originale | PNG regolare | Delta PNG | Fonte di output |
---|---|---|---|---|
Primo piano |
0xFFrrggbb
|
0xFFrrggbb
|
0x00FFFFFF
|
Originale |
Sfondo |
0xFFrrggbb
|
0x00000000
|
0x00000000
|
Delta PNG |
Bordo |
0xFFrrggbb
|
0x80rrggbb
|
0x80rrggbb
|
Delta PNG |
Ciò significa che quando decodifichi i valori di pixel Delta PNG, devi solamente prendere il valore di pixel attuale dall'Originale quando vedi il bianco trasparente 0x00FFFFFF
. Gli altri pixel hanno lo stesso valore nel formato PNG regolare.
Ecco un esempio di codice TypeScript per la decodifica del 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; }
Per maggiori informazioni sulle operazioni con immagini e dati di pixel in JavaScript, consulta l'eccellente guida Pixel manipulation with canvas tutorial sulla Mozilla Developer Network.
La tua libreria di caricamento immagini deve essere in grado di preservare i valori di pixel anche per i pixel interamente trasparenti, come funziona normalmente.
Tuttavia, se usi per esempio Python e la nota libreria OpenCV, devi usare il flag cv2.IMREAD_UNCHANGED
e caricare l'immagine nel seguente modo: cv2.imread(path, cv2.IMREAD_UNCHANGED)
. In caso contrario OpenCV altera i valori di pixel effettivi dei pixel completamente trasparenti.
Purtroppo OpenCV non applica nessuna informazione di rotazione conservata nell'immagine quando usi il flag. Per questo motivo restituiamo l'intestazione X-Input-Orientation
per consentirti di applicare l'orientamento corretto all'immagine in tale caso.
Il seguente è un esempio di codice Python+OpenCV per applicare l'orientamento:
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