Des images en 8-bits pour iOS

Warning: Input PNG does not have an 8 bit input depth

Lors du packaging d’une application, XCode vérifie les caractéristiques des images embarquées avec l’application. En interactif on ne voit rien, mais lorsque l’on scripte les opérations de fabrication, ce type de messages apparaît :

CopyPNGFile build/Release-iphoneos/Ipad.app/interview-frP05-100-2.png Ipad/Images/Interview/Portrait/100/interview-frP05-100-2.png 
libpng warning: Warning: Input PNG does not have an 8 bit input depth. Please convert your PNG to 8-bit for optimal performance on iPhone OS

Si on regarde d’un peu plus près on se rend compte que les images concernées sont toutes du même type.

L’application contient un entretien "PDF" zoomable stocké sous forme d’images 2048×1538. Pour améliorer les performances à l’affichage ces images ont été découpées en tuiles. Au zoom maximal, certaines zones sont assez vides ou monochromes, en particulier les bords d’images.

Les images sont découpées avec ImageMagick. Un examen des images avec warning montre qu’elles n’ont pas les mêmes caractériques que les images qui ne causent pas d’erreur.

Une image sans erreur

identify -verbose Ipad/Images/Interview/Landscape/100/interview-frL02-100-13.png Image: IpadCorporate/Images/Essentiel/Interview/Landscape/100/interview-frL02-100-13.png
  Format: PNG (Portable Network Graphics)
  Class: DirectClass
  Geometry: 256x256+0+0
  Resolution: 72x72
  Print size: 3.55556x3.55556
  Units: Undefined
  Type: TrueColor
  Endianess: Undefined
  Colorspace: RGB
  Depth: 8-bit
  Channel depth:
    red: 8-bit
    green: 8-bit
    blue: 8-bit

L’image la plus à gauche, qui ne contient quasiment que tu texte en gris est en GrayScale 

identify -verbose Ipad/Images/Interview/Portrait/100/interview-frP01-100-1.png Image: IpadCorporate/Images/Essentiel/Interview/Portrait/100/interview-frP01-100-1.png
  Format: PNG (Portable Network Graphics)
  Class: PseudoClass
  Geometry: 256x256+0+0
  Resolution: 72x72
  Print size: 3.55556x3.55556
  Units: Undefined
  Type: Grayscale
  Base type: Grayscale
  Endianess: Undefined
  Colorspace: Gray
  Depth: 8-bit
  Channel depth:
    gray: 8-bit

Certaines autres images sont en Bilevel (Black & White) 

identify -verbose Ipad/Images/Interview/Landscape/100/interview-frL02-100-32.png Image: IpadCorporate/Images/Essentiel/Interview/Landscape/100/interview-frL02-100-32.png
  Format: PNG (Portable Network Graphics)
  Class: PseudoClass
  Geometry: 256x256+0+0
  Resolution: 72x72
  Print size: 3.55556x3.55556
  Units: Undefined
  Type: Bilevel
  Base type: Bilevel
  Endianess: Undefined
  Colorspace: Gray
  Depth: 8/1-bit
  Channel depth:
    gray: 1-bit

ImageMagick cherche le format le plus adapté ce qui revient parfois à transformer l’image en niveaux de gris voir en Noir et Blanc si elle n’a pas de contenu.

Une première solution

J’ai d’abord tenté de forcer la profondeur à 8-bits avec la syntaxe png8:nom-fichier

convert interview-frP01-100.png -crop 256x256 +repage +adjoin png8:interview-frP01-100-%d.png

Cette option supprime bien les warnings mais ne rend pas un très bon résultat. Sur l’image réassemblée, le dégradé sur le fond est remplacé par un effet psychédélique assez laid.

L’image est postérisée car le nombre de couleurs est réduit.

identify -verbose generated_images/Interview/Portrait/100/interview-frP01-100-10.png Image: generated_images/Interview/Portrait/100/interview-frP01-100-10.png
  Format: PNG (Portable Network Graphics)
  Class: PseudoClass
  Geometry: 256x256+0+0
  Resolution: 72x72
  Print size: 3.55556x3.55556
  Units: Undefined
  Type: Palette
  Endianess: Undefined
  Colorspace: RGB
  Depth: 8/4-bit
  Channel depth:
    red: 4-bit
    green: 4-bit
    blue: 4-bit

Ceci dit cette option marche bien sur un autre jeu de tuiles qui ne contient que des images monochromes.

La solution correcte

J’ai ensuite tenté diverses options (-depth, -colorspace, -type, -define png:bit-depth). En fait, CopyPNGFile semble rejeter le colorscale Gray mais je n’ai pas réussi à convaincre ImageMagick de ne pas changer le colorscale des tuiles très simples.

L’issue est dans le pngN: mais il faut lui donner les bonnes valeurs.

Le build veut 8 bits par canal de couleur.

Les images en RGB (Red Green Bleu le color scale le plus courant) comportent 3 canaux :
  • un qui contient la valeur du rouge,
  • un qui contient la valeur du vert (Green)
  • et un qui contient la valeur du bleu.

Chaque pixel est codé sur 8 bits soit une valeur entre 0 et 255. La combinaison de la valeur de chaque canal produit la couleur souhaitée parmi 16 millions de couleurs (256x256x256).

Pour les images transparentes, elles comportent un quatrième canal, le canal alpha, qui indique la transparence du pixel.

Si on veut 8 bits par canal il faut indiquer png24 (3×8) pour une image sans transparence, ou png32 (4×8) pour une image avec un canal alpha.

convert interview-frP01-100.png -crop 256x256 +repage +adjoin png24:interview-frP01-100-%d.png

Cette option supprime les warnings et ne dégrade pas l’image.

L’image de gauche en niveau de gris devient

identify -verbose Ipad/Images/Interview/Portrait/100/interview-frP01-100-1.png Image: IpadCorporate/Images/Essentiel/Interview/Portrait/100/interview-frP01-100-1.png
  Format: PNG (Portable Network Graphics)
  Class: DirectClass
  Geometry: 256x256+0+0
  Resolution: 72x72
  Print size: 3.55556x3.55556
  Units: Undefined
  Type: Grayscale
  Base type: Grayscale
  Endianess: Undefined
  Colorspace: RGB
  Depth: 8-bit
  Channel depth:
    gray: 8-bit

et la plupart des images ressemblent à ce qui suit

identify -verbose Ipad/Images/Interview/Portrait/100/interview-frP01-100-10.png Image: IpadCorporate/Images/Essentiel/Interview/Portrait/100/interview-frP01-100-10.png
  Format: PNG (Portable Network Graphics)
  Class: DirectClass
  Geometry: 256x256+0+0
  Resolution: 72x72
  Print size: 3.55556x3.55556
  Units: Undefined
  Type: TrueColor
  Endianess: Undefined
  Colorspace: RGB
  Depth: 8-bit
  Channel depth:
    red: 8-bit
    green: 8-bit
    blue: 8-bit