read($files['rgb.jpg']); $rgba = $pngDecoder->decode($files['rgba.png']); $cmyk = $jpegReader->read($files['cmyk.jpg']); $palette = $pngDecoder->decode($files['palette.png']); // 3. Composition creates the /Subtype /Image streams from Table 89. // JPEG remains DCTDecode byte for byte. PNG is reconstructed, then // compressed with FlateDecode; its alpha becomes another /SMask stream. // Mask references are discovered through the writer's graph. $factory = new ImageXObjectFactory(); $images = [ 'JpegRGB' => $factory->create($rgb), 'PngRGBA' => $factory->create($rgba), 'JpegCMYK' => $factory->create($cmyk), 'PngPalette' => $factory->create($palette), ]; $imageEntries = []; foreach ($images as $name => $image) { $imageEntries[] = new Entry(new NameType($name), new IndirectReference($image)); } $helvetica = new Type1Font(StandardFont::Helvetica); $resources = new ResourceDictionary( new Font(new DictionaryType(new Entry(new NameType('F1'), new IndirectReference($helvetica)))), new XObject(new DictionaryType(...$imageEntries)), ); $operators = [ new SetNonstrokingRGBColor(new NumericType(0.08), new NumericType(0.18), new NumericType(0.28)), new BeginTextObject(), new SetTextFontAndSize(new NameType('F1'), new NumericType(24)), new MoveTextPosition(new NumericType(52), new NumericType(732)), new ShowText(new LiteralString('JPEG et PNG : des octets aux objets PDF')), new SetTextFontAndSize(new NameType('F1'), new NumericType(11)), new MoveTextPosition(new NumericType(0), new NumericType(-26)), new ShowText(new LiteralString('Quatre images originales de 48 x 36 pixels. Taille sur la page : 216 x 162 points.')), new EndTextObject(), ]; // 4. Each PDF image occupies the unit square. The explicit matrix produces // a 216 × 162 rectangle, then translates it; there is no automatic placement. // A checkerboard behind images reveals both PNGs' alpha channels. $panels = [ ['JpegRGB', 52, 452, 'JPEG RGB', 'DCTDecode : les octets JPEG restent intacts.', 'Trois composantes, transformation YCbCr.'], ['PngRGBA', 328, 452, 'PNG avec alpha', 'FlateDecode + /SMask en niveaux de gris.', 'L\'opacite augmente de gauche a droite.'], ['JpegCMYK', 52, 190, 'JPEG Adobe CMYK', 'Quatre composantes et /Decode inverse.', 'Le marqueur Adobe explicite les couleurs.'], ['PngPalette', 328, 190, 'PNG palette et tRNS', 'Les indices sont developpes en RGB.', 'Quatre opacites : 0, 85, 170 et 255.'], ]; foreach ($panels as [$name, $x, $y, $title, $line1, $line2]) { $operators[] = new BeginTextObject(); $operators[] = new SetTextFontAndSize(new NameType('F1'), new NumericType(16)); $operators[] = new MoveTextPosition(new NumericType($x), new NumericType($y + 184)); $operators[] = new ShowText(new LiteralString($title)); $operators[] = new EndTextObject(); for ($row = 0; $row < 6; ++$row) { for ($column = 0; $column < 8; ++$column) { $operators[] = new SetNonstrokingGray(new NumericType(($row + $column) % 2 === 0 ? 0.85 : 0.98)); $operators[] = new AppendRectangle(new NumericType($x + $column * 27), new NumericType($y + $row * 27), new NumericType(27), new NumericType(27)); $operators[] = new FillPathNonzero(); } } $operators[] = new SaveGraphicsState(); $operators[] = new ConcatenateMatrix(new Matrix( new NumericType(216), new NumericType(0), new NumericType(0), new NumericType(162), new NumericType($x), new NumericType($y), )); $operators[] = new InvokeXObject(new NameType($name)); $operators[] = new RestoreGraphicsState(); $operators[] = new SetNonstrokingRGBColor(new NumericType(0.08), new NumericType(0.18), new NumericType(0.28)); $operators[] = new BeginTextObject(); $operators[] = new SetTextFontAndSize(new NameType('F1'), new NumericType(10)); $operators[] = new MoveTextPosition(new NumericType($x), new NumericType($y - 21)); $operators[] = new ShowText(new LiteralString($line1)); $operators[] = new MoveTextPosition(new NumericType(0), new NumericType(-17)); $operators[] = new ShowText(new LiteralString($line2)); $operators[] = new EndTextObject(); } // 5. The document graph follows previous tutorials: resources, content, // page, page tree and catalog, all as explicit objects. $contents = new StreamObject(new ContentStreams(...$operators)); $page = new PageObject( new Rectangle(new NumericType(0), new NumericType(0), new NumericType(612), new NumericType(792)), $resources, $contents, ); $pages = (new PageTreeNode())->addKid($page); $catalog = new DocumentCatalog($pages); $file = new FileStructure(new FileHeader('1.7'), new FileBody($catalog), new IndirectReference($catalog)); $path = $argv[1] ?? __DIR__ . '/image-files.pdf'; $file->writeTo($path); echo $path . PHP_EOL;