Как заполнить PDF?

Как заполнить готовый бланк PDF?
  • Вопрос задан
  • 1602 просмотра
Решения вопроса 2
zenden2k
@zenden2k
PHP & C++ programmer
На самом деле, вопрос не так прост, как кажется.
После долгих мучений я так и не нашел идеального варианта.
Почти все решения, имеющиеся в инете, имеют проблемы с юникодом.
И тут проблема может быть не только в кодировке, а и то, что в pdf файле могут отсутствовать шрифты для нужных букв, или буквы отображаются каким-то нестандартным образом.
Почти все портят pdf файл или поддерживают далеко не все файлы (например защищенные или запакованные файл). Тут уж как повезет.
Еще решение зависит от того, нужно ли вам, чтобы поля оставались редактируемыми, или нет.
Если поля вы оставите редактируемыми, то может оказаться, что скажем значение в поле правильное, а отображается неправильно. Или наоборот, отображается правильно, а редактируется неправильное значение. Или вообще не отображается (например, в гугл хроме)
Все усложняется, если в форме есть комбобоксы, радиобаттоны и т.д.

Сперва надо узнать список полей программой pdftk:
pdftk samplex.pdf dump_data_fields

Вот мои варианты:

Вариант с zend1
нужен патченный zend pdf.php https://drive.google.com/file/d/0B_RKTUl10DcrOF9uZ...
весь архив с zend1 https://drive.google.com/file/d/0B_RKTUl10DcrbV8wN...

set_include_path(implode(PATH_SEPARATOR, array(
    realpath('./zend1/library/'),//the path
    get_include_path(),
)));
require "Zend/Loader/Autoloader.php";
$autoloader = Zend_Loader_Autoloader::getInstance();

$pdf = Zend_Pdf::load('form.pdf');
$pdf->setTextField("name","value");
$pdf->save('outputfile.pdf');


Вариант с FPDM:
$pdf = new FPDM('template.pdf');
$pdf->Load(array("field" => "value"), false); // second parameter: false if field values are in ISO-8859-1, true if UTF-8
$pdf->Merge();
$pdf->Output();


Вариант с xfdf файлом:
function createXFDF($file,$info,$enc='UTF-8'){
    $data=
        '<?xml version="1.0" encoding="'.$enc.'"?>
<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">
    <fields>';
    foreach($info as $field => $val){
        $data.='
        <field name="'.$field.'">';
        if(is_array($val)){
            foreach($val as $opt)
//2013.01.17 - Jon Hulka - all non-ascii characters get character references
            $data.='
            <value>'.mb_encode_numericentity(htmlspecialchars($opt),array(0x0080, 0xffff, 0, 0xffff), 'UTF-8').'</value>';
        }else{
            $data.='
            <value>'.mb_encode_numericentity(htmlspecialchars($val),array(0x0080, 0xffff, 0, 0xffff), 'UTF-8').'</value>';
        }
        $data.='
        </field>';
    }
    $data.='
    </fields>
    <ids original="'.md5($file).'" modified="'.time().'" />
    <f href="'.$file.'" />
</xfdf>';
    return $data;
}

$pdf = new FPDM('template.pdf', 'fields.fdf');
$pdf->Merge();
$pdf->Output();

Вариант с программой pdftk:
pdftk formfile.pdf fill_form fieldinfo.fdf output outputfile.pdf flatten

Если убрать flatten поля останутся редактируемыми.
fdf файл имеет формат:
%FDF-1.2
%,,oe"
1 0 obj
<<
/FDF << /Fields [
<< /T (CheckBox1) /V /A>>
<< /T (CheckBox2) /V /Off>>
<< /T (CheckBox3) /V /Off>>
<< /T (ComboBox1) /V (Option 1)>>
<< /T (ListBox1) /V (Item2)>>
<< /T (MultiLineText1) 
/V (This is a Multi-line text box. Note that the text wraps around to the next line!)>>
<< /T (RadioGroup1) /V /Yes>>
<< /T (TextBox1) /V (Sample Text)>>
]
/F (testfile.pdf)>>
>>
endobj
trailer
<<
/Root 1 0 R
>>
%%EOF


Вариант со встроенным javascript и скриптом addjstopdf.py (заполнение полей внутри просмотрщика с помощью javascript, поля остаются редактируемыми, работает в adobe reader, foxit, x-pdf, не работает в google chrome, едва ли работает в firefox, не работает в линуксе):
<?php
class Helper_Pdf {

    protected function build_pdf_javascript(array $fields) {
        $js = "app.alert({cMsg: \"Please fill out this form.\",cTitle: \"Title\", nIcon: 3});";
        foreach ( $fields as $key => $value) {
            if ( $value === null ) {
                $value = '';
            }
            $encodedValue = json_encode($value);
            $encodedValue = str_replace("\\u", "\\\\u", $encodedValue);
            $keyEncode = str_replace("\\u", "\\\\u", json_encode($key));
            $js .= " if ( this.getField($keyEncode) != null) {
            this.getField($keyEncode).value=$encodedValue;
            }
            ";
        }

        return $js;
    }

    function escapeJs($js) {
        $js = str_replace("(","\\(",$js);
        $js = str_replace(")","\\)",$js);
        $js = str_replace("/","\\/",$js);
        $js = str_replace("\r\n","\\r\\n",$js);
        return $js;
    }
    public function generate(){

        $addJsToPdfFilePath = DOCROOT . "plugins/addjstopdf/addjstopdf.py";
        $sourcePdf = DOCROOT . "data/pdf/rental_contract.pdf";
        $embeddedJsPath = DOCROOT . "data/pdf/js/" . uniqid().".js";

        $fields =
        array(
        'field1' => 'value'
        'field2' => 'value2'
        );

        $embeddedJs = $this->build_pdf_javascript($fields);
        file_put_contents($embeddedJsPath,$this->escapeJs($embeddedJs));
        $outFilePath = DOCROOT . "data/pdf/temp/" .  uniqid().".pdf";
        $pythonPath = Kohana::$is_windows ? "c:\\Python27\\python2.exe" : "/usr/bin/python2";
        $command = "$pythonPath $addJsToPdfFilePath -f $embeddedJsPath $sourcePdf $outFilePath";
        $command = str_replace( "\\","/", $command);
        system($command);
    }
}


Все варианты, кроме javascript, плохо работают с юникодом.
Ответ написан
Pjeroo
@Pjeroo
Веб-разработчик
www.fpdf.org - в руки, а дальше подбирать размеры, переносы, шрифты, положение.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы