1<?php
2
3namespace Mpdf\Writer;
4
5use Mpdf\Strict;
6use Mpdf\Mpdf;
7
8final class ImageWriter
9{
10
11	use Strict;
12
13	/**
14	 * @var \Mpdf\Mpdf
15	 */
16	private $mpdf;
17
18	/**
19	 * @var \Mpdf\Writer\BaseWriter
20	 */
21	private $writer;
22
23	public function __construct(Mpdf $mpdf, BaseWriter $writer)
24	{
25		$this->mpdf = $mpdf;
26		$this->writer = $writer;
27	}
28
29	public function writeImages()
30	{
31		$filter = $this->mpdf->compress ? '/Filter /FlateDecode ' : '';
32
33		foreach ($this->mpdf->images as $file => $info) {
34
35			$this->writer->object();
36
37			$this->mpdf->images[$file]['n'] = $this->mpdf->n;
38
39			$this->writer->write('<</Type /XObject');
40			$this->writer->write('/Subtype /Image');
41			$this->writer->write('/Width ' . $info['w']);
42			$this->writer->write('/Height ' . $info['h']);
43
44			if (isset($info['interpolation']) && $info['interpolation']) {
45				$this->writer->write('/Interpolate true'); // mPDF 6 - image interpolation shall be performed by a conforming reader
46			}
47
48			if (isset($info['masked'])) {
49				$this->writer->write('/SMask ' . ($this->mpdf->n - 1) . ' 0 R');
50			}
51
52			// set color space
53			$icc = false;
54			if (isset($info['icc']) && ( $info['icc'] !== false)) {
55				// ICC Colour Space
56				$icc = true;
57				$this->writer->write('/ColorSpace [/ICCBased ' . ($this->mpdf->n + 1) . ' 0 R]');
58			} elseif ($info['cs'] === 'Indexed') {
59				if ($this->mpdf->PDFX || ($this->mpdf->PDFA && $this->mpdf->restrictColorSpace === 3)) {
60					throw new \Mpdf\MpdfException('PDFA1-b and PDFX/1-a files do not permit using mixed colour space (' . $file . ').');
61				}
62				$this->writer->write('/ColorSpace [/Indexed /DeviceRGB ' . (strlen($info['pal']) / 3 - 1) . ' ' . ($this->mpdf->n + 1) . ' 0 R]');
63			} else {
64				$this->writer->write('/ColorSpace /' . $info['cs']);
65				if ($info['cs'] === 'DeviceCMYK') {
66					if ($this->mpdf->PDFA && $this->mpdf->restrictColorSpace !== 3) {
67						throw new \Mpdf\MpdfException('PDFA1-b does not permit Images using mixed colour space (' . $file . ').');
68					}
69					if ($info['type'] === 'jpg') {
70						$this->writer->write('/Decode [1 0 1 0 1 0 1 0]');
71					}
72				} elseif (($this->mpdf->PDFX || ($this->mpdf->PDFA && $this->mpdf->restrictColorSpace === 3)) && $info['cs'] === 'DeviceRGB') {
73					throw new \Mpdf\MpdfException('PDFA1-b and PDFX/1-a files do not permit using mixed colour space (' . $file . ').');
74				}
75			}
76
77			$this->writer->write('/BitsPerComponent ' . $info['bpc']);
78
79			if (isset($info['f']) && $info['f']) {
80				$this->writer->write('/Filter /' . $info['f']);
81			}
82
83			if (isset($info['parms'])) {
84				$this->writer->write($info['parms']);
85			}
86
87			if (isset($info['trns']) && is_array($info['trns'])) {
88				$trns = '';
89				$maskCount = count($info['trns']);
90				for ($i = 0; $i < $maskCount; $i++) {
91					$trns .= $info['trns'][$i] . ' ' . $info['trns'][$i] . ' ';
92				}
93				$this->writer->write('/Mask [' . $trns . ']');
94			}
95
96			$this->writer->write('/Length ' . strlen($info['data']) . '>>');
97			$this->writer->stream($info['data']);
98
99			unset($this->mpdf->images[$file]['data']);
100
101			$this->writer->write('endobj');
102
103			if ($icc) { // ICC colour profile
104				$this->writer->object();
105				$icc = $this->mpdf->compress ? gzcompress($info['icc']) : $info['icc'];
106				$this->writer->write('<</N ' . $info['ch'] . ' ' . $filter . '/Length ' . strlen($icc) . '>>');
107				$this->writer->stream($icc);
108				$this->writer->write('endobj');
109			} elseif ($info['cs'] === 'Indexed') { // Palette
110				$this->writer->object();
111				$pal = $this->mpdf->compress ? gzcompress($info['pal']) : $info['pal'];
112				$this->writer->write('<<' . $filter . '/Length ' . strlen($pal) . '>>');
113				$this->writer->stream($pal);
114				$this->writer->write('endobj');
115			}
116		}
117	}
118
119}
120