20.5. Рисование
Пред. | Глава 20. Zend_Pdf | След.

## 20.5. Рисование

### 20.5.1. Геометрия

PDF использует ту же самую геометрию, что и PostScript. Она начинается с нижнего левого угла страницы и по умолчанию измеряется в пойнтах (1/72 дюйма).

Размер страницы может быть получен из объекта страницы:

    $width  = $pdfPage->getWidth();
    $height = $pdfPage->getHeight();

### 20.5.2. Цвета

PDF имеет мощные возможности для представления цветов. Модуль Zend_Pdf поддерживает шкалу серого цвета, цветовые пространства RGB и CMYK. Они могут использоваться в любом месте, где требуется объект `Zend_Pdf_Color`. Классы `Zend_Pdf_Color_GrayScale`, `Zend_Pdf_Color_RGB` и `Zend_Pdf_Color_CMYK` предоставляют этот функционал:

    // $grayLevel (число с плавающей точкой)
    // 0.0 (черный) - 1.0 (белый)
    $color1 = new Zend_Pdf_Color_GrayScale($grayLevel);

    // $r, $g, $b (числа с плавающей точкой)
    // 0.0 (минимальная интенсивность) - 1.0 (максимальная интенсивность)
    $color2 = new Zend_Pdf_Color_RGB($r, $g, $b);

    // $c, $m, $y, $k (числа с плавающей точкой)
    // 0.0 (минимальная интенсивность) - 1.0 (максимальная интенсивность)
    $color3 = new Zend_Pdf_Color_CMYK($c, $m, $y, $k);

### 20.5.3. Рисование фигур

Все операции прорисовки могут быть выполнены в контексте страницы PDF.

Класс `Zend_Pdf_Page` предоставляет набор примитивов для рисования:

    /**
     * Рисует линию от x1,y1 до x2,y2.
     *
     * @param float $x1
     * @param float $y1
     * @param float $x2
     * @param float $y2
     */
    public function drawLine($x1, $y1, $x2, $y2);

    /**
     * Рисует прямоугольник.
     *
     * Fill types:
     * Zend_Pdf_Const::SHAPEDRAW_FILLNSTROKE - заполнить прямоугольник и заштриховать (значение по умолчанию)
     * Zend_Pdf_Const::SHAPEDRAW_STROKE      - заштриховать прямоугольник
     * Zend_Pdf_Const::SHAPEDRAW_FILL        - заполнить прямоугольник
     *
     * @param float $x1
     * @param float $y1
     * @param float $x2
     * @param float $y2
     * @param integer $fillType
     */
    public function drawRectangle($x1, $y1, $x2, $y2, $fillType = Zend_Pdf_Const::SHAPEDRAW_FILLNSTROKE);

    /**
     * Риcует многоугольник.
     *
     * Если $fillType (тип заполнения) равен Zend_Pdf_Const::SHAPEDRAW_FILLNSTROKE
     * или Zend_Pdf_Const::SHAPEDRAW_FILL, то многоугольник будет автоматически замкнут.
     * См. более подробное описание этих методов в документации PDF
     * (section 4.4.2 Path painting Operators, Filling)
     *
     * @param array $x  - массив чисел с плавающей точкой (X-координаты вершин)
     * @param array $y  - массив чисел с плавающей точкой (Y-координаты вершин)
     * @param integer $fillType
     * @param integer $fillMethod
     */
    public function drawPolygon($x, $y,
                                $fillType = Zend_Pdf_Const::SHAPEDRAW_FILLNSTROKE,
                                $fillMethod = Zend_Pdf_Const::FILLMETHOD_NONZEROWINDING);

    /**
     * Рисует окружность, центр которой находится в точке с координатами x и y,
     * с радиусом radius.
     *
     * Углы задаются в радианах.
     *
     * Сигнатуры метода:
     * drawCircle($x, $y, $radius);
     * drawCircle($x, $y, $radius, $fillType);
     * drawCircle($x, $y, $radius, $startAngle, $endAngle);
     * drawCircle($x, $y, $radius, $startAngle, $endAngle, $fillType);
     *
     *
     * Это не настоящая окружность, так как PDF поддерживает только кубические кривые Безье.
     * Но в очень хорошем приближении.
     * Она отличается от реальной окружности максимум на 0.00026 доли радиуса
     * (на углах PI/8, 3*PI/8, 5*PI/8, 7*PI/8, 9*PI/8, 11*PI/8, 13*PI/8 и 15*PI/8).
     * На углах 0, PI/4, PI/2, 3*PI/4, PI, 5*PI/4, 3*PI/2 и 7*PI/4 это точная касательная к окружности.
     *
     * @param float $x
     * @param float $y
     * @param float $radius
     * @param mixed $param4
     * @param mixed $param5
     * @param mixed $param6
     */
    public function  drawCircle($x, $y, $radius, $param4 = null, $param5 = null, $param6 = null);

    /**
     * Рисует эллипс внутри заданного прямоугольника.
     *
     * Сигнатуры метода:
     * drawEllipse($x1, $y1, $x2, $y2);
     * drawEllipse($x1, $y1, $x2, $y2, $fillType);
     * drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle);
     * drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle, $fillType);
     *
     * Углы задаются в радианах.
     *
     * @param float $x1
     * @param float $y1
     * @param float $x2
     * @param float $y2
     * @param mixed $param5
     * @param mixed $param6
     * @param mixed $param7
     */
    public function drawEllipse($x1, $y1, $x2, $y2, $param5 = null, $param6 = null, $param7 = null);

### 20.5.4. Написание текста

Операции по написанию текста также существуют в контексте страницы PDF.

    /**
     * Выводит строку текста в заданной позиции.
     *
     * @param string $text
     * @param float $x
     * @param float $y
     * @throws Zend_Pdf_Exception
     */
    public function drawText($text, $x, $y );

Для написания текста используются текущий шрифт и его текущий размер. См. подробное описание ниже.

### 20.5.5. Применение шрифтов

Метод `Zend_Pdf_Page::drawText()` использует текущий шрифт, который может быть установлен методом `Zend_Pdf_Page::setFont()`:

    /**
     * Устанавливает текущий шрифт.
     *
     * @param Zend_Pdf_Font $font
     * @param float $fontSize
     */
    public function setFont(Zend_Pdf_Font $font, $fontSize);

PDF поддерживает Type1, TrueType, Type3 и составные шрифты. Он предоставляет еще 14 стандартных шрифтов Type1. На данный момент модуль `Zend_Pdf` предусматривает только эти стандартные шрифты. Они могут быть получены с помощью класса `Zend_Pdf_Font_Standard`. Конкретный шрифт указывается в качестве аргумента конструктора.

Пример 20.5. Создание стандартного шрифта

    <?php
    ...
    // Создание нового шрифта
    $font = new Zend_Pdf_Font_Standard(Zend_Pdf_Const::FONT_HELVETICA);

    // Применение шрифта
    $pdfPage->setFont($font, 36);
    ...
    ?>

Константы для 14 стандартных шрифтов определены с помощью класса `Zend_Pdf_Const`:

- Zend_Pdf_Const::FONT_TIMES_ROMAN

- Zend_Pdf_Const::FONT_TIMES_BOLD

- Zend_Pdf_Const::FONT_TIMES_ITALIC

- Zend_Pdf_Const::FONT_TIMES_BOLDITALIC

- Zend_Pdf_Const::FONT_HELVETICA

- Zend_Pdf_Const::FONT_HELVETICA_BOLD

- Zend_Pdf_Const::FONT_HELVETICA_ITALIC

- Zend_Pdf_Const::FONT_HELVETICA_BOLDITALIC

- Zend_Pdf_Const::FONT_COURIER

- Zend_Pdf_Const::FONT_COURIER_BOLD

- Zend_Pdf_Const::FONT_COURIER_ITALIC

- Zend_Pdf_Const::FONT_COURIER_BOLDITALIC

- Zend_Pdf_Const::FONT_SYMBOL

- Zend_Pdf_Const::FONT_ZAPFDINGBATS

### 20.5.6. Рисование изображений

Класс предоставляет метод `drawImage()` для рисования изображений.

    /**
     * Рисует изображение в заданной позиции на странице.
     *
     * @param Zend_Pdf_Image $image
     * @param float $x1
     * @param float $y1
     * @param float $x2
     * @param float $y2
     */
    public function drawImage(Zend_Pdf_Image $image, $x1, $y1, $x2, $y2);

Объекты изображения представляются потомками класса `Zend_Pdf_Image`.

Сейчас поддерживаются изображения JPG, PNG и TIFF.

Пример 20.6. Рисование изображений

    <?php
    ...
    //Создаем объект изображения непосредственно
    $image = new Zend_Pdf_Image_JPEG('my_image.jpg');
    $image = new Zend_Pdf_Image_TIFF('my_image.tiff');
    $image = new Zend_Pdf_Image_PNG('my_image.png');

    //либо используем Zend_Pdf_ImageFactory для загрузки соответствующего типа
    $image = Zend_Pdf_ImageFactory::factory('my_image.jpg');

    $pdfPage->drawImage($image, 100, 100, 400, 300);
    ...
    ?>

Важно! Класс `Zend_Pdf_Image_JPEG` требует сконфигурированного расширения GD. Важно! Класс `Zend_Pdf_Image_PNG` требует расширения ZLIB, сконфигурированного для работы с изображениями с Альфа-каналом.

См. документацию PHP за более подробной информацией (http://www.php.net/manual/en/ref.image.php). (http://www.php.net/manual/en/ref.zlib.php).

### 20.5.7. Стили рисования линий

Стили рисования линий определяются толщиной линии, цветом линии и шаблоном пунктира. Все эти параметры могут быть определены методами класса `Zend_Pdf_Page`.

    /** Установка цвета линии. */
    public function setLineColor(Zend_Pdf_Color $color);

    /** Установка толщины линии. */
    public function setLineWidth(float $width);

    /**
     * Установка шаблона пунктира.
     *
     * $pattern (шаблон) является массивом чисел с плавающей точкой:
     * array(on_length, off_length, on_length, off_length, ...)
     * $phase (фаза) является сдвигом от начала линии.
     *
     * @param array $pattern
     * @param array $phase
     */
    public function setLineDashingPattern($pattern, $phase = 0);

### 20.5.8. Стиль заполнения

Методы `Zend_Pdf_Page::drawRectangle()`, `Zend_Pdf_Page::drawPoligon()`, `Zend_Pdf_Page::drawCircle()` и `Zend_Pdf_Page::drawEllipse()` принимают аргумент `$fillType` как необязательный параметр. Это может быть:

- Zend_Pdf_Const::SHAPEDRAW_STROKE - штрихует фигуру

- Zend_Pdf_Const::SHAPEDRAW_FILL - заполняет фигуру

- Zend_Pdf_Const::SHAPEDRAW_FILLNSTROKE - заполняет и штрихует (поведение по умолчанию)

Метод `Zend_Pdf_Page::drawPoligon()` принимает дополнительный параметр `$fillMethod`:

- Zend_Pdf_Const::FILLMETHOD_NONZEROWINDING (поведение по умолчанию)

  Справка по PDF описывает это правило следующим образом:

  > Правило ненулевого количества витков определяет, находится ли данная точка внутри траектории путем мысленного проведения луча из этой точки в бесконечность в любом направлении и последующего определения мест, где участок траектории пересекает луч. Начиная отсчет с нуля, правило добавляет 1 каждый раз, когда участок траектории пересекает луч слева направо и отнимает 1 каждый раз, когда участок траектории пересекает участок справа налево. Если после подсчета всех пересечений результатом будет 0, то точка находится вне траектории, иначе — внутри траектории. Примечание: Метод не указывает, что делать, если участок траектории совпадает или является касательной к выбранному лучу. Поскольку направление луча является произвольным, правило просто выбирает луч, который не создает таких пересечений. Для простых выпуклых траекторий правило ненулевого количества витков определяет внутреннюю и внешнюю части так, как это интуитивно предполагается. Более интересными случаями являются те, которые включают в себя сложные или самопересекающиеся траектории, как, например, на Рис. 4.10 (в справке по PDF). Для траектории, представляющую собой пятиконечную звезду, состоящую из пяти соединенных отрезков, правило считает внутренней частью всю площадь, окруженную звездой, включая пятиугольник в центре. Для траектории, состоящей из двух концентрических окружностей, площадь, окруженная обеими окружностями, считается внутренней в том случае, если обе окружности нарисованы в одном и том же направлении. Если окружности нарисованы в противоположных направлениях, то, согласно правилу, только фигура в виде баранки между ними будет внутренней частью, "дырка" будет внешней частью.

- Zend_Pdf_Const::FILLMETHOD_EVENODD

  Справка по PDF описывает это правило следующим образом:

  > Альтернативой правилу ненулевого количества витков является правило чета-нечета. Это правило определяет нахождение точки проведением луча из этой точки в любом направлении и простым подсчетом количества пересечений частей траектории с этим лучом, независимо от направления пересечения. Если число нечетное, то точка находится во внутренней части; если четное, то точка находится снаружи. Это правило дает такой же результат, как и правило ненулевого количества витков для траекторий с простыми фигурами, но дает разные результаты в случае более сложных фигур. Рис. 4.11 (в справке по PDF) показывает результаты применения правила чета-нечета к сложным фигурам. В случае пятиконечной звезды правило считает точки треугольников находящимися внутри траектории, но не пятиугольник в центре. Для двух концентрических окружностей только фигура в виде баранки будет считаться внутренней частью, независимо от направлений, в которых нарисованы окружности.

### 20.5.9. Поворот

Страница PDF может быть повернута перед применением любых операций рисования. Это может быть сделано методом `Zend_Pdf_Page::rotate()`:

    /**
     * Поворачивает страницу вокруг точки ($x, $y) на заданный угол (в радианах).
     *
     * @param float $angle
     */
    public function rotate($x, $y, $angle);

### 20.5.10. Сохранение/восстановление графического состояния

В любое время графическое состояние страницы (текущий шрифт, размер шрифта, цвет линии, цвет заполнения, стиль линии, поворот страницы, область ограничения) может быть сохранено и после восстановлено. Операция сохранения сохраняет данные в стек графического состояния, операция восстановления извлекает данные из стека.

Методы в классе `Zend_Pdf_Page` для этих операций:

    /**
     * Сохраняет графическое состояние данной страницы.
     * Выполняет снимок используемых на данный момент стилей, положений, ... и всех
     * поворотов/преобразований/масштабирований которые были применены.
     * This takes a snapshot of the currently applied style, position, clipping area and
     * any rotation/translation/scaling that has been applied.
     */
    public function saveGS();

    /**
     * Восстанавливает графическое состояние, которое было сохранено последним
     * вызовом saveGS().
     */
    public function restoreGS();

### 20.5.11. Ограничение области рисования

PDF и модуль Zend_Pdf поддерживают ограничение области рисования. Ограничение определяет область страницы, затрагиваемой операциями рисования. Вначале эта область представляет собой всю страницу.

Класс `Zend_Pdf_Page` предоставляет набор методов для операций ограничения.

    /**
     * Делит текущую площадь ограничения с помощью прямоугольника.
     *
     * @param float $x1
     * @param float $y1
     * @param float $x2
     * @param float $y2
     */
    public function clipRectangle($x1, $y1, $x2, $y2);

    /**
     * Делит текущую площадь ограничения с помощью многоугольника.
     *
     * @param array $x  - массив чисел с плавающей точкой (X-координаты верхушек)
     * @param array $y  - массив чисел с плавающей точкой (Y-координаты верхушек)
     * @param integer $fillMethod
     */
    public function clipPolygon($x, $y, $fillMethod = Zend_Pdf_Const::FILLMETHOD_NONZEROWINDING);

    /**
     * Делит текущую площадь ограничения с помощью окружности.
     *
     * @param float $x
     * @param float $y
     * @param float $radius
     * @param float $startAngle
     * @param float $endAngle
     */
    public function clipCircle($x, $y, $radius, $startAngle = null, $endAngle = null);

    /**
     * Делит текущую площадь ограничения с помощью эллипса.
     *
     * Сигнатуры метода:
     * drawEllipse($x1, $y1, $x2, $y2);
     * drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle);
     *
     * @todo обрабатывать случаи, когда $x2-$x1 == 0 или $y2-$y1 == 0
     *
     * @param float $x1
     * @param float $y1
     * @param float $x2
     * @param float $y2
     * @param float $startAngle
     * @param float $endAngle
     */
    public function clipEllipse($x1, $y1, $x2, $y2, $startAngle = null, $endAngle = null);

### 20.5.12. Стили

Класс `Zend_Pdf_Style` предоставляет набор функциональных возможностей для работы со стилями.

Стили могут использоваться для сохранения набора параметров графического состояния и применять их к странице PDF одной операцией:

    /**
     * Установить стиль для будущих операций рисования на данной странице
     *
     * @param Zend_Pdf_Style $style
     */
    public function setStyle(Zend_Pdf_Style $style);

    /**
     * Возвращает стили, используемые на странице
     *
     * @return Zend_Pdf_Style|null
     */
    public function getStyle();

Класс `Zend_Pdf_Style` предоставляет набор методов для установки или получения различных параметров графического состояния:

    /**
     * Устанавливает цвет линии.
     *
     * @param Zend_Pdf_Color $color
     */
    public function setLineColor(Zend_Pdf_Color $color);

    /**
     * Возвращает цвет линии.
     *
     * @return Zend_Pdf_Color|null
     */
    public function getLineColor();

    /**
     * Устанавливает толщину линии.
     *
     * @param float $width
     */
    public function setLineWidth($width);

    /**
     * Возвращает толщину линии.
     *
     * @return float
     */
    public function getLineWidth();

    /**
     * Устанавливает шаблон пунктира.
     *
     * @param array $pattern
     * @param float $phase
     */
    public function setLineDashingPattern($pattern, $phase = 0);

    /**
     * Возвращает шаблон пунктира.
     *
     * @return array
     */
    public function getLineDashingPattern();

    /**
     * Возвращает фазу пунктира.
     *
     * @return float
     */
    public function getLineDashingPhase();

    /**
     * Устанавливает цвет заполнения.
     *
     * @param Zend_Pdf_Color $color
     */
    public function setFillColor(Zend_Pdf_Color $color);

    /**
     * Возвращает цвет заполнения.
     *
     * @return Zend_Pdf_Color|null
     */
    public function getFillColor();

    /**
     * Устанавливает текущий шрифт.
     *
     * @param Zend_Pdf_Font $font
     * @param float $fontSize
     */
    public function setFont(Zend_Pdf_Font $font, $fontSize);

    /**
     * Изменяет текущий размер шрифта
     *
     * @param float $fontSize
     */
    public function setFontSize($fontSize);

    /**
     * Возвращает текущий шрифт.
     *
     * @return Zend_Pdf_Font $font
     */
    public function getFont();

    /**
     * Возвращает текущий размер шрифта.
     *
     * @return float $fontSize
     */
    public function getFontSize();

Пред. | Уровень выше | След.
20.4. Страницы документа | Начало | 20.6. Пример использования модуля Zend_Pdf