Module optionnel · pdftoolkit/pdf-codecs 0.1.0
English | Français
PDFToolkit\Codecs\Jpeg\JpegDecoder décode les processus DCT Huffman à huit bits utilisés par PDF : séquentiel de base (SOF0), séquentiel étendu (SOF1) et progressif (SOF2). Il n'accède pas aux fichiers et n'exécute aucun processus. Chaque appel possède son analyseur, son historique de scans, ses tables, ses coefficients et ses budgets.
use PDFToolkit\Codecs\Codec;
use PDFToolkit\Codecs\DecodeLimits;
use PDFToolkit\Codecs\DecodeRequest;
use PDFToolkit\Codecs\Jpeg\JpegDecoder;
$decoder = new JpegDecoder(new DecodeLimits(maxPixels: 4_000_000));
$image = $decoder->decode(new DecodeRequest(Codec::Jpeg, $jpegBytes, colorTransform: null));
$firstComponent = $image->components[0];
$sample = $firstComponent->sample(0, 0);
Le décodeur accepte une à quatre composantes, les scans entrelacés ou séparés, les facteurs d'échantillonnage 1–4 (y compris les rapports d'expansion fractionnaires), les tables de quantification sur 8/16 bits lorsque le processus les autorise, les redéfinitions de tables Huffman, les octets d'échappement et les marqueurs de redémarrage ordonnés. La sélection spectrale progressive, l'approximation successive, les suites EOB et le raffinement des coefficients sont décodés avec vérification de l'ordre des scans par composante. Une image progressive limitée au premier scan DC peut être décodée avec des coefficients AC non transmis nuls. La table de quantification d'une composante est conservée au début de son premier scan, ce qui permet de réutiliser une destination de table pour des composantes ultérieures.
La DCT inverse suit la définition mathématique séparable de l'annexe A de l'UIT T.81. Les composantes sous-échantillonnées sont étendues aux dimensions de l'image par réplication du voisin le plus proche. Chaque ComponentPlane retourné possède donc une précision de 8, des échantillons non signés, une séparation de 1 et exactement largeur × hauteur octets, dans l'ordre original des composantes. Cette API ne redimensionne pas les images et n'assure pas la gestion des couleurs. L'interpolation et les DCT inverses entières d'autres décodeurs peuvent produire des valeurs légèrement différentes.
Règles de couleur
La transformation Adobe APP14 est prioritaire sur le colorTransform de la requête. Sans APP14, la valeur explicite 0 ou 1 s'applique ; lorsque les deux sont absents, trois composantes impliquent la transformation 1 et les autres nombres de composantes la transformation 0. JFIF et les identifiants R/G/B ne remplacent pas cette règle PDF. Le paramètre 1 est ignoré pour une ou deux composantes.
La transformation 0 préserve les valeurs décodées. La transformation 1 convertit YCbCr en RGB pour trois composantes, ou YCCK en CMYK pour quatre. Pour YCCK, les trois premières composantes transformées sont 255-R, 255-G, 255-B ; K reste inchangé. La valeur 2 du marqueur Adobe désigne explicitement YCCK et prévaut également sur ColorTransform. Il n'y a aucune inversion automatique de toutes les composantes CMYK ni conversion CMYK vers RGB. Les tableaux PDF /Decode, les espaces de couleurs et la gestion des couleurs relèvent de l'appelant.
ColorInformation indique Gray pour une composante, RGB/CMYK après la transformation correspondante, et Unknown pour plusieurs composantes non transformées : leur nombre ne détermine pas leur espace de couleurs PDF. Les fragments ICC APP2 sont assemblés dans l'ordre et conservés comme octets opaques dans iccProfile ; le profil n'est pas appliqué. Les fragments manquants, dupliqués ou incohérents sont rejetés.
Limites et erreurs
DecodeLimits borne les octets d'entrée et de sortie, les dimensions, les pixels, les composantes, les allocations mémoire cumulées, le travail, les marqueurs et les métadonnées. Les marqueurs de redémarrage consomment le même budget que les autres marqueurs. Les métadonnées comprennent les contenus APP/COM ignorés. Le stockage compact des coefficients signés évite une entrée de tableau PHP pour chaque coefficient. Les allocations sont vérifiées avant la création des buffers ; la DCT inverse et la lecture entropique consomment du travail. Les budgets sont réinitialisés à chaque appel, y compris après un échec. Le comptage des allocations est conservateur et cumulé ; il ne garantit pas la consommation mémoire totale du processus PHP. JPEG n'utilise ici ni arbre récursif ni tuiles : maxDepth et maxTiles n'ajoutent pas de limite propre à JPEG.
MalformedImage identifie les longueurs, tables, références, ordres de scans, bits de bourrage ou redémarrages invalides. ResourceLimit identifie un budget épuisé. UnsupportedFeature identifie un processus extérieur à ce profil DCT PDF : échantillons autres que huit bits, codage arithmétique, JPEG sans perte/hiérarchique, hauteur dépendant de DNL ou marqueur d'extension non pris en charge. Le décodeur ne répare pas les scans manquants, n'invente pas de hauteur, ne saute pas les données entropiques endommagées et ne réduit pas silencieusement la précision. SOI, une trame, les données DC initiales de chaque composante et EOI sont requis ; les octets qui suivent EOI sont extérieurs à l'image décodée.
Validation reproductible et provenance
php vendor/bin/phpunit tests/Jpeg
python -m pip install --require-hashes -r tools/jpeg-validation-requirements.txt
python tools/validate_jpeg.py --php php --report _build/jpeg-validation.json
L'oracle nécessite pdfimages de Poppler et Python 3.13 ou ultérieur. Ses 25 fichiers encodés indépendamment couvrent les données séquentielles/progressives, redémarrages, dimensions impaires, gris/RGB/CMYK/YCCK, images Adobe codées en RGB, scans séparés et sous-échantillonnage horizontal/vertical. Chaque coefficient quantifié est comparé exactement à IJG libjpeg via jpeglib. Les pixels utilisent une tolérance maximale explicite de 1 niveau pour le gris/CMYK brut et de 3 pour RGB/YCCK transformé, avec erreur moyenne ≤0,15 et interpolation améliorée désactivée pour comparer la même politique de réplication. Quatorze cas à composantes de pleine résolution comparent également les images PDF JPEG et à composantes décodées extraites par Poppler, avec une tolérance maximale de 3. La sortie Poppler sous-échantillonnée n'est pas un oracle pixel, car son interpolation diffère.
Les tests unitaires couvrent aussi les coefficients connus, deux composantes, SOF1 et les quantificateurs sur 16 bits, l'échantillonnage fractionnaire 3:2, la réutilisation des tables, la priorité APP14, K inchangé, ICC, les scans malformés et les budgets. tools/jpeg_generate.py régénère les fichiers conservés avec les encodeurs indépendants Pillow/libjpeg et jpeglib ; leurs empreintes et les versions des encodeurs figurent dans le manifeste. Ces tests établissent les cas indiqués, sans prouver une conformité JPEG universelle.
Les algorithmes entropiques progressifs ont été étudiés et adaptés depuis Mozilla PDF.js à la révision 24a63a4d488d4fe26c2a5ca32216ac9698d0de59 (Apache-2.0). Les empreintes exactes, mentions, licence et limites de l'adaptation sont conservées dans resources/jpeg. Son API de rendu, sa récupération d'erreurs et sa DCT inverse n'ont pas été portées. Les références normatives sont ISO 32000-2 §7.4.8, UIT T.81 annexes A/B/C/F/G et Adobe Technical Note 5116 §§6, 13, 15 et 18.